/[rdesktop]/sourceforge.net/trunk/rdesktop/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

  ViewVC Help
Powered by ViewVC 1.1.26