/[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 199 - (show annotations)
Wed Sep 25 11:17:59 2002 UTC (21 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 14389 byte(s)
Support for Break key.

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

  ViewVC Help
Powered by ViewVC 1.1.26