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

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

  ViewVC Help
Powered by ViewVC 1.1.26