/[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 973 - (hide annotations)
Thu Aug 4 12:44:10 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23581 byte(s)
Reorganized the automatic selection of keymap: The message about autoselection is not printed if -k is not given.

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

  ViewVC Help
Powered by ViewVC 1.1.26