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

Legend:
Removed from v.70  
changed lines
  Added in v.1199

  ViewVC Help
Powered by ViewVC 1.1.26