/[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 310 by astrand, Tue Feb 4 15:54:58 2003 UTC revision 1405 by jsorg71, Thu May 3 04:53:39 2007 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X keyboard mapping     User interface services - X keyboard mapping
4     Copyright (C) Matthew Chapman 1999-2002  
5         Copyright (C) Matthew Chapman 1999-2007
6       Copyright (C) Peter Astrand <astrand@cendio.se> 2003-2007
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
10     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.     (at your option) any later version.
12      
13     This program is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.     GNU General Public License for more details.
17      
18     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */  */
22    
23    #ifdef RDP2VNC
24    #include "vnc/x11stubs.h"
25    #else
26  #include <X11/Xlib.h>  #include <X11/Xlib.h>
27  #define XK_MISCELLANY  #include <X11/keysym.h>
28  #include <X11/keysymdef.h>  #endif
29    
30  #include <ctype.h>  #include <ctype.h>
31  #include <limits.h>  #include <limits.h>
32  #include <time.h>  #include <time.h>
33    #include <string.h>
34  #include "rdesktop.h"  #include "rdesktop.h"
35  #include "scancodes.h"  #include "scancodes.h"
36    
# Line 31  Line 38 
38  #define KEYMAP_MASK 0xffff  #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    extern int g_keyboard_subtype;
47    extern int g_keyboard_functionkeys;
48    extern int g_win_button_size;
49    extern RD_BOOL g_enable_compose;
50    extern RD_BOOL g_use_rdp5;
51    extern RD_BOOL g_numlock_sync;
52    
53  static BOOL keymap_loaded;  static RD_BOOL keymap_loaded;
54  static key_translation keymap[KEYMAP_SIZE];  static key_translation *keymap[KEYMAP_SIZE];
55  static int min_keycode;  static int min_keycode;
56  static uint16 remote_modifier_state = 0;  static uint16 remote_modifier_state = 0;
57    static uint16 saved_remote_modifier_state = 0;
58    
59  static void update_modifier_state(uint8 scancode, BOOL pressed);  static void update_modifier_state(uint8 scancode, RD_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                  warning("Bad keysym %s in keymap %s\n", keyname, mapname);                  DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
85                  return;                  return;
86          }          }
87    
88          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
89                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
90    
91          keymap[keysym & KEYMAP_MASK].scancode = scancode;          tr = (key_translation *) xmalloc(sizeof(key_translation));
92          keymap[keysym & KEYMAP_MASK].modifiers = modifiers;          memset(tr, 0, sizeof(key_translation));
93            tr->scancode = scancode;
94            tr->modifiers = modifiers;
95            free_key_translation(keymap[keysym & KEYMAP_MASK]);
96            keymap[keysym & KEYMAP_MASK] = tr;
97    
98          return;          return;
99  }  }
100    
101    static void
102    add_sequence(char *rest, char *mapname)
103    {
104            KeySym keysym;
105            key_translation *tr, **prev_next;
106            size_t chars;
107            char keyname[KEYMAP_MAX_LINE_LENGTH];
108    
109            /* Skip over whitespace after the sequence keyword */
110            chars = strspn(rest, " \t");
111            rest += chars;
112    
113            /* Fetch the keysym name */
114            chars = strcspn(rest, " \t\0");
115            STRNCPY(keyname, rest, chars + 1);
116            rest += chars;
117    
118            keysym = XStringToKeysym(keyname);
119            if (keysym == NoSymbol)
120            {
121                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
122                    return;
123            }
124    
125    
126            DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
127    
128            free_key_translation(keymap[keysym & KEYMAP_MASK]);
129            prev_next = &keymap[keysym & KEYMAP_MASK];
130    
131            while (*rest)
132            {
133                    /* Skip whitespace */
134                    chars = strspn(rest, " \t");
135                    rest += chars;
136    
137                    /* Fetch the keysym name */
138                    chars = strcspn(rest, " \t\0");
139                    STRNCPY(keyname, rest, chars + 1);
140                    rest += chars;
141    
142                    keysym = XStringToKeysym(keyname);
143                    if (keysym == NoSymbol)
144                    {
145                            DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
146                                       mapname));
147                            return;
148                    }
149    
150                    /* Allocate space for key_translation structure */
151                    tr = (key_translation *) xmalloc(sizeof(key_translation));
152                    memset(tr, 0, sizeof(key_translation));
153                    *prev_next = tr;
154                    prev_next = &tr->next;
155                    tr->seq_keysym = keysym;
156    
157                    DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
158            }
159            DEBUG_KBD(("\n"));
160    }
161    
162    RD_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  static BOOL          /* 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                    xfree(str);
210                    return True;
211            }
212    
213            xfree(str);
214            return False;
215    }
216    
217    
218    /* Joins two path components. The result should be freed with
219       xfree(). */
220    static char *
221    pathjoin(const char *a, const char *b)
222    {
223            char *result;
224            result = xmalloc(PATH_MAX * 2 + 1);
225    
226            if (b[0] == '/')
227            {
228                    strncpy(result, b, PATH_MAX);
229            }
230            else
231            {
232                    strncpy(result, a, PATH_MAX);
233                    strcat(result, "/");
234                    strncat(result, b, PATH_MAX);
235            }
236            return result;
237    }
238    
239    /* Try to open a keymap with fopen() */
240    FILE *
241    xkeymap_open(const char *filename)
242    {
243            char *path1, *path2;
244            char *home;
245            FILE *fp;
246    
247            /* Try ~/.rdesktop/keymaps */
248            home = getenv("HOME");
249            if (home)
250            {
251                    path1 = pathjoin(home, ".rdesktop/keymaps");
252                    path2 = pathjoin(path1, filename);
253                    xfree(path1);
254                    fp = fopen(path2, "r");
255                    xfree(path2);
256                    if (fp)
257                            return fp;
258            }
259    
260            /* Try KEYMAP_PATH */
261            path1 = pathjoin(KEYMAP_PATH, filename);
262            fp = fopen(path1, "r");
263            xfree(path1);
264            if (fp)
265                    return fp;
266    
267            /* Try current directory, in case we are running from the source
268               tree */
269            path1 = pathjoin("keymaps", filename);
270            fp = fopen(path1, "r");
271            xfree(path1);
272            if (fp)
273                    return fp;
274    
275            return NULL;
276    }
277    
278    static RD_BOOL
279  xkeymap_read(char *mapname)  xkeymap_read(char *mapname)
280  {  {
281          FILE *fp;          FILE *fp;
282          char line[KEYMAP_MAX_LINE_LENGTH];          char line[KEYMAP_MAX_LINE_LENGTH];
         char path[PATH_MAX], inplace_path[PATH_MAX];  
283          unsigned int line_num = 0;          unsigned int line_num = 0;
284          unsigned int line_length = 0;          unsigned int line_length = 0;
285          char *keyname, *p;          char *keyname, *p;
# Line 78  xkeymap_read(char *mapname) Line 287  xkeymap_read(char *mapname)
287          uint8 scancode;          uint8 scancode;
288          uint16 modifiers;          uint16 modifiers;
289    
290            fp = xkeymap_open(mapname);
         strcpy(path, KEYMAP_PATH);  
         strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));  
   
         fp = fopen(path, "r");  
291          if (fp == NULL)          if (fp == NULL)
292          {          {
293                  /* in case we are running from the source tree */                  error("Failed to open keymap %s\n", mapname);
294                  strcpy(inplace_path, "keymaps/");                  return False;
                 strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));  
   
                 fp = fopen(inplace_path, "r");  
                 if (fp == NULL)  
                 {  
                         error("Failed to open keymap %s\n", path);  
                         return False;  
                 }  
295          }          }
296    
297          /* FIXME: More tolerant on white space */          /* FIXME: More tolerant on white space */
# Line 116  xkeymap_read(char *mapname) Line 313  xkeymap_read(char *mapname)
313                  }                  }
314    
315                  /* Include */                  /* Include */
316                  if (strncmp(line, "include ", 8) == 0)                  if (str_startswith(line, "include "))
317                  {                  {
318                          if (!xkeymap_read(line + 8))                          if (!xkeymap_read(line + sizeof("include ") - 1))
319                                  return False;                                  return False;
320                          continue;                          continue;
321                  }                  }
322    
323                  /* map */                  /* map */
324                  if (strncmp(line, "map ", 4) == 0)                  if (str_startswith(line, "map "))
325                  {                  {
326                          keylayout = strtol(line + 4, NULL, 16);                          g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16);
327                          DEBUG_KBD(("Keylayout 0x%x\n", keylayout));                          DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
328                          continue;                          continue;
329                  }                  }
330    
331                  /* compose */                  /* compose */
332                  if (strncmp(line, "enable_compose", 15) == 0)                  if (str_startswith(line, "enable_compose"))
333                  {                  {
334                          DEBUG_KBD(("Enabling compose handling\n"));                          DEBUG_KBD(("Enabling compose handling\n"));
335                          enable_compose = True;                          g_enable_compose = True;
336                            continue;
337                    }
338    
339                    /* sequence */
340                    if (str_startswith(line, "sequence"))
341                    {
342                            add_sequence(line + sizeof("sequence") - 1, mapname);
343                            continue;
344                    }
345    
346                    /* keyboard_type */
347                    if (str_startswith(line, "keyboard_type "))
348                    {
349                            g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
350                            DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
351                            continue;
352                    }
353    
354                    /* keyboard_subtype */
355                    if (str_startswith(line, "keyboard_subtype "))
356                    {
357                            g_keyboard_subtype =
358                                    strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
359                            DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
360                            continue;
361                    }
362    
363                    /* keyboard_functionkeys */
364                    if (str_startswith(line, "keyboard_functionkeys "))
365                    {
366                            g_keyboard_functionkeys =
367                                    strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
368                            DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
369                          continue;                          continue;
370                  }                  }
371    
# Line 198  xkeymap_read(char *mapname) Line 428  xkeymap_read(char *mapname)
428                          /* Automatically add uppercase key, with same modifiers                          /* Automatically add uppercase key, with same modifiers
429                             plus shift */                             plus shift */
430                          for (p = keyname; *p; p++)                          for (p = keyname; *p; p++)
431                                  *p = toupper((int)*p);                                  *p = toupper((int) *p);
432                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);                          MASK_ADD_BITS(modifiers, MapLeftShiftMask);
433                          add_to_keymap(keyname, scancode, modifiers, mapname);                          add_to_keymap(keyname, scancode, modifiers, mapname);
434                  }                  }
# Line 214  void Line 444  void
444  xkeymap_init(void)  xkeymap_init(void)
445  {  {
446          unsigned int max_keycode;          unsigned int max_keycode;
         char *mapname_ptr;  
447    
448          /* Make keymapname lowercase */          if (strcmp(g_keymapname, "none"))
         mapname_ptr = keymapname;  
         while (*mapname_ptr)  
449          {          {
450                  *mapname_ptr = tolower((int)*mapname_ptr);                  if (xkeymap_read(g_keymapname))
451                  mapname_ptr++;                          keymap_loaded = True;
452          }          }
453    
454          if (strcmp(keymapname, "none"))          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
455    }
456    
457    static void
458    send_winkey(uint32 ev_time, RD_BOOL pressed, RD_BOOL leftkey)
459    {
460            uint8 winkey;
461    
462            if (leftkey)
463                    winkey = SCANCODE_CHAR_LWIN;
464            else
465                    winkey = SCANCODE_CHAR_RWIN;
466    
467            if (pressed)
468          {          {
469                  if (xkeymap_read(keymapname))                  if (g_use_rdp5)
470                          keymap_loaded = True;                  {
471                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
472                    }
473                    else
474                    {
475                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
476                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
477                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
478                    }
479            }
480            else
481            {
482                    /* key released */
483                    if (g_use_rdp5)
484                    {
485                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
486                    }
487                    else
488                    {
489                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
490                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
491                    }
492          }          }
493    }
494    
495          XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);  static void
496    reset_winkey(uint32 ev_time)
497    {
498            if (g_use_rdp5)
499            {
500                    /* For some reason, it seems to suffice to release
501                     *either* the left or right winkey. */
502                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
503            }
504  }  }
505    
506  /* Handles, for example, multi-scancode keypresses (which is not  /* Handle special key combinations */
507     possible via keymap-files) */  RD_BOOL
508  BOOL  handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed)
 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)  
509  {  {
510          switch (keysym)          switch (keysym)
511          {          {
# Line 263  handle_special_keys(uint32 keysym, unsig Line 532  handle_special_keys(uint32 keysym, unsig
532                          }                          }
533                          /* No release sequence */                          /* No release sequence */
534                          return True;                          return True;
535                            break;
536    
537                  case XK_Pause:                  case XK_Pause:
538                          /* According to MS Keyboard Scan Code                          /* According to MS Keyboard Scan Code
# Line 289  handle_special_keys(uint32 keysym, unsig Line 559  handle_special_keys(uint32 keysym, unsig
559                                                 0x1d, 0);                                                 0x1d, 0);
560                          }                          }
561                          return True;                          return True;
562                            break;
563    
564                  case XK_Meta_L: /* Windows keys */                  case XK_Meta_L: /* Windows keys */
565                  case XK_Super_L:                  case XK_Super_L:
566                  case XK_Hyper_L:                  case XK_Hyper_L:
567                            send_winkey(ev_time, pressed, True);
568                            return True;
569                            break;
570    
571                  case XK_Meta_R:                  case XK_Meta_R:
572                  case XK_Super_R:                  case XK_Super_R:
573                  case XK_Hyper_R:                  case XK_Hyper_R:
574                          if (pressed)                          send_winkey(ev_time, pressed, False);
575                          {                          return True;
576                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);                          break;
577                                  rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);  
578                          }                  case XK_space:
579                          else                          /* Prevent access to the Windows system menu in single app mode */
580                          {                          if (g_win_button_size
581                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);                              && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
582                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);                                  return True;
583                          }                          break;
584    
585                    case XK_Num_Lock:
586                            /* Synchronize on key release */
587                            if (g_numlock_sync && !pressed)
588                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
589                                                   ui_get_numlock_state(read_keyboard_state()), 0);
590    
591                            /* Inhibit */
592                          return True;                          return True;
593                            break;
594                    case XK_Overlay1_Enable:
595                            /* Toggle SeamlessRDP */
596                            if (pressed)
597                                    ui_seamless_toggle();
598                            break;
599    
600          }          }
601          return False;          return False;
602  }  }
# Line 315  handle_special_keys(uint32 keysym, unsig Line 605  handle_special_keys(uint32 keysym, unsig
605  key_translation  key_translation
606  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)  xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
607  {  {
608          key_translation tr = { 0, 0 };          key_translation tr = { 0, 0, 0, 0 };
609            key_translation *ptr;
610    
611          tr = keymap[keysym & KEYMAP_MASK];          ptr = keymap[keysym & KEYMAP_MASK];
612            if (ptr)
         if (tr.modifiers & MapInhibitMask)  
613          {          {
614                  DEBUG_KBD(("Inhibiting key\n"));                  tr = *ptr;
615                  tr.scancode = 0;                  if (tr.seq_keysym == 0) /* Normal scancode translation */
616                  return tr;                  {
617          }                          if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
618                            {
619                                    DEBUG_KBD(("Inhibiting key\n"));
620                                    tr.scancode = 0;
621                                    return tr;
622                            }
623    
624                            if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask))
625                            {
626                                    /* The modifiers to send for this key should be obtained
627                                       from the local state. Currently, only shift is implemented. */
628                                    if (MASK_HAS_BITS(state, ShiftMask))
629                                    {
630                                            tr.modifiers = MapLeftShiftMask;
631                                    }
632                            }
633    
634          if (tr.modifiers & MapLocalStateMask)                          /* Windows interprets CapsLock+Ctrl+key
635                               differently from Shift+Ctrl+key. Since we
636                               are simulating CapsLock with Shifts, things
637                               like Ctrl+f with CapsLock on breaks. To
638                               solve this, we are releasing Shift if Ctrl
639                               is on, but only if Shift isn't physically pressed. */
640                            if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
641                                && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
642                                && !MASK_HAS_BITS(state, ShiftMask))
643                            {
644                                    DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
645                                    MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
646                            }
647    
648                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
649                                       tr.scancode, tr.modifiers));
650                    }
651            }
652            else
653          {          {
654                  /* The modifiers to send for this key should be obtained                  if (keymap_loaded)
655                     from the local state. Currently, only shift is implemented. */                          warning("No translation for (keysym 0x%lx, %s)\n", keysym,
656                  if (state & ShiftMask)                                  get_ksname(keysym));
657    
658                    /* not in keymap, try to interpret the raw scancode */
659                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
660                    {
661                            tr.scancode = keycode - min_keycode;
662    
663                            /* The modifiers to send for this key should be
664                               obtained from the local state. Currently, only
665                               shift is implemented. */
666                            if (MASK_HAS_BITS(state, ShiftMask))
667                            {
668                                    tr.modifiers = MapLeftShiftMask;
669                            }
670    
671                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
672                    }
673                    else
674                  {                  {
675                          tr.modifiers = MapLeftShiftMask;                          DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
676                  }                  }
677          }          }
678    
679          if (tr.scancode != 0)          return tr;
680    }
681    
682    static RD_BOOL
683    is_modifier(uint8 scancode)
684    {
685            switch (scancode)
686          {          {
687                  DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",                  case SCANCODE_CHAR_LSHIFT:
688                             tr.scancode, tr.modifiers));                  case SCANCODE_CHAR_RSHIFT:
689                  return tr;                  case SCANCODE_CHAR_LCTRL:
690                    case SCANCODE_CHAR_RCTRL:
691                    case SCANCODE_CHAR_LALT:
692                    case SCANCODE_CHAR_RALT:
693                    case SCANCODE_CHAR_LWIN:
694                    case SCANCODE_CHAR_RWIN:
695                    case SCANCODE_CHAR_NUMLOCK:
696                            return True;
697                    default:
698                            break;
699          }          }
700            return False;
701    }
702    
703          if (keymap_loaded)  static void
704                  warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));  save_remote_modifiers_if_modifier(uint8 scancode)
705    {
706            if (!is_modifier(scancode))
707                    return;
708    
709          /* not in keymap, try to interpret the raw scancode */          saved_remote_modifier_state = remote_modifier_state;
710          if ((keycode >= min_keycode) && (keycode <= 0x60))  }
711    
712    void
713    xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
714                      RD_BOOL pressed, uint8 nesting)
715    {
716            key_translation tr, *ptr;
717            tr = xkeymap_translate_key(keysym, keycode, state);
718    
719            if (tr.seq_keysym == 0)
720          {          {
721                  tr.scancode = keycode - min_keycode;                  /* Scancode translation */
722                    if (tr.scancode == 0)
723                            return;
724    
725                  /* The modifiers to send for this key should be                  if (pressed)
                    obtained from the local state. Currently, only  
                    shift is implemented. */  
                 if (state & ShiftMask)  
726                  {                  {
727                          tr.modifiers = MapLeftShiftMask;                          save_remote_modifiers(tr.scancode);
728                            ensure_remote_modifiers(ev_time, tr);
729                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
730                  }                  }
731                    else
732                  DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));                  {
733                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
734                            restore_remote_modifiers(ev_time, tr.scancode);
735                            save_remote_modifiers_if_modifier(tr.scancode);
736                    }
737                    return;
738          }          }
739          else  
740            /* Sequence, only on key down */
741            if (pressed)
742          {          {
743                  DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));                  ptr = &tr;
744          }                  do
745                    {
746                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
747                                       (unsigned int) ptr->seq_keysym));
748    
749          return tr;                          if (nesting++ > 32)
750                            {
751                                    error("Sequence nesting too deep\n");
752                                    return;
753                            }
754    
755                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
756                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
757                            ptr = ptr->next;
758                    }
759                    while (ptr);
760            }
761  }  }
762    
763  uint16  uint16
# Line 402  get_ksname(uint32 keysym) Line 793  get_ksname(uint32 keysym)
793          return ksname;          return ksname;
794  }  }
795    
796    void
797    save_remote_modifiers(uint8 scancode)
798    {
799            if (is_modifier(scancode))
800                    return;
801    
802            saved_remote_modifier_state = remote_modifier_state;
803    }
804    
805    void
806    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
807    {
808            key_translation dummy;
809    
810            if (is_modifier(scancode))
811                    return;
812    
813            dummy.scancode = 0;
814            dummy.modifiers = saved_remote_modifier_state;
815            ensure_remote_modifiers(ev_time, dummy);
816    }
817    
818  void  void
819  ensure_remote_modifiers(uint32 ev_time, key_translation tr)  ensure_remote_modifiers(uint32 ev_time, key_translation tr)
820  {  {
821          /* If this key is a modifier, do nothing */          /* If this key is a modifier, do nothing */
822          switch (tr.scancode)          if (is_modifier(tr.scancode))
823          {                  return;
                 case SCANCODE_CHAR_LSHIFT:  
                 case SCANCODE_CHAR_RSHIFT:  
                 case SCANCODE_CHAR_LCTRL:  
                 case SCANCODE_CHAR_RCTRL:  
                 case SCANCODE_CHAR_LALT:  
                 case SCANCODE_CHAR_RALT:  
                 case SCANCODE_CHAR_LWIN:  
                 case SCANCODE_CHAR_RWIN:  
                 case SCANCODE_CHAR_NUMLOCK:  
                         return;  
                 default:  
                         break;  
         }  
824    
825          /* NumLock */          if (!g_numlock_sync)
         if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)  
             != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))  
826          {          {
827                  /* The remote modifier state is not correct */                  /* NumLock */
828                  uint16 new_remote_state;                  if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
829                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
                 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))  
                 {  
                         DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));  
                         new_remote_state = KBD_FLAG_NUMLOCK;  
                         remote_modifier_state = MapNumLockMask;  
                 }  
                 else  
830                  {                  {
831                          DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));                          /* The remote modifier state is not correct */
832                          new_remote_state = 0;                          uint16 new_remote_state;
833                          remote_modifier_state = 0;  
834                  }                          if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
835                            {
836                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
837                                    new_remote_state = KBD_FLAG_NUMLOCK;
838                                    remote_modifier_state = MapNumLockMask;
839                            }
840                            else
841                            {
842                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
843                                    new_remote_state = 0;
844                                    remote_modifier_state = 0;
845                            }
846    
847                  rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);                          rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
848                    }
849          }          }
850    
851    
852          /* Shift. Left shift and right shift are treated as equal; either is fine. */          /* Shift. Left shift and right shift are treated as equal; either is fine. */
853          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)          if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
854              != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))              != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
# Line 494  ensure_remote_modifiers(uint32 ev_time, Line 897  ensure_remote_modifiers(uint32 ev_time,
897  }  }
898    
899    
900    unsigned int
901    read_keyboard_state()
902    {
903    #ifdef RDP2VNC
904            return 0;
905    #else
906            unsigned int state;
907            Window wdummy;
908            int dummy;
909    
910            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
911            return state;
912    #endif
913    }
914    
915    
916    uint16
917    ui_get_numlock_state(unsigned int state)
918    {
919            uint16 numlock_state = 0;
920    
921            if (get_key_state(state, XK_Num_Lock))
922                    numlock_state = KBD_FLAG_NUMLOCK;
923    
924            return numlock_state;
925    }
926    
927    
928  void  void
929  reset_modifier_keys(unsigned int state)  reset_modifier_keys()
930  {  {
931            unsigned int state = read_keyboard_state();
932    
933          /* reset keys */          /* reset keys */
934          uint32 ev_time;          uint32 ev_time;
935          ev_time = time(NULL);          ev_time = time(NULL);
# Line 521  reset_modifier_keys(unsigned int state) Line 954  reset_modifier_keys(unsigned int state)
954                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
955    
956          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&          if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
957              !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))              !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
958                && !get_key_state(state, XK_ISO_Level3_Shift))
959                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);                  rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
960    
961            reset_winkey(ev_time);
962    
963            if (g_numlock_sync)
964                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
965  }  }
966    
967    
968  static void  static void
969  update_modifier_state(uint8 scancode, BOOL pressed)  update_modifier_state(uint8 scancode, RD_BOOL pressed)
970  {  {
971  #ifdef WITH_DEBUG_KBD  #ifdef WITH_DEBUG_KBD
972          uint16 old_modifier_state;          uint16 old_modifier_state;
# Line 564  update_modifier_state(uint8 scancode, BO Line 1003  update_modifier_state(uint8 scancode, BO
1003                  case SCANCODE_CHAR_NUMLOCK:                  case SCANCODE_CHAR_NUMLOCK:
1004                          /* KeyReleases for NumLocks are sent immediately. Toggle the                          /* KeyReleases for NumLocks are sent immediately. Toggle the
1005                             modifier state only on Keypress */                             modifier state only on Keypress */
1006                          if (pressed)                          if (pressed && !g_numlock_sync)
1007                          {                          {
1008                                  BOOL newNumLockState;                                  RD_BOOL newNumLockState;
1009                                  newNumLockState =                                  newNumLockState =
1010                                          (MASK_HAS_BITS                                          (MASK_HAS_BITS
1011                                           (remote_modifier_state, MapNumLockMask) == False);                                           (remote_modifier_state, MapNumLockMask) == False);
1012                                  MASK_CHANGE_BIT(remote_modifier_state,                                  MASK_CHANGE_BIT(remote_modifier_state,
1013                                                  MapNumLockMask, newNumLockState);                                                  MapNumLockMask, newNumLockState);
1014                          }                          }
                         break;  
1015          }          }
1016    
1017  #ifdef WITH_DEBUG_KBD  #ifdef WITH_DEBUG_KBD

Legend:
Removed from v.310  
changed lines
  Added in v.1405

  ViewVC Help
Powered by ViewVC 1.1.26