/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 949 - (hide annotations)
Tue Aug 2 15:07:35 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 20836 byte(s)
Implemented support for keyboard "sequences", which makes it possible to send multiple scancodes to the RDP server in response to one X11 keyboard event.

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

  ViewVC Help
Powered by ViewVC 1.1.26