/[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 56 by jsorg71, Fri Jul 12 22:40:32 2002 UTC revision 976 by astrand, Thu Aug 4 13:39:57 2005 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 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 (strncmp(line, "include ", sizeof("include ") - 1) == 0)
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 (strncmp(line, "map ", sizeof("map ") - 1) == 0)
323                                          error("Bad keysym %s in keymap %s\n", keyname, mapname);                  {
324                            g_keylayout = strtol(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 (strncmp(line, "enable_compose", sizeof("enable_compose") - 1) == 0)
331                    {
332                            DEBUG_KBD(("Enabling compose handling\n"));
333                            g_enable_compose = True;
334                            continue;
335                    }
336    
337                          } while (keyname != NULL);                  /* sequence */
338                    if (strncmp(line, "sequence", sizeof("sequence") - 1) == 0)
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 (strncmp(line, "keyboard_type ", sizeof("keyboard_type ") - 1) == 0)
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 (strncmp(line, "keyboard_subtype ", sizeof("keyboard_subtype ") - 1) == 0)
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 (strncmp(line, "keyboard_functionkeys ", sizeof("keyboard_functionkeys ") - 1) ==
363                        0)
364                    {
365                            g_keyboard_functionkeys =
366                                    strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
367                            DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
368                            continue;
369                    }
370    
371                    /* Comment */
372                    if (line[0] == '#')
373                    {
374                            continue;
375                    }
376    
377                    /* Normal line */
378                    keyname = line;
379                    p = strchr(line, ' ');
380                    if (p == NULL)
381                  {                  {
382                          keylayout = strtol(line+4, NULL, 16);                          error("Bad line %d in keymap %s\n", line_num, mapname);
383                            continue;
384                  }                  }
385                  else if (line[0] != '#')                  else
386                    {
387                            *p = 0;
388                    }
389    
390                    /* scancode */
391                    p++;
392                    scancode = strtol(p, &line_rest, 16);
393    
394                    /* flags */
395                    /* FIXME: Should allow case-insensitive flag names.
396                       Fix by using lex+yacc... */
397                    modifiers = 0;
398                    if (strstr(line_rest, "altgr"))
399                  {                  {
400                          error("Malformed line in keymap %s\n", mapname);                          MASK_ADD_BITS(modifiers, MapAltGrMask);
401                    }
402    
403                    if (strstr(line_rest, "shift"))
404                    {
405                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
406                    }
407    
408                    if (strstr(line_rest, "numlock"))
409                    {
410                            MASK_ADD_BITS(modifiers, MapNumLockMask);
411                    }
412    
413                    if (strstr(line_rest, "localstate"))
414                    {
415                            MASK_ADD_BITS(modifiers, MapLocalStateMask);
416                    }
417    
418                    if (strstr(line_rest, "inhibit"))
419                    {
420                            MASK_ADD_BITS(modifiers, MapInhibitMask);
421                    }
422    
423                    add_to_keymap(keyname, scancode, modifiers, mapname);
424    
425                    if (strstr(line_rest, "addupper"))
426                    {
427                            /* Automatically add uppercase key, with same modifiers
428                               plus shift */
429                            for (p = keyname; *p; p++)
430                                    *p = toupper((int) *p);
431                            MASK_ADD_BITS(modifiers, MapLeftShiftMask);
432                            add_to_keymap(keyname, scancode, modifiers, mapname);
433                  }                  }
434          }          }
435    
# Line 98  static BOOL xkeymap_read(char *mapname) Line 437  static BOOL xkeymap_read(char *mapname)
437          return True;          return True;
438  }  }
439    
440  void xkeymap_init(void)  
441    /* Before connecting and creating UI */
442    void
443    xkeymap_init(void)
444  {  {
445          unsigned int max_keycode;          unsigned int max_keycode;
446    
447          XDisplayKeycodes(display, &min_keycode, &max_keycode);          if (strcmp(g_keymapname, "none"))
448            {
449                    if (xkeymap_read(g_keymapname))
450                            keymap_loaded = True;
451            }
452    
453          if (strcmp(keymapname, "none"))          XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
                 xkeymap_read(keymapname);  
454  }  }
455    
456  uint8 xkeymap_translate_key(unsigned int keysym, unsigned int keycode, uint16 *flags)  static void
457    send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
458  {  {
459          uint8 scancode;          uint8 winkey;
460    
461          scancode = keymap[keysym & KEYMAP_MASK];          if (leftkey)
462          if (scancode != 0)                  winkey = SCANCODE_CHAR_LWIN;
463            else
464                    winkey = SCANCODE_CHAR_RWIN;
465    
466            if (pressed)
467          {          {
468                  if (scancode & 0x80)                  if (g_use_rdp5)
469                          *flags |= KBD_FLAG_EXT;                  {
470                            rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
471                    }
472                    else
473                    {
474                            /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
475                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
476                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
477                    }
478            }
479            else
480            {
481                    /* key released */
482                    if (g_use_rdp5)
483                    {
484                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
485                    }
486                    else
487                    {
488                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
489                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
490                    }
491            }
492    }
493    
494                  return (scancode & 0x7f);  static void
495    reset_winkey(uint32 ev_time)
496    {
497            if (g_use_rdp5)
498            {
499                    /* For some reason, it seems to suffice to release
500                     *either* the left or right winkey. */
501                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
502          }          }
503    }
504    
505    /* Handle special key combinations */
506    BOOL
507    handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
508    {
509            switch (keysym)
510            {
511                    case XK_Return:
512                            if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
513                                && (get_key_state(state, XK_Control_L)
514                                    || get_key_state(state, XK_Control_R)))
515                            {
516                                    /* Ctrl-Alt-Enter: toggle full screen */
517                                    if (pressed)
518                                            xwin_toggle_fullscreen();
519                                    return True;
520                            }
521                            break;
522    
523                    case XK_Break:
524                            /* Send Break sequence E0 46 E0 C6 */
525                            if (pressed)
526                            {
527                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
528                                                      (SCANCODE_EXTENDED | 0x46));
529                                    rdp_send_scancode(ev_time, RDP_KEYPRESS,
530                                                      (SCANCODE_EXTENDED | 0xc6));
531                            }
532                            /* No release sequence */
533                            return True;
534                            break;
535    
536                    case XK_Pause:
537                            /* According to MS Keyboard Scan Code
538                               Specification, pressing Pause should result
539                               in E1 1D 45 E1 9D C5. I'm not exactly sure
540                               of how this is supposed to be sent via
541                               RDP. The code below seems to work, but with
542                               the side effect that Left Ctrl stays
543                               down. Therefore, we release it when Pause
544                               is released. */
545                            if (pressed)
546                            {
547                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
548                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
549                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
550                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
551                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
552                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
553                            }
554                            else
555                            {
556                                    /* Release Left Ctrl */
557                                    rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
558                                                   0x1d, 0);
559                            }
560                            return True;
561                            break;
562    
563                    case XK_Meta_L: /* Windows keys */
564                    case XK_Super_L:
565                    case XK_Hyper_L:
566                            send_winkey(ev_time, pressed, True);
567                            return True;
568                            break;
569    
570                    case XK_Meta_R:
571                    case XK_Super_R:
572                    case XK_Hyper_R:
573                            send_winkey(ev_time, pressed, False);
574                            return True;
575                            break;
576    
577                    case XK_space:
578                            /* Prevent access to the Windows system menu in single app mode */
579                            if (g_win_button_size
580                                && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
581                                    return True;
582                            break;
583    
584                    case XK_Num_Lock:
585                            /* Synchronize on key release */
586                            if (g_numlock_sync && !pressed)
587                                    rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
588                                                   ui_get_numlock_state(read_keyboard_state()), 0);
589    
590                            /* Inhibit */
591                            return True;
592                            break;
593    
         /* 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;  
594          }          }
595            return False;
596    }
597    
598          return 0;  
599    key_translation
600    xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
601    {
602            key_translation tr = { 0, 0, 0, 0 };
603            key_translation *ptr;
604    
605            ptr = keymap[keysym & KEYMAP_MASK];
606            if (ptr)
607            {
608                    tr = *ptr;
609                    if (tr.seq_keysym == 0) /* Normal scancode translation */
610                    {
611                            if (tr.modifiers & MapInhibitMask)
612                            {
613                                    DEBUG_KBD(("Inhibiting key\n"));
614                                    tr.scancode = 0;
615                                    return tr;
616                            }
617    
618                            if (tr.modifiers & MapLocalStateMask)
619                            {
620                                    /* The modifiers to send for this key should be obtained
621                                       from the local state. Currently, only shift is implemented. */
622                                    if (state & ShiftMask)
623                                    {
624                                            tr.modifiers = MapLeftShiftMask;
625                                    }
626                            }
627    
628                            if ((tr.modifiers & MapLeftShiftMask)
629                                && ((remote_modifier_state & MapLeftCtrlMask)
630                                    || (remote_modifier_state & MapRightCtrlMask))
631                                && get_key_state(state, XK_Caps_Lock))
632                            {
633                                    DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
634                                    tr.modifiers ^= MapLeftShiftMask;
635                            }
636    
637                            DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
638                                       tr.scancode, tr.modifiers));
639                    }
640            }
641            else
642            {
643                    if (keymap_loaded)
644                            warning("No translation for (keysym 0x%lx, %s)\n", keysym,
645                                    get_ksname(keysym));
646    
647                    /* not in keymap, try to interpret the raw scancode */
648                    if (((int) keycode >= min_keycode) && (keycode <= 0x60))
649                    {
650                            tr.scancode = keycode - min_keycode;
651    
652                            /* The modifiers to send for this key should be
653                               obtained from the local state. Currently, only
654                               shift is implemented. */
655                            if (state & ShiftMask)
656                            {
657                                    tr.modifiers = MapLeftShiftMask;
658                            }
659    
660                            DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
661                    }
662                    else
663                    {
664                            DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
665                    }
666            }
667    
668            return tr;
669  }  }
670    
671  uint16 xkeymap_translate_button(unsigned int button)  void
672    xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
673                      BOOL pressed, uint8 nesting)
674    {
675            key_translation tr, *ptr;
676            tr = xkeymap_translate_key(keysym, keycode, state);
677    
678            if (tr.seq_keysym == 0)
679            {
680                    /* Scancode translation */
681                    if (tr.scancode == 0)
682                            return;
683    
684                    if (pressed)
685                    {
686                            save_remote_modifiers(tr.scancode);
687                            ensure_remote_modifiers(ev_time, tr);
688                            rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
689                            restore_remote_modifiers(ev_time, tr.scancode);
690                    }
691                    else
692                    {
693                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
694                    }
695                    return;
696            }
697    
698            /* Sequence, only on key down */
699            if (pressed)
700            {
701                    ptr = &tr;
702                    do
703                    {
704                            DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
705                                       (unsigned int) ptr->seq_keysym));
706    
707                            if (nesting++ > 32)
708                            {
709                                    error("Sequence nesting too deep\n");
710                                    return;
711                            }
712    
713                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
714                            xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
715                            ptr = ptr->next;
716                    }
717                    while (ptr);
718            }
719    }
720    
721    uint16
722    xkeymap_translate_button(unsigned int button)
723  {  {
724          switch (button)          switch (button)
725          {          {
726                  case Button1:   /* left */                  case Button1:   /* left */
727                          return MOUSE_FLAG_BUTTON1;                          return MOUSE_FLAG_BUTTON1;
728                  case Button2:   /* middle */                  case Button2:   /* middle */
729                          return MOUSE_FLAG_BUTTON3;                          return MOUSE_FLAG_BUTTON3;
730                  case Button3:   /* right */                  case Button3:   /* right */
731                          return MOUSE_FLAG_BUTTON2;                          return MOUSE_FLAG_BUTTON2;
732                  case Button4:   /* wheel up */                  case Button4:   /* wheel up */
733                          return MOUSE_FLAG_BUTTON4;                          return MOUSE_FLAG_BUTTON4;
734                  case Button5:   /* wheel down */                  case Button5:   /* wheel down */
735                          return MOUSE_FLAG_BUTTON5;                          return MOUSE_FLAG_BUTTON5;
736          }          }
737    
738          return 0;          return 0;
739  }  }
740    
741    char *
742    get_ksname(uint32 keysym)
743    {
744            char *ksname = NULL;
745    
746            if (keysym == NoSymbol)
747                    ksname = "NoSymbol";
748            else if (!(ksname = XKeysymToString(keysym)))
749                    ksname = "(no name)";
750    
751            return ksname;
752    }
753    
754    static BOOL
755    is_modifier(uint8 scancode)
756    {
757            switch (scancode)
758            {
759                    case SCANCODE_CHAR_LSHIFT:
760                    case SCANCODE_CHAR_RSHIFT:
761                    case SCANCODE_CHAR_LCTRL:
762                    case SCANCODE_CHAR_RCTRL:
763                    case SCANCODE_CHAR_LALT:
764                    case SCANCODE_CHAR_RALT:
765                    case SCANCODE_CHAR_LWIN:
766                    case SCANCODE_CHAR_RWIN:
767                    case SCANCODE_CHAR_NUMLOCK:
768                            return True;
769                    default:
770                            break;
771            }
772            return False;
773    }
774    
775    void
776    save_remote_modifiers(uint8 scancode)
777    {
778            if (is_modifier(scancode))
779                    return;
780    
781            saved_remote_modifier_state = remote_modifier_state;
782    }
783    
784    void
785    restore_remote_modifiers(uint32 ev_time, uint8 scancode)
786    {
787            key_translation dummy;
788    
789            if (is_modifier(scancode))
790                    return;
791    
792            dummy.scancode = 0;
793            dummy.modifiers = saved_remote_modifier_state;
794            ensure_remote_modifiers(ev_time, dummy);
795    }
796    
797    void
798    ensure_remote_modifiers(uint32 ev_time, key_translation tr)
799    {
800            /* If this key is a modifier, do nothing */
801            if (is_modifier(tr.scancode))
802                    return;
803    
804            if (!g_numlock_sync)
805            {
806                    /* NumLock */
807                    if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
808                        != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
809                    {
810                            /* The remote modifier state is not correct */
811                            uint16 new_remote_state;
812    
813                            if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
814                            {
815                                    DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
816                                    new_remote_state = KBD_FLAG_NUMLOCK;
817                                    remote_modifier_state = MapNumLockMask;
818                            }
819                            else
820                            {
821                                    DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
822                                    new_remote_state = 0;
823                                    remote_modifier_state = 0;
824                            }
825    
826                            rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
827                    }
828            }
829    
830    
831            /* Shift. Left shift and right shift are treated as equal; either is fine. */
832            if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
833                != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
834            {
835                    /* The remote modifier state is not correct */
836                    if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
837                    {
838                            /* Needs left shift. Send down. */
839                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
840                    }
841                    else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
842                    {
843                            /* Needs right shift. Send down. */
844                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
845                    }
846                    else
847                    {
848                            /* Should not use this modifier. Send up for shift currently pressed. */
849                            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
850                                    /* Left shift is down */
851                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
852                            else
853                                    /* Right shift is down */
854                                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
855                    }
856            }
857    
858            /* AltGr */
859            if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
860                != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
861            {
862                    /* The remote modifier state is not correct */
863                    if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
864                    {
865                            /* Needs this modifier. Send down. */
866                            rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
867                    }
868                    else
869                    {
870                            /* Should not use this modifier. Send up. */
871                            rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
872                    }
873            }
874    
875    
876    }
877    
878    
879    unsigned int
880    read_keyboard_state()
881    {
882    #ifdef RDP2VNC
883            return 0;
884    #else
885            unsigned int state;
886            Window wdummy;
887            int dummy;
888    
889            XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
890            return state;
891    #endif
892    }
893    
894    
895    uint16
896    ui_get_numlock_state(unsigned int state)
897    {
898            uint16 numlock_state = 0;
899    
900            if (get_key_state(state, XK_Num_Lock))
901                    numlock_state = KBD_FLAG_NUMLOCK;
902    
903            return numlock_state;
904    }
905    
906    
907    void
908    reset_modifier_keys()
909    {
910            unsigned int state = read_keyboard_state();
911    
912            /* reset keys */
913            uint32 ev_time;
914            ev_time = time(NULL);
915    
916            if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
917                && !get_key_state(state, XK_Shift_L))
918                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
919    
920            if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
921                && !get_key_state(state, XK_Shift_R))
922                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
923    
924            if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
925                && !get_key_state(state, XK_Control_L))
926                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
927    
928            if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
929                && !get_key_state(state, XK_Control_R))
930                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
931    
932            if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
933                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
934    
935            if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
936                !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
937                && !get_key_state(state, XK_ISO_Level3_Shift))
938                    rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
939    
940            reset_winkey(ev_time);
941    
942            if (g_numlock_sync)
943                    rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
944    }
945    
946    
947    static void
948    update_modifier_state(uint8 scancode, BOOL pressed)
949    {
950    #ifdef WITH_DEBUG_KBD
951            uint16 old_modifier_state;
952    
953            old_modifier_state = remote_modifier_state;
954    #endif
955    
956            switch (scancode)
957            {
958                    case SCANCODE_CHAR_LSHIFT:
959                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
960                            break;
961                    case SCANCODE_CHAR_RSHIFT:
962                            MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
963                            break;
964                    case SCANCODE_CHAR_LCTRL:
965                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
966                            break;
967                    case SCANCODE_CHAR_RCTRL:
968                            MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
969                            break;
970                    case SCANCODE_CHAR_LALT:
971                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
972                            break;
973                    case SCANCODE_CHAR_RALT:
974                            MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
975                            break;
976                    case SCANCODE_CHAR_LWIN:
977                            MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
978                            break;
979                    case SCANCODE_CHAR_RWIN:
980                            MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
981                            break;
982                    case SCANCODE_CHAR_NUMLOCK:
983                            /* KeyReleases for NumLocks are sent immediately. Toggle the
984                               modifier state only on Keypress */
985                            if (pressed && !g_numlock_sync)
986                            {
987                                    BOOL newNumLockState;
988                                    newNumLockState =
989                                            (MASK_HAS_BITS
990                                             (remote_modifier_state, MapNumLockMask) == False);
991                                    MASK_CHANGE_BIT(remote_modifier_state,
992                                                    MapNumLockMask, newNumLockState);
993                            }
994            }
995    
996    #ifdef WITH_DEBUG_KBD
997            if (old_modifier_state != remote_modifier_state)
998            {
999                    DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1000                               old_modifier_state, pressed));
1001                    DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1002            }
1003    #endif
1004    
1005    }
1006    
1007    /* Send keyboard input */
1008    void
1009    rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1010    {
1011            update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1012    
1013            if (scancode & SCANCODE_EXTENDED)
1014            {
1015                    DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1016                               scancode & ~SCANCODE_EXTENDED, flags));
1017                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1018                                   scancode & ~SCANCODE_EXTENDED, 0);
1019            }
1020            else
1021            {
1022                    DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1023                    rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1024            }
1025    }

Legend:
Removed from v.56  
changed lines
  Added in v.976

  ViewVC Help
Powered by ViewVC 1.1.26