/[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 965 - (hide annotations)
Wed Aug 3 11:47:20 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23616 byte(s)
Replaced magic numbers for string lenghts with sizeof. Corrected sizeof statements for keyboard_*; we shouldn't count the trailing zero.

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

  ViewVC Help
Powered by ViewVC 1.1.26