/[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 50 by matthewc, Sat Apr 20 09:41:03 2002 UTC revision 960 by astrand, Wed Aug 3 08:41:02 2005 UTC
# Line 1  Line 1 
1  /*  /*
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>  
30  #include <string.h>  #include <ctype.h>
31  #include <limits.h>  #include <limits.h>
32    #include <time.h>
33  #include "rdesktop.h"  #include "rdesktop.h"
34    #include "scancodes.h"
35    
36  #define KEYMAP_SIZE 4096  #define KEYMAP_SIZE 0xffff+1
37  #define KEYMAP_MASK (KEYMAP_SIZE - 1)  #define KEYMAP_MASK 0xffff
38    #define KEYMAP_MAX_LINE_LENGTH 80
39    
40  extern Display *display;  extern Display *g_display;
41    extern Window g_wnd;
42  extern char keymapname[16];  extern char keymapname[16];
43  extern int keylayout;  extern int g_keylayout;
44    extern int g_win_button_size;
45    extern BOOL g_enable_compose;
46    extern BOOL g_use_rdp5;
47    extern BOOL g_numlock_sync;
48    
49    static BOOL keymap_loaded;
50    static key_translation *keymap[KEYMAP_SIZE];
51    static int min_keycode;
52    static uint16 remote_modifier_state = 0;
53    static uint16 saved_remote_modifier_state = 0;
54    
55    static void update_modifier_state(uint8 scancode, BOOL pressed);
56    
57    /* Free key_translation structure, including linked list */
58    static void
59    free_key_translation(key_translation * ptr)
60    {
61            key_translation *next;
62    
63  static uint8 keymap[KEYMAP_SIZE];          while (ptr)
64  static unsigned int min_keycode;          {
65                    next = ptr->next;
66                    xfree(ptr);
67                    ptr = next;
68            }
69    }
70    
71  static BOOL xkeymap_read(char *mapname)  static void
72    add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
73  {  {
         FILE *fp;  
         char line[PATH_MAX], path[PATH_MAX];  
         char *keyname, *p;  
74          KeySym keysym;          KeySym keysym;
75          unsigned char keycode;          key_translation *tr;
76    
77            keysym = XStringToKeysym(keyname);
78            if (keysym == NoSymbol)
79            {
80                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
81                    return;
82            }
83    
84          strcpy(path, KEYMAP_PATH);          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
85          strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
86    
87          fp = fopen(path, "r");          tr = (key_translation *) xmalloc(sizeof(key_translation));
88            memset(tr, 0, sizeof(key_translation));
89            tr->scancode = scancode;
90            tr->modifiers = modifiers;
91            free_key_translation(keymap[keysym & KEYMAP_MASK]);
92            keymap[keysym & KEYMAP_MASK] = tr;
93    
94            return;
95    }
96    
97    static void
98    add_sequence(char *rest, char *mapname)
99    {
100            KeySym keysym;
101            key_translation *tr, **prev_next;
102            size_t chars;
103            char keyname[KEYMAP_MAX_LINE_LENGTH];
104    
105            /* Skip over whitespace after the sequence keyword */
106            chars = strspn(rest, " \t");
107            rest += chars;
108    
109            /* Fetch the keysym name */
110            chars = strcspn(rest, " \t\0");
111            STRNCPY(keyname, rest, chars + 1);
112            rest += chars;
113    
114            keysym = XStringToKeysym(keyname);
115            if (keysym == NoSymbol)
116            {
117                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
118                    return;
119            }
120    
121    
122            DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
123    
124            free_key_translation(keymap[keysym & KEYMAP_MASK]);
125            prev_next = &keymap[keysym & KEYMAP_MASK];
126    
127            while (*rest)
128            {
129                    /* Skip whitespace */
130                    chars = strspn(rest, " \t");
131                    rest += chars;
132    
133                    /* Fetch the keysym name */
134                    chars = strcspn(rest, " \t\0");
135                    STRNCPY(keyname, rest, chars + 1);
136                    rest += chars;
137    
138                    keysym = XStringToKeysym(keyname);
139                    if (keysym == NoSymbol)
140                    {
141                            DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
142                                       mapname));
143                            return;
144                    }
145    
146                    /* Allocate space for key_translation structure */
147                    tr = (key_translation *) xmalloc(sizeof(key_translation));
148                    memset(tr, 0, sizeof(key_translation));
149                    *prev_next = tr;
150                    prev_next = &tr->next;
151                    tr->seq_keysym = keysym;
152    
153                    DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
154            }
155            DEBUG_KBD(("\n"));
156    }
157    
158    /* Joins two path components. The result should be freed with
159       xfree(). */
160    static char *
161    pathjoin(const char *a, const char *b)
162    {
163            char *result;
164            result = xmalloc(PATH_MAX * 2 + 1);
165    
166            if (b[0] == '/')
167            {
168                    strncpy(result, b, PATH_MAX);
169            }
170            else
171            {
172                    strncpy(result, a, PATH_MAX);
173                    strcat(result, "/");
174                    strncat(result, b, PATH_MAX);
175            }
176            return result;
177    }
178    
179    /* Try to open a keymap with fopen() */
180    FILE *
181    xkeymap_open(const char *filename)
182    {
183            char *path1, *path2;
184            char *home;
185            FILE *fp;
186    
187            /* Try ~/.rdesktop/keymaps */
188            home = getenv("HOME");
189            if (home)
190            {
191                    path1 = pathjoin(home, ".rdesktop/keymaps");
192                    path2 = pathjoin(path1, filename);
193                    xfree(path1);
194                    fp = fopen(path2, "r");
195                    xfree(path2);
196                    if (fp)
197                            return fp;
198            }
199    
200            /* Try KEYMAP_PATH */
201            path1 = pathjoin(KEYMAP_PATH, filename);
202            fp = fopen(path1, "r");
203            xfree(path1);
204            if (fp)
205                    return fp;
206    
207            /* Try current directory, in case we are running from the source
208               tree */
209            path1 = pathjoin("keymaps", filename);
210            fp = fopen(path1, "r");
211            xfree(path1);
212            if (fp)
213                    return fp;
214    
215            return NULL;
216    }
217    
218    static BOOL
219    xkeymap_read(char *mapname)
220    {
221            FILE *fp;
222            char line[KEYMAP_MAX_LINE_LENGTH];
223            unsigned int line_num = 0;
224            unsigned int line_length = 0;
225            char *keyname, *p;
226            char *line_rest;
227            uint8 scancode;
228            uint16 modifiers;
229    
230            fp = xkeymap_open(mapname);
231          if (fp == NULL)          if (fp == NULL)
232          {          {
233                  error("Failed to open keymap %s\n", path);                  error("Failed to open keymap %s\n", mapname);
234                  return False;                  return False;
235          }          }
236    
237            /* FIXME: More tolerant on white space */
238          while (fgets(line, sizeof(line), fp) != NULL)          while (fgets(line, sizeof(line), fp) != NULL)
239          {          {
240                    line_num++;
241    
242                    /* Replace the \n with \0 */
243                  p = strchr(line, '\n');                  p = strchr(line, '\n');
244                  if (p != NULL)                  if (p != NULL)
245                          *p = 0;                          *p = 0;
246    
247                  keycode = strtol(line, &keyname, 16);                  line_length = strlen(line);
248                  if ((keycode != 0) && (*keyname == ' '))  
249                    /* Completely empty line */
250                    if (strspn(line, " \t\n\r\f\v") == line_length)
251                  {                  {
252                          do                          continue;
253                          {                  }
                                 keyname++;  
                                 p = strchr(keyname, ' ');  
                                 if (p != NULL)  
                                         *p = 0;  
254    
255                                  keysym = XStringToKeysym(keyname);                  /* Include */
256                                  if (keysym == NoSymbol)                  if (strncmp(line, "include ", 8) == 0)
257                                          error("Bad keysym %s in keymap %s\n", keyname, mapname);                  {
258                            if (!xkeymap_read(line + 8))
259                                    return False;
260                            continue;
261                    }
262    
263                                  keymap[keysym & KEYMAP_MASK] = keycode;                  /* map */
264                                  keyname = p;                  if (strncmp(line, "map ", 4) == 0)
265                    {
266                            g_keylayout = strtol(line + 4, NULL, 16);
267                            DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
268                            continue;
269                    }
270    
271                          } while (keyname != NULL);                  /* compose */
272                    if (strncmp(line, "enable_compose", 15) == 0)
273                    {
274                            DEBUG_KBD(("Enabling compose handling\n"));
275                            g_enable_compose = True;
276                            continue;
277                  }                  }
278                  else if (strncmp(line, "include ", 8) == 0)  
279                    /* sequence */
280                    if (strncmp(line, "sequence", 8) == 0)
281                  {                  {
282                          if (!xkeymap_read(line+8))                          add_sequence(line + 8, mapname);
283                                  return False;                          continue;
284                    }
285    
286                    /* Comment */
287                    if (line[0] == '#')
288                    {
289                            continue;
290                    }
291    
292                    /* Normal line */
293                    keyname = line;
294                    p = strchr(line, ' ');
295                    if (p == NULL)
296                    {
297                            error("Bad line %d in keymap %s\n", line_num, mapname);
298                            continue;
299                    }
300                    else
301                    {
302                            *p = 0;
303                    }
304    
305                    /* scancode */
306                    p++;
307                    scancode = strtol(p, &line_rest, 16);
308    
309                    /* flags */
310                    /* FIXME: Should allow case-insensitive flag names.
311                       Fix by using lex+yacc... */
312                    modifiers = 0;
313                    if (strstr(line_rest, "altgr"))
314                    {
315                            MASK_ADD_BITS(modifiers, MapAltGrMask);
316                    }
317    
318                    if (strstr(line_rest, "shift"))
319                    {
320                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
321                    }
322    
323                    if (strstr(line_rest, "numlock"))
324                    {
325                            MASK_ADD_BITS(modifiers, MapNumLockMask);
326                    }
327    
328                    if (strstr(line_rest, "localstate"))
329                    {
330                            MASK_ADD_BITS(modifiers, MapLocalStateMask);
331                  }                  }
332                  else if (strncmp(line, "map ", 4) == 0)  
333                    if (strstr(line_rest, "inhibit"))
334                  {                  {
335                          keylayout = strtol(line+4, NULL, 16);                          MASK_ADD_BITS(modifiers, MapInhibitMask);
336                  }                  }
337                  else if (line[0] != '#')  
338                    add_to_keymap(keyname, scancode, modifiers, mapname);
339    
340                    if (strstr(line_rest, "addupper"))
341                  {                  {
342                          error("Malformed line in keymap %s\n", mapname);                          /* Automatically add uppercase key, with same modifiers
343                               plus shift */
344                            for (p = keyname; *p; p++)
345                                    *p = toupper((int) *p);
346                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
347                            add_to_keymap(keyname, scancode, modifiers, mapname);
348                  }                  }
349          }          }
350    
# Line 98  static BOOL xkeymap_read(char *mapname) Line 352  static BOOL xkeymap_read(char *mapname)
352          return True;          return True;
353  }  }
354    
355  void xkeymap_init(void)  
356    /* Before connecting and creating UI */
357    void
358    xkeymap_init(void)
359  {  {
360          unsigned int max_keycode;          unsigned int max_keycode;
361            char *mapname_ptr;
362    
363          XDisplayKeycodes(display, &min_keycode, &max_keycode);          /* Make keymapname lowercase */
364            mapname_ptr = keymapname;
365            while (*mapname_ptr)
366            {
367                    *mapname_ptr = tolower((int) *mapname_ptr);
368                    mapname_ptr++;
369            }
370    
371          if (strcmp(keymapname, "none"))          if (strcmp(keymapname, "none"))
372                  xkeymap_read(keymapname);          {
373                    if (xkeymap_read(keymapname))
374                            keymap_loaded = True;
375            }
376    
377            XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
378  }  }
379    
380  uint8 xkeymap_translate_key(unsigned int keysym, unsigned int keycode, uint16 *flags)  static void
381    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
382  {  {
383          uint8 scancode;          uint8 winkey;
384    
385          scancode = keymap[keysym & KEYMAP_MASK];          if (leftkey)
386          if (scancode != 0)                  winkey = SCANCODE_CHAR_LWIN;
387            else
388                    winkey = SCANCODE_CHAR_RWIN;
389    
390            if (pressed)
391            {
392                    if (g_use_rdp5)
393                    {
394                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
395                    }
396                    else
397                    {
398                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
399                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
400                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
401                    }
402            }
403            else
404          {          {
405                  if (scancode & 0x80)                  /* key released */
406                          *flags |= KBD_FLAG_EXT;                  if (g_use_rdp5)
407                    {
408                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
409                    }
410                    else
411                    {
412                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
413                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
414                    }
415            }
416    }
417    
418                  return (scancode & 0x7f);  static void
419    reset_winkey(uint32 ev_time)
420    {
421            if (g_use_rdp5)
422            {
423                    /* For some reason, it seems to suffice to release
424                     *either* the left or right winkey. */
425                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
426          }          }
427    }
428    
429    /* Handle special key combinations */
430    BOOL
431    handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
432    {
433            switch (keysym)
434            {
435                    case XK_Return:
436                            if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
437                                && (get_key_state(state, XK_Control_L)
438                                    || get_key_state(state, XK_Control_R)))
439                            {
440                                    /* Ctrl-Alt-Enter: toggle full screen */
441                                    if (pressed)
442                                            xwin_toggle_fullscreen();
443                                    return True;
444                            }
445                            break;
446    
447                    case XK_Break:
448                            /* Send Break sequence E0 46 E0 C6 */
449                            if (pressed)
450                            {
451                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
452                                                      (SCANCODE_EXTENDED | 0x46));
453                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
454                                                      (SCANCODE_EXTENDED | 0xc6));
455                            }
456                            /* No release sequence */
457                            return True;
458                            break;
459    
460                    case XK_Pause:
461                            /* According to MS Keyboard Scan Code
462                               Specification, pressing Pause should result
463                               in E1 1D 45 E1 9D C5. I'm not exactly sure
464                               of how this is supposed to be sent via
465                               RDP. The code below seems to work, but with
466                               the side effect that Left Ctrl stays
467                               down. Therefore, we release it when Pause
468                               is released. */
469                            if (pressed)
470                            {
471                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
472                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
473                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
474                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
475                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
476                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
477                            }
478                            else
479                            {
480                                    /* Release Left Ctrl */
481                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
482                                                   0x1d, 0);
483                            }
484                            return True;
485                            break;
486    
487                    case XK_Meta_L: /* Windows keys */
488                    case XK_Super_L:
489                    case XK_Hyper_L:
490                            send_winkey(ev_time, pressed, True);
491                            return True;
492                            break;
493    
494                    case XK_Meta_R:
495                    case XK_Super_R:
496                    case XK_Hyper_R:
497                            send_winkey(ev_time, pressed, False);
498                            return True;
499                            break;
500    
501                    case XK_space:
502                            /* Prevent access to the Windows system menu in single app mode */
503                            if (g_win_button_size
504                                && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
505                                    return True;
506                            break;
507    
508                    case XK_Num_Lock:
509                            /* Synchronize on key release */
510                            if (g_numlock_sync && !pressed)
511                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
512                                                   ui_get_numlock_state(read_keyboard_state()), 0);
513    
514                            /* Inhibit */
515                            return True;
516                            break;
517    
         /* not in keymap, try to interpret the raw scancode */  
   
         if ((keycode >= min_keycode) && (keycode <= 0x60))  
                 return (uint8)(keycode - min_keycode);  
   
         *flags |= KBD_FLAG_EXT;  
   
         switch (keycode)  
         {  
                 case 0x61:      /* home */  
                         return 0x47;  
                 case 0x62:      /* up arrow */  
                         return 0x48;  
                 case 0x63:      /* page up */  
                         return 0x49;  
                 case 0x64:      /* left arrow */  
                         return 0x4b;  
                 case 0x66:      /* right arrow */  
                         return 0x4d;  
                 case 0x67:      /* end */  
                         return 0x4f;  
                 case 0x68:      /* down arrow */  
                         return 0x50;  
                 case 0x69:      /* page down */  
                         return 0x51;  
                 case 0x6a:      /* insert */  
                         return 0x52;  
                 case 0x6b:      /* delete */  
                         return 0x53;  
                 case 0x6c:      /* keypad enter */  
                         return 0x1c;  
                 case 0x6d:      /* right ctrl */  
                         return 0x1d;  
                 case 0x6f:      /* ctrl - print screen */  
                         return 0x37;  
                 case 0x70:      /* keypad '/' */  
                         return 0x35;  
                 case 0x71:      /* right alt */  
                         return 0x38;  
                 case 0x72:      /* ctrl break */  
                         return 0x46;  
                 case 0x73:      /* left window key */  
                         return 0x5b;  
                 case 0x74:      /* right window key */  
                         return 0x5c;  
                 case 0x75:      /* menu key */  
                         return 0x5d;  
518          }          }
519            return False;
520    }
521    
522          return 0;  
523    key_translation
524    xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
525    {
526            key_translation tr = { 0, 0, 0, 0 };
527            key_translation *ptr;
528    
529            ptr = keymap[keysym & KEYMAP_MASK];
530            if (ptr)
531            {
532                    tr = *ptr;
533                    if (tr.seq_keysym == 0) /* Normal scancode translation */
534                    {
535                            if (tr.modifiers & MapInhibitMask)
536                            {
537                                    DEBUG_KBD(("Inhibiting key\n"));
538                                    tr.scancode = 0;
539                                    return tr;
540                            }
541    
542                            if (tr.modifiers & MapLocalStateMask)
543                            {
544                                    /* The modifiers to send for this key should be obtained
545                                       from the local state. Currently, only shift is implemented. */
546                                    if (state & ShiftMask)
547                                    {
548                                            tr.modifiers = MapLeftShiftMask;
549                                    }
550                            }
551    
552                            if ((tr.modifiers & MapLeftShiftMask)
553                                && ((remote_modifier_state & MapLeftCtrlMask)
554                                    || (remote_modifier_state & MapRightCtrlMask))
555                                && get_key_state(state, XK_Caps_Lock))
556                            {
557                                    DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
558                                    tr.modifiers ^= MapLeftShiftMask;
559                            }
560    
561                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
562                                       tr.scancode, tr.modifiers));
563                    }
564            }
565            else
566            {
567                    if (keymap_loaded)
568                            warning("No translation for (keysym 0x%lx, %s)\n", keysym,
569                                    get_ksname(keysym));
570    
571                    /* not in keymap, try to interpret the raw scancode */
572                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
573                    {
574                            tr.scancode = keycode - min_keycode;
575    
576                            /* The modifiers to send for this key should be
577                               obtained from the local state. Currently, only
578                               shift is implemented. */
579                            if (state & ShiftMask)
580                            {
581                                    tr.modifiers = MapLeftShiftMask;
582                            }
583    
584                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
585                    }
586                    else
587                    {
588                            DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
589                    }
590            }
591    
592            return tr;
593  }  }
594    
595  uint16 xkeymap_translate_button(unsigned int button)  void
596    xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
597                      BOOL pressed)
598    {
599            key_translation tr, *ptr;
600            tr = xkeymap_translate_key(keysym, keycode, state);
601    
602            if (tr.seq_keysym == 0)
603            {
604                    /* Scancode translation */
605                    if (tr.scancode == 0)
606                            return;
607    
608                    if (pressed)
609                    {
610                            save_remote_modifiers(tr.scancode);
611                            ensure_remote_modifiers(ev_time, tr);
612                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
613                            restore_remote_modifiers(ev_time, tr.scancode);
614                    }
615                    else
616                    {
617                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
618                    }
619                    return;
620            }
621    
622            /* Sequence, only on key down */
623            if (pressed)
624            {
625                    ptr = &tr;
626                    do
627                    {
628                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
629                                       (unsigned int) ptr->seq_keysym));
630                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
631                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
632                            ptr = ptr->next;
633                    }
634                    while (ptr);
635            }
636    }
637    
638    uint16
639    xkeymap_translate_button(unsigned int button)
640  {  {
641          switch (button)          switch (button)
642          {          {
643                  case Button1:   /* left */                  case Button1:   /* left */
644                          return MOUSE_FLAG_BUTTON1;                          return MOUSE_FLAG_BUTTON1;
645                  case Button2:   /* middle */                  case Button2:   /* middle */
646                          return MOUSE_FLAG_BUTTON3;                          return MOUSE_FLAG_BUTTON3;
647                  case Button3:   /* right */                  case Button3:   /* right */
648                          return MOUSE_FLAG_BUTTON2;                          return MOUSE_FLAG_BUTTON2;
649                    case Button4:   /* wheel up */
650                            return MOUSE_FLAG_BUTTON4;
651                    case Button5:   /* wheel down */
652                            return MOUSE_FLAG_BUTTON5;
653          }          }
654    
655          return 0;          return 0;
656  }  }
657    
658    char *
659    get_ksname(uint32 keysym)
660    {
661            char *ksname = NULL;
662    
663            if (keysym == NoSymbol)
664                    ksname = "NoSymbol";
665            else if (!(ksname = XKeysymToString(keysym)))
666                    ksname = "(no name)";
667    
668            return ksname;
669    }
670    
671    static BOOL
672    is_modifier(uint8 scancode)
673    {
674            switch (scancode)
675            {
676                    case SCANCODE_CHAR_LSHIFT:
677                    case SCANCODE_CHAR_RSHIFT:
678                    case SCANCODE_CHAR_LCTRL:
679                    case SCANCODE_CHAR_RCTRL:
680                    case SCANCODE_CHAR_LALT:
681                    case SCANCODE_CHAR_RALT:
682                    case SCANCODE_CHAR_LWIN:
683                    case SCANCODE_CHAR_RWIN:
684                    case SCANCODE_CHAR_NUMLOCK:
685                            return True;
686                    default:
687                            break;
688            }
689            return False;
690    }
691    
692    void
693    save_remote_modifiers(uint8 scancode)
694    {
695            if (is_modifier(scancode))
696                    return;
697    
698            saved_remote_modifier_state = remote_modifier_state;
699    }
700    
701    void
702    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
703    {
704            key_translation dummy;
705    
706            if (is_modifier(scancode))
707                    return;
708    
709            dummy.scancode = 0;
710            dummy.modifiers = saved_remote_modifier_state;
711            ensure_remote_modifiers(ev_time, dummy);
712    }
713    
714    void
715    ensure_remote_modifiers(uint32 ev_time, key_translation tr)
716    {
717            /* If this key is a modifier, do nothing */
718            if (is_modifier(tr.scancode))
719                    return;
720    
721            if (!g_numlock_sync)
722            {
723                    /* NumLock */
724                    if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
725                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
726                    {
727                            /* The remote modifier state is not correct */
728                            uint16 new_remote_state;
729    
730                            if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
731                            {
732                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
733                                    new_remote_state = KBD_FLAG_NUMLOCK;
734                                    remote_modifier_state = MapNumLockMask;
735                            }
736                            else
737                            {
738                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
739                                    new_remote_state = 0;
740                                    remote_modifier_state = 0;
741                            }
742    
743                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
744                    }
745            }
746    
747    
748            /* Shift. Left shift and right shift are treated as equal; either is fine. */
749            if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
750                != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
751            {
752                    /* The remote modifier state is not correct */
753                    if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
754                    {
755                            /* Needs left shift. Send down. */
756                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
757                    }
758                    else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
759                    {
760                            /* Needs right shift. Send down. */
761                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
762                    }
763                    else
764                    {
765                            /* Should not use this modifier. Send up for shift currently pressed. */
766                            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
767                                    /* Left shift is down */
768                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
769                            else
770                                    /* Right shift is down */
771                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
772                    }
773            }
774    
775            /* AltGr */
776            if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
777                != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
778            {
779                    /* The remote modifier state is not correct */
780                    if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
781                    {
782                            /* Needs this modifier. Send down. */
783                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
784                    }
785                    else
786                    {
787                            /* Should not use this modifier. Send up. */
788                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
789                    }
790            }
791    
792    
793    }
794    
795    
796    unsigned int
797    read_keyboard_state()
798    {
799    #ifdef RDP2VNC
800            return 0;
801    #else
802            unsigned int state;
803            Window wdummy;
804            int dummy;
805    
806            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
807            return state;
808    #endif
809    }
810    
811    
812    uint16
813    ui_get_numlock_state(unsigned int state)
814    {
815            uint16 numlock_state = 0;
816    
817            if (get_key_state(state, XK_Num_Lock))
818                    numlock_state = KBD_FLAG_NUMLOCK;
819    
820            return numlock_state;
821    }
822    
823    
824    void
825    reset_modifier_keys()
826    {
827            unsigned int state = read_keyboard_state();
828    
829            /* reset keys */
830            uint32 ev_time;
831            ev_time = time(NULL);
832    
833            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
834                && !get_key_state(state, XK_Shift_L))
835                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
836    
837            if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
838                && !get_key_state(state, XK_Shift_R))
839                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
840    
841            if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
842                && !get_key_state(state, XK_Control_L))
843                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
844    
845            if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
846                && !get_key_state(state, XK_Control_R))
847                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
848    
849            if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
850                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
851    
852            if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
853                !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
854                && !get_key_state(state, XK_ISO_Level3_Shift))
855                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
856    
857            reset_winkey(ev_time);
858    
859            if (g_numlock_sync)
860                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
861    }
862    
863    
864    static void
865    update_modifier_state(uint8 scancode, BOOL pressed)
866    {
867    #ifdef WITH_DEBUG_KBD
868            uint16 old_modifier_state;
869    
870            old_modifier_state = remote_modifier_state;
871    #endif
872    
873            switch (scancode)
874            {
875                    case SCANCODE_CHAR_LSHIFT:
876                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
877                            break;
878                    case SCANCODE_CHAR_RSHIFT:
879                            MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
880                            break;
881                    case SCANCODE_CHAR_LCTRL:
882                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
883                            break;
884                    case SCANCODE_CHAR_RCTRL:
885                            MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
886                            break;
887                    case SCANCODE_CHAR_LALT:
888                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
889                            break;
890                    case SCANCODE_CHAR_RALT:
891                            MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
892                            break;
893                    case SCANCODE_CHAR_LWIN:
894                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
895                            break;
896                    case SCANCODE_CHAR_RWIN:
897                            MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
898                            break;
899                    case SCANCODE_CHAR_NUMLOCK:
900                            /* KeyReleases for NumLocks are sent immediately. Toggle the
901                               modifier state only on Keypress */
902                            if (pressed && !g_numlock_sync)
903                            {
904                                    BOOL newNumLockState;
905                                    newNumLockState =
906                                            (MASK_HAS_BITS
907                                             (remote_modifier_state, MapNumLockMask) == False);
908                                    MASK_CHANGE_BIT(remote_modifier_state,
909                                                    MapNumLockMask, newNumLockState);
910                            }
911            }
912    
913    #ifdef WITH_DEBUG_KBD
914            if (old_modifier_state != remote_modifier_state)
915            {
916                    DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
917                               old_modifier_state, pressed));
918                    DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
919            }
920    #endif
921    
922    }
923    
924    /* Send keyboard input */
925    void
926    rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
927    {
928            update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
929    
930            if (scancode & SCANCODE_EXTENDED)
931            {
932                    DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
933                               scancode & ~SCANCODE_EXTENDED, flags));
934                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
935                                   scancode & ~SCANCODE_EXTENDED, 0);
936            }
937            else
938            {
939                    DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
940                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
941            }
942    }

Legend:
Removed from v.50  
changed lines
  Added in v.960

  ViewVC Help
Powered by ViewVC 1.1.26