2
rdesktop: A Remote Desktop Protocol client.
3
User interface services - X keyboard mapping
5
Copyright (C) Matthew Chapman 1999-2002
6
Copyright (C) Peter Astrand <peter@cendio.se> 2003
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
#include "vnc/x11stubs.h"
27
#include <X11/keysym.h>
34
#include "scancodes.h"
36
#define KEYMAP_SIZE 0xffff+1
37
#define KEYMAP_MASK 0xffff
38
#define KEYMAP_MAX_LINE_LENGTH 80
40
extern Display *g_display;
42
extern char keymapname[16];
44
extern int g_win_button_size;
45
extern BOOL g_enable_compose;
46
extern BOOL g_use_rdp5;
47
extern BOOL g_numlock_sync;
49
static BOOL keymap_loaded;
50
static key_translation keymap[KEYMAP_SIZE];
51
static int min_keycode;
52
static uint16 remote_modifier_state = 0;
53
static uint16 saved_remote_modifier_state = 0;
55
static void update_modifier_state(uint8 scancode, BOOL pressed);
58
add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
62
keysym = XStringToKeysym(keyname);
63
if (keysym == NoSymbol)
65
DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
69
DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
70
"modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
72
keymap[keysym & KEYMAP_MASK].scancode = scancode;
73
keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
80
xkeymap_read(char *mapname)
83
char line[KEYMAP_MAX_LINE_LENGTH];
84
char path[PATH_MAX], inplace_path[PATH_MAX];
85
unsigned int line_num = 0;
86
unsigned int line_length = 0;
93
strcpy(path, KEYMAP_PATH);
94
strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
96
fp = fopen(path, "r");
99
/* in case we are running from the source tree */
100
strcpy(inplace_path, "keymaps/");
101
strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));
103
fp = fopen(inplace_path, "r");
106
error("Failed to open keymap %s\n", path);
111
/* FIXME: More tolerant on white space */
112
while (fgets(line, sizeof(line), fp) != NULL)
116
/* Replace the \n with \0 */
117
p = strchr(line, '\n');
121
line_length = strlen(line);
123
/* Completely empty line */
124
if (strspn(line, " \t\n\r\f\v") == line_length)
130
if (strncmp(line, "include ", 8) == 0)
132
if (!xkeymap_read(line + 8))
138
if (strncmp(line, "map ", 4) == 0)
140
keylayout = strtol(line + 4, NULL, 16);
141
DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
146
if (strncmp(line, "enable_compose", 15) == 0)
148
DEBUG_KBD(("Enabling compose handling\n"));
149
g_enable_compose = True;
161
p = strchr(line, ' ');
164
error("Bad line %d in keymap %s\n", line_num, mapname);
174
scancode = strtol(p, &line_rest, 16);
177
/* FIXME: Should allow case-insensitive flag names.
178
Fix by using lex+yacc... */
180
if (strstr(line_rest, "altgr"))
182
MASK_ADD_BITS(modifiers, MapAltGrMask);
185
if (strstr(line_rest, "shift"))
187
MASK_ADD_BITS(modifiers, MapLeftShiftMask);
190
if (strstr(line_rest, "numlock"))
192
MASK_ADD_BITS(modifiers, MapNumLockMask);
195
if (strstr(line_rest, "localstate"))
197
MASK_ADD_BITS(modifiers, MapLocalStateMask);
200
if (strstr(line_rest, "inhibit"))
202
MASK_ADD_BITS(modifiers, MapInhibitMask);
205
add_to_keymap(keyname, scancode, modifiers, mapname);
207
if (strstr(line_rest, "addupper"))
209
/* Automatically add uppercase key, with same modifiers
211
for (p = keyname; *p; p++)
212
*p = toupper((int) *p);
213
MASK_ADD_BITS(modifiers, MapLeftShiftMask);
214
add_to_keymap(keyname, scancode, modifiers, mapname);
223
/* Before connecting and creating UI */
227
unsigned int max_keycode;
230
/* Make keymapname lowercase */
231
mapname_ptr = keymapname;
234
*mapname_ptr = tolower((int) *mapname_ptr);
238
if (strcmp(keymapname, "none"))
240
if (xkeymap_read(keymapname))
241
keymap_loaded = True;
244
XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
248
send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
253
winkey = SCANCODE_CHAR_LWIN;
255
winkey = SCANCODE_CHAR_RWIN;
261
rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
265
/* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
266
rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
267
rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
275
rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
279
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
280
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
286
reset_winkey(uint32 ev_time)
290
/* For some reason, it seems to suffice to release
291
*either* the left or right winkey. */
292
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
296
/* Handles, for example, multi-scancode keypresses (which is not
297
possible via keymap-files) */
299
handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
304
if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
305
&& (get_key_state(state, XK_Control_L)
306
|| get_key_state(state, XK_Control_R)))
308
/* Ctrl-Alt-Enter: toggle full screen */
310
xwin_toggle_fullscreen();
316
/* Send Break sequence E0 46 E0 C6 */
319
rdp_send_scancode(ev_time, RDP_KEYPRESS,
320
(SCANCODE_EXTENDED | 0x46));
321
rdp_send_scancode(ev_time, RDP_KEYPRESS,
322
(SCANCODE_EXTENDED | 0xc6));
324
/* No release sequence */
329
/* According to MS Keyboard Scan Code
330
Specification, pressing Pause should result
331
in E1 1D 45 E1 9D C5. I'm not exactly sure
332
of how this is supposed to be sent via
333
RDP. The code below seems to work, but with
334
the side effect that Left Ctrl stays
335
down. Therefore, we release it when Pause
339
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
340
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
341
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
342
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
343
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
344
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
348
/* Release Left Ctrl */
349
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
355
case XK_Meta_L: /* Windows keys */
358
send_winkey(ev_time, pressed, True);
365
send_winkey(ev_time, pressed, False);
370
/* Prevent access to the Windows system menu in single app mode */
371
if (g_win_button_size
372
&& (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
376
/* FIXME: We might want to do RDP_INPUT_SYNCHRONIZE here, if g_numlock_sync */
388
xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
390
key_translation tr = { 0, 0 };
392
tr = keymap[keysym & KEYMAP_MASK];
394
if (tr.modifiers & MapInhibitMask)
396
DEBUG_KBD(("Inhibiting key\n"));
401
if (tr.modifiers & MapLocalStateMask)
403
/* The modifiers to send for this key should be obtained
404
from the local state. Currently, only shift is implemented. */
405
if (state & ShiftMask)
407
tr.modifiers = MapLeftShiftMask;
411
if (tr.scancode != 0)
413
DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
414
tr.scancode, tr.modifiers));
419
warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
421
/* not in keymap, try to interpret the raw scancode */
422
if (((int) keycode >= min_keycode) && (keycode <= 0x60))
424
tr.scancode = keycode - min_keycode;
426
/* The modifiers to send for this key should be
427
obtained from the local state. Currently, only
428
shift is implemented. */
429
if (state & ShiftMask)
431
tr.modifiers = MapLeftShiftMask;
434
DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
438
DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
445
xkeymap_translate_button(unsigned int button)
449
case Button1: /* left */
450
return MOUSE_FLAG_BUTTON1;
451
case Button2: /* middle */
452
return MOUSE_FLAG_BUTTON3;
453
case Button3: /* right */
454
return MOUSE_FLAG_BUTTON2;
455
case Button4: /* wheel up */
456
return MOUSE_FLAG_BUTTON4;
457
case Button5: /* wheel down */
458
return MOUSE_FLAG_BUTTON5;
465
get_ksname(uint32 keysym)
469
if (keysym == NoSymbol)
471
else if (!(ksname = XKeysymToString(keysym)))
472
ksname = "(no name)";
478
is_modifier(uint8 scancode)
482
case SCANCODE_CHAR_LSHIFT:
483
case SCANCODE_CHAR_RSHIFT:
484
case SCANCODE_CHAR_LCTRL:
485
case SCANCODE_CHAR_RCTRL:
486
case SCANCODE_CHAR_LALT:
487
case SCANCODE_CHAR_RALT:
488
case SCANCODE_CHAR_LWIN:
489
case SCANCODE_CHAR_RWIN:
490
case SCANCODE_CHAR_NUMLOCK:
499
save_remote_modifiers(uint8 scancode)
501
if (is_modifier(scancode))
504
saved_remote_modifier_state = remote_modifier_state;
508
restore_remote_modifiers(uint32 ev_time, uint8 scancode)
510
key_translation dummy;
512
if (is_modifier(scancode))
516
dummy.modifiers = saved_remote_modifier_state;
517
ensure_remote_modifiers(ev_time, dummy);
521
ensure_remote_modifiers(uint32 ev_time, key_translation tr)
523
/* If this key is a modifier, do nothing */
524
if (is_modifier(tr.scancode))
530
if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
531
!= MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
533
/* The remote modifier state is not correct */
534
uint16 new_remote_state;
536
if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
538
DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
539
new_remote_state = KBD_FLAG_NUMLOCK;
540
remote_modifier_state = MapNumLockMask;
544
DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
545
new_remote_state = 0;
546
remote_modifier_state = 0;
549
rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
554
/* Shift. Left shift and right shift are treated as equal; either is fine. */
555
if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
556
!= MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
558
/* The remote modifier state is not correct */
559
if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
561
/* Needs left shift. Send down. */
562
rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
564
else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
566
/* Needs right shift. Send down. */
567
rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
571
/* Should not use this modifier. Send up for shift currently pressed. */
572
if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
573
/* Left shift is down */
574
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
576
/* Right shift is down */
577
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
582
if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
583
!= MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
585
/* The remote modifier state is not correct */
586
if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
588
/* Needs this modifier. Send down. */
589
rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
593
/* Should not use this modifier. Send up. */
594
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
603
read_keyboard_state()
609
XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
615
ui_get_numlock_state(unsigned int state)
617
uint16 numlock_state = 0;
619
if (get_key_state(state, XK_Num_Lock))
620
numlock_state = KBD_FLAG_NUMLOCK;
622
return numlock_state;
627
reset_modifier_keys()
629
unsigned int state = read_keyboard_state();
633
ev_time = time(NULL);
635
if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
636
&& !get_key_state(state, XK_Shift_L))
637
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
639
if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
640
&& !get_key_state(state, XK_Shift_R))
641
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
643
if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
644
&& !get_key_state(state, XK_Control_L))
645
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
647
if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
648
&& !get_key_state(state, XK_Control_R))
649
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
651
if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
652
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
654
if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
655
!get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
656
rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
658
reset_winkey(ev_time);
661
rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
666
update_modifier_state(uint8 scancode, BOOL pressed)
668
#ifdef WITH_DEBUG_KBD
669
uint16 old_modifier_state;
671
old_modifier_state = remote_modifier_state;
676
case SCANCODE_CHAR_LSHIFT:
677
MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
679
case SCANCODE_CHAR_RSHIFT:
680
MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
682
case SCANCODE_CHAR_LCTRL:
683
MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
685
case SCANCODE_CHAR_RCTRL:
686
MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
688
case SCANCODE_CHAR_LALT:
689
MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
691
case SCANCODE_CHAR_RALT:
692
MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
694
case SCANCODE_CHAR_LWIN:
695
MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
697
case SCANCODE_CHAR_RWIN:
698
MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
700
case SCANCODE_CHAR_NUMLOCK:
701
/* KeyReleases for NumLocks are sent immediately. Toggle the
702
modifier state only on Keypress */
703
if (pressed && !g_numlock_sync)
705
BOOL newNumLockState;
708
(remote_modifier_state, MapNumLockMask) == False);
709
MASK_CHANGE_BIT(remote_modifier_state,
710
MapNumLockMask, newNumLockState);
714
#ifdef WITH_DEBUG_KBD
715
if (old_modifier_state != remote_modifier_state)
717
DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
718
old_modifier_state, pressed));
719
DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
725
/* Send keyboard input */
727
rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
729
update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
731
if (scancode & SCANCODE_EXTENDED)
733
DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
734
scancode & ~SCANCODE_EXTENDED, flags));
735
rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
736
scancode & ~SCANCODE_EXTENDED, 0);
740
DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
741
rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);