/[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 1218 by astrand, Fri Apr 7 22:17:14 2006 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X keyboard mapping     User interface services - X keyboard mapping
4     Copyright (C) Matthew Chapman 1999-2001  
5       Copyright (C) Matthew Chapman 1999-2005
6       Copyright (C) Peter Astrand <peter@cendio.se> 2003
7        
8     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 12  Line 14 
14     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.     GNU General Public License for more details.
17      
18     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */  */
22    
23    #ifdef RDP2VNC
24    #include "vnc/x11stubs.h"
25    #else
26  #include <X11/Xlib.h>  #include <X11/Xlib.h>
27  #include <X11/keysym.h>  #include <X11/keysym.h>
28  #include <stdio.h>  #endif
29  #include <stdlib.h>  
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 0xffff+1
38    #define KEYMAP_MASK 0xffff
39    #define KEYMAP_MAX_LINE_LENGTH 80
40    
41    extern Display *g_display;
42    extern Window g_wnd;
43    extern char g_keymapname[16];
44    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 BOOL g_enable_compose;
50    extern BOOL g_use_rdp5;
51    extern BOOL g_numlock_sync;
52    
53    static BOOL keymap_loaded;
54    static key_translation *keymap[KEYMAP_SIZE];
55    static int min_keycode;
56    static uint16 remote_modifier_state = 0;
57    static uint16 saved_remote_modifier_state = 0;
58    
59    static void update_modifier_state(uint8 scancode, BOOL pressed);
60    
61    /* Free key_translation structure, including linked list */
62    static void
63    free_key_translation(key_translation * ptr)
64    {
65            key_translation *next;
66    
67            while (ptr)
68            {
69                    next = ptr->next;
70                    xfree(ptr);
71                    ptr = next;
72            }
73    }
74    
75    static void
76    add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
77    {
78            KeySym keysym;
79            key_translation *tr;
80    
81            keysym = XStringToKeysym(keyname);
82            if (keysym == NoSymbol)
83            {
84                    DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
85                    return;
86            }
87    
88  #define KEYMAP_SIZE 4096          DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
89  #define KEYMAP_MASK (KEYMAP_SIZE - 1)                     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
90    
91  extern Display *display;          tr = (key_translation *) xmalloc(sizeof(key_translation));
92  extern char keymapname[16];          memset(tr, 0, sizeof(key_translation));
93  extern int keylayout;          tr->scancode = scancode;
94            tr->modifiers = modifiers;
95            free_key_translation(keymap[keysym & KEYMAP_MASK]);
96            keymap[keysym & KEYMAP_MASK] = tr;
97    
98  static uint8 keymap[KEYMAP_SIZE];          return;
99  static unsigned int min_keycode;  }
100    
101  static BOOL xkeymap_read(char *mapname)  static void
102    add_sequence(char *rest, char *mapname)
103  {  {
         FILE *fp;  
         char line[PATH_MAX], path[PATH_MAX];  
         char *keyname, *p;  
104          KeySym keysym;          KeySym keysym;
105          unsigned char keycode;          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          strcpy(path, KEYMAP_PATH);  BOOL
163          strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));  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          fp = fopen(path, "r");          /* 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)          if (fp == NULL)
195          {          {
196                  error("Failed to open keymap %s\n", path);                  /* Truncate at dash */
197                    ptr = strrchr(str, '-');
198                    if (ptr)
199                            *ptr = '\0';
200    
201                    /* Try the short name (da) */
202                    fp = xkeymap_open(str);
203            }
204    
205            if (fp)
206            {
207                    fclose(fp);
208                    STRNCPY(g_keymapname, str, sizeof(g_keymapname));
209                    return True;
210            }
211    
212            return False;
213    }
214    
215    
216    /* Joins two path components. The result should be freed with
217       xfree(). */
218    static char *
219    pathjoin(const char *a, const char *b)
220    {
221            char *result;
222            result = xmalloc(PATH_MAX * 2 + 1);
223    
224            if (b[0] == '/')
225            {
226                    strncpy(result, b, PATH_MAX);
227            }
228            else
229            {
230                    strncpy(result, a, PATH_MAX);
231                    strcat(result, "/");
232                    strncat(result, b, PATH_MAX);
233            }
234            return result;
235    }
236    
237    /* Try to open a keymap with fopen() */
238    FILE *
239    xkeymap_open(const char *filename)
240    {
241            char *path1, *path2;
242            char *home;
243            FILE *fp;
244    
245            /* Try ~/.rdesktop/keymaps */
246            home = getenv("HOME");
247            if (home)
248            {
249                    path1 = pathjoin(home, ".rdesktop/keymaps");
250                    path2 = pathjoin(path1, filename);
251                    xfree(path1);
252                    fp = fopen(path2, "r");
253                    xfree(path2);
254                    if (fp)
255                            return fp;
256            }
257    
258            /* Try KEYMAP_PATH */
259            path1 = pathjoin(KEYMAP_PATH, filename);
260            fp = fopen(path1, "r");
261            xfree(path1);
262            if (fp)
263                    return fp;
264    
265            /* Try current directory, in case we are running from the source
266               tree */
267            path1 = pathjoin("keymaps", filename);
268            fp = fopen(path1, "r");
269            xfree(path1);
270            if (fp)
271                    return fp;
272    
273            return NULL;
274    }
275    
276    static BOOL
277    xkeymap_read(char *mapname)
278    {
279            FILE *fp;
280            char line[KEYMAP_MAX_LINE_LENGTH];
281            unsigned int line_num = 0;
282            unsigned int line_length = 0;
283            char *keyname, *p;
284            char *line_rest;
285            uint8 scancode;
286            uint16 modifiers;
287    
288            fp = xkeymap_open(mapname);
289            if (fp == NULL)
290            {
291                    error("Failed to open keymap %s\n", mapname);
292                  return False;                  return False;
293          }          }
294    
295            /* FIXME: More tolerant on white space */
296          while (fgets(line, sizeof(line), fp) != NULL)          while (fgets(line, sizeof(line), fp) != NULL)
297          {          {
298                    line_num++;
299    
300                    /* Replace the \n with \0 */
301                  p = strchr(line, '\n');                  p = strchr(line, '\n');
302                  if (p != NULL)                  if (p != NULL)
303                          *p = 0;                          *p = 0;
304    
305                  keycode = strtol(line, &keyname, 16);                  line_length = strlen(line);
306                  if ((keycode != 0) && (*keyname == ' '))  
307                    /* Completely empty line */
308                    if (strspn(line, " \t\n\r\f\v") == line_length)
309                  {                  {
310                          do                          continue;
311                          {                  }
312                                  keyname++;  
313                                  p = strchr(keyname, ' ');                  /* Include */
314                                  if (p != NULL)                  if (str_startswith(line, "include "))
315                                          *p = 0;                  {
316                            if (!xkeymap_read(line + sizeof("include ") - 1))
317                                    return False;
318                            continue;
319                    }
320    
321                                  keysym = XStringToKeysym(keyname);                  /* map */
322                                  if (keysym == NoSymbol)                  if (str_startswith(line, "map "))
323                                          error("Bad keysym %s in keymap %s\n", keyname, mapname);                  {
324                            g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16);
325                            DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
326                            continue;
327                    }
328    
329                                  keymap[keysym & KEYMAP_MASK] = keycode;                  /* compose */
330                                  keyname = p;                  if (str_startswith(line, "enable_compose"))
331                    {
332                            DEBUG_KBD(("Enabling compose handling\n"));
333                            g_enable_compose = True;
334                            continue;
335                    }
336    
337                          } while (keyname != NULL);                  /* sequence */
338                    if (str_startswith(line, "sequence"))
339                    {
340                            add_sequence(line + sizeof("sequence") - 1, mapname);
341                            continue;
342                  }                  }
343                  else if (strncmp(line, "include ", 8) == 0)  
344                    /* keyboard_type */
345                    if (str_startswith(line, "keyboard_type "))
346                  {                  {
347                          if (!xkeymap_read(line+8))                          g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
348                                  return False;                          DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
349                            continue;
350                  }                  }
351                  else if (strncmp(line, "map ", 4) == 0)  
352                    /* keyboard_subtype */
353                    if (str_startswith(line, "keyboard_subtype "))
354                    {
355                            g_keyboard_subtype =
356                                    strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
357                            DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
358                            continue;
359                    }
360    
361                    /* keyboard_functionkeys */
362                    if (str_startswith(line, "keyboard_functionkeys "))
363                    {
364                            g_keyboard_functionkeys =
365                                    strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
366                            DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
367                            continue;
368                    }
369    
370                    /* Comment */
371                    if (line[0] == '#')
372                    {
373                            continue;
374                    }
375    
376                    /* Normal line */
377                    keyname = line;
378                    p = strchr(line, ' ');
379                    if (p == NULL)
380                  {                  {
381                          keylayout = strtol(line+4, NULL, 16);                          error("Bad line %d in keymap %s\n", line_num, mapname);
382                            continue;
383                  }                  }
384                  else if (line[0] != '#')                  else
385                    {
386                            *p = 0;
387                    }
388    
389                    /* scancode */
390                    p++;
391                    scancode = strtol(p, &line_rest, 16);
392    
393                    /* flags */
394                    /* FIXME: Should allow case-insensitive flag names.
395                       Fix by using lex+yacc... */
396                    modifiers = 0;
397                    if (strstr(line_rest, "altgr"))
398                  {                  {
399                          error("Malformed line in keymap %s\n", mapname);                          MASK_ADD_BITS(modifiers, MapAltGrMask);
400                    }
401    
402                    if (strstr(line_rest, "shift"))
403                    {
404                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
405                    }
406    
407                    if (strstr(line_rest, "numlock"))
408                    {
409                            MASK_ADD_BITS(modifiers, MapNumLockMask);
410                    }
411    
412                    if (strstr(line_rest, "localstate"))
413                    {
414                            MASK_ADD_BITS(modifiers, MapLocalStateMask);
415                    }
416    
417                    if (strstr(line_rest, "inhibit"))
418                    {
419                            MASK_ADD_BITS(modifiers, MapInhibitMask);
420                    }
421    
422                    add_to_keymap(keyname, scancode, modifiers, mapname);
423    
424                    if (strstr(line_rest, "addupper"))
425                    {
426                            /* Automatically add uppercase key, with same modifiers
427                               plus shift */
428                            for (p = keyname; *p; p++)
429                                    *p = toupper((int) *p);
430                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
431                            add_to_keymap(keyname, scancode, modifiers, mapname);
432                  }                  }
433          }          }
434    
# Line 98  static BOOL xkeymap_read(char *mapname) Line 436  static BOOL xkeymap_read(char *mapname)
436          return True;          return True;
437  }  }
438    
439  void xkeymap_init(void)  
440    /* Before connecting and creating UI */
441    void
442    xkeymap_init(void)
443  {  {
444          unsigned int max_keycode;          unsigned int max_keycode;
445    
446          XDisplayKeycodes(display, &min_keycode, &max_keycode);          if (strcmp(g_keymapname, "none"))
447            {
448                    if (xkeymap_read(g_keymapname))
449                            keymap_loaded = True;
450            }
451    
452          if (strcmp(keymapname, "none"))          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
                 xkeymap_read(keymapname);  
453  }  }
454    
455  uint8 xkeymap_translate_key(unsigned int keysym, unsigned int keycode, uint16 *flags)  static void
456    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
457  {  {
458          uint8 scancode;          uint8 winkey;
459    
460          scancode = keymap[keysym & KEYMAP_MASK];          if (leftkey)
461          if (scancode != 0)                  winkey = SCANCODE_CHAR_LWIN;
462            else
463                    winkey = SCANCODE_CHAR_RWIN;
464    
465            if (pressed)
466          {          {
467                  if (scancode & 0x80)                  if (g_use_rdp5)
468                          *flags |= KBD_FLAG_EXT;                  {
469                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
470                    }
471                    else
472                    {
473                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
474                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
475                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
476                    }
477            }
478            else
479            {
480                    /* key released */
481                    if (g_use_rdp5)
482                    {
483                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
484                    }
485                    else
486                    {
487                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
488                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
489                    }
490            }
491    }
492    
493                  return (scancode & 0x7f);  static void
494    reset_winkey(uint32 ev_time)
495    {
496            if (g_use_rdp5)
497            {
498                    /* For some reason, it seems to suffice to release
499                     *either* the left or right winkey. */
500                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
501          }          }
502    }
503    
504    /* Handle special key combinations */
505    BOOL
506    handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
507    {
508            switch (keysym)
509            {
510                    case XK_Return:
511                            if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
512                                && (get_key_state(state, XK_Control_L)
513                                    || get_key_state(state, XK_Control_R)))
514                            {
515                                    /* Ctrl-Alt-Enter: toggle full screen */
516                                    if (pressed)
517                                            xwin_toggle_fullscreen();
518                                    return True;
519                            }
520                            break;
521    
522                    case XK_Break:
523                            /* Send Break sequence E0 46 E0 C6 */
524                            if (pressed)
525                            {
526                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
527                                                      (SCANCODE_EXTENDED | 0x46));
528                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
529                                                      (SCANCODE_EXTENDED | 0xc6));
530                            }
531                            /* No release sequence */
532                            return True;
533                            break;
534    
535                    case XK_Pause:
536                            /* According to MS Keyboard Scan Code
537                               Specification, pressing Pause should result
538                               in E1 1D 45 E1 9D C5. I'm not exactly sure
539                               of how this is supposed to be sent via
540                               RDP. The code below seems to work, but with
541                               the side effect that Left Ctrl stays
542                               down. Therefore, we release it when Pause
543                               is released. */
544                            if (pressed)
545                            {
546                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
547                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
548                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
549                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
550                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
551                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
552                            }
553                            else
554                            {
555                                    /* Release Left Ctrl */
556                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
557                                                   0x1d, 0);
558                            }
559                            return True;
560                            break;
561    
562                    case XK_Meta_L: /* Windows keys */
563                    case XK_Super_L:
564                    case XK_Hyper_L:
565                            send_winkey(ev_time, pressed, True);
566                            return True;
567                            break;
568    
569                    case XK_Meta_R:
570                    case XK_Super_R:
571                    case XK_Hyper_R:
572                            send_winkey(ev_time, pressed, False);
573                            return True;
574                            break;
575    
576                    case XK_space:
577                            /* Prevent access to the Windows system menu in single app mode */
578                            if (g_win_button_size
579                                && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
580                                    return True;
581                            break;
582    
583                    case XK_Num_Lock:
584                            /* Synchronize on key release */
585                            if (g_numlock_sync && !pressed)
586                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
587                                                   ui_get_numlock_state(read_keyboard_state()), 0);
588    
589                            /* Inhibit */
590                            return True;
591                            break;
592                    case XK_Overlay1_Enable:
593                            /* Toggle SeamlessRDP */
594                            if (pressed)
595                                    ui_seamless_toggle();
596                            break;
597    
         /* 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;  
598          }          }
599            return False;
600    }
601    
602          return 0;  
603    key_translation
604    xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
605    {
606            key_translation tr = { 0, 0, 0, 0 };
607            key_translation *ptr;
608    
609            ptr = keymap[keysym & KEYMAP_MASK];
610            if (ptr)
611            {
612                    tr = *ptr;
613                    if (tr.seq_keysym == 0) /* Normal scancode translation */
614                    {
615                            if (tr.modifiers & MapInhibitMask)
616                            {
617                                    DEBUG_KBD(("Inhibiting key\n"));
618                                    tr.scancode = 0;
619                                    return tr;
620                            }
621    
622                            if (tr.modifiers & MapLocalStateMask)
623                            {
624                                    /* The modifiers to send for this key should be obtained
625                                       from the local state. Currently, only shift is implemented. */
626                                    if (state & ShiftMask)
627                                    {
628                                            tr.modifiers = MapLeftShiftMask;
629                                    }
630                            }
631    
632                            /* Windows interprets CapsLock+Ctrl+key
633                               differently from Shift+Ctrl+key. Since we
634                               are simulating CapsLock with Shifts, things
635                               like Ctrl+f with CapsLock on breaks. To
636                               solve this, we are releasing Shift if Ctrl
637                               is on, but only if Shift isn't physically pressed. */
638                            if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
639                                && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
640                                && !MASK_HAS_BITS(state, ShiftMask))
641                            {
642                                    DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
643                                    MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
644                            }
645    
646                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
647                                       tr.scancode, tr.modifiers));
648                    }
649            }
650            else
651            {
652                    if (keymap_loaded)
653                            warning("No translation for (keysym 0x%lx, %s)\n", keysym,
654                                    get_ksname(keysym));
655    
656                    /* not in keymap, try to interpret the raw scancode */
657                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
658                    {
659                            tr.scancode = keycode - min_keycode;
660    
661                            /* The modifiers to send for this key should be
662                               obtained from the local state. Currently, only
663                               shift is implemented. */
664                            if (state & ShiftMask)
665                            {
666                                    tr.modifiers = MapLeftShiftMask;
667                            }
668    
669                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
670                    }
671                    else
672                    {
673                            DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
674                    }
675            }
676    
677            return tr;
678  }  }
679    
680  uint16 xkeymap_translate_button(unsigned int button)  void
681    xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
682                      BOOL pressed, uint8 nesting)
683    {
684            key_translation tr, *ptr;
685            tr = xkeymap_translate_key(keysym, keycode, state);
686    
687            if (tr.seq_keysym == 0)
688            {
689                    /* Scancode translation */
690                    if (tr.scancode == 0)
691                            return;
692    
693                    if (pressed)
694                    {
695                            save_remote_modifiers(tr.scancode);
696                            ensure_remote_modifiers(ev_time, tr);
697                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
698                            restore_remote_modifiers(ev_time, tr.scancode);
699                    }
700                    else
701                    {
702                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
703                    }
704                    return;
705            }
706    
707            /* Sequence, only on key down */
708            if (pressed)
709            {
710                    ptr = &tr;
711                    do
712                    {
713                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
714                                       (unsigned int) ptr->seq_keysym));
715    
716                            if (nesting++ > 32)
717                            {
718                                    error("Sequence nesting too deep\n");
719                                    return;
720                            }
721    
722                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
723                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
724                            ptr = ptr->next;
725                    }
726                    while (ptr);
727            }
728    }
729    
730    uint16
731    xkeymap_translate_button(unsigned int button)
732  {  {
733          switch (button)          switch (button)
734          {          {
735                  case Button1:   /* left */                  case Button1:   /* left */
736                          return MOUSE_FLAG_BUTTON1;                          return MOUSE_FLAG_BUTTON1;
737                  case Button2:   /* middle */                  case Button2:   /* middle */
738                          return MOUSE_FLAG_BUTTON3;                          return MOUSE_FLAG_BUTTON3;
739                  case Button3:   /* right */                  case Button3:   /* right */
740                          return MOUSE_FLAG_BUTTON2;                          return MOUSE_FLAG_BUTTON2;
741                    case Button4:   /* wheel up */
742                            return MOUSE_FLAG_BUTTON4;
743                    case Button5:   /* wheel down */
744                            return MOUSE_FLAG_BUTTON5;
745            }
746    
747            return 0;
748    }
749    
750    char *
751    get_ksname(uint32 keysym)
752    {
753            char *ksname = NULL;
754    
755            if (keysym == NoSymbol)
756                    ksname = "NoSymbol";
757            else if (!(ksname = XKeysymToString(keysym)))
758                    ksname = "(no name)";
759    
760            return ksname;
761    }
762    
763    static BOOL
764    is_modifier(uint8 scancode)
765    {
766            switch (scancode)
767            {
768                    case SCANCODE_CHAR_LSHIFT:
769                    case SCANCODE_CHAR_RSHIFT:
770                    case SCANCODE_CHAR_LCTRL:
771                    case SCANCODE_CHAR_RCTRL:
772                    case SCANCODE_CHAR_LALT:
773                    case SCANCODE_CHAR_RALT:
774                    case SCANCODE_CHAR_LWIN:
775                    case SCANCODE_CHAR_RWIN:
776                    case SCANCODE_CHAR_NUMLOCK:
777                            return True;
778                    default:
779                            break;
780            }
781            return False;
782    }
783    
784    void
785    save_remote_modifiers(uint8 scancode)
786    {
787            if (is_modifier(scancode))
788                    return;
789    
790            saved_remote_modifier_state = remote_modifier_state;
791    }
792    
793    void
794    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
795    {
796            key_translation dummy;
797    
798            if (is_modifier(scancode))
799                    return;
800    
801            dummy.scancode = 0;
802            dummy.modifiers = saved_remote_modifier_state;
803            ensure_remote_modifiers(ev_time, dummy);
804    }
805    
806    void
807    ensure_remote_modifiers(uint32 ev_time, key_translation tr)
808    {
809            /* If this key is a modifier, do nothing */
810            if (is_modifier(tr.scancode))
811                    return;
812    
813            if (!g_numlock_sync)
814            {
815                    /* NumLock */
816                    if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
817                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
818                    {
819                            /* The remote modifier state is not correct */
820                            uint16 new_remote_state;
821    
822                            if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
823                            {
824                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
825                                    new_remote_state = KBD_FLAG_NUMLOCK;
826                                    remote_modifier_state = MapNumLockMask;
827                            }
828                            else
829                            {
830                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
831                                    new_remote_state = 0;
832                                    remote_modifier_state = 0;
833                            }
834    
835                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
836                    }
837            }
838    
839    
840            /* Shift. Left shift and right shift are treated as equal; either is fine. */
841            if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
842                != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
843            {
844                    /* The remote modifier state is not correct */
845                    if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
846                    {
847                            /* Needs left shift. Send down. */
848                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
849                    }
850                    else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
851                    {
852                            /* Needs right shift. Send down. */
853                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
854                    }
855                    else
856                    {
857                            /* Should not use this modifier. Send up for shift currently pressed. */
858                            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
859                                    /* Left shift is down */
860                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
861                            else
862                                    /* Right shift is down */
863                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
864                    }
865          }          }
866    
867            /* AltGr */
868            if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
869                != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
870            {
871                    /* The remote modifier state is not correct */
872                    if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
873                    {
874                            /* Needs this modifier. Send down. */
875                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
876                    }
877                    else
878                    {
879                            /* Should not use this modifier. Send up. */
880                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
881                    }
882            }
883    
884    
885    }
886    
887    
888    unsigned int
889    read_keyboard_state()
890    {
891    #ifdef RDP2VNC
892          return 0;          return 0;
893    #else
894            unsigned int state;
895            Window wdummy;
896            int dummy;
897    
898            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
899            return state;
900    #endif
901    }
902    
903    
904    uint16
905    ui_get_numlock_state(unsigned int state)
906    {
907            uint16 numlock_state = 0;
908    
909            if (get_key_state(state, XK_Num_Lock))
910                    numlock_state = KBD_FLAG_NUMLOCK;
911    
912            return numlock_state;
913    }
914    
915    
916    void
917    reset_modifier_keys()
918    {
919            unsigned int state = read_keyboard_state();
920    
921            /* reset keys */
922            uint32 ev_time;
923            ev_time = time(NULL);
924    
925            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
926                && !get_key_state(state, XK_Shift_L))
927                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
928    
929            if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
930                && !get_key_state(state, XK_Shift_R))
931                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
932    
933            if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
934                && !get_key_state(state, XK_Control_L))
935                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
936    
937            if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
938                && !get_key_state(state, XK_Control_R))
939                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
940    
941            if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
942                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
943    
944            if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
945                !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
946                && !get_key_state(state, XK_ISO_Level3_Shift))
947                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
948    
949            reset_winkey(ev_time);
950    
951            if (g_numlock_sync)
952                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
953    }
954    
955    
956    static void
957    update_modifier_state(uint8 scancode, BOOL pressed)
958    {
959    #ifdef WITH_DEBUG_KBD
960            uint16 old_modifier_state;
961    
962            old_modifier_state = remote_modifier_state;
963    #endif
964    
965            switch (scancode)
966            {
967                    case SCANCODE_CHAR_LSHIFT:
968                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
969                            break;
970                    case SCANCODE_CHAR_RSHIFT:
971                            MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
972                            break;
973                    case SCANCODE_CHAR_LCTRL:
974                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
975                            break;
976                    case SCANCODE_CHAR_RCTRL:
977                            MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
978                            break;
979                    case SCANCODE_CHAR_LALT:
980                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
981                            break;
982                    case SCANCODE_CHAR_RALT:
983                            MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
984                            break;
985                    case SCANCODE_CHAR_LWIN:
986                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
987                            break;
988                    case SCANCODE_CHAR_RWIN:
989                            MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
990                            break;
991                    case SCANCODE_CHAR_NUMLOCK:
992                            /* KeyReleases for NumLocks are sent immediately. Toggle the
993                               modifier state only on Keypress */
994                            if (pressed && !g_numlock_sync)
995                            {
996                                    BOOL newNumLockState;
997                                    newNumLockState =
998                                            (MASK_HAS_BITS
999                                             (remote_modifier_state, MapNumLockMask) == False);
1000                                    MASK_CHANGE_BIT(remote_modifier_state,
1001                                                    MapNumLockMask, newNumLockState);
1002                            }
1003            }
1004    
1005    #ifdef WITH_DEBUG_KBD
1006            if (old_modifier_state != remote_modifier_state)
1007            {
1008                    DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1009                               old_modifier_state, pressed));
1010                    DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1011            }
1012    #endif
1013    
1014    }
1015    
1016    /* Send keyboard input */
1017    void
1018    rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1019    {
1020            update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1021    
1022            if (scancode & SCANCODE_EXTENDED)
1023            {
1024                    DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1025                               scancode & ~SCANCODE_EXTENDED, flags));
1026                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1027                                   scancode & ~SCANCODE_EXTENDED, 0);
1028            }
1029            else
1030            {
1031                    DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1032                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1033            }
1034  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26