/[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 69 by astrand, Sat Jul 27 22:35:38 2002 UTC revision 965 by astrand, Wed Aug 3 11:47:20 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-2001  
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  #include <X11/keysym.h>  #include <X11/keysym.h>
28  #include <stdio.h>  #endif
29  #include <stdlib.h>  
 #include <string.h>  
30  #include <ctype.h>  #include <ctype.h>
31  #include <limits.h>  #include <limits.h>
32    #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 int g_keyboard_type;
46  static key_translation keymap[KEYMAP_SIZE];  extern int g_keyboard_subtype;
47  static unsigned int min_keycode;  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;
54    static key_translation *keymap[KEYMAP_SIZE];
55    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);
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=0x%x\n", (unsigned int) keysym, scancode, modifiers));
                   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    void
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                    fprintf(stderr, "Autoselected keyboard map %s.\n", keymapname);
215            }
216    }
217    
218    
219    /* Joins two path components. The result should be freed with
220       xfree(). */
221    static char *
222    pathjoin(const char *a, const char *b)
223    {
224            char *result;
225            result = xmalloc(PATH_MAX * 2 + 1);
226    
227            if (b[0] == '/')
228            {
229                    strncpy(result, b, PATH_MAX);
230            }
231            else
232            {
233                    strncpy(result, a, PATH_MAX);
234                    strcat(result, "/");
235                    strncat(result, b, PATH_MAX);
236            }
237            return result;
238    }
239    
240    /* Try to open a keymap with fopen() */
241    FILE *
242    xkeymap_open(const char *filename)
243    {
244            char *path1, *path2;
245            char *home;
246            FILE *fp;
247    
248            /* Try ~/.rdesktop/keymaps */
249            home = getenv("HOME");
250            if (home)
251            {
252                    path1 = pathjoin(home, ".rdesktop/keymaps");
253                    path2 = pathjoin(path1, filename);
254                    xfree(path1);
255                    fp = fopen(path2, "r");
256                    xfree(path2);
257                    if (fp)
258                            return fp;
259            }
260    
261            /* Try KEYMAP_PATH */
262            path1 = pathjoin(KEYMAP_PATH, filename);
263            fp = fopen(path1, "r");
264            xfree(path1);
265            if (fp)
266                    return fp;
267    
268            /* Try current directory, in case we are running from the source
269               tree */
270            path1 = pathjoin("keymaps", filename);
271            fp = fopen(path1, "r");
272            xfree(path1);
273            if (fp)
274                    return fp;
275    
276            return NULL;
277    }
278    
279  static BOOL  static BOOL
280  xkeymap_read(char *mapname)  xkeymap_read(char *mapname)
281  {  {
282          FILE *fp;          FILE *fp;
283          char line[KEYMAP_MAX_LINE_LENGTH], path[PATH_MAX];          char line[KEYMAP_MAX_LINE_LENGTH];
284          unsigned int line_num = 0;          unsigned int line_num = 0;
285          unsigned int line_length = 0;          unsigned int line_length = 0;
286          char *keyname, *p;          char *keyname, *p;
# Line 75  xkeymap_read(char *mapname) Line 288  xkeymap_read(char *mapname)
288          uint8 scancode;          uint8 scancode;
289          uint16 modifiers;          uint16 modifiers;
290    
291            fp = xkeymap_open(mapname);
         strcpy(path, KEYMAP_PATH);  
         strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));  
   
         fp = fopen(path, "r");  
292          if (fp == NULL)          if (fp == NULL)
293          {          {
294                  error("Failed to open keymap %s\n", path);                  error("Failed to open keymap %s\n", mapname);
295                  return False;                  return False;
296          }          }
297    
# Line 105  xkeymap_read(char *mapname) Line 314  xkeymap_read(char *mapname)
314                  }                  }
315    
316                  /* Include */                  /* Include */
317                  if (strncmp(line, "include ", 8) == 0)                  if (strncmp(line, "include ", sizeof("include ") - 1) == 0)
318                  {                  {
319                          if (!xkeymap_read(line + 8))                          if (!xkeymap_read(line + sizeof("include ") - 1))
320                                  return False;                                  return False;
321                          continue;                          continue;
322                  }                  }
323    
324                  /* map */                  /* map */
325                  if (strncmp(line, "map ", 4) == 0)                  if (strncmp(line, "map ", sizeof("map ") - 1) == 0)
326                    {
327                            g_keylayout = strtol(line + sizeof("map ") - 1, NULL, 16);
328                            DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
329                            continue;
330                    }
331    
332                    /* compose */
333                    if (strncmp(line, "enable_compose", sizeof("enable_compose") - 1) == 0)
334                    {
335                            DEBUG_KBD(("Enabling compose handling\n"));
336                            g_enable_compose = True;
337                            continue;
338                    }
339    
340                    /* sequence */
341                    if (strncmp(line, "sequence", sizeof("sequence") - 1) == 0)
342                  {                  {
343                          keylayout = strtol(line + 4, NULL, 16);                          add_sequence(line + sizeof("sequence") - 1, mapname);
344                          DEBUG_KBD("Keylayout 0x%x\n", keylayout);                          continue;
345                    }
346    
347                    /* keyboard_type */
348                    if (strncmp(line, "keyboard_type ", sizeof("keyboard_type ") - 1) == 0)
349                    {
350                            g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
351                            DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
352                            continue;
353                    }
354    
355                    /* keyboard_subtype */
356                    if (strncmp(line, "keyboard_subtype ", sizeof("keyboard_subtype ") - 1) == 0)
357                    {
358                            g_keyboard_subtype =
359                                    strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
360                            DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
361                            continue;
362                    }
363    
364                    /* keyboard_functionkeys */
365                    if (strncmp(line, "keyboard_functionkeys ", sizeof("keyboard_functionkeys ") - 1) ==
366                        0)
367                    {
368                            g_keyboard_functionkeys =
369                                    strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
370                            DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
371                          continue;                          continue;
372                  }                  }
373    
# Line 131  xkeymap_read(char *mapname) Line 382  xkeymap_read(char *mapname)
382                  p = strchr(line, ' ');                  p = strchr(line, ' ');
383                  if (p == NULL)                  if (p == NULL)
384                  {                  {
385                          error("Bad line %d in keymap %s\n", line_num,                          error("Bad line %d in keymap %s\n", line_num, mapname);
                               mapname);  
386                          continue;                          continue;
387                  }                  }
388                  else                  else
# Line 168  xkeymap_read(char *mapname) Line 418  xkeymap_read(char *mapname)
418                          MASK_ADD_BITS(modifiers, MapLocalStateMask);                          MASK_ADD_BITS(modifiers, MapLocalStateMask);
419                  }                  }
420    
421                    if (strstr(line_rest, "inhibit"))
422                    {
423                            MASK_ADD_BITS(modifiers, MapInhibitMask);
424                    }
425    
426                  add_to_keymap(keyname, scancode, modifiers, mapname);                  add_to_keymap(keyname, scancode, modifiers, mapname);
427    
428                  if (strstr(line_rest, "addupper"))                  if (strstr(line_rest, "addupper"))
# Line 175  xkeymap_read(char *mapname) Line 430  xkeymap_read(char *mapname)
430                          /* Automatically add uppercase key, with same modifiers                          /* Automatically add uppercase key, with same modifiers
431                             plus shift */                             plus shift */
432                          for (p = keyname; *p; p++)                          for (p = keyname; *p; p++)
433                                  *p = toupper(*p);                                  *p = toupper((int) *p);
434                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);
435                          add_to_keymap(keyname, scancode, modifiers, mapname);                          add_to_keymap(keyname, scancode, modifiers, mapname);
436                  }                  }
# Line 188  xkeymap_read(char *mapname) Line 443  xkeymap_read(char *mapname)
443    
444  /* Before connecting and creating UI */  /* Before connecting and creating UI */
445  void  void
446  xkeymap_init1(void)  xkeymap_init(void)
447  {  {
448          int i;          unsigned int max_keycode;
449    
450          /* Zeroing keymap */          if (strcmp(keymapname, "none"))
         for (i = 0; i < KEYMAP_SIZE; i++)  
451          {          {
452                  keymap[i].scancode = 0;                  if (xkeymap_read(keymapname))
453                  keymap[i].modifiers = 0;                          keymap_loaded = True;
454          }          }
455    
456          if (strcmp(keymapname, "none"))          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
457    }
458    
459    static void
460    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
461    {
462            uint8 winkey;
463    
464            if (leftkey)
465                    winkey = SCANCODE_CHAR_LWIN;
466            else
467                    winkey = SCANCODE_CHAR_RWIN;
468    
469            if (pressed)
470            {
471                    if (g_use_rdp5)
472                    {
473                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
474                    }
475                    else
476                    {
477                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
478                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
479                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
480                    }
481            }
482            else
483          {          {
484                  xkeymap_read(keymapname);                  /* key released */
485                    if (g_use_rdp5)
486                    {
487                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
488                    }
489                    else
490                    {
491                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
492                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
493                    }
494          }          }
495    }
496    
497    static void
498    reset_winkey(uint32 ev_time)
499    {
500            if (g_use_rdp5)
501            {
502                    /* For some reason, it seems to suffice to release
503                     *either* the left or right winkey. */
504                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
505            }
506  }  }
507    
508  /* After connecting and creating UI */  /* Handle special key combinations */
509  void  BOOL
510  xkeymap_init2(void)  handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
511  {  {
512          unsigned int max_keycode;          switch (keysym)
513          XDisplayKeycodes(display, &min_keycode, &max_keycode);          {
514                    case XK_Return:
515                            if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
516                                && (get_key_state(state, XK_Control_L)
517                                    || get_key_state(state, XK_Control_R)))
518                            {
519                                    /* Ctrl-Alt-Enter: toggle full screen */
520                                    if (pressed)
521                                            xwin_toggle_fullscreen();
522                                    return True;
523                            }
524                            break;
525    
526                    case XK_Break:
527                            /* Send Break sequence E0 46 E0 C6 */
528                            if (pressed)
529                            {
530                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
531                                                      (SCANCODE_EXTENDED | 0x46));
532                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
533                                                      (SCANCODE_EXTENDED | 0xc6));
534                            }
535                            /* No release sequence */
536                            return True;
537                            break;
538    
539                    case XK_Pause:
540                            /* According to MS Keyboard Scan Code
541                               Specification, pressing Pause should result
542                               in E1 1D 45 E1 9D C5. I'm not exactly sure
543                               of how this is supposed to be sent via
544                               RDP. The code below seems to work, but with
545                               the side effect that Left Ctrl stays
546                               down. Therefore, we release it when Pause
547                               is released. */
548                            if (pressed)
549                            {
550                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
551                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
552                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
553                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
554                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
555                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
556                            }
557                            else
558                            {
559                                    /* Release Left Ctrl */
560                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
561                                                   0x1d, 0);
562                            }
563                            return True;
564                            break;
565    
566                    case XK_Meta_L: /* Windows keys */
567                    case XK_Super_L:
568                    case XK_Hyper_L:
569                            send_winkey(ev_time, pressed, True);
570                            return True;
571                            break;
572    
573                    case XK_Meta_R:
574                    case XK_Super_R:
575                    case XK_Hyper_R:
576                            send_winkey(ev_time, pressed, False);
577                            return True;
578                            break;
579    
580                    case XK_space:
581                            /* Prevent access to the Windows system menu in single app mode */
582                            if (g_win_button_size
583                                && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
584                                    return True;
585                            break;
586    
587                    case XK_Num_Lock:
588                            /* Synchronize on key release */
589                            if (g_numlock_sync && !pressed)
590                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
591                                                   ui_get_numlock_state(read_keyboard_state()), 0);
592    
593                            /* Inhibit */
594                            return True;
595                            break;
596    
597            }
598            return False;
599  }  }
600    
601    
602  key_translation  key_translation
603  xkeymap_translate_key(KeySym keysym, unsigned int keycode, unsigned int state)  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
604  {  {
605          key_translation tr = { 0, 0 };          key_translation tr = { 0, 0, 0, 0 };
606            key_translation *ptr;
607    
608          tr = keymap[keysym & KEYMAP_MASK];          ptr = keymap[keysym & KEYMAP_MASK];
609            if (ptr)
         if (tr.modifiers & MapLocalStateMask)  
610          {          {
611                  /* The modifiers to send for this key should be obtained                  tr = *ptr;
612                     from the local state. Currently, only shift is implemented. */                  if (tr.seq_keysym == 0) /* Normal scancode translation */
                 if (state & ShiftMask)  
613                  {                  {
614                          tr.modifiers = MapLeftShiftMask;                          if (tr.modifiers & MapInhibitMask)
615                            {
616                                    DEBUG_KBD(("Inhibiting key\n"));
617                                    tr.scancode = 0;
618                                    return tr;
619                            }
620    
621                            if (tr.modifiers & MapLocalStateMask)
622                            {
623                                    /* The modifiers to send for this key should be obtained
624                                       from the local state. Currently, only shift is implemented. */
625                                    if (state & ShiftMask)
626                                    {
627                                            tr.modifiers = MapLeftShiftMask;
628                                    }
629                            }
630    
631                            if ((tr.modifiers & MapLeftShiftMask)
632                                && ((remote_modifier_state & MapLeftCtrlMask)
633                                    || (remote_modifier_state & MapRightCtrlMask))
634                                && get_key_state(state, XK_Caps_Lock))
635                            {
636                                    DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
637                                    tr.modifiers ^= MapLeftShiftMask;
638                            }
639    
640                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
641                                       tr.scancode, tr.modifiers));
642                  }                  }
643          }          }
644            else
         if (tr.scancode != 0)  
645          {          {
646                  DEBUG_KBD                  if (keymap_loaded)
647                          ("Found key translation, scancode=0x%x, modifiers=0x%x\n",                          warning("No translation for (keysym 0x%lx, %s)\n", keysym,
648                           tr.scancode, tr.modifiers);                                  get_ksname(keysym));
649                  return tr;  
650                    /* not in keymap, try to interpret the raw scancode */
651                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
652                    {
653                            tr.scancode = keycode - min_keycode;
654    
655                            /* The modifiers to send for this key should be
656                               obtained from the local state. Currently, only
657                               shift is implemented. */
658                            if (state & ShiftMask)
659                            {
660                                    tr.modifiers = MapLeftShiftMask;
661                            }
662    
663                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
664                    }
665                    else
666                    {
667                            DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
668                    }
669          }          }
670    
671          printf("No translation for (keysym 0x%lx, %s)\n", keysym,          return tr;
672                 get_ksname(keysym));  }
673    
674    void
675    xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
676                      BOOL pressed)
677    {
678            key_translation tr, *ptr;
679            tr = xkeymap_translate_key(keysym, keycode, state);
680    
681          /* not in keymap, try to interpret the raw scancode */          if (tr.seq_keysym == 0)
         if ((keycode >= min_keycode) && (keycode <= 0x60))  
682          {          {
683                  tr.scancode = keycode - min_keycode;                  /* Scancode translation */
684                  printf("Sending guessed scancode 0x%x\n", tr.scancode);                  if (tr.scancode == 0)
685                            return;
686    
687                    if (pressed)
688                    {
689                            save_remote_modifiers(tr.scancode);
690                            ensure_remote_modifiers(ev_time, tr);
691                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
692                            restore_remote_modifiers(ev_time, tr.scancode);
693                    }
694                    else
695                    {
696                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
697                    }
698                    return;
699          }          }
700          else  
701            /* Sequence, only on key down */
702            if (pressed)
703          {          {
704                  printf("No good guess for keycode 0x%x found\n", keycode);                  ptr = &tr;
705                    do
706                    {
707                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
708                                       (unsigned int) ptr->seq_keysym));
709                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
710                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
711                            ptr = ptr->next;
712                    }
713                    while (ptr);
714          }          }
   
         return tr;  
715  }  }
716    
717  uint16  uint16
# Line 278  xkeymap_translate_button(unsigned int bu Line 735  xkeymap_translate_button(unsigned int bu
735  }  }
736    
737  char *  char *
738  get_ksname(KeySym keysym)  get_ksname(uint32 keysym)
739  {  {
740          char *ksname = NULL;          char *ksname = NULL;
741    
# Line 290  get_ksname(KeySym keysym) Line 747  get_ksname(KeySym keysym)
747          return ksname;          return ksname;
748  }  }
749    
750  BOOL  static BOOL
751  inhibit_key(KeySym keysym)  is_modifier(uint8 scancode)
752  {  {
753          switch (keysym)          switch (scancode)
754          {          {
755                  case XK_Caps_Lock:                  case SCANCODE_CHAR_LSHIFT:
756                          return True;                  case SCANCODE_CHAR_RSHIFT:
757                          break;                  case SCANCODE_CHAR_LCTRL:
758                  case XK_Multi_key:                  case SCANCODE_CHAR_RCTRL:
759                    case SCANCODE_CHAR_LALT:
760                    case SCANCODE_CHAR_RALT:
761                    case SCANCODE_CHAR_LWIN:
762                    case SCANCODE_CHAR_RWIN:
763                    case SCANCODE_CHAR_NUMLOCK:
764                          return True;                          return True;
                         break;  
765                  default:                  default:
766                          break;                          break;
767          }          }
# Line 308  inhibit_key(KeySym keysym) Line 769  inhibit_key(KeySym keysym)
769  }  }
770    
771  void  void
772    save_remote_modifiers(uint8 scancode)
773    {
774            if (is_modifier(scancode))
775                    return;
776    
777            saved_remote_modifier_state = remote_modifier_state;
778    }
779    
780    void
781    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
782    {
783            key_translation dummy;
784    
785            if (is_modifier(scancode))
786                    return;
787    
788            dummy.scancode = 0;
789            dummy.modifiers = saved_remote_modifier_state;
790            ensure_remote_modifiers(ev_time, dummy);
791    }
792    
793    void
794  ensure_remote_modifiers(uint32 ev_time, key_translation tr)  ensure_remote_modifiers(uint32 ev_time, key_translation tr)
795  {  {
796          /* If this key is a modifier, do nothing */          /* If this key is a modifier, do nothing */
797          switch (tr.scancode)          if (is_modifier(tr.scancode))
798                    return;
799    
800            if (!g_numlock_sync)
801          {          {
802                  case SCANCODE_CHAR_LSHIFT:                  /* NumLock */
803                  case SCANCODE_CHAR_RSHIFT:                  if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
804                  case SCANCODE_CHAR_LCTRL:                      != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
805                  case SCANCODE_CHAR_RCTRL:                  {
806                  case SCANCODE_CHAR_LALT:                          /* The remote modifier state is not correct */
807                  case SCANCODE_CHAR_RALT:                          uint16 new_remote_state;
808                  case SCANCODE_CHAR_LWIN:  
809                  case SCANCODE_CHAR_RWIN:                          if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
810                  case SCANCODE_CHAR_NUMLOCK:                          {
811                          return;                                  DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
812                  default:                                  new_remote_state = KBD_FLAG_NUMLOCK;
813                          break;                                  remote_modifier_state = MapNumLockMask;
814                            }
815                            else
816                            {
817                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
818                                    new_remote_state = 0;
819                                    remote_modifier_state = 0;
820                            }
821    
822                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
823                    }
824          }          }
825    
826          /* Shift */  
827            /* Shift. Left shift and right shift are treated as equal; either is fine. */
828          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
829              != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))              != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
830          {          {
831                  /* The remote modifier state is not correct */                  /* The remote modifier state is not correct */
832                  if (MASK_HAS_BITS(tr.modifiers, MapShiftMask))                  if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
833                  {                  {
834                          /* Needs this modifier. Send down. */                          /* Needs left shift. Send down. */
835                          rdp_send_scancode(ev_time, RDP_KEYPRESS,                          rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
836                                            SCANCODE_CHAR_LSHIFT);                  }
837                    else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
838                    {
839                            /* Needs right shift. Send down. */
840                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
841                  }                  }
842                  else                  else
843                  {                  {
844                          /* Should not use this modifier. Send up. */                          /* Should not use this modifier. Send up for shift currently pressed. */
845                          rdp_send_scancode(ev_time, RDP_KEYRELEASE,                          if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
846                                            SCANCODE_CHAR_LSHIFT);                                  /* Left shift is down */
847                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
848                            else
849                                    /* Right shift is down */
850                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
851                  }                  }
852          }          }
853    
# Line 354  ensure_remote_modifiers(uint32 ev_time, Line 859  ensure_remote_modifiers(uint32 ev_time,
859                  if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))                  if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
860                  {                  {
861                          /* Needs this modifier. Send down. */                          /* Needs this modifier. Send down. */
862                          rdp_send_scancode(ev_time, RDP_KEYPRESS,                          rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
                                           SCANCODE_CHAR_RALT);  
863                  }                  }
864                  else                  else
865                  {                  {
866                          /* Should not use this modifier. Send up. */                          /* Should not use this modifier. Send up. */
867                          rdp_send_scancode(ev_time, RDP_KEYRELEASE,                          rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
                                           SCANCODE_CHAR_RALT);  
868                  }                  }
869          }          }
870    
         /* NumLock */  
         if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)  
             != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))  
         {  
                 /* The remote modifier state is not correct */  
                 DEBUG_KBD("Remote NumLock state is incorrect. Toggling\n");  
                 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))  
                 {  
                         /* Needs this modifier. Toggle */  
                         rdp_send_scancode(ev_time, RDP_KEYPRESS,  
                                           SCANCODE_CHAR_NUMLOCK);  
                         rdp_send_scancode(ev_time, RDP_KEYRELEASE,  
                                           SCANCODE_CHAR_NUMLOCK);  
                 }  
                 else  
                 {  
                         /* Should not use this modifier. Toggle */  
                         rdp_send_scancode(ev_time, RDP_KEYPRESS,  
                                           SCANCODE_CHAR_NUMLOCK);  
                         rdp_send_scancode(ev_time, RDP_KEYRELEASE,  
                                           SCANCODE_CHAR_NUMLOCK);  
                 }  
         }  
871    
872  }  }
873    
874    
875    unsigned int
876    read_keyboard_state()
877    {
878    #ifdef RDP2VNC
879            return 0;
880    #else
881            unsigned int state;
882            Window wdummy;
883            int dummy;
884    
885            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
886            return state;
887    #endif
888    }
889    
890    
891    uint16
892    ui_get_numlock_state(unsigned int state)
893    {
894            uint16 numlock_state = 0;
895    
896            if (get_key_state(state, XK_Num_Lock))
897                    numlock_state = KBD_FLAG_NUMLOCK;
898    
899            return numlock_state;
900    }
901    
902    
903    void
904    reset_modifier_keys()
905    {
906            unsigned int state = read_keyboard_state();
907    
908            /* reset keys */
909            uint32 ev_time;
910            ev_time = time(NULL);
911    
912            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
913                && !get_key_state(state, XK_Shift_L))
914                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
915    
916            if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
917                && !get_key_state(state, XK_Shift_R))
918                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
919    
920            if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
921                && !get_key_state(state, XK_Control_L))
922                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
923    
924            if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
925                && !get_key_state(state, XK_Control_R))
926                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
927    
928            if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
929                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
930    
931            if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
932                !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
933                && !get_key_state(state, XK_ISO_Level3_Shift))
934                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
935    
936            reset_winkey(ev_time);
937    
938            if (g_numlock_sync)
939                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
940    }
941    
942    
943  static void  static void
944  update_modifier_state(uint16 modifiers, BOOL pressed)  update_modifier_state(uint8 scancode, BOOL pressed)
945  {  {
946    #ifdef WITH_DEBUG_KBD
947            uint16 old_modifier_state;
948    
949          DEBUG_KBD("Before updating modifier_state:0x%x, pressed=0x%x\n",          old_modifier_state = remote_modifier_state;
950                    remote_modifier_state, pressed);  #endif
951          switch (modifiers)  
952            switch (scancode)
953          {          {
954                  case SCANCODE_CHAR_LSHIFT:                  case SCANCODE_CHAR_LSHIFT:
955                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
                                         MapLeftShiftMask, pressed);  
956                          break;                          break;
957                  case SCANCODE_CHAR_RSHIFT:                  case SCANCODE_CHAR_RSHIFT:
958                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
                                         MapRightShiftMask, pressed);  
959                          break;                          break;
960                  case SCANCODE_CHAR_LCTRL:                  case SCANCODE_CHAR_LCTRL:
961                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
                                         MapLeftCtrlMask, pressed);  
962                          break;                          break;
963                  case SCANCODE_CHAR_RCTRL:                  case SCANCODE_CHAR_RCTRL:
964                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
                                         MapRightCtrlMask, pressed);  
965                          break;                          break;
966                  case SCANCODE_CHAR_LALT:                  case SCANCODE_CHAR_LALT:
967                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask,                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
                                         pressed);  
968                          break;                          break;
969                  case SCANCODE_CHAR_RALT:                  case SCANCODE_CHAR_RALT:
970                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
                                         MapRightAltMask, pressed);  
971                          break;                          break;
972                  case SCANCODE_CHAR_LWIN:                  case SCANCODE_CHAR_LWIN:
973                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask,                          MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
                                         pressed);  
974                          break;                          break;
975                  case SCANCODE_CHAR_RWIN:                  case SCANCODE_CHAR_RWIN:
976                          MASK_CHANGE_BIT(remote_modifier_state,                          MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
                                         MapRightWinMask, pressed);  
977                          break;                          break;
978                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
979                          /* KeyReleases for NumLocks are sent immediately. Toggle the                          /* KeyReleases for NumLocks are sent immediately. Toggle the
980                             modifier state only on Keypress */                             modifier state only on Keypress */
981                          if (pressed)                          if (pressed && !g_numlock_sync)
982                          {                          {
983                                  BOOL newNumLockState;                                  BOOL newNumLockState;
984                                  newNumLockState =                                  newNumLockState =
985                                          (MASK_HAS_BITS                                          (MASK_HAS_BITS
986                                           (remote_modifier_state,                                           (remote_modifier_state, MapNumLockMask) == False);
                                           MapNumLockMask) == False);  
987                                  MASK_CHANGE_BIT(remote_modifier_state,                                  MASK_CHANGE_BIT(remote_modifier_state,
988                                                  MapNumLockMask,                                                  MapNumLockMask, newNumLockState);
                                                 newNumLockState);  
989                          }                          }
                         break;  
990          }          }
991          DEBUG_KBD("After updating modifier_state:0x%x\n",  
992                    remote_modifier_state);  #ifdef WITH_DEBUG_KBD
993            if (old_modifier_state != remote_modifier_state)
994            {
995                    DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
996                               old_modifier_state, pressed));
997                    DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
998            }
999    #endif
1000    
1001  }  }
1002    
1003  /* Send keyboard input */  /* Send keyboard input */
1004  void  void
1005  rdp_send_scancode(uint32 time, uint16 flags, uint16 scancode)  rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1006  {  {
1007          update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));          update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1008    
1009          if (scancode & SCANCODE_EXTENDED)          if (scancode & SCANCODE_EXTENDED)
1010          {          {
1011                  DEBUG_KBD("Sending extended scancode=0x%x, flags=0x%x\n",                  DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1012                            scancode & ~SCANCODE_EXTENDED, flags);                             scancode & ~SCANCODE_EXTENDED, flags));
1013                  rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,                  rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1014                                 scancode & ~SCANCODE_EXTENDED, 0);                                 scancode & ~SCANCODE_EXTENDED, 0);
1015          }          }
1016          else          else
1017          {          {
1018                  DEBUG_KBD("Sending scancode=0x%x, flags=0x%x\n", scancode,                  DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
                           flags);  
1019                  rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);                  rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1020          }          }
1021  }  }

Legend:
Removed from v.69  
changed lines
  Added in v.965

  ViewVC Help
Powered by ViewVC 1.1.26