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

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

  ViewVC Help
Powered by ViewVC 1.1.26