/[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 300 - (show annotations)
Thu Jan 30 11:20:30 2003 UTC (21 years, 3 months ago) by matthewc
File MIME type: text/plain
File size: 15105 byte(s)
Fix a few compile warnings.

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 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 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 warning("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((int)*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((int)*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, 0xe1, 0);
279 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
280 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
281 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
282 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
283 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
284 }
285 else
286 {
287 /* Release Left Ctrl */
288 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
289 0x1d, 0);
290 }
291 return True;
292
293 case XK_Meta_L: /* Windows keys */
294 case XK_Super_L:
295 case XK_Hyper_L:
296 case XK_Meta_R:
297 case XK_Super_R:
298 case XK_Hyper_R:
299 if (pressed)
300 {
301 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
302 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
303 }
304 else
305 {
306 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
307 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
308 }
309 return True;
310 }
311 return False;
312 }
313
314
315 key_translation
316 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
317 {
318 key_translation tr = { 0, 0 };
319
320 tr = keymap[keysym & KEYMAP_MASK];
321
322 if (tr.modifiers & MapInhibitMask)
323 {
324 DEBUG_KBD(("Inhibiting key\n"));
325 tr.scancode = 0;
326 return tr;
327 }
328
329 if (tr.modifiers & MapLocalStateMask)
330 {
331 /* The modifiers to send for this key should be obtained
332 from the local state. Currently, only shift is implemented. */
333 if (state & ShiftMask)
334 {
335 tr.modifiers = MapLeftShiftMask;
336 }
337 }
338
339 if (tr.scancode != 0)
340 {
341 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
342 tr.scancode, tr.modifiers));
343 return tr;
344 }
345
346 if (keymap_loaded)
347 warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
348
349 /* not in keymap, try to interpret the raw scancode */
350 if ((keycode >= min_keycode) && (keycode <= 0x60))
351 {
352 tr.scancode = keycode - min_keycode;
353
354 /* The modifiers to send for this key should be
355 obtained from the local state. Currently, only
356 shift is implemented. */
357 if (state & ShiftMask)
358 {
359 tr.modifiers = MapLeftShiftMask;
360 }
361
362 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
363 }
364 else
365 {
366 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
367 }
368
369 return tr;
370 }
371
372 uint16
373 xkeymap_translate_button(unsigned int button)
374 {
375 switch (button)
376 {
377 case Button1: /* left */
378 return MOUSE_FLAG_BUTTON1;
379 case Button2: /* middle */
380 return MOUSE_FLAG_BUTTON3;
381 case Button3: /* right */
382 return MOUSE_FLAG_BUTTON2;
383 case Button4: /* wheel up */
384 return MOUSE_FLAG_BUTTON4;
385 case Button5: /* wheel down */
386 return MOUSE_FLAG_BUTTON5;
387 }
388
389 return 0;
390 }
391
392 char *
393 get_ksname(uint32 keysym)
394 {
395 char *ksname = NULL;
396
397 if (keysym == NoSymbol)
398 ksname = "NoSymbol";
399 else if (!(ksname = XKeysymToString(keysym)))
400 ksname = "(no name)";
401
402 return ksname;
403 }
404
405
406 void
407 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
408 {
409 /* If this key is a modifier, do nothing */
410 switch (tr.scancode)
411 {
412 case SCANCODE_CHAR_LSHIFT:
413 case SCANCODE_CHAR_RSHIFT:
414 case SCANCODE_CHAR_LCTRL:
415 case SCANCODE_CHAR_RCTRL:
416 case SCANCODE_CHAR_LALT:
417 case SCANCODE_CHAR_RALT:
418 case SCANCODE_CHAR_LWIN:
419 case SCANCODE_CHAR_RWIN:
420 case SCANCODE_CHAR_NUMLOCK:
421 return;
422 default:
423 break;
424 }
425
426 /* Shift. Left shift and right shift are treated as equal; either is fine. */
427 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
428 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
429 {
430 /* The remote modifier state is not correct */
431 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
432 {
433 /* Needs left shift. Send down. */
434 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
435 }
436 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
437 {
438 /* Needs right shift. Send down. */
439 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
440 }
441 else
442 {
443 /* Should not use this modifier. Send up for shift currently pressed. */
444 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
445 /* Left shift is down */
446 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
447 else
448 /* Right shift is down */
449 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
450 }
451 }
452
453 /* AltGr */
454 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
455 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
456 {
457 /* The remote modifier state is not correct */
458 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
459 {
460 /* Needs this modifier. Send down. */
461 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
462 }
463 else
464 {
465 /* Should not use this modifier. Send up. */
466 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
467 }
468 }
469
470 /* NumLock */
471 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
472 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
473 {
474 /* The remote modifier state is not correct */
475 uint16 new_remote_state = 0;
476
477 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
478 {
479 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
480 new_remote_state |= KBD_FLAG_NUMLOCK;
481 }
482 else
483 {
484 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
485 }
486
487 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
488 update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);
489 }
490 }
491
492
493 void
494 reset_modifier_keys(unsigned int state)
495 {
496 /* reset keys */
497 uint32 ev_time;
498 ev_time = time(NULL);
499
500 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
501 && !get_key_state(state, XK_Shift_L))
502 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
503
504 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
505 && !get_key_state(state, XK_Shift_R))
506 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
507
508 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
509 && !get_key_state(state, XK_Control_L))
510 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
511
512 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
513 && !get_key_state(state, XK_Control_R))
514 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
515
516 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
517 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
518
519 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
520 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
521 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
522 }
523
524
525 static void
526 update_modifier_state(uint8 scancode, BOOL pressed)
527 {
528 #ifdef WITH_DEBUG_KBD
529 uint16 old_modifier_state;
530
531 old_modifier_state = remote_modifier_state;
532 #endif
533
534 switch (scancode)
535 {
536 case SCANCODE_CHAR_LSHIFT:
537 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
538 break;
539 case SCANCODE_CHAR_RSHIFT:
540 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
541 break;
542 case SCANCODE_CHAR_LCTRL:
543 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
544 break;
545 case SCANCODE_CHAR_RCTRL:
546 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
547 break;
548 case SCANCODE_CHAR_LALT:
549 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
550 break;
551 case SCANCODE_CHAR_RALT:
552 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
553 break;
554 case SCANCODE_CHAR_LWIN:
555 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
556 break;
557 case SCANCODE_CHAR_RWIN:
558 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
559 break;
560 case SCANCODE_CHAR_NUMLOCK:
561 /* KeyReleases for NumLocks are sent immediately. Toggle the
562 modifier state only on Keypress */
563 if (pressed)
564 {
565 BOOL newNumLockState;
566 newNumLockState =
567 (MASK_HAS_BITS
568 (remote_modifier_state, MapNumLockMask) == False);
569 MASK_CHANGE_BIT(remote_modifier_state,
570 MapNumLockMask, newNumLockState);
571 }
572 break;
573 }
574
575 #ifdef WITH_DEBUG_KBD
576 if (old_modifier_state != remote_modifier_state)
577 {
578 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
579 old_modifier_state, pressed));
580 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
581 }
582 #endif
583
584 }
585
586 /* Send keyboard input */
587 void
588 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
589 {
590 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
591
592 if (scancode & SCANCODE_EXTENDED)
593 {
594 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
595 scancode & ~SCANCODE_EXTENDED, flags));
596 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
597 scancode & ~SCANCODE_EXTENDED, 0);
598 }
599 else
600 {
601 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
602 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
603 }
604 }

  ViewVC Help
Powered by ViewVC 1.1.26