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

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

  ViewVC Help
Powered by ViewVC 1.1.26