/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 963 - (hide annotations)
Wed Aug 3 10:56:16 2005 UTC (18 years, 10 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 22533 byte(s)
Added missing c-basic-offset:s and license headers

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

  ViewVC Help
Powered by ViewVC 1.1.26