/[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 964 - (hide annotations)
Wed Aug 3 11:30:53 2005 UTC (18 years, 11 months ago) by astrand
File MIME type: text/plain
File size: 23438 byte(s)
It is now possible to specify keyboard type, subtype and number of functionskeys. From patch #974509, by Dekaino.

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

  ViewVC Help
Powered by ViewVC 1.1.26