/[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 1218 - (hide annotations)
Fri Apr 7 22:17:14 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 23861 byte(s)
Only release Shift if non-physical shift plus Ctrl is pressed;
not if CapsLock is active. This should solve bug 1228691.

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

  ViewVC Help
Powered by ViewVC 1.1.26