/[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 1293 - (hide annotations)
Wed Oct 11 17:56:05 2006 UTC (17 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 24135 byte(s)
Changed the Copyright: tag to License: in accordance with RPM 4

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 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 astrand 64 static BOOL
279     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     send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
459     {
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 astrand 1293 printf("reset_winkey\n");
499 astrand 548 if (g_use_rdp5)
500     {
501     /* For some reason, it seems to suffice to release
502     *either* the left or right winkey. */
503     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
504     }
505     }
506    
507 astrand 952 /* Handle special key combinations */
508 astrand 118 BOOL
509 matthewc 203 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
510 astrand 118 {
511     switch (keysym)
512     {
513 matthewc 244 case XK_Return:
514 matthewc 212 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
515 astrand 226 && (get_key_state(state, XK_Control_L)
516     || get_key_state(state, XK_Control_R)))
517 astrand 118 {
518 matthewc 244 /* Ctrl-Alt-Enter: toggle full screen */
519 matthewc 193 if (pressed)
520     xwin_toggle_fullscreen();
521 matthewc 244 return True;
522     }
523     break;
524 astrand 199
525 matthewc 244 case XK_Break:
526     /* Send Break sequence E0 46 E0 C6 */
527     if (pressed)
528     {
529     rdp_send_scancode(ev_time, RDP_KEYPRESS,
530     (SCANCODE_EXTENDED | 0x46));
531     rdp_send_scancode(ev_time, RDP_KEYPRESS,
532     (SCANCODE_EXTENDED | 0xc6));
533 astrand 118 }
534 matthewc 244 /* No release sequence */
535     return True;
536 astrand 553 break;
537 matthewc 244
538     case XK_Pause:
539     /* According to MS Keyboard Scan Code
540     Specification, pressing Pause should result
541     in E1 1D 45 E1 9D C5. I'm not exactly sure
542     of how this is supposed to be sent via
543     RDP. The code below seems to work, but with
544     the side effect that Left Ctrl stays
545     down. Therefore, we release it when Pause
546     is released. */
547     if (pressed)
548 astrand 199 {
549 astrand 260 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
550     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
551     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
552     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
553     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
554     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
555 astrand 199 }
556 matthewc 244 else
557 astrand 197 {
558 matthewc 244 /* Release Left Ctrl */
559     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
560     0x1d, 0);
561 astrand 197 }
562     return True;
563 astrand 553 break;
564 astrand 197
565 astrand 118 case XK_Meta_L: /* Windows keys */
566     case XK_Super_L:
567     case XK_Hyper_L:
568 astrand 452 send_winkey(ev_time, pressed, True);
569     return True;
570 astrand 553 break;
571 astrand 452
572 astrand 118 case XK_Meta_R:
573     case XK_Super_R:
574     case XK_Hyper_R:
575 astrand 452 send_winkey(ev_time, pressed, False);
576 astrand 118 return True;
577 astrand 553 break;
578 astrand 331
579     case XK_space:
580     /* Prevent access to the Windows system menu in single app mode */
581 jsorg71 450 if (g_win_button_size
582 astrand 331 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
583     return True;
584 astrand 553 break;
585 astrand 910
586 astrand 552 case XK_Num_Lock:
587 astrand 910 /* Synchronize on key release */
588     if (g_numlock_sync && !pressed)
589     rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
590     ui_get_numlock_state(read_keyboard_state()), 0);
591    
592     /* Inhibit */
593     return True;
594 astrand 553 break;
595 astrand 1199 case XK_Overlay1_Enable:
596     /* Toggle SeamlessRDP */
597     if (pressed)
598     ui_seamless_toggle();
599     break;
600 astrand 331
601 astrand 118 }
602     return False;
603     }
604    
605    
606 astrand 66 key_translation
607 matthewc 190 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
608 astrand 66 {
609 astrand 949 key_translation tr = { 0, 0, 0, 0 };
610     key_translation *ptr;
611 astrand 66
612 astrand 949 ptr = keymap[keysym & KEYMAP_MASK];
613     if (ptr)
614     {
615     tr = *ptr;
616     if (tr.seq_keysym == 0) /* Normal scancode translation */
617     {
618 astrand 1219 if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
619 astrand 949 {
620     DEBUG_KBD(("Inhibiting key\n"));
621     tr.scancode = 0;
622     return tr;
623     }
624 astrand 66
625 astrand 1219 if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask))
626 astrand 949 {
627     /* The modifiers to send for this key should be obtained
628     from the local state. Currently, only shift is implemented. */
629 astrand 1219 if (MASK_HAS_BITS(state, ShiftMask))
630 astrand 949 {
631     tr.modifiers = MapLeftShiftMask;
632     }
633     }
634    
635 astrand 1218 /* Windows interprets CapsLock+Ctrl+key
636     differently from Shift+Ctrl+key. Since we
637     are simulating CapsLock with Shifts, things
638     like Ctrl+f with CapsLock on breaks. To
639     solve this, we are releasing Shift if Ctrl
640     is on, but only if Shift isn't physically pressed. */
641     if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
642     && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
643     && !MASK_HAS_BITS(state, ShiftMask))
644 astrand 949 {
645 astrand 1218 DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
646     MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
647 astrand 949 }
648    
649     DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
650     tr.scancode, tr.modifiers));
651     }
652     }
653     else
654 astrand 116 {
655 astrand 949 if (keymap_loaded)
656     warning("No translation for (keysym 0x%lx, %s)\n", keysym,
657     get_ksname(keysym));
658 astrand 116
659 astrand 949 /* not in keymap, try to interpret the raw scancode */
660     if (((int) keycode >= min_keycode) && (keycode <= 0x60))
661 astrand 69 {
662 astrand 949 tr.scancode = keycode - min_keycode;
663    
664     /* The modifiers to send for this key should be
665     obtained from the local state. Currently, only
666     shift is implemented. */
667 astrand 1219 if (MASK_HAS_BITS(state, ShiftMask))
668 astrand 949 {
669     tr.modifiers = MapLeftShiftMask;
670     }
671    
672     DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
673 astrand 69 }
674 astrand 949 else
675     {
676     DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
677     }
678 astrand 69 }
679    
680 astrand 949 return tr;
681     }
682 stargo 810
683 astrand 949 void
684     xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
685 astrand 976 BOOL pressed, uint8 nesting)
686 astrand 949 {
687     key_translation tr, *ptr;
688     tr = xkeymap_translate_key(keysym, keycode, state);
689 matthewc 50
690 astrand 949 if (tr.seq_keysym == 0)
691 matthewc 38 {
692 astrand 949 /* Scancode translation */
693     if (tr.scancode == 0)
694     return;
695 astrand 165
696 astrand 949 if (pressed)
697 astrand 165 {
698 astrand 949 save_remote_modifiers(tr.scancode);
699     ensure_remote_modifiers(ev_time, tr);
700     rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
701     restore_remote_modifiers(ev_time, tr.scancode);
702 astrand 165 }
703 astrand 949 else
704     {
705     rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
706     }
707     return;
708     }
709 astrand 165
710 astrand 949 /* Sequence, only on key down */
711     if (pressed)
712 astrand 66 {
713 astrand 949 ptr = &tr;
714     do
715     {
716     DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
717     (unsigned int) ptr->seq_keysym));
718 astrand 976
719     if (nesting++ > 32)
720     {
721     error("Sequence nesting too deep\n");
722     return;
723     }
724    
725     xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
726     xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
727 astrand 949 ptr = ptr->next;
728     }
729     while (ptr);
730 astrand 66 }
731 matthewc 38 }
732    
733 astrand 64 uint16
734     xkeymap_translate_button(unsigned int button)
735 matthewc 38 {
736     switch (button)
737     {
738 astrand 64 case Button1: /* left */
739 matthewc 38 return MOUSE_FLAG_BUTTON1;
740 astrand 64 case Button2: /* middle */
741 matthewc 38 return MOUSE_FLAG_BUTTON3;
742 astrand 64 case Button3: /* right */
743 matthewc 38 return MOUSE_FLAG_BUTTON2;
744 jsorg71 67 case Button4: /* wheel up */
745     return MOUSE_FLAG_BUTTON4;
746     case Button5: /* wheel down */
747     return MOUSE_FLAG_BUTTON5;
748 matthewc 38 }
749    
750     return 0;
751     }
752 astrand 66
753     char *
754 matthewc 190 get_ksname(uint32 keysym)
755 astrand 66 {
756     char *ksname = NULL;
757    
758     if (keysym == NoSymbol)
759     ksname = "NoSymbol";
760     else if (!(ksname = XKeysymToString(keysym)))
761     ksname = "(no name)";
762    
763     return ksname;
764     }
765    
766 astrand 470 static BOOL
767     is_modifier(uint8 scancode)
768     {
769     switch (scancode)
770     {
771     case SCANCODE_CHAR_LSHIFT:
772     case SCANCODE_CHAR_RSHIFT:
773     case SCANCODE_CHAR_LCTRL:
774     case SCANCODE_CHAR_RCTRL:
775     case SCANCODE_CHAR_LALT:
776     case SCANCODE_CHAR_RALT:
777     case SCANCODE_CHAR_LWIN:
778     case SCANCODE_CHAR_RWIN:
779     case SCANCODE_CHAR_NUMLOCK:
780     return True;
781     default:
782     break;
783     }
784     return False;
785     }
786    
787 astrand 449 void
788 astrand 470 save_remote_modifiers(uint8 scancode)
789 astrand 449 {
790 astrand 470 if (is_modifier(scancode))
791     return;
792    
793 astrand 449 saved_remote_modifier_state = remote_modifier_state;
794     }
795 astrand 66
796     void
797 astrand 470 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
798 astrand 449 {
799     key_translation dummy;
800    
801 astrand 470 if (is_modifier(scancode))
802     return;
803    
804 astrand 449 dummy.scancode = 0;
805     dummy.modifiers = saved_remote_modifier_state;
806     ensure_remote_modifiers(ev_time, dummy);
807     }
808    
809     void
810 astrand 66 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
811     {
812     /* If this key is a modifier, do nothing */
813 astrand 470 if (is_modifier(tr.scancode))
814     return;
815 astrand 66
816 astrand 552 if (!g_numlock_sync)
817     {
818     /* NumLock */
819     if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
820     != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
821     {
822     /* The remote modifier state is not correct */
823     uint16 new_remote_state;
824    
825     if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
826     {
827     DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
828     new_remote_state = KBD_FLAG_NUMLOCK;
829     remote_modifier_state = MapNumLockMask;
830     }
831     else
832     {
833     DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
834     new_remote_state = 0;
835     remote_modifier_state = 0;
836     }
837    
838     rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
839     }
840     }
841    
842    
843 astrand 183 /* Shift. Left shift and right shift are treated as equal; either is fine. */
844 astrand 66 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
845     != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
846     {
847     /* The remote modifier state is not correct */
848 astrand 183 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
849 astrand 66 {
850 astrand 183 /* Needs left shift. Send down. */
851 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
852 astrand 66 }
853 astrand 183 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
854     {
855     /* Needs right shift. Send down. */
856     rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
857     }
858 astrand 66 else
859     {
860 astrand 183 /* Should not use this modifier. Send up for shift currently pressed. */
861     if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
862     /* Left shift is down */
863     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
864     else
865     /* Right shift is down */
866     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
867 astrand 66 }
868     }
869    
870     /* AltGr */
871     if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
872     != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
873     {
874     /* The remote modifier state is not correct */
875     if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
876     {
877     /* Needs this modifier. Send down. */
878 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
879 astrand 66 }
880     else
881     {
882     /* Should not use this modifier. Send up. */
883 astrand 82 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
884 astrand 66 }
885     }
886    
887 astrand 115
888 astrand 66 }
889    
890    
891 astrand 543 unsigned int
892     read_keyboard_state()
893     {
894 stargo 648 #ifdef RDP2VNC
895     return 0;
896     #else
897 astrand 543 unsigned int state;
898     Window wdummy;
899     int dummy;
900    
901     XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
902     return state;
903 stargo 648 #endif
904 astrand 543 }
905    
906    
907     uint16
908     ui_get_numlock_state(unsigned int state)
909     {
910     uint16 numlock_state = 0;
911    
912     if (get_key_state(state, XK_Num_Lock))
913     numlock_state = KBD_FLAG_NUMLOCK;
914    
915     return numlock_state;
916     }
917    
918    
919 astrand 170 void
920 astrand 543 reset_modifier_keys()
921 astrand 170 {
922 astrand 543 unsigned int state = read_keyboard_state();
923    
924 astrand 170 /* reset keys */
925     uint32 ev_time;
926     ev_time = time(NULL);
927    
928 astrand 226 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
929     && !get_key_state(state, XK_Shift_L))
930 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
931    
932 astrand 226 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
933     && !get_key_state(state, XK_Shift_R))
934 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
935    
936 astrand 226 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
937     && !get_key_state(state, XK_Control_L))
938 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
939    
940 astrand 226 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
941     && !get_key_state(state, XK_Control_R))
942 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
943    
944 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
945 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
946    
947     if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
948 astrand 706 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
949     && !get_key_state(state, XK_ISO_Level3_Shift))
950 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
951 astrand 543
952 astrand 548 reset_winkey(ev_time);
953    
954 astrand 552 if (g_numlock_sync)
955     rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
956 astrand 1293
957     //sleep(4);
958     //rdp_send_input(time(NULL), RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9c, 0);
959     //rdp_send_input(time(NULL), RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x9c, 0);
960 astrand 170 }
961    
962    
963 astrand 66 static void
964 matthewc 203 update_modifier_state(uint8 scancode, BOOL pressed)
965 astrand 66 {
966 astrand 113 #ifdef WITH_DEBUG_KBD
967     uint16 old_modifier_state;
968 astrand 66
969 astrand 113 old_modifier_state = remote_modifier_state;
970     #endif
971    
972 matthewc 203 switch (scancode)
973 astrand 66 {
974     case SCANCODE_CHAR_LSHIFT:
975 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
976 astrand 66 break;
977     case SCANCODE_CHAR_RSHIFT:
978 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
979 astrand 66 break;
980     case SCANCODE_CHAR_LCTRL:
981 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
982 astrand 66 break;
983     case SCANCODE_CHAR_RCTRL:
984 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
985 astrand 66 break;
986     case SCANCODE_CHAR_LALT:
987 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
988 astrand 66 break;
989     case SCANCODE_CHAR_RALT:
990 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
991 astrand 66 break;
992     case SCANCODE_CHAR_LWIN:
993 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
994 astrand 66 break;
995     case SCANCODE_CHAR_RWIN:
996 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
997 astrand 66 break;
998 astrand 552 case SCANCODE_CHAR_NUMLOCK:
999     /* KeyReleases for NumLocks are sent immediately. Toggle the
1000     modifier state only on Keypress */
1001     if (pressed && !g_numlock_sync)
1002     {
1003     BOOL newNumLockState;
1004     newNumLockState =
1005     (MASK_HAS_BITS
1006     (remote_modifier_state, MapNumLockMask) == False);
1007     MASK_CHANGE_BIT(remote_modifier_state,
1008     MapNumLockMask, newNumLockState);
1009     }
1010 astrand 66 }
1011    
1012 astrand 113 #ifdef WITH_DEBUG_KBD
1013     if (old_modifier_state != remote_modifier_state)
1014     {
1015     DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1016     old_modifier_state, pressed));
1017     DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1018     }
1019     #endif
1020    
1021 astrand 66 }
1022    
1023     /* Send keyboard input */
1024     void
1025 matthewc 203 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1026 astrand 66 {
1027     update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1028    
1029     if (scancode & SCANCODE_EXTENDED)
1030     {
1031 astrand 84 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1032     scancode & ~SCANCODE_EXTENDED, flags));
1033 astrand 66 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1034     scancode & ~SCANCODE_EXTENDED, 0);
1035     }
1036     else
1037     {
1038 astrand 85 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1039     rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1040 astrand 66 }
1041     }

  ViewVC Help
Powered by ViewVC 1.1.26