/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 197 - (show annotations)
Wed Sep 25 11:07:57 2002 UTC (21 years, 7 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 14099 byte(s)
Support for Pause 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: /* toggle full screen */
222 if (get_key_state(XK_Alt_L) || get_key_state(XK_Alt_R))
223 {
224 if (pressed)
225 xwin_toggle_fullscreen();
226 return True;
227 }
228 break;
229
230 case XK_Pause:
231 /* According to MS Keyboard Scan Code
232 Specification, pressing Pause should result
233 in E1 1D 45 E1 9D C5. I'm not exactly sure
234 of how this is supposed to be sent via
235 RDP. The code below seems to work, but with
236 the side effect that Left Ctrl stays
237 down. Therefore, we release it when Pause
238 is released. */
239 if (pressed)
240 {
241 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
242 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
243 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
244 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
245 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
246 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
247 }
248 else
249 {
250 // Release Left Ctrl
251 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d,
252 0);
253 }
254
255 return True;
256 break;
257
258 case XK_Meta_L: /* Windows keys */
259 case XK_Super_L:
260 case XK_Hyper_L:
261 case XK_Meta_R:
262 case XK_Super_R:
263 case XK_Hyper_R:
264 if (pressed)
265 {
266 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
267 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
268 }
269 else
270 {
271 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
272 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
273 }
274 return True;
275 break;
276 }
277 return False;
278 }
279
280
281 key_translation
282 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
283 {
284 key_translation tr = { 0, 0 };
285
286 tr = keymap[keysym & KEYMAP_MASK];
287
288 if (tr.modifiers & MapInhibitMask)
289 {
290 DEBUG_KBD(("Inhibiting key\n"));
291 tr.scancode = 0;
292 return tr;
293 }
294
295 if (tr.modifiers & MapLocalStateMask)
296 {
297 /* The modifiers to send for this key should be obtained
298 from the local state. Currently, only shift is implemented. */
299 if (state & ShiftMask)
300 {
301 tr.modifiers = MapLeftShiftMask;
302 }
303 }
304
305 if (tr.scancode != 0)
306 {
307 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
308 tr.scancode, tr.modifiers));
309 return tr;
310 }
311
312 DEBUG_KBD(("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)));
313
314 /* not in keymap, try to interpret the raw scancode */
315 if ((keycode >= min_keycode) && (keycode <= 0x60))
316 {
317 tr.scancode = keycode - min_keycode;
318
319 /* The modifiers to send for this key should be
320 obtained from the local state. Currently, only
321 shift is implemented. */
322 if (state & ShiftMask)
323 {
324 tr.modifiers = MapLeftShiftMask;
325 }
326
327 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
328 }
329 else
330 {
331 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
332 }
333
334 return tr;
335 }
336
337 uint16
338 xkeymap_translate_button(unsigned int button)
339 {
340 switch (button)
341 {
342 case Button1: /* left */
343 return MOUSE_FLAG_BUTTON1;
344 case Button2: /* middle */
345 return MOUSE_FLAG_BUTTON3;
346 case Button3: /* right */
347 return MOUSE_FLAG_BUTTON2;
348 case Button4: /* wheel up */
349 return MOUSE_FLAG_BUTTON4;
350 case Button5: /* wheel down */
351 return MOUSE_FLAG_BUTTON5;
352 }
353
354 return 0;
355 }
356
357 char *
358 get_ksname(uint32 keysym)
359 {
360 char *ksname = NULL;
361
362 if (keysym == NoSymbol)
363 ksname = "NoSymbol";
364 else if (!(ksname = XKeysymToString(keysym)))
365 ksname = "(no name)";
366
367 return ksname;
368 }
369
370
371 void
372 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
373 {
374 /* If this key is a modifier, do nothing */
375 switch (tr.scancode)
376 {
377 case SCANCODE_CHAR_LSHIFT:
378 case SCANCODE_CHAR_RSHIFT:
379 case SCANCODE_CHAR_LCTRL:
380 case SCANCODE_CHAR_RCTRL:
381 case SCANCODE_CHAR_LALT:
382 case SCANCODE_CHAR_RALT:
383 case SCANCODE_CHAR_LWIN:
384 case SCANCODE_CHAR_RWIN:
385 case SCANCODE_CHAR_NUMLOCK:
386 return;
387 default:
388 break;
389 }
390
391 /* Shift. Left shift and right shift are treated as equal; either is fine. */
392 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
393 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
394 {
395 /* The remote modifier state is not correct */
396 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
397 {
398 /* Needs left shift. Send down. */
399 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
400 }
401 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
402 {
403 /* Needs right shift. Send down. */
404 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
405 }
406 else
407 {
408 /* Should not use this modifier. Send up for shift currently pressed. */
409 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
410 /* Left shift is down */
411 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
412 else
413 /* Right shift is down */
414 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
415 }
416 }
417
418 /* AltGr */
419 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
420 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
421 {
422 /* The remote modifier state is not correct */
423 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
424 {
425 /* Needs this modifier. Send down. */
426 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
427 }
428 else
429 {
430 /* Should not use this modifier. Send up. */
431 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
432 }
433 }
434
435 /* NumLock */
436 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
437 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
438 {
439 /* The remote modifier state is not correct */
440 uint16 new_remote_state = 0;
441
442 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
443 {
444 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
445 new_remote_state |= KBD_FLAG_NUMLOCK;
446 }
447 else
448 {
449 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
450 }
451
452 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
453 update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);
454 }
455 }
456
457
458 void
459 reset_modifier_keys(void)
460 {
461 /* reset keys */
462 uint32 ev_time;
463 ev_time = time(NULL);
464
465 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask) && !get_key_state(XK_Shift_L))
466 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
467
468 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask) && !get_key_state(XK_Shift_R))
469 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
470
471 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask) && !get_key_state(XK_Control_L))
472 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
473
474 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask) && !get_key_state(XK_Control_R))
475 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
476
477 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(XK_Alt_L))
478 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
479
480 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
481 !get_key_state(XK_Alt_R) && !get_key_state(XK_Mode_switch))
482 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
483 }
484
485
486 static void
487 update_modifier_state(uint16 modifiers, BOOL pressed)
488 {
489 #ifdef WITH_DEBUG_KBD
490 uint16 old_modifier_state;
491
492 old_modifier_state = remote_modifier_state;
493 #endif
494
495 switch (modifiers)
496 {
497 case SCANCODE_CHAR_LSHIFT:
498 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
499 break;
500 case SCANCODE_CHAR_RSHIFT:
501 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
502 break;
503 case SCANCODE_CHAR_LCTRL:
504 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
505 break;
506 case SCANCODE_CHAR_RCTRL:
507 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
508 break;
509 case SCANCODE_CHAR_LALT:
510 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
511 break;
512 case SCANCODE_CHAR_RALT:
513 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
514 break;
515 case SCANCODE_CHAR_LWIN:
516 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
517 break;
518 case SCANCODE_CHAR_RWIN:
519 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
520 break;
521 case SCANCODE_CHAR_NUMLOCK:
522 /* KeyReleases for NumLocks are sent immediately. Toggle the
523 modifier state only on Keypress */
524 if (pressed)
525 {
526 BOOL newNumLockState;
527 newNumLockState =
528 (MASK_HAS_BITS
529 (remote_modifier_state, MapNumLockMask) == False);
530 MASK_CHANGE_BIT(remote_modifier_state,
531 MapNumLockMask, newNumLockState);
532 }
533 break;
534 }
535
536 #ifdef WITH_DEBUG_KBD
537 if (old_modifier_state != remote_modifier_state)
538 {
539 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
540 old_modifier_state, pressed));
541 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
542 }
543 #endif
544
545 }
546
547 /* Send keyboard input */
548 void
549 rdp_send_scancode(uint32 time, uint16 flags, uint16 scancode)
550 {
551 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
552
553 if (scancode & SCANCODE_EXTENDED)
554 {
555 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
556 scancode & ~SCANCODE_EXTENDED, flags));
557 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
558 scancode & ~SCANCODE_EXTENDED, 0);
559 }
560 else
561 {
562 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
563 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
564 }
565 }

  ViewVC Help
Powered by ViewVC 1.1.26