/[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 226 by astrand, Fri Oct 11 09:37:48 2002 UTC revision 961 by astrand, Wed Aug 3 09:32:22 2005 UTC
# Line 1  Line 1 
1  /*  /*
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     Copyright (C) Matthew Chapman 1999-2002  
5       Copyright (C) Matthew Chapman 1999-2005
6       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
9     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 12  Line 14 
14     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.     GNU General Public License for more details.
17      
18     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */  */
22    
23    #ifdef RDP2VNC
24    #include "vnc/x11stubs.h"
25    #else
26  #include <X11/Xlib.h>  #include <X11/Xlib.h>
27  #define XK_MISCELLANY  #include <X11/keysym.h>
28  #include <X11/keysymdef.h>  #endif
29    
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    
37  #define KEYMAP_SIZE 4096  #define KEYMAP_SIZE 0xffff+1
38  #define KEYMAP_MASK (KEYMAP_SIZE - 1)  #define KEYMAP_MASK 0xffff
39  #define KEYMAP_MAX_LINE_LENGTH 80  #define KEYMAP_MAX_LINE_LENGTH 80
40    
41  extern Display *display;  extern Display *g_display;
42    extern Window g_wnd;
43  extern char keymapname[16];  extern char keymapname[16];
44  extern int keylayout;  extern int g_keylayout;
45  extern BOOL enable_compose;  extern int g_win_button_size;
46    extern BOOL g_enable_compose;
47    extern BOOL g_use_rdp5;
48    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;
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)
80          {          {
81                  error("Bad keysym %s in keymap %s\n", keyname, mapname);                  DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
82                  return;                  return;
83          }          }
84    
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 78  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 126  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 135  xkeymap_read(char *mapname) Line 273  xkeymap_read(char *mapname)
273                  if (strncmp(line, "enable_compose", 15) == 0)                  if (strncmp(line, "enable_compose", 15) == 0)
274                  {                  {
275                          DEBUG_KBD(("Enabling compose handling\n"));                          DEBUG_KBD(("Enabling compose handling\n"));
276                          enable_compose = True;                          g_enable_compose = True;
277                            continue;
278                    }
279    
280                    /* sequence */
281                    if (strncmp(line, "sequence", 8) == 0)
282                    {
283                            add_sequence(line + 8, mapname);
284                          continue;                          continue;
285                  }                  }
286    
# Line 198  xkeymap_read(char *mapname) Line 343  xkeymap_read(char *mapname)
343                          /* Automatically add uppercase key, with same modifiers                          /* Automatically add uppercase key, with same modifiers
344                             plus shift */                             plus shift */
345                          for (p = keyname; *p; p++)                          for (p = keyname; *p; p++)
346                                  *p = toupper(*p);                                  *p = toupper((int) *p);
347                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);
348                          add_to_keymap(keyname, scancode, modifiers, mapname);                          add_to_keymap(keyname, scancode, modifiers, mapname);
349                  }                  }
# Line 216  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(*mapname_ptr);  
   
364          if (strcmp(keymapname, "none"))          if (strcmp(keymapname, "none"))
365          {          {
366                  if (xkeymap_read(keymapname))                  if (xkeymap_read(keymapname))
367                          keymap_loaded = True;                          keymap_loaded = True;
368          }          }
369    
370          XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
371    }
372    
373    static void
374    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
375    {
376            uint8 winkey;
377    
378            if (leftkey)
379                    winkey = SCANCODE_CHAR_LWIN;
380            else
381                    winkey = SCANCODE_CHAR_RWIN;
382    
383            if (pressed)
384            {
385                    if (g_use_rdp5)
386                    {
387                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
388                    }
389                    else
390                    {
391                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
392                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
393                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
394                    }
395            }
396            else
397            {
398                    /* key released */
399                    if (g_use_rdp5)
400                    {
401                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
402                    }
403                    else
404                    {
405                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
406                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
407                    }
408            }
409    }
410    
411    static void
412    reset_winkey(uint32 ev_time)
413    {
414            if (g_use_rdp5)
415            {
416                    /* For some reason, it seems to suffice to release
417                     *either* the left or right winkey. */
418                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
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  {  {
426          switch (keysym)          switch (keysym)
427          {          {
428                  case XK_Break:                  case XK_Return:
                 case XK_Pause:  
429                          if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))                          if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
430                              && (get_key_state(state, XK_Control_L)                              && (get_key_state(state, XK_Control_L)
431                                  || get_key_state(state, XK_Control_R)))                                  || get_key_state(state, XK_Control_R)))
432                          {                          {
433                                  /* Ctrl-Alt-Break: toggle full screen */                                  /* Ctrl-Alt-Enter: toggle full screen */
434                                  if (pressed)                                  if (pressed)
435                                          xwin_toggle_fullscreen();                                          xwin_toggle_fullscreen();
436                                    return True;
437                            }
438                            break;
439    
440                    case XK_Break:
441                            /* Send Break sequence E0 46 E0 C6 */
442                            if (pressed)
443                            {
444                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
445                                                      (SCANCODE_EXTENDED | 0x46));
446                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
447                                                      (SCANCODE_EXTENDED | 0xc6));
448                          }                          }
449                          else if (keysym == XK_Break)                          /* No release sequence */
450                            return True;
451                            break;
452    
453                    case XK_Pause:
454                            /* According to MS Keyboard Scan Code
455                               Specification, pressing Pause should result
456                               in E1 1D 45 E1 9D C5. I'm not exactly sure
457                               of how this is supposed to be sent via
458                               RDP. The code below seems to work, but with
459                               the side effect that Left Ctrl stays
460                               down. Therefore, we release it when Pause
461                               is released. */
462                            if (pressed)
463                          {                          {
464                                  /* Send Break sequence E0 46 E0 C6 */                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
465                                  if (pressed)                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
466                                  {                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
467                                          rdp_send_scancode(ev_time, RDP_KEYPRESS,                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
468                                                            (SCANCODE_EXTENDED | 0x46));                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
469                                          rdp_send_scancode(ev_time, RDP_KEYPRESS,                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
                                                           (SCANCODE_EXTENDED | 0xc6));  
                                 }  
                                 /* No break sequence */  
470                          }                          }
471                          else    /* XK_Pause */                          else
472                          {                          {
473                                  /* According to MS Keyboard Scan Code                                  /* Release Left Ctrl */
474                                     Specification, pressing Pause should result                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
475                                     in E1 1D 45 E1 9D C5. I'm not exactly sure                                                 0x1d, 0);
                                    of how this is supposed to be sent via  
                                    RDP. The code below seems to work, but with  
                                    the side effect that Left Ctrl stays  
                                    down. Therefore, we release it when Pause  
                                    is released. */  
                                 if (pressed)  
                                 {  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0xe1, 0);  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0x1d, 0);  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0x45, 0);  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0xe1, 0);  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0x9d, 0);  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,  
                                                        0xc5, 0);  
                                 }  
                                 else  
                                 {  
                                         /* Release Left Ctrl */  
                                         rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,  
                                                        0x1d, 0);  
                                 }  
476                          }                          }
477                          return True;                          return True;
478                            break;
479    
480                  case XK_Meta_L: /* Windows keys */                  case XK_Meta_L: /* Windows keys */
481                  case XK_Super_L:                  case XK_Super_L:
482                  case XK_Hyper_L:                  case XK_Hyper_L:
483                            send_winkey(ev_time, pressed, True);
484                            return True;
485                            break;
486    
487                  case XK_Meta_R:                  case XK_Meta_R:
488                  case XK_Super_R:                  case XK_Super_R:
489                  case XK_Hyper_R:                  case XK_Hyper_R:
490                          if (pressed)                          send_winkey(ev_time, pressed, False);
491                          {                          return True;
492                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);                          break;
493                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);  
494                          }                  case XK_space:
495                          else                          /* Prevent access to the Windows system menu in single app mode */
496                          {                          if (g_win_button_size
497                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);                              && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
498                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);                                  return True;
499                          }                          break;
500    
501                    case XK_Num_Lock:
502                            /* Synchronize on key release */
503                            if (g_numlock_sync && !pressed)
504                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
505                                                   ui_get_numlock_state(read_keyboard_state()), 0);
506    
507                            /* Inhibit */
508                          return True;                          return True;
509                            break;
510    
511          }          }
512          return False;          return False;
513  }  }
# Line 319  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;
521    
522          tr = keymap[keysym & KEYMAP_MASK];          ptr = keymap[keysym & KEYMAP_MASK];
523            if (ptr)
         if (tr.modifiers & MapInhibitMask)  
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)                          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                            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                  error("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 ((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 406  get_ksname(uint32 keysym) Line 661  get_ksname(uint32 keysym)
661          return ksname;          return ksname;
662  }  }
663    
664    static BOOL
665  void  is_modifier(uint8 scancode)
 ensure_remote_modifiers(uint32 ev_time, key_translation tr)  
666  {  {
667          /* If this key is a modifier, do nothing */          switch (scancode)
         switch (tr.scancode)  
668          {          {
669                  case SCANCODE_CHAR_LSHIFT:                  case SCANCODE_CHAR_LSHIFT:
670                  case SCANCODE_CHAR_RSHIFT:                  case SCANCODE_CHAR_RSHIFT:
# Line 422  ensure_remote_modifiers(uint32 ev_time, Line 675  ensure_remote_modifiers(uint32 ev_time,
675                  case SCANCODE_CHAR_LWIN:                  case SCANCODE_CHAR_LWIN:
676                  case SCANCODE_CHAR_RWIN:                  case SCANCODE_CHAR_RWIN:
677                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
678                          return;                          return True;
679                  default:                  default:
680                          break;                          break;
681          }          }
682            return False;
683    }
684    
685    void
686    save_remote_modifiers(uint8 scancode)
687    {
688            if (is_modifier(scancode))
689                    return;
690    
691            saved_remote_modifier_state = remote_modifier_state;
692    }
693    
694    void
695    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
696    {
697            key_translation dummy;
698    
699            if (is_modifier(scancode))
700                    return;
701    
702            dummy.scancode = 0;
703            dummy.modifiers = saved_remote_modifier_state;
704            ensure_remote_modifiers(ev_time, dummy);
705    }
706    
707    void
708    ensure_remote_modifiers(uint32 ev_time, key_translation tr)
709    {
710            /* If this key is a modifier, do nothing */
711            if (is_modifier(tr.scancode))
712                    return;
713    
714            if (!g_numlock_sync)
715            {
716                    /* NumLock */
717                    if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
718                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
719                    {
720                            /* The remote modifier state is not correct */
721                            uint16 new_remote_state;
722    
723                            if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
724                            {
725                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
726                                    new_remote_state = KBD_FLAG_NUMLOCK;
727                                    remote_modifier_state = MapNumLockMask;
728                            }
729                            else
730                            {
731                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
732                                    new_remote_state = 0;
733                                    remote_modifier_state = 0;
734                            }
735    
736                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
737                    }
738            }
739    
740    
741          /* Shift. Left shift and right shift are treated as equal; either is fine. */          /* Shift. Left shift and right shift are treated as equal; either is fine. */
742          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
# Line 471  ensure_remote_modifiers(uint32 ev_time, Line 782  ensure_remote_modifiers(uint32 ev_time,
782                  }                  }
783          }          }
784    
         /* NumLock */  
         if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)  
             != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))  
         {  
                 /* The remote modifier state is not correct */  
                 uint16 new_remote_state = 0;  
785    
786                  if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))  }
                 {  
                         DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));  
                         new_remote_state |= KBD_FLAG_NUMLOCK;  
                 }  
                 else  
                 {  
                         DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));  
                 }  
787    
788                  rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);  
789                  update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);  unsigned int
790          }  read_keyboard_state()
791    {
792    #ifdef RDP2VNC
793            return 0;
794    #else
795            unsigned int state;
796            Window wdummy;
797            int dummy;
798    
799            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
800            return state;
801    #endif
802    }
803    
804    
805    uint16
806    ui_get_numlock_state(unsigned int state)
807    {
808            uint16 numlock_state = 0;
809    
810            if (get_key_state(state, XK_Num_Lock))
811                    numlock_state = KBD_FLAG_NUMLOCK;
812    
813            return numlock_state;
814  }  }
815    
816    
817  void  void
818  reset_modifier_keys(unsigned int state)  reset_modifier_keys()
819  {  {
820            unsigned int state = read_keyboard_state();
821    
822          /* reset keys */          /* reset keys */
823          uint32 ev_time;          uint32 ev_time;
824          ev_time = time(NULL);          ev_time = time(NULL);
# Line 521  reset_modifier_keys(unsigned int state) Line 843  reset_modifier_keys(unsigned int state)
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);
851    
852            if (g_numlock_sync)
853                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
854  }  }
855    
856    
# Line 564  update_modifier_state(uint8 scancode, BO Line 892  update_modifier_state(uint8 scancode, BO
892                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
893                          /* KeyReleases for NumLocks are sent immediately. Toggle the                          /* KeyReleases for NumLocks are sent immediately. Toggle the
894                             modifier state only on Keypress */                             modifier state only on Keypress */
895                          if (pressed)                          if (pressed && !g_numlock_sync)
896                          {                          {
897                                  BOOL newNumLockState;                                  BOOL newNumLockState;
898                                  newNumLockState =                                  newNumLockState =
# Line 573  update_modifier_state(uint8 scancode, BO Line 901  update_modifier_state(uint8 scancode, BO
901                                  MASK_CHANGE_BIT(remote_modifier_state,                                  MASK_CHANGE_BIT(remote_modifier_state,
902                                                  MapNumLockMask, newNumLockState);                                                  MapNumLockMask, newNumLockState);
903                          }                          }
                         break;  
904          }          }
905    
906  #ifdef WITH_DEBUG_KBD  #ifdef WITH_DEBUG_KBD

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

  ViewVC Help
Powered by ViewVC 1.1.26