/[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 227 by astrand, Fri Oct 11 09:38:49 2002 UTC revision 973 by astrand, Thu Aug 4 12:44:10 2005 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
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_keyboard_type;
46    extern int g_keyboard_subtype;
47    extern int g_keyboard_functionkeys;
48    extern int g_win_button_size;
49    extern BOOL g_enable_compose;
50    extern BOOL g_use_rdp5;
51    extern BOOL g_numlock_sync;
52    
53  static BOOL keymap_loaded;  static BOOL keymap_loaded;
54  static key_translation keymap[KEYMAP_SIZE];  static key_translation *keymap[KEYMAP_SIZE];
55  static int min_keycode;  static int min_keycode;
56  static uint16 remote_modifier_state = 0;  static uint16 remote_modifier_state = 0;
57    static uint16 saved_remote_modifier_state = 0;
58    
59  static void update_modifier_state(uint8 scancode, BOOL pressed);  static void update_modifier_state(uint8 scancode, BOOL pressed);
60    
61    /* Free key_translation structure, including linked list */
62    static void
63    free_key_translation(key_translation * ptr)
64    {
65            key_translation *next;
66    
67            while (ptr)
68            {
69                    next = ptr->next;
70                    xfree(ptr);
71                    ptr = next;
72            }
73    }
74    
75  static void  static void
76  add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)  add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
77  {  {
78          KeySym keysym;          KeySym keysym;
79            key_translation *tr;
80    
81          keysym = XStringToKeysym(keyname);          keysym = XStringToKeysym(keyname);
82          if (keysym == NoSymbol)          if (keysym == NoSymbol)
83          {          {
84                  error("Bad keysym %s in keymap %s\n", keyname, mapname);                  DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
85                  return;                  return;
86          }          }
87    
88          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
89                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
90    
91          keymap[keysym & KEYMAP_MASK].scancode = scancode;          tr = (key_translation *) xmalloc(sizeof(key_translation));
92          keymap[keysym & KEYMAP_MASK].modifiers = modifiers;          memset(tr, 0, sizeof(key_translation));
93            tr->scancode = scancode;
94            tr->modifiers = modifiers;
95            free_key_translation(keymap[keysym & KEYMAP_MASK]);
96            keymap[keysym & KEYMAP_MASK] = tr;
97    
98          return;          return;
99  }  }
100    
101    static void
102    add_sequence(char *rest, char *mapname)
103    {
104            KeySym keysym;
105            key_translation *tr, **prev_next;
106            size_t chars;
107            char keyname[KEYMAP_MAX_LINE_LENGTH];
108    
109            /* Skip over whitespace after the sequence keyword */
110            chars = strspn(rest, " \t");
111            rest += chars;
112    
113            /* Fetch the keysym name */
114            chars = strcspn(rest, " \t\0");
115            STRNCPY(keyname, rest, chars + 1);
116            rest += chars;
117    
118            keysym = XStringToKeysym(keyname);
119            if (keysym == NoSymbol)
120            {
121                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
122                    return;
123            }
124    
125    
126            DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
127    
128            free_key_translation(keymap[keysym & KEYMAP_MASK]);
129            prev_next = &keymap[keysym & KEYMAP_MASK];
130    
131            while (*rest)
132            {
133                    /* Skip whitespace */
134                    chars = strspn(rest, " \t");
135                    rest += chars;
136    
137                    /* Fetch the keysym name */
138                    chars = strcspn(rest, " \t\0");
139                    STRNCPY(keyname, rest, chars + 1);
140                    rest += chars;
141    
142                    keysym = XStringToKeysym(keyname);
143                    if (keysym == NoSymbol)
144                    {
145                            DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
146                                       mapname));
147                            return;
148                    }
149    
150                    /* Allocate space for key_translation structure */
151                    tr = (key_translation *) xmalloc(sizeof(key_translation));
152                    memset(tr, 0, sizeof(key_translation));
153                    *prev_next = tr;
154                    prev_next = &tr->next;
155                    tr->seq_keysym = keysym;
156    
157                    DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
158            }
159            DEBUG_KBD(("\n"));
160    }
161    
162    BOOL
163    xkeymap_from_locale(const char *locale)
164    {
165            char *str, *ptr;
166            FILE *fp;
167    
168            /* Create a working copy */
169            str = strdup(locale);
170            if (str == NULL)
171            {
172                    perror("strdup");
173                    exit(1);
174            }
175    
176            /* Truncate at dot and at */
177            ptr = strrchr(str, '.');
178            if (ptr)
179                    *ptr = '\0';
180            ptr = strrchr(str, '@');
181            if (ptr)
182                    *ptr = '\0';
183    
184            /* Replace _ with - */
185            ptr = strrchr(str, '_');
186            if (ptr)
187                    *ptr = '-';
188    
189            /* Convert to lowercase */
190            ptr = str;
191            while (*ptr)
192            {
193                    *ptr = tolower((int) *ptr);
194                    ptr++;
195            }
196    
197            /* Try to open this keymap (da-dk) */
198            fp = xkeymap_open(str);
199            if (fp == NULL)
200            {
201                    /* Truncate at dash */
202                    ptr = strrchr(str, '-');
203                    if (ptr)
204                            *ptr = '\0';
205    
206                    /* Try the short name (da) */
207                    fp = xkeymap_open(str);
208            }
209    
210            if (fp)
211            {
212                    fclose(fp);
213                    STRNCPY(keymapname, str, sizeof(keymapname));
214                    return True;
215            }
216    
217            return False;
218    }
219    
220    
221    /* Joins two path components. The result should be freed with
222       xfree(). */
223    static char *
224    pathjoin(const char *a, const char *b)
225    {
226            char *result;
227            result = xmalloc(PATH_MAX * 2 + 1);
228    
229            if (b[0] == '/')
230            {
231                    strncpy(result, b, PATH_MAX);
232            }
233            else
234            {
235                    strncpy(result, a, PATH_MAX);
236                    strcat(result, "/");
237                    strncat(result, b, PATH_MAX);
238            }
239            return result;
240    }
241    
242    /* Try to open a keymap with fopen() */
243    FILE *
244    xkeymap_open(const char *filename)
245    {
246            char *path1, *path2;
247            char *home;
248            FILE *fp;
249    
250            /* Try ~/.rdesktop/keymaps */
251            home = getenv("HOME");
252            if (home)
253            {
254                    path1 = pathjoin(home, ".rdesktop/keymaps");
255                    path2 = pathjoin(path1, filename);
256                    xfree(path1);
257                    fp = fopen(path2, "r");
258                    xfree(path2);
259                    if (fp)
260                            return fp;
261            }
262    
263            /* Try KEYMAP_PATH */
264            path1 = pathjoin(KEYMAP_PATH, filename);
265            fp = fopen(path1, "r");
266            xfree(path1);
267            if (fp)
268                    return fp;
269    
270            /* Try current directory, in case we are running from the source
271               tree */
272            path1 = pathjoin("keymaps", filename);
273            fp = fopen(path1, "r");
274            xfree(path1);
275            if (fp)
276                    return fp;
277    
278            return NULL;
279    }
280    
281  static BOOL  static BOOL
282  xkeymap_read(char *mapname)  xkeymap_read(char *mapname)
283  {  {
284          FILE *fp;          FILE *fp;
285          char line[KEYMAP_MAX_LINE_LENGTH];          char line[KEYMAP_MAX_LINE_LENGTH];
         char path[PATH_MAX], inplace_path[PATH_MAX];  
286          unsigned int line_num = 0;          unsigned int line_num = 0;
287          unsigned int line_length = 0;          unsigned int line_length = 0;
288          char *keyname, *p;          char *keyname, *p;
# Line 78  xkeymap_read(char *mapname) Line 290  xkeymap_read(char *mapname)
290          uint8 scancode;          uint8 scancode;
291          uint16 modifiers;          uint16 modifiers;
292    
293            fp = xkeymap_open(mapname);
         strcpy(path, KEYMAP_PATH);  
         strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));  
   
         fp = fopen(path, "r");  
294          if (fp == NULL)          if (fp == NULL)
295          {          {
296                  /* in case we are running from the source tree */                  error("Failed to open keymap %s\n", mapname);
297                  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;  
                 }  
298          }          }
299    
300          /* FIXME: More tolerant on white space */          /* FIXME: More tolerant on white space */
# Line 116  xkeymap_read(char *mapname) Line 316  xkeymap_read(char *mapname)
316                  }                  }
317    
318                  /* Include */                  /* Include */
319                  if (strncmp(line, "include ", 8) == 0)                  if (strncmp(line, "include ", sizeof("include ") - 1) == 0)
320                  {                  {
321                          if (!xkeymap_read(line + 8))                          if (!xkeymap_read(line + sizeof("include ") - 1))
322                                  return False;                                  return False;
323                          continue;                          continue;
324                  }                  }
325    
326                  /* map */                  /* map */
327                  if (strncmp(line, "map ", 4) == 0)                  if (strncmp(line, "map ", sizeof("map ") - 1) == 0)
328                  {                  {
329                          keylayout = strtol(line + 4, NULL, 16);                          g_keylayout = strtol(line + sizeof("map ") - 1, NULL, 16);
330                          DEBUG_KBD(("Keylayout 0x%x\n", keylayout));                          DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
331                          continue;                          continue;
332                  }                  }
333    
334                  /* compose */                  /* compose */
335                  if (strncmp(line, "enable_compose", 15) == 0)                  if (strncmp(line, "enable_compose", sizeof("enable_compose") - 1) == 0)
336                  {                  {
337                          DEBUG_KBD(("Enabling compose handling\n"));                          DEBUG_KBD(("Enabling compose handling\n"));
338                          enable_compose = True;                          g_enable_compose = True;
339                            continue;
340                    }
341    
342                    /* sequence */
343                    if (strncmp(line, "sequence", sizeof("sequence") - 1) == 0)
344                    {
345                            add_sequence(line + sizeof("sequence") - 1, mapname);
346                            continue;
347                    }
348    
349                    /* keyboard_type */
350                    if (strncmp(line, "keyboard_type ", sizeof("keyboard_type ") - 1) == 0)
351                    {
352                            g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
353                            DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
354                            continue;
355                    }
356    
357                    /* keyboard_subtype */
358                    if (strncmp(line, "keyboard_subtype ", sizeof("keyboard_subtype ") - 1) == 0)
359                    {
360                            g_keyboard_subtype =
361                                    strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
362                            DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
363                            continue;
364                    }
365    
366                    /* keyboard_functionkeys */
367                    if (strncmp(line, "keyboard_functionkeys ", sizeof("keyboard_functionkeys ") - 1) ==
368                        0)
369                    {
370                            g_keyboard_functionkeys =
371                                    strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
372                            DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
373                          continue;                          continue;
374                  }                  }
375    
# Line 198  xkeymap_read(char *mapname) Line 432  xkeymap_read(char *mapname)
432                          /* Automatically add uppercase key, with same modifiers                          /* Automatically add uppercase key, with same modifiers
433                             plus shift */                             plus shift */
434                          for (p = keyname; *p; p++)                          for (p = keyname; *p; p++)
435                                  *p = toupper(*p);                                  *p = toupper((int) *p);
436                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);
437                          add_to_keymap(keyname, scancode, modifiers, mapname);                          add_to_keymap(keyname, scancode, modifiers, mapname);
438                  }                  }
# Line 214  void Line 448  void
448  xkeymap_init(void)  xkeymap_init(void)
449  {  {
450          unsigned int max_keycode;          unsigned int max_keycode;
         char *mapname_ptr;  
   
         /* Make keymapname lowercase */  
         mapname_ptr = keymapname;  
         while (*mapname_ptr)  
         {  
                 *mapname_ptr = tolower(*mapname_ptr);  
                 mapname_ptr++;  
         }  
451    
452          if (strcmp(keymapname, "none"))          if (strcmp(keymapname, "none"))
453          {          {
# Line 230  xkeymap_init(void) Line 455  xkeymap_init(void)
455                          keymap_loaded = True;                          keymap_loaded = True;
456          }          }
457    
458          XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
459    }
460    
461    static void
462    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
463    {
464            uint8 winkey;
465    
466            if (leftkey)
467                    winkey = SCANCODE_CHAR_LWIN;
468            else
469                    winkey = SCANCODE_CHAR_RWIN;
470    
471            if (pressed)
472            {
473                    if (g_use_rdp5)
474                    {
475                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
476                    }
477                    else
478                    {
479                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
480                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
481                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
482                    }
483            }
484            else
485            {
486                    /* key released */
487                    if (g_use_rdp5)
488                    {
489                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
490                    }
491                    else
492                    {
493                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
494                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
495                    }
496            }
497    }
498    
499    static void
500    reset_winkey(uint32 ev_time)
501    {
502            if (g_use_rdp5)
503            {
504                    /* For some reason, it seems to suffice to release
505                     *either* the left or right winkey. */
506                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
507            }
508  }  }
509    
510  /* Handles, for example, multi-scancode keypresses (which is not  /* Handle special key combinations */
    possible via keymap-files) */  
511  BOOL  BOOL
512  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)
513  {  {
514          switch (keysym)          switch (keysym)
515          {          {
516                  case XK_Break:                  case XK_Return:
                 case XK_Pause:  
517                          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))
518                              && (get_key_state(state, XK_Control_L)                              && (get_key_state(state, XK_Control_L)
519                                  || get_key_state(state, XK_Control_R)))                                  || get_key_state(state, XK_Control_R)))
520                          {                          {
521                                  /* Ctrl-Alt-Break: toggle full screen */                                  /* Ctrl-Alt-Enter: toggle full screen */
522                                  if (pressed)                                  if (pressed)
523                                          xwin_toggle_fullscreen();                                          xwin_toggle_fullscreen();
524                                    return True;
525                            }
526                            break;
527    
528                    case XK_Break:
529                            /* Send Break sequence E0 46 E0 C6 */
530                            if (pressed)
531                            {
532                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
533                                                      (SCANCODE_EXTENDED | 0x46));
534                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
535                                                      (SCANCODE_EXTENDED | 0xc6));
536                          }                          }
537                          else if (keysym == XK_Break)                          /* No release sequence */
538                            return True;
539                            break;
540    
541                    case XK_Pause:
542                            /* According to MS Keyboard Scan Code
543                               Specification, pressing Pause should result
544                               in E1 1D 45 E1 9D C5. I'm not exactly sure
545                               of how this is supposed to be sent via
546                               RDP. The code below seems to work, but with
547                               the side effect that Left Ctrl stays
548                               down. Therefore, we release it when Pause
549                               is released. */
550                            if (pressed)
551                          {                          {
552                                  /* Send Break sequence E0 46 E0 C6 */                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
553                                  if (pressed)                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
554                                  {                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
555                                          rdp_send_scancode(ev_time, RDP_KEYPRESS,                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
556                                                            (SCANCODE_EXTENDED | 0x46));                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
557                                          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 */  
558                          }                          }
559                          else    /* XK_Pause */                          else
560                          {                          {
561                                  /* According to MS Keyboard Scan Code                                  /* Release Left Ctrl */
562                                     Specification, pressing Pause should result                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
563                                     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);  
                                 }  
564                          }                          }
565                          return True;                          return True;
566                            break;
567    
568                  case XK_Meta_L: /* Windows keys */                  case XK_Meta_L: /* Windows keys */
569                  case XK_Super_L:                  case XK_Super_L:
570                  case XK_Hyper_L:                  case XK_Hyper_L:
571                            send_winkey(ev_time, pressed, True);
572                            return True;
573                            break;
574    
575                  case XK_Meta_R:                  case XK_Meta_R:
576                  case XK_Super_R:                  case XK_Super_R:
577                  case XK_Hyper_R:                  case XK_Hyper_R:
578                          if (pressed)                          send_winkey(ev_time, pressed, False);
579                          {                          return True;
580                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);                          break;
581                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);  
582                          }                  case XK_space:
583                          else                          /* Prevent access to the Windows system menu in single app mode */
584                          {                          if (g_win_button_size
585                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);                              && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
586                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);                                  return True;
587                          }                          break;
588    
589                    case XK_Num_Lock:
590                            /* Synchronize on key release */
591                            if (g_numlock_sync && !pressed)
592                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
593                                                   ui_get_numlock_state(read_keyboard_state()), 0);
594    
595                            /* Inhibit */
596                          return True;                          return True;
597                            break;
598    
599          }          }
600          return False;          return False;
601  }  }
# Line 322  handle_special_keys(uint32 keysym, unsig Line 604  handle_special_keys(uint32 keysym, unsig
604  key_translation  key_translation
605  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
606  {  {
607          key_translation tr = { 0, 0 };          key_translation tr = { 0, 0, 0, 0 };
608            key_translation *ptr;
609    
610          tr = keymap[keysym & KEYMAP_MASK];          ptr = keymap[keysym & KEYMAP_MASK];
611            if (ptr)
         if (tr.modifiers & MapInhibitMask)  
612          {          {
613                  DEBUG_KBD(("Inhibiting key\n"));                  tr = *ptr;
614                  tr.scancode = 0;                  if (tr.seq_keysym == 0) /* Normal scancode translation */
615                  return tr;                  {
616          }                          if (tr.modifiers & MapInhibitMask)
617                            {
618                                    DEBUG_KBD(("Inhibiting key\n"));
619                                    tr.scancode = 0;
620                                    return tr;
621                            }
622    
623                            if (tr.modifiers & MapLocalStateMask)
624                            {
625                                    /* The modifiers to send for this key should be obtained
626                                       from the local state. Currently, only shift is implemented. */
627                                    if (state & ShiftMask)
628                                    {
629                                            tr.modifiers = MapLeftShiftMask;
630                                    }
631                            }
632    
633          if (tr.modifiers & MapLocalStateMask)                          if ((tr.modifiers & MapLeftShiftMask)
634                                && ((remote_modifier_state & MapLeftCtrlMask)
635                                    || (remote_modifier_state & MapRightCtrlMask))
636                                && get_key_state(state, XK_Caps_Lock))
637                            {
638                                    DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
639                                    tr.modifiers ^= MapLeftShiftMask;
640                            }
641    
642                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
643                                       tr.scancode, tr.modifiers));
644                    }
645            }
646            else
647          {          {
648                  /* The modifiers to send for this key should be obtained                  if (keymap_loaded)
649                     from the local state. Currently, only shift is implemented. */                          warning("No translation for (keysym 0x%lx, %s)\n", keysym,
650                  if (state & ShiftMask)                                  get_ksname(keysym));
651    
652                    /* not in keymap, try to interpret the raw scancode */
653                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
654                    {
655                            tr.scancode = keycode - min_keycode;
656    
657                            /* The modifiers to send for this key should be
658                               obtained from the local state. Currently, only
659                               shift is implemented. */
660                            if (state & ShiftMask)
661                            {
662                                    tr.modifiers = MapLeftShiftMask;
663                            }
664    
665                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
666                    }
667                    else
668                  {                  {
669                          tr.modifiers = MapLeftShiftMask;                          DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
670                  }                  }
671          }          }
672    
673          if (tr.scancode != 0)          return tr;
674          {  }
                 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",  
                            tr.scancode, tr.modifiers));  
                 return tr;  
         }  
675    
676          if (keymap_loaded)  void
677                  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,
678                      BOOL pressed)
679    {
680            key_translation tr, *ptr;
681            tr = xkeymap_translate_key(keysym, keycode, state);
682    
683          /* not in keymap, try to interpret the raw scancode */          if (tr.seq_keysym == 0)
         if ((keycode >= min_keycode) && (keycode <= 0x60))  
684          {          {
685                  tr.scancode = keycode - min_keycode;                  /* Scancode translation */
686                    if (tr.scancode == 0)
687                            return;
688    
689                  /* The modifiers to send for this key should be                  if (pressed)
                    obtained from the local state. Currently, only  
                    shift is implemented. */  
                 if (state & ShiftMask)  
690                  {                  {
691                          tr.modifiers = MapLeftShiftMask;                          save_remote_modifiers(tr.scancode);
692                            ensure_remote_modifiers(ev_time, tr);
693                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
694                            restore_remote_modifiers(ev_time, tr.scancode);
695                  }                  }
696                    else
697                  DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));                  {
698                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
699                    }
700                    return;
701          }          }
702          else  
703            /* Sequence, only on key down */
704            if (pressed)
705          {          {
706                  DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));                  ptr = &tr;
707                    do
708                    {
709                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
710                                       (unsigned int) ptr->seq_keysym));
711                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
712                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
713                            ptr = ptr->next;
714                    }
715                    while (ptr);
716          }          }
   
         return tr;  
717  }  }
718    
719  uint16  uint16
# Line 409  get_ksname(uint32 keysym) Line 749  get_ksname(uint32 keysym)
749          return ksname;          return ksname;
750  }  }
751    
752    static BOOL
753  void  is_modifier(uint8 scancode)
 ensure_remote_modifiers(uint32 ev_time, key_translation tr)  
754  {  {
755          /* If this key is a modifier, do nothing */          switch (scancode)
         switch (tr.scancode)  
756          {          {
757                  case SCANCODE_CHAR_LSHIFT:                  case SCANCODE_CHAR_LSHIFT:
758                  case SCANCODE_CHAR_RSHIFT:                  case SCANCODE_CHAR_RSHIFT:
# Line 425  ensure_remote_modifiers(uint32 ev_time, Line 763  ensure_remote_modifiers(uint32 ev_time,
763                  case SCANCODE_CHAR_LWIN:                  case SCANCODE_CHAR_LWIN:
764                  case SCANCODE_CHAR_RWIN:                  case SCANCODE_CHAR_RWIN:
765                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
766                          return;                          return True;
767                  default:                  default:
768                          break;                          break;
769          }          }
770            return False;
771    }
772    
773    void
774    save_remote_modifiers(uint8 scancode)
775    {
776            if (is_modifier(scancode))
777                    return;
778    
779            saved_remote_modifier_state = remote_modifier_state;
780    }
781    
782    void
783    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
784    {
785            key_translation dummy;
786    
787            if (is_modifier(scancode))
788                    return;
789    
790            dummy.scancode = 0;
791            dummy.modifiers = saved_remote_modifier_state;
792            ensure_remote_modifiers(ev_time, dummy);
793    }
794    
795    void
796    ensure_remote_modifiers(uint32 ev_time, key_translation tr)
797    {
798            /* If this key is a modifier, do nothing */
799            if (is_modifier(tr.scancode))
800                    return;
801    
802            if (!g_numlock_sync)
803            {
804                    /* NumLock */
805                    if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
806                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
807                    {
808                            /* The remote modifier state is not correct */
809                            uint16 new_remote_state;
810    
811                            if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
812                            {
813                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
814                                    new_remote_state = KBD_FLAG_NUMLOCK;
815                                    remote_modifier_state = MapNumLockMask;
816                            }
817                            else
818                            {
819                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
820                                    new_remote_state = 0;
821                                    remote_modifier_state = 0;
822                            }
823    
824                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
825                    }
826            }
827    
828    
829          /* 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. */
830          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
# Line 474  ensure_remote_modifiers(uint32 ev_time, Line 870  ensure_remote_modifiers(uint32 ev_time,
870                  }                  }
871          }          }
872    
         /* 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;  
873    
874                  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"));  
                 }  
875    
876                  rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);  
877                  update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);  unsigned int
878          }  read_keyboard_state()
879    {
880    #ifdef RDP2VNC
881            return 0;
882    #else
883            unsigned int state;
884            Window wdummy;
885            int dummy;
886    
887            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
888            return state;
889    #endif
890    }
891    
892    
893    uint16
894    ui_get_numlock_state(unsigned int state)
895    {
896            uint16 numlock_state = 0;
897    
898            if (get_key_state(state, XK_Num_Lock))
899                    numlock_state = KBD_FLAG_NUMLOCK;
900    
901            return numlock_state;
902  }  }
903    
904    
905  void  void
906  reset_modifier_keys(unsigned int state)  reset_modifier_keys()
907  {  {
908            unsigned int state = read_keyboard_state();
909    
910          /* reset keys */          /* reset keys */
911          uint32 ev_time;          uint32 ev_time;
912          ev_time = time(NULL);          ev_time = time(NULL);
# Line 524  reset_modifier_keys(unsigned int state) Line 931  reset_modifier_keys(unsigned int state)
931                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
932    
933          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
934              !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)
935                && !get_key_state(state, XK_ISO_Level3_Shift))
936                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
937    
938            reset_winkey(ev_time);
939    
940            if (g_numlock_sync)
941                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
942  }  }
943    
944    
# Line 567  update_modifier_state(uint8 scancode, BO Line 980  update_modifier_state(uint8 scancode, BO
980                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
981                          /* KeyReleases for NumLocks are sent immediately. Toggle the                          /* KeyReleases for NumLocks are sent immediately. Toggle the
982                             modifier state only on Keypress */                             modifier state only on Keypress */
983                          if (pressed)                          if (pressed && !g_numlock_sync)
984                          {                          {
985                                  BOOL newNumLockState;                                  BOOL newNumLockState;
986                                  newNumLockState =                                  newNumLockState =
# Line 576  update_modifier_state(uint8 scancode, BO Line 989  update_modifier_state(uint8 scancode, BO
989                                  MASK_CHANGE_BIT(remote_modifier_state,                                  MASK_CHANGE_BIT(remote_modifier_state,
990                                                  MapNumLockMask, newNumLockState);                                                  MapNumLockMask, newNumLockState);
991                          }                          }
                         break;  
992          }          }
993    
994  #ifdef WITH_DEBUG_KBD  #ifdef WITH_DEBUG_KBD

Legend:
Removed from v.227  
changed lines
  Added in v.973

  ViewVC Help
Powered by ViewVC 1.1.26