showkeys.c 3.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/* Showkeys
   Copyright Noufal Ibrahim <noufal@nibrahim.net.in> 2011

   Licensed under the GPLv3 : http://www.gnu.org/licenses/gpl.txt

   Please see LICENSE file for complete license.
*/


#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/extensions/record.h>

#include <xosd.h>

#include "showkeys.h"
#include "keystack.h"

Display *d0, *d1;
KeyStack *keystack;
xosd *osd;


int
process_modifiers(KeySym ks, int * meta, int *ctrl, int *shift, int val)
{
  int modifier_pressed = 0;
  switch(ks) {
    case XK_Shift_L:
    case XK_Shift_R:
      *shift = val;
      modifier_pressed = 1;
      break;
    case XK_Control_L:
    case XK_Control_R:
      *ctrl = val;
      modifier_pressed = 1;
      break;
    case XK_Alt_L:
    case XK_Alt_R:
      *meta = val;       /* This is not accurate but it's correct for my keyboard mappings */
      modifier_pressed = 1;
      break;
  }
  return modifier_pressed;
}

char *
create_emacs_keyname(char *keyname, int meta, int ctrl, int shift)
{
  char *retval;
  /* TBD: Handle <. > and others like that wehere XLookupString gives the right values */
  printf("%d %d %d ", meta, ctrl, shift);
  asprintf(&retval, "%s%s%s%s", ctrl?"C-":"", meta?"M-":"", shift?"S-":"", keyname);
  printf(" %s\n",retval);
  return retval;
}

xosd *
configure_osd(int lines)
{
  xosd *osd;
  osd = xosd_create (NKEYS);
  //xosd_set_font(osd, "-adobe-courier-bold-r-normal--34-240-100-100-m-200-iso8859-1");
  xosd_set_font(osd, "-misc-fixed-bold-r-normal-*-18-*-*-*-*-90-iso8859-*");
  xosd_set_pos(osd, XOSD_top);
  xosd_set_align(osd, XOSD_right);

  xosd_set_colour(osd, "green");
  xosd_set_outline_colour(osd, "black");
  xosd_set_outline_offset(osd, 7);
  xosd_set_shadow_colour(osd, "grey");
  xosd_set_shadow_offset(osd, 0);

  xosd_set_timeout(osd, -1);
  return osd;
}

void
display_keystrokes(xosd *osd, KeyStack *stack)
{
  int i;
  for(i = 0; i < NKEYS; i++) {
    if (stack->keystrokes[i].keyname) {
  xosd_display(osd, i, XOSD_printf, "%s", stack->keystrokes[i].keyname);
    }
  }
}

void
update_key_ring (XPointer priv, XRecordInterceptData *data)
{
  static int meta = 0;
  static int ctrl = 0;
  static int shift = 0;
  xEvent *event;
  KeySym ks;
  char *display_string;
  char *ksname;
  if (data->category==XRecordFromServer) {
    event=(xEvent *)data->data;
    display_keystack(keystack);
    switch (event->u.u.type) {
      case KeyPress:
  ks = XKeycodeToKeysym(d0, event->u.u.detail, 0);
  ksname = XKeysymToString (ks); /* TBD: Might have to handle no symbol keys */
  if (! process_modifiers(ks, &meta, &ctrl, &shift, 1)) {
    display_string = create_emacs_keyname(ksname, meta, ctrl, shift);
    push(keystack, display_string);
    display_keystrokes(osd, keystack);
  }
  break;
      case KeyRelease:
  ks = XKeycodeToKeysym(d0, event->u.u.detail, 0);
  process_modifiers(ks, &meta, &ctrl, &shift, 0);
  break;
    }
  }
}


int
main()
{
  XRecordContext xrd;
  XRecordRange *range;
  XRecordClientSpec client;

  osd  = configure_osd(NKEYS);
  keystack = create_keystack(NKEYS);

  d0 = XOpenDisplay(NULL);
  d1 = XOpenDisplay(NULL);

  XSynchronize(d0, True);
  if (d0 == NULL || d1 == NULL) {
    fprintf(stderr, "Cannot connect to X server");
    exit (-1);
  }

  client=XRecordAllClients;

  range=XRecordAllocRange();
  memset(range, 0, sizeof(XRecordRange));
  range->device_events.first=KeyPress;
  range->device_events.last=KeyRelease;

  xrd = XRecordCreateContext(d0, 0, &client, 1, &range, 1);

  if (! xrd) {
    fprintf(stderr, "Error in creating context");
    exit (-1);
  }

  XRecordEnableContext(d1, xrd, update_key_ring, (XPointer)osd);

  XRecordProcessReplies (d1);


  XRecordDisableContext (d0, xrd);
  XRecordFreeContext (d0, xrd);


  XCloseDisplay(d0);
  XCloseDisplay(d1);
  exit(0);
}