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

Contents of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 244 - (show annotations)
Thu Oct 24 08:48:51 2002 UTC (21 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 15170 byte(s)
Change fullscreen toggle key to Ctrl-Alt-Enter.

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

  ViewVC Help
Powered by ViewVC 1.1.26