/[rdesktop]/sourceforge.net/trunk/rdesktop/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 553 by astrand, Mon Dec 8 15:28:24 2003 UTC revision 961 by astrand, Wed Aug 3 09:32:22 2005 UTC
# Line 2  Line 2 
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X keyboard mapping     User interface services - X keyboard mapping
4    
5     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
6     Copyright (C) Peter Astrand <peter@cendio.se> 2003     Copyright (C) Peter Astrand <peter@cendio.se> 2003
7        
8     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
# Line 30  Line 30 
30  #include <ctype.h>  #include <ctype.h>
31  #include <limits.h>  #include <limits.h>
32  #include <time.h>  #include <time.h>
33    #include <string.h>
34  #include "rdesktop.h"  #include "rdesktop.h"
35  #include "scancodes.h"  #include "scancodes.h"
36    
# Line 40  Line 41 
41  extern Display *g_display;  extern Display *g_display;
42  extern Window g_wnd;  extern Window g_wnd;
43  extern char keymapname[16];  extern char keymapname[16];
44  extern int keylayout;  extern int g_keylayout;
45  extern int g_win_button_size;  extern int g_win_button_size;
46  extern BOOL g_enable_compose;  extern BOOL g_enable_compose;
47  extern BOOL g_use_rdp5;  extern BOOL g_use_rdp5;
48  extern BOOL g_numlock_sync;  extern BOOL g_numlock_sync;
49    
50  static BOOL keymap_loaded;  static BOOL keymap_loaded;
51  static key_translation keymap[KEYMAP_SIZE];  static key_translation *keymap[KEYMAP_SIZE];
52  static int min_keycode;  static int min_keycode;
53  static uint16 remote_modifier_state = 0;  static uint16 remote_modifier_state = 0;
54  static uint16 saved_remote_modifier_state = 0;  static uint16 saved_remote_modifier_state = 0;
55    
56  static void update_modifier_state(uint8 scancode, BOOL pressed);  static void update_modifier_state(uint8 scancode, BOOL pressed);
57    
58    /* Free key_translation structure, including linked list */
59    static void
60    free_key_translation(key_translation * ptr)
61    {
62            key_translation *next;
63    
64            while (ptr)
65            {
66                    next = ptr->next;
67                    xfree(ptr);
68                    ptr = next;
69            }
70    }
71    
72  static void  static void
73  add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)  add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
74  {  {
75          KeySym keysym;          KeySym keysym;
76            key_translation *tr;
77    
78          keysym = XStringToKeysym(keyname);          keysym = XStringToKeysym(keyname);
79          if (keysym == NoSymbol)          if (keysym == NoSymbol)
# Line 69  add_to_keymap(char *keyname, uint8 scanc Line 85  add_to_keymap(char *keyname, uint8 scanc
85          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
86                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
87    
88          keymap[keysym & KEYMAP_MASK].scancode = scancode;          tr = (key_translation *) xmalloc(sizeof(key_translation));
89          keymap[keysym & KEYMAP_MASK].modifiers = modifiers;          memset(tr, 0, sizeof(key_translation));
90            tr->scancode = scancode;
91            tr->modifiers = modifiers;
92            free_key_translation(keymap[keysym & KEYMAP_MASK]);
93            keymap[keysym & KEYMAP_MASK] = tr;
94    
95          return;          return;
96  }  }
97    
98    static void
99    add_sequence(char *rest, char *mapname)
100    {
101            KeySym keysym;
102            key_translation *tr, **prev_next;
103            size_t chars;
104            char keyname[KEYMAP_MAX_LINE_LENGTH];
105    
106            /* Skip over whitespace after the sequence keyword */
107            chars = strspn(rest, " \t");
108            rest += chars;
109    
110            /* Fetch the keysym name */
111            chars = strcspn(rest, " \t\0");
112            STRNCPY(keyname, rest, chars + 1);
113            rest += chars;
114    
115            keysym = XStringToKeysym(keyname);
116            if (keysym == NoSymbol)
117            {
118                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
119                    return;
120            }
121    
122    
123            DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
124    
125            free_key_translation(keymap[keysym & KEYMAP_MASK]);
126            prev_next = &keymap[keysym & KEYMAP_MASK];
127    
128            while (*rest)
129            {
130                    /* Skip whitespace */
131                    chars = strspn(rest, " \t");
132                    rest += chars;
133    
134                    /* Fetch the keysym name */
135                    chars = strcspn(rest, " \t\0");
136                    STRNCPY(keyname, rest, chars + 1);
137                    rest += chars;
138    
139                    keysym = XStringToKeysym(keyname);
140                    if (keysym == NoSymbol)
141                    {
142                            DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
143                                       mapname));
144                            return;
145                    }
146    
147                    /* Allocate space for key_translation structure */
148                    tr = (key_translation *) xmalloc(sizeof(key_translation));
149                    memset(tr, 0, sizeof(key_translation));
150                    *prev_next = tr;
151                    prev_next = &tr->next;
152                    tr->seq_keysym = keysym;
153    
154                    DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
155            }
156            DEBUG_KBD(("\n"));
157    }
158    
159    /* Joins two path components. The result should be freed with
160       xfree(). */
161    static char *
162    pathjoin(const char *a, const char *b)
163    {
164            char *result;
165            result = xmalloc(PATH_MAX * 2 + 1);
166    
167            if (b[0] == '/')
168            {
169                    strncpy(result, b, PATH_MAX);
170            }
171            else
172            {
173                    strncpy(result, a, PATH_MAX);
174                    strcat(result, "/");
175                    strncat(result, b, PATH_MAX);
176            }
177            return result;
178    }
179    
180    /* Try to open a keymap with fopen() */
181    FILE *
182    xkeymap_open(const char *filename)
183    {
184            char *path1, *path2;
185            char *home;
186            FILE *fp;
187    
188            /* Try ~/.rdesktop/keymaps */
189            home = getenv("HOME");
190            if (home)
191            {
192                    path1 = pathjoin(home, ".rdesktop/keymaps");
193                    path2 = pathjoin(path1, filename);
194                    xfree(path1);
195                    fp = fopen(path2, "r");
196                    xfree(path2);
197                    if (fp)
198                            return fp;
199            }
200    
201            /* Try KEYMAP_PATH */
202            path1 = pathjoin(KEYMAP_PATH, filename);
203            fp = fopen(path1, "r");
204            xfree(path1);
205            if (fp)
206                    return fp;
207    
208            /* Try current directory, in case we are running from the source
209               tree */
210            path1 = pathjoin("keymaps", filename);
211            fp = fopen(path1, "r");
212            xfree(path1);
213            if (fp)
214                    return fp;
215    
216            return NULL;
217    }
218    
219  static BOOL  static BOOL
220  xkeymap_read(char *mapname)  xkeymap_read(char *mapname)
221  {  {
222          FILE *fp;          FILE *fp;
223          char line[KEYMAP_MAX_LINE_LENGTH];          char line[KEYMAP_MAX_LINE_LENGTH];
         char path[PATH_MAX], inplace_path[PATH_MAX];  
224          unsigned int line_num = 0;          unsigned int line_num = 0;
225          unsigned int line_length = 0;          unsigned int line_length = 0;
226          char *keyname, *p;          char *keyname, *p;
# Line 89  xkeymap_read(char *mapname) Line 228  xkeymap_read(char *mapname)
228          uint8 scancode;          uint8 scancode;
229          uint16 modifiers;          uint16 modifiers;
230    
231            fp = xkeymap_open(mapname);
         strcpy(path, KEYMAP_PATH);  
         strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));  
   
         fp = fopen(path, "r");  
232          if (fp == NULL)          if (fp == NULL)
233          {          {
234                  /* in case we are running from the source tree */                  error("Failed to open keymap %s\n", mapname);
235                  strcpy(inplace_path, "keymaps/");                  return False;
                 strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));  
   
                 fp = fopen(inplace_path, "r");  
                 if (fp == NULL)  
                 {  
                         error("Failed to open keymap %s\n", path);  
                         return False;  
                 }  
236          }          }
237    
238          /* FIXME: More tolerant on white space */          /* FIXME: More tolerant on white space */
# Line 137  xkeymap_read(char *mapname) Line 264  xkeymap_read(char *mapname)
264                  /* map */                  /* map */
265                  if (strncmp(line, "map ", 4) == 0)                  if (strncmp(line, "map ", 4) == 0)
266                  {                  {
267                          keylayout = strtol(line + 4, NULL, 16);                          g_keylayout = strtol(line + 4, NULL, 16);
268                          DEBUG_KBD(("Keylayout 0x%x\n", keylayout));                          DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
269                          continue;                          continue;
270                  }                  }
271    
# Line 150  xkeymap_read(char *mapname) Line 277  xkeymap_read(char *mapname)
277                          continue;                          continue;
278                  }                  }
279    
280                    /* sequence */
281                    if (strncmp(line, "sequence", 8) == 0)
282                    {
283                            add_sequence(line + 8, mapname);
284                            continue;
285                    }
286    
287                  /* Comment */                  /* Comment */
288                  if (line[0] == '#')                  if (line[0] == '#')
289                  {                  {
# Line 227  xkeymap_init(void) Line 361  xkeymap_init(void)
361          unsigned int max_keycode;          unsigned int max_keycode;
362          char *mapname_ptr;          char *mapname_ptr;
363    
         /* Make keymapname lowercase */  
         mapname_ptr = keymapname;  
         while (*mapname_ptr)  
         {  
                 *mapname_ptr = tolower((int) *mapname_ptr);  
                 mapname_ptr++;  
         }  
   
364          if (strcmp(keymapname, "none"))          if (strcmp(keymapname, "none"))
365          {          {
366                  if (xkeymap_read(keymapname))                  if (xkeymap_read(keymapname))
# Line 293  reset_winkey(uint32 ev_time) Line 419  reset_winkey(uint32 ev_time)
419          }          }
420  }  }
421    
422  /* Handles, for example, multi-scancode keypresses (which is not  /* Handle special key combinations */
    possible via keymap-files) */  
423  BOOL  BOOL
424  handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)  handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
425  {  {
# Line 372  handle_special_keys(uint32 keysym, unsig Line 497  handle_special_keys(uint32 keysym, unsig
497                              && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))                              && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
498                                  return True;                                  return True;
499                          break;                          break;
500    
501                  case XK_Num_Lock:                  case XK_Num_Lock:
502                          /* FIXME: We might want to do RDP_INPUT_SYNCHRONIZE here, if g_numlock_sync */                          /* Synchronize on key release */
503                          if (!g_numlock_sync)                          if (g_numlock_sync && !pressed)
504                                  /* Inhibit */                                  rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
505                                  return True;                                                 ui_get_numlock_state(read_keyboard_state()), 0);
506    
507                            /* Inhibit */
508                            return True;
509                          break;                          break;
510    
511          }          }
# Line 387  handle_special_keys(uint32 keysym, unsig Line 516  handle_special_keys(uint32 keysym, unsig
516  key_translation  key_translation
517  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
518  {  {
519          key_translation tr = { 0, 0 };          key_translation tr = { 0, 0, 0, 0 };
520            key_translation *ptr;
         tr = keymap[keysym & KEYMAP_MASK];  
521    
522          if (tr.modifiers & MapInhibitMask)          ptr = keymap[keysym & KEYMAP_MASK];
523            if (ptr)
524          {          {
525                  DEBUG_KBD(("Inhibiting key\n"));                  tr = *ptr;
526                  tr.scancode = 0;                  if (tr.seq_keysym == 0) /* Normal scancode translation */
527                  return tr;                  {
528          }                          if (tr.modifiers & MapInhibitMask)
529                            {
530                                    DEBUG_KBD(("Inhibiting key\n"));
531                                    tr.scancode = 0;
532                                    return tr;
533                            }
534    
535                            if (tr.modifiers & MapLocalStateMask)
536                            {
537                                    /* The modifiers to send for this key should be obtained
538                                       from the local state. Currently, only shift is implemented. */
539                                    if (state & ShiftMask)
540                                    {
541                                            tr.modifiers = MapLeftShiftMask;
542                                    }
543                            }
544    
545                            if ((tr.modifiers & MapLeftShiftMask)
546                                && ((remote_modifier_state & MapLeftCtrlMask)
547                                    || (remote_modifier_state & MapRightCtrlMask))
548                                && get_key_state(state, XK_Caps_Lock))
549                            {
550                                    DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
551                                    tr.modifiers ^= MapLeftShiftMask;
552                            }
553    
554          if (tr.modifiers & MapLocalStateMask)                          DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
555                                       tr.scancode, tr.modifiers));
556                    }
557            }
558            else
559          {          {
560                  /* The modifiers to send for this key should be obtained                  if (keymap_loaded)
561                     from the local state. Currently, only shift is implemented. */                          warning("No translation for (keysym 0x%lx, %s)\n", keysym,
562                  if (state & ShiftMask)                                  get_ksname(keysym));
563    
564                    /* not in keymap, try to interpret the raw scancode */
565                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
566                    {
567                            tr.scancode = keycode - min_keycode;
568    
569                            /* The modifiers to send for this key should be
570                               obtained from the local state. Currently, only
571                               shift is implemented. */
572                            if (state & ShiftMask)
573                            {
574                                    tr.modifiers = MapLeftShiftMask;
575                            }
576    
577                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
578                    }
579                    else
580                  {                  {
581                          tr.modifiers = MapLeftShiftMask;                          DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
582                  }                  }
583          }          }
584    
585          if (tr.scancode != 0)          return tr;
586          {  }
                 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",  
                            tr.scancode, tr.modifiers));  
                 return tr;  
         }  
587    
588          if (keymap_loaded)  void
589                  warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));  xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
590                      BOOL pressed)
591    {
592            key_translation tr, *ptr;
593            tr = xkeymap_translate_key(keysym, keycode, state);
594    
595          /* not in keymap, try to interpret the raw scancode */          if (tr.seq_keysym == 0)
         if (((int) keycode >= min_keycode) && (keycode <= 0x60))  
596          {          {
597                  tr.scancode = keycode - min_keycode;                  /* Scancode translation */
598                    if (tr.scancode == 0)
599                            return;
600    
601                  /* The modifiers to send for this key should be                  if (pressed)
                    obtained from the local state. Currently, only  
                    shift is implemented. */  
                 if (state & ShiftMask)  
602                  {                  {
603                          tr.modifiers = MapLeftShiftMask;                          save_remote_modifiers(tr.scancode);
604                            ensure_remote_modifiers(ev_time, tr);
605                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
606                            restore_remote_modifiers(ev_time, tr.scancode);
607                  }                  }
608                    else
609                  DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));                  {
610                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
611                    }
612                    return;
613          }          }
614          else  
615            /* Sequence, only on key down */
616            if (pressed)
617          {          {
618                  DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));                  ptr = &tr;
619                    do
620                    {
621                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
622                                       (unsigned int) ptr->seq_keysym));
623                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
624                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
625                            ptr = ptr->next;
626                    }
627                    while (ptr);
628          }          }
   
         return tr;  
629  }  }
630    
631  uint16  uint16
# Line 602  ensure_remote_modifiers(uint32 ev_time, Line 789  ensure_remote_modifiers(uint32 ev_time,
789  unsigned int  unsigned int
790  read_keyboard_state()  read_keyboard_state()
791  {  {
792    #ifdef RDP2VNC
793            return 0;
794    #else
795          unsigned int state;          unsigned int state;
796          Window wdummy;          Window wdummy;
797          int dummy;          int dummy;
798    
799          XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);          XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
800          return state;          return state;
801    #endif
802  }  }
803    
804    
# Line 652  reset_modifier_keys() Line 843  reset_modifier_keys()
843                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
844    
845          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
846              !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))              !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
847                && !get_key_state(state, XK_ISO_Level3_Shift))
848                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
849    
850          reset_winkey(ev_time);          reset_winkey(ev_time);

Legend:
Removed from v.553  
changed lines
  Added in v.961

  ViewVC Help
Powered by ViewVC 1.1.26