/[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

Contents of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 331 - (show annotations)
Tue Feb 18 13:44:27 2003 UTC (21 years, 3 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 15399 byte(s)
Prevent access to sys menu in single app mode

1 /*
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X keyboard mapping
4 Copyright (C) Matthew Chapman 1999-2002
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <X11/Xlib.h>
22 #define XK_MISCELLANY
23 #include <X11/keysym.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <time.h>
27 #include "rdesktop.h"
28 #include "scancodes.h"
29
30 #define KEYMAP_SIZE 0xffff+1
31 #define KEYMAP_MASK 0xffff
32 #define KEYMAP_MAX_LINE_LENGTH 80
33
34 extern Display *display;
35 extern char keymapname[16];
36 extern int keylayout;
37 extern int win_button_size;
38 extern BOOL enable_compose;
39
40 static BOOL keymap_loaded;
41 static key_translation keymap[KEYMAP_SIZE];
42 static int min_keycode;
43 static uint16 remote_modifier_state = 0;
44
45 static void update_modifier_state(uint8 scancode, BOOL pressed);
46
47 static void
48 add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
49 {
50 KeySym keysym;
51
52 keysym = XStringToKeysym(keyname);
53 if (keysym == NoSymbol)
54 {
55 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
56 return;
57 }
58
59 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
60 "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
61
62 keymap[keysym & KEYMAP_MASK].scancode = scancode;
63 keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
64
65 return;
66 }
67
68
69 static BOOL
70 xkeymap_read(char *mapname)
71 {
72 FILE *fp;
73 char line[KEYMAP_MAX_LINE_LENGTH];
74 char path[PATH_MAX], inplace_path[PATH_MAX];
75 unsigned int line_num = 0;
76 unsigned int line_length = 0;
77 char *keyname, *p;
78 char *line_rest;
79 uint8 scancode;
80 uint16 modifiers;
81
82
83 strcpy(path, KEYMAP_PATH);
84 strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
85
86 fp = fopen(path, "r");
87 if (fp == NULL)
88 {
89 /* in case we are running from the source tree */
90 strcpy(inplace_path, "keymaps/");
91 strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));
92
93 fp = fopen(inplace_path, "r");
94 if (fp == NULL)
95 {
96 error("Failed to open keymap %s\n", path);
97 return False;
98 }
99 }
100
101 /* FIXME: More tolerant on white space */
102 while (fgets(line, sizeof(line), fp) != NULL)
103 {
104 line_num++;
105
106 /* Replace the \n with \0 */
107 p = strchr(line, '\n');
108 if (p != NULL)
109 *p = 0;
110
111 line_length = strlen(line);
112
113 /* Completely empty line */
114 if (strspn(line, " \t\n\r\f\v") == line_length)
115 {
116 continue;
117 }
118
119 /* Include */
120 if (strncmp(line, "include ", 8) == 0)
121 {
122 if (!xkeymap_read(line + 8))
123 return False;
124 continue;
125 }
126
127 /* map */
128 if (strncmp(line, "map ", 4) == 0)
129 {
130 keylayout = strtol(line + 4, NULL, 16);
131 DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
132 continue;
133 }
134
135 /* compose */
136 if (strncmp(line, "enable_compose", 15) == 0)
137 {
138 DEBUG_KBD(("Enabling compose handling\n"));
139 enable_compose = True;
140 continue;
141 }
142
143 /* Comment */
144 if (line[0] == '#')
145 {
146 continue;
147 }
148
149 /* Normal line */
150 keyname = line;
151 p = strchr(line, ' ');
152 if (p == NULL)
153 {
154 error("Bad line %d in keymap %s\n", line_num, mapname);
155 continue;
156 }
157 else
158 {
159 *p = 0;
160 }
161
162 /* scancode */
163 p++;
164 scancode = strtol(p, &line_rest, 16);
165
166 /* flags */
167 /* FIXME: Should allow case-insensitive flag names.
168 Fix by using lex+yacc... */
169 modifiers = 0;
170 if (strstr(line_rest, "altgr"))
171 {
172 MASK_ADD_BITS(modifiers, MapAltGrMask);
173 }
174
175 if (strstr(line_rest, "shift"))
176 {
177 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
178 }
179
180 if (strstr(line_rest, "numlock"))
181 {
182 MASK_ADD_BITS(modifiers, MapNumLockMask);
183 }
184
185 if (strstr(line_rest, "localstate"))
186 {
187 MASK_ADD_BITS(modifiers, MapLocalStateMask);
188 }
189
190 if (strstr(line_rest, "inhibit"))
191 {
192 MASK_ADD_BITS(modifiers, MapInhibitMask);
193 }
194
195 add_to_keymap(keyname, scancode, modifiers, mapname);
196
197 if (strstr(line_rest, "addupper"))
198 {
199 /* Automatically add uppercase key, with same modifiers
200 plus shift */
201 for (p = keyname; *p; p++)
202 *p = toupper((int) *p);
203 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
204 add_to_keymap(keyname, scancode, modifiers, mapname);
205 }
206 }
207
208 fclose(fp);
209 return True;
210 }
211
212
213 /* Before connecting and creating UI */
214 void
215 xkeymap_init(void)
216 {
217 unsigned int max_keycode;
218 char *mapname_ptr;
219
220 /* Make keymapname lowercase */
221 mapname_ptr = keymapname;
222 while (*mapname_ptr)
223 {
224 *mapname_ptr = tolower((int) *mapname_ptr);
225 mapname_ptr++;
226 }
227
228 if (strcmp(keymapname, "none"))
229 {
230 if (xkeymap_read(keymapname))
231 keymap_loaded = True;
232 }
233
234 XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);
235 }
236
237 /* Handles, for example, multi-scancode keypresses (which is not
238 possible via keymap-files) */
239 BOOL
240 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
241 {
242 switch (keysym)
243 {
244 case XK_Return:
245 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
246 && (get_key_state(state, XK_Control_L)
247 || get_key_state(state, XK_Control_R)))
248 {
249 /* Ctrl-Alt-Enter: toggle full screen */
250 if (pressed)
251 xwin_toggle_fullscreen();
252 return True;
253 }
254 break;
255
256 case XK_Break:
257 /* Send Break sequence E0 46 E0 C6 */
258 if (pressed)
259 {
260 rdp_send_scancode(ev_time, RDP_KEYPRESS,
261 (SCANCODE_EXTENDED | 0x46));
262 rdp_send_scancode(ev_time, RDP_KEYPRESS,
263 (SCANCODE_EXTENDED | 0xc6));
264 }
265 /* No release sequence */
266 return True;
267
268 case XK_Pause:
269 /* According to MS Keyboard Scan Code
270 Specification, pressing Pause should result
271 in E1 1D 45 E1 9D C5. I'm not exactly sure
272 of how this is supposed to be sent via
273 RDP. The code below seems to work, but with
274 the side effect that Left Ctrl stays
275 down. Therefore, we release it when Pause
276 is released. */
277 if (pressed)
278 {
279 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
280 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
281 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
282 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
283 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
284 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
285 }
286 else
287 {
288 /* Release Left Ctrl */
289 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
290 0x1d, 0);
291 }
292 return True;
293
294 case XK_Meta_L: /* Windows keys */
295 case XK_Super_L:
296 case XK_Hyper_L:
297 case XK_Meta_R:
298 case XK_Super_R:
299 case XK_Hyper_R:
300 if (pressed)
301 {
302 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
303 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
304 }
305 else
306 {
307 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
308 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
309 }
310 return True;
311
312 case XK_space:
313 /* Prevent access to the Windows system menu in single app mode */
314 if (win_button_size
315 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
316 return True;
317
318 }
319 return False;
320 }
321
322
323 key_translation
324 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
325 {
326 key_translation tr = { 0, 0 };
327
328 tr = keymap[keysym & KEYMAP_MASK];
329
330 if (tr.modifiers & MapInhibitMask)
331 {
332 DEBUG_KBD(("Inhibiting key\n"));
333 tr.scancode = 0;
334 return tr;
335 }
336
337 if (tr.modifiers & MapLocalStateMask)
338 {
339 /* The modifiers to send for this key should be obtained
340 from the local state. Currently, only shift is implemented. */
341 if (state & ShiftMask)
342 {
343 tr.modifiers = MapLeftShiftMask;
344 }
345 }
346
347 if (tr.scancode != 0)
348 {
349 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
350 tr.scancode, tr.modifiers));
351 return tr;
352 }
353
354 if (keymap_loaded)
355 warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
356
357 /* not in keymap, try to interpret the raw scancode */
358 if ((keycode >= min_keycode) && (keycode <= 0x60))
359 {
360 tr.scancode = keycode - min_keycode;
361
362 /* The modifiers to send for this key should be
363 obtained from the local state. Currently, only
364 shift is implemented. */
365 if (state & ShiftMask)
366 {
367 tr.modifiers = MapLeftShiftMask;
368 }
369
370 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
371 }
372 else
373 {
374 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
375 }
376
377 return tr;
378 }
379
380 uint16
381 xkeymap_translate_button(unsigned int button)
382 {
383 switch (button)
384 {
385 case Button1: /* left */
386 return MOUSE_FLAG_BUTTON1;
387 case Button2: /* middle */
388 return MOUSE_FLAG_BUTTON3;
389 case Button3: /* right */
390 return MOUSE_FLAG_BUTTON2;
391 case Button4: /* wheel up */
392 return MOUSE_FLAG_BUTTON4;
393 case Button5: /* wheel down */
394 return MOUSE_FLAG_BUTTON5;
395 }
396
397 return 0;
398 }
399
400 char *
401 get_ksname(uint32 keysym)
402 {
403 char *ksname = NULL;
404
405 if (keysym == NoSymbol)
406 ksname = "NoSymbol";
407 else if (!(ksname = XKeysymToString(keysym)))
408 ksname = "(no name)";
409
410 return ksname;
411 }
412
413
414 void
415 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
416 {
417 /* If this key is a modifier, do nothing */
418 switch (tr.scancode)
419 {
420 case SCANCODE_CHAR_LSHIFT:
421 case SCANCODE_CHAR_RSHIFT:
422 case SCANCODE_CHAR_LCTRL:
423 case SCANCODE_CHAR_RCTRL:
424 case SCANCODE_CHAR_LALT:
425 case SCANCODE_CHAR_RALT:
426 case SCANCODE_CHAR_LWIN:
427 case SCANCODE_CHAR_RWIN:
428 case SCANCODE_CHAR_NUMLOCK:
429 return;
430 default:
431 break;
432 }
433
434 /* NumLock */
435 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
436 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
437 {
438 /* The remote modifier state is not correct */
439 uint16 new_remote_state;
440
441 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
442 {
443 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
444 new_remote_state = KBD_FLAG_NUMLOCK;
445 remote_modifier_state = MapNumLockMask;
446 }
447 else
448 {
449 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
450 new_remote_state = 0;
451 remote_modifier_state = 0;
452 }
453
454 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
455 }
456
457 /* Shift. Left shift and right shift are treated as equal; either is fine. */
458 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
459 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
460 {
461 /* The remote modifier state is not correct */
462 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
463 {
464 /* Needs left shift. Send down. */
465 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
466 }
467 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
468 {
469 /* Needs right shift. Send down. */
470 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
471 }
472 else
473 {
474 /* Should not use this modifier. Send up for shift currently pressed. */
475 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
476 /* Left shift is down */
477 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
478 else
479 /* Right shift is down */
480 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
481 }
482 }
483
484 /* AltGr */
485 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
486 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
487 {
488 /* The remote modifier state is not correct */
489 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
490 {
491 /* Needs this modifier. Send down. */
492 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
493 }
494 else
495 {
496 /* Should not use this modifier. Send up. */
497 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
498 }
499 }
500
501
502 }
503
504
505 void
506 reset_modifier_keys(unsigned int state)
507 {
508 /* reset keys */
509 uint32 ev_time;
510 ev_time = time(NULL);
511
512 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
513 && !get_key_state(state, XK_Shift_L))
514 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
515
516 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
517 && !get_key_state(state, XK_Shift_R))
518 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
519
520 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
521 && !get_key_state(state, XK_Control_L))
522 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
523
524 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
525 && !get_key_state(state, XK_Control_R))
526 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
527
528 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
529 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
530
531 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
532 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
533 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
534 }
535
536
537 static void
538 update_modifier_state(uint8 scancode, BOOL pressed)
539 {
540 #ifdef WITH_DEBUG_KBD
541 uint16 old_modifier_state;
542
543 old_modifier_state = remote_modifier_state;
544 #endif
545
546 switch (scancode)
547 {
548 case SCANCODE_CHAR_LSHIFT:
549 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
550 break;
551 case SCANCODE_CHAR_RSHIFT:
552 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
553 break;
554 case SCANCODE_CHAR_LCTRL:
555 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
556 break;
557 case SCANCODE_CHAR_RCTRL:
558 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
559 break;
560 case SCANCODE_CHAR_LALT:
561 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
562 break;
563 case SCANCODE_CHAR_RALT:
564 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
565 break;
566 case SCANCODE_CHAR_LWIN:
567 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
568 break;
569 case SCANCODE_CHAR_RWIN:
570 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
571 break;
572 case SCANCODE_CHAR_NUMLOCK:
573 /* KeyReleases for NumLocks are sent immediately. Toggle the
574 modifier state only on Keypress */
575 if (pressed)
576 {
577 BOOL newNumLockState;
578 newNumLockState =
579 (MASK_HAS_BITS
580 (remote_modifier_state, MapNumLockMask) == False);
581 MASK_CHANGE_BIT(remote_modifier_state,
582 MapNumLockMask, newNumLockState);
583 }
584 break;
585 }
586
587 #ifdef WITH_DEBUG_KBD
588 if (old_modifier_state != remote_modifier_state)
589 {
590 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
591 old_modifier_state, pressed));
592 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
593 }
594 #endif
595
596 }
597
598 /* Send keyboard input */
599 void
600 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
601 {
602 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
603
604 if (scancode & SCANCODE_EXTENDED)
605 {
606 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
607 scancode & ~SCANCODE_EXTENDED, flags));
608 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
609 scancode & ~SCANCODE_EXTENDED, 0);
610 }
611 else
612 {
613 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
614 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
615 }
616 }

  ViewVC Help
Powered by ViewVC 1.1.26