/[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 976 - (hide annotations)
Thu Aug 4 13:39:57 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23659 byte(s)
Protection against recursive sequences

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

  ViewVC Help
Powered by ViewVC 1.1.26