/[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 1405 - (hide annotations)
Thu May 3 04:53:39 2007 UTC (17 years, 1 month ago) by jsorg71
File MIME type: text/plain
File size: 24202 byte(s)
update save_remote_modifier when keyup on a modifier

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

  ViewVC Help
Powered by ViewVC 1.1.26