1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    User interface services - X keyboard mapping
4 
5    Copyright (C) Matthew Chapman 1999-2005
6    Copyright (C) Peter Astrand <peter@cendio.se> 2003
7 
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.
12 
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.
17 
18    You should have received a copy of the GNU General Public License along
19    with this program; if not, write to the Free Software Foundation, Inc.,
20    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 
23 #ifdef RDP2VNC
24 #include "vnc/x11stubs.h"
25 #else
26 #include <X11/Xlib.h>
27 #include <X11/keysym.h>
28 #endif
29 
30 #include <ctype.h>
31 #include <limits.h>
32 #include <time.h>
33 #include <string.h>
34 #include "rdesktop.h"
35 #include "scancodes.h"
36 
37 #define KEYMAP_MASK 0xffff
38 #define KEYMAP_MAX_LINE_LENGTH 80
39 
40 static void update_modifier_state(RDPCLIENT * This, uint8 scancode, BOOL pressed);
41 
42 /* Free key_translation structure, including linked list */
43 static void
free_key_translation(key_translation * ptr)44 free_key_translation(key_translation * ptr)
45 {
46 	key_translation *next;
47 
48 	while (ptr)
49 	{
50 		next = ptr->next;
51 		xfree(ptr);
52 		ptr = next;
53 	}
54 }
55 
56 static void
add_to_keymap(RDPCLIENT * This,char * keyname,uint8 scancode,uint16 modifiers,char * mapname)57 add_to_keymap(RDPCLIENT * This, char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
58 {
59 	KeySym keysym;
60 	key_translation *tr;
61 
62 	keysym = XStringToKeysym(keyname);
63 	if (keysym == NoSymbol)
64 	{
65 		DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
66 		return;
67 	}
68 
69 	DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
70 		   "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
71 
72 	tr = (key_translation *) xmalloc(sizeof(key_translation));
73 	memset(tr, 0, sizeof(key_translation));
74 	tr->scancode = scancode;
75 	tr->modifiers = modifiers;
76 	free_key_translation(This->xkeymap.keymap[keysym & KEYMAP_MASK]);
77 	This->xkeymap.keymap[keysym & KEYMAP_MASK] = tr;
78 
79 	return;
80 }
81 
82 static void
add_sequence(RDPCLIENT * This,char * rest,char * mapname)83 add_sequence(RDPCLIENT * This, char *rest, char *mapname)
84 {
85 	KeySym keysym;
86 	key_translation *tr, **prev_next;
87 	size_t chars;
88 	char keyname[KEYMAP_MAX_LINE_LENGTH];
89 
90 	/* Skip over whitespace after the sequence keyword */
91 	chars = strspn(rest, " \t");
92 	rest += chars;
93 
94 	/* Fetch the keysym name */
95 	chars = strcspn(rest, " \t\0");
96 	STRNCPY(keyname, rest, chars + 1);
97 	rest += chars;
98 
99 	keysym = XStringToKeysym(keyname);
100 	if (keysym == NoSymbol)
101 	{
102 		DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
103 		return;
104 	}
105 
106 
107 	DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
108 
109 	free_key_translation(This->xkeymap.keymap[keysym & KEYMAP_MASK]);
110 	prev_next = &This->xkeymap.keymap[keysym & KEYMAP_MASK];
111 
112 	while (*rest)
113 	{
114 		/* Skip whitespace */
115 		chars = strspn(rest, " \t");
116 		rest += chars;
117 
118 		/* Fetch the keysym name */
119 		chars = strcspn(rest, " \t\0");
120 		STRNCPY(keyname, rest, chars + 1);
121 		rest += chars;
122 
123 		keysym = XStringToKeysym(keyname);
124 		if (keysym == NoSymbol)
125 		{
126 			DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
127 				   mapname));
128 			return;
129 		}
130 
131 		/* Allocate space for key_translation structure */
132 		tr = (key_translation *) xmalloc(sizeof(key_translation));
133 		memset(tr, 0, sizeof(key_translation));
134 		*prev_next = tr;
135 		prev_next = &tr->next;
136 		tr->seq_keysym = keysym;
137 
138 		DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
139 	}
140 	DEBUG_KBD(("\n"));
141 }
142 
143 BOOL
xkeymap_from_locale(RDPCLIENT * This,const char * locale)144 xkeymap_from_locale(RDPCLIENT * This, const char *locale)
145 {
146 	char *str, *ptr;
147 	FILE *fp;
148 
149 	/* Create a working copy */
150 	str = xstrdup(locale);
151 
152 	/* Truncate at dot and at */
153 	ptr = strrchr(str, '.');
154 	if (ptr)
155 		*ptr = '\0';
156 	ptr = strrchr(str, '@');
157 	if (ptr)
158 		*ptr = '\0';
159 
160 	/* Replace _ with - */
161 	ptr = strrchr(str, '_');
162 	if (ptr)
163 		*ptr = '-';
164 
165 	/* Convert to lowercase */
166 	ptr = str;
167 	while (*ptr)
168 	{
169 		*ptr = tolower((int) *ptr);
170 		ptr++;
171 	}
172 
173 	/* Try to open this keymap (da-dk) */
174 	fp = xkeymap_open(str);
175 	if (fp == NULL)
176 	{
177 		/* Truncate at dash */
178 		ptr = strrchr(str, '-');
179 		if (ptr)
180 			*ptr = '\0';
181 
182 		/* Try the short name (da) */
183 		fp = xkeymap_open(str);
184 	}
185 
186 	if (fp)
187 	{
188 		fclose(fp);
189 		STRNCPY(This->keymapname, str, sizeof(This->keymapname));
190 		xfree(str);
191 		return True;
192 	}
193 
194 	xfree(str);
195 	return False;
196 }
197 
198 
199 /* Joins two path components. The result should be freed with
200    xfree(). */
201 static char *
pathjoin(const char * a,const char * b)202 pathjoin(const char *a, const char *b)
203 {
204 	char *result;
205 	result = xmalloc(PATH_MAX * 2 + 1);
206 
207 	if (b[0] == '/')
208 	{
209 		strncpy(result, b, PATH_MAX);
210 	}
211 	else
212 	{
213 		strncpy(result, a, PATH_MAX);
214 		strcat(result, "/");
215 		strncat(result, b, PATH_MAX);
216 	}
217 	return result;
218 }
219 
220 /* Try to open a keymap with fopen() */
221 FILE *
xkeymap_open(const char * filename)222 xkeymap_open(const char *filename)
223 {
224 	char *path1, *path2;
225 	char *home;
226 	FILE *fp;
227 
228 	/* Try ~/.rdesktop/keymaps */
229 	home = getenv("HOME");
230 	if (home)
231 	{
232 		path1 = pathjoin(home, ".rdesktop/keymaps");
233 		path2 = pathjoin(path1, filename);
234 		xfree(path1);
235 		fp = fopen(path2, "r");
236 		xfree(path2);
237 		if (fp)
238 			return fp;
239 	}
240 
241 	/* Try KEYMAP_PATH */
242 	path1 = pathjoin(KEYMAP_PATH, filename);
243 	fp = fopen(path1, "r");
244 	xfree(path1);
245 	if (fp)
246 		return fp;
247 
248 	/* Try current directory, in case we are running from the source
249 	   tree */
250 	path1 = pathjoin("keymaps", filename);
251 	fp = fopen(path1, "r");
252 	xfree(path1);
253 	if (fp)
254 		return fp;
255 
256 	return NULL;
257 }
258 
259 static BOOL
xkeymap_read(RDPCLIENT * This,char * mapname)260 xkeymap_read(RDPCLIENT * This, char *mapname)
261 {
262 	FILE *fp;
263 	char line[KEYMAP_MAX_LINE_LENGTH];
264 	unsigned int line_num = 0;
265 	unsigned int line_length = 0;
266 	char *keyname, *p;
267 	char *line_rest;
268 	uint8 scancode;
269 	uint16 modifiers;
270 
271 	fp = xkeymap_open(mapname);
272 	if (fp == NULL)
273 	{
274 		error("Failed to open keymap %s\n", mapname);
275 		return False;
276 	}
277 
278 	/* FIXME: More tolerant on white space */
279 	while (fgets(line, sizeof(line), fp) != NULL)
280 	{
281 		line_num++;
282 
283 		/* Replace the \n with \0 */
284 		p = strchr(line, '\n');
285 		if (p != NULL)
286 			*p = 0;
287 
288 		line_length = strlen(line);
289 
290 		/* Completely empty line */
291 		if (strspn(line, " \t\n\r\f\v") == line_length)
292 		{
293 			continue;
294 		}
295 
296 		/* Include */
297 		if (str_startswith(line, "include "))
298 		{
299 			if (!xkeymap_read(This, line + sizeof("include ") - 1))
300 				return False;
301 			continue;
302 		}
303 
304 		/* map */
305 		if (str_startswith(line, "map "))
306 		{
307 			This->keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16);
308 			DEBUG_KBD(("Keylayout 0x%x\n", This->keylayout));
309 			continue;
310 		}
311 
312 		/* compose */
313 		if (str_startswith(line, "enable_compose"))
314 		{
315 			DEBUG_KBD(("Enabling compose handling\n"));
316 			This->enable_compose = True;
317 			continue;
318 		}
319 
320 		/* sequence */
321 		if (str_startswith(line, "sequence"))
322 		{
323 			add_sequence(This, line + sizeof("sequence") - 1, mapname);
324 			continue;
325 		}
326 
327 		/* keyboard_type */
328 		if (str_startswith(line, "keyboard_type "))
329 		{
330 			This->keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
331 			DEBUG_KBD(("keyboard_type 0x%x\n", This->keyboard_type));
332 			continue;
333 		}
334 
335 		/* keyboard_subtype */
336 		if (str_startswith(line, "keyboard_subtype "))
337 		{
338 			This->keyboard_subtype =
339 				strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
340 			DEBUG_KBD(("keyboard_subtype 0x%x\n", This->keyboard_subtype));
341 			continue;
342 		}
343 
344 		/* keyboard_functionkeys */
345 		if (str_startswith(line, "keyboard_functionkeys "))
346 		{
347 			This->keyboard_functionkeys =
348 				strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
349 			DEBUG_KBD(("keyboard_functionkeys 0x%x\n", This->keyboard_functionkeys));
350 			continue;
351 		}
352 
353 		/* Comment */
354 		if (line[0] == '#')
355 		{
356 			continue;
357 		}
358 
359 		/* Normal line */
360 		keyname = line;
361 		p = strchr(line, ' ');
362 		if (p == NULL)
363 		{
364 			error("Bad line %d in keymap %s\n", line_num, mapname);
365 			continue;
366 		}
367 		else
368 		{
369 			*p = 0;
370 		}
371 
372 		/* scancode */
373 		p++;
374 		scancode = strtol(p, &line_rest, 16);
375 
376 		/* flags */
377 		/* FIXME: Should allow case-insensitive flag names.
378 		   Fix by using lex+yacc... */
379 		modifiers = 0;
380 		if (strstr(line_rest, "altgr"))
381 		{
382 			MASK_ADD_BITS(modifiers, MapAltGrMask);
383 		}
384 
385 		if (strstr(line_rest, "shift"))
386 		{
387 			MASK_ADD_BITS(modifiers, MapLeftShiftMask);
388 		}
389 
390 		if (strstr(line_rest, "numlock"))
391 		{
392 			MASK_ADD_BITS(modifiers, MapNumLockMask);
393 		}
394 
395 		if (strstr(line_rest, "localstate"))
396 		{
397 			MASK_ADD_BITS(modifiers, MapLocalStateMask);
398 		}
399 
400 		if (strstr(line_rest, "inhibit"))
401 		{
402 			MASK_ADD_BITS(modifiers, MapInhibitMask);
403 		}
404 
405 		add_to_keymap(This, keyname, scancode, modifiers, mapname);
406 
407 		if (strstr(line_rest, "addupper"))
408 		{
409 			/* Automatically add uppercase key, with same modifiers
410 			   plus shift */
411 			for (p = keyname; *p; p++)
412 				*p = toupper((int) *p);
413 			MASK_ADD_BITS(modifiers, MapLeftShiftMask);
414 			add_to_keymap(This, keyname, scancode, modifiers, mapname);
415 		}
416 	}
417 
418 	fclose(fp);
419 	return True;
420 }
421 
422 
423 /* Before connecting and creating UI */
424 void
xkeymap_init(RDPCLIENT * This)425 xkeymap_init(RDPCLIENT * This)
426 {
427 	unsigned int max_keycode;
428 
429 	if (strcmp(This->keymapname, "none"))
430 	{
431 		if (xkeymap_read(This, This->keymapname))
432 			This->xkeymap.keymap_loaded = True;
433 	}
434 
435 	XDisplayKeycodes(This->display, &This->xkeymap.min_keycode, (int *) &max_keycode);
436 }
437 
438 static void
send_winkey(RDPCLIENT * This,uint32 ev_time,BOOL pressed,BOOL leftkey)439 send_winkey(RDPCLIENT * This, uint32 ev_time, BOOL pressed, BOOL leftkey)
440 {
441 	uint8 winkey;
442 
443 	if (leftkey)
444 		winkey = SCANCODE_CHAR_LWIN;
445 	else
446 		winkey = SCANCODE_CHAR_RWIN;
447 
448 	if (pressed)
449 	{
450 		if (This->use_rdp5)
451 		{
452 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, winkey);
453 		}
454 		else
455 		{
456 			/* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
457 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
458 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
459 		}
460 	}
461 	else
462 	{
463 		/* key released */
464 		if (This->use_rdp5)
465 		{
466 			rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, winkey);
467 		}
468 		else
469 		{
470 			rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
471 			rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
472 		}
473 	}
474 }
475 
476 static void
reset_winkey(RDPCLIENT * This,uint32 ev_time)477 reset_winkey(RDPCLIENT * This, uint32 ev_time)
478 {
479 	if (This->use_rdp5)
480 	{
481 		/* For some reason, it seems to suffice to release
482 		 *either* the left or right winkey. */
483 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
484 	}
485 }
486 
487 /* Handle special key combinations */
488 BOOL
handle_special_keys(RDPCLIENT * This,uint32 keysym,unsigned int state,uint32 ev_time,BOOL pressed)489 handle_special_keys(RDPCLIENT * This, uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
490 {
491 	switch (keysym)
492 	{
493 		case XK_Return:
494 			if ((get_key_state(This, state, XK_Alt_L) || get_key_state(This, state, XK_Alt_R))
495 			    && (get_key_state(This, state, XK_Control_L)
496 				|| get_key_state(This, state, XK_Control_R)))
497 			{
498 				/* Ctrl-Alt-Enter: toggle full screen */
499 				if (pressed)
500 					xwin_toggle_fullscreen(This);
501 				return True;
502 			}
503 			break;
504 
505 		case XK_Break:
506 			/* Send Break sequence E0 46 E0 C6 */
507 			if (pressed)
508 			{
509 				rdp_send_scancode(This, ev_time, RDP_KEYPRESS,
510 						  (SCANCODE_EXTENDED | 0x46));
511 				rdp_send_scancode(This, ev_time, RDP_KEYPRESS,
512 						  (SCANCODE_EXTENDED | 0xc6));
513 			}
514 			/* No release sequence */
515 			return True;
516 			break;
517 
518 		case XK_Pause:
519 			/* According to MS Keyboard Scan Code
520 			   Specification, pressing Pause should result
521 			   in E1 1D 45 E1 9D C5. I'm not exactly sure
522 			   of how this is supposed to be sent via
523 			   RDP. The code below seems to work, but with
524 			   the side effect that Left Ctrl stays
525 			   down. Therefore, we release it when Pause
526 			   is released. */
527 			if (pressed)
528 			{
529 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
530 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
531 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
532 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
533 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
534 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
535 			}
536 			else
537 			{
538 				/* Release Left Ctrl */
539 				rdp_send_input(This, ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
540 					       0x1d, 0);
541 			}
542 			return True;
543 			break;
544 
545 		case XK_Meta_L:	/* Windows keys */
546 		case XK_Super_L:
547 		case XK_Hyper_L:
548 			send_winkey(This, ev_time, pressed, True);
549 			return True;
550 			break;
551 
552 		case XK_Meta_R:
553 		case XK_Super_R:
554 		case XK_Hyper_R:
555 			send_winkey(This, ev_time, pressed, False);
556 			return True;
557 			break;
558 
559 		case XK_space:
560 			/* Prevent access to the Windows system menu in single app mode */
561 			if (This->win_button_size
562 			    && (get_key_state(This, state, XK_Alt_L) || get_key_state(This, state, XK_Alt_R)))
563 				return True;
564 			break;
565 
566 		case XK_Num_Lock:
567 			/* Synchronize on key release */
568 			if (This->numlock_sync && !pressed)
569 				rdp_send_input(This, 0, RDP_INPUT_SYNCHRONIZE, 0,
570 					       ui_get_numlock_state(This, read_keyboard_state(This)), 0);
571 
572 			/* Inhibit */
573 			return True;
574 			break;
575 		case XK_Overlay1_Enable:
576 			/* Toggle SeamlessRDP */
577 			if (pressed)
578 				ui_seamless_toggle(This);
579 			break;
580 
581 	}
582 	return False;
583 }
584 
585 
586 key_translation
xkeymap_translate_key(RDPCLIENT * This,uint32 keysym,unsigned int keycode,unsigned int state)587 xkeymap_translate_key(RDPCLIENT * This, uint32 keysym, unsigned int keycode, unsigned int state)
588 {
589 	key_translation tr = { 0, 0, 0, 0 };
590 	key_translation *ptr;
591 
592 	ptr = This->xkeymap.keymap[keysym & KEYMAP_MASK];
593 	if (ptr)
594 	{
595 		tr = *ptr;
596 		if (tr.seq_keysym == 0)	/* Normal scancode translation */
597 		{
598 			if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
599 			{
600 				DEBUG_KBD(("Inhibiting key\n"));
601 				tr.scancode = 0;
602 				return tr;
603 			}
604 
605 			if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask))
606 			{
607 				/* The modifiers to send for this key should be obtained
608 				   from the local state. Currently, only shift is implemented. */
609 				if (MASK_HAS_BITS(state, ShiftMask))
610 				{
611 					tr.modifiers = MapLeftShiftMask;
612 				}
613 			}
614 
615 			/* Windows interprets CapsLock+Ctrl+key
616 			   differently from Shift+Ctrl+key. Since we
617 			   are simulating CapsLock with Shifts, things
618 			   like Ctrl+f with CapsLock on breaks. To
619 			   solve this, we are releasing Shift if Ctrl
620 			   is on, but only if Shift isn't physically pressed. */
621 			if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
622 			    && MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapCtrlMask)
623 			    && !MASK_HAS_BITS(state, ShiftMask))
624 			{
625 				DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
626 				MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
627 			}
628 
629 			DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
630 				   tr.scancode, tr.modifiers));
631 		}
632 	}
633 	else
634 	{
635 		if (This->xkeymap.keymap_loaded)
636 			warning("No translation for (keysym 0x%lx, %s)\n", keysym,
637 				get_ksname(keysym));
638 
639 		/* not in keymap, try to interpret the raw scancode */
640 		if (((int) keycode >= This->xkeymap.min_keycode) && (keycode <= 0x60))
641 		{
642 			tr.scancode = keycode - This->xkeymap.min_keycode;
643 
644 			/* The modifiers to send for this key should be
645 			   obtained from the local state. Currently, only
646 			   shift is implemented. */
647 			if (MASK_HAS_BITS(state, ShiftMask))
648 			{
649 				tr.modifiers = MapLeftShiftMask;
650 			}
651 
652 			DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
653 		}
654 		else
655 		{
656 			DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
657 		}
658 	}
659 
660 	return tr;
661 }
662 
663 void
xkeymap_send_keys(RDPCLIENT * This,uint32 keysym,unsigned int keycode,unsigned int state,uint32 ev_time,BOOL pressed,uint8 nesting)664 xkeymap_send_keys(RDPCLIENT * This, uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
665 		  BOOL pressed, uint8 nesting)
666 {
667 	key_translation tr, *ptr;
668 	tr = xkeymap_translate_key(This, keysym, keycode, state);
669 
670 	if (tr.seq_keysym == 0)
671 	{
672 		/* Scancode translation */
673 		if (tr.scancode == 0)
674 			return;
675 
676 		if (pressed)
677 		{
678 			save_remote_modifiers(This, tr.scancode);
679 			ensure_remote_modifiers(This, ev_time, tr);
680 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, tr.scancode);
681 			restore_remote_modifiers(This, ev_time, tr.scancode);
682 		}
683 		else
684 		{
685 			rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, tr.scancode);
686 		}
687 		return;
688 	}
689 
690 	/* Sequence, only on key down */
691 	if (pressed)
692 	{
693 		ptr = &tr;
694 		do
695 		{
696 			DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
697 				   (unsigned int) ptr->seq_keysym));
698 
699 			if (nesting++ > 32)
700 			{
701 				error("Sequence nesting too deep\n");
702 				return;
703 			}
704 
705 			xkeymap_send_keys(This, ptr->seq_keysym, keycode, state, ev_time, True, nesting);
706 			xkeymap_send_keys(This, ptr->seq_keysym, keycode, state, ev_time, False, nesting);
707 			ptr = ptr->next;
708 		}
709 		while (ptr);
710 	}
711 }
712 
713 uint16
xkeymap_translate_button(unsigned int button)714 xkeymap_translate_button(unsigned int button)
715 {
716 	switch (button)
717 	{
718 		case Button1:	/* left */
719 			return MOUSE_FLAG_BUTTON1;
720 		case Button2:	/* middle */
721 			return MOUSE_FLAG_BUTTON3;
722 		case Button3:	/* right */
723 			return MOUSE_FLAG_BUTTON2;
724 		case Button4:	/* wheel up */
725 			return MOUSE_FLAG_BUTTON4;
726 		case Button5:	/* wheel down */
727 			return MOUSE_FLAG_BUTTON5;
728 	}
729 
730 	return 0;
731 }
732 
733 char *
get_ksname(uint32 keysym)734 get_ksname(uint32 keysym)
735 {
736 	char *ksname = NULL;
737 
738 	if (keysym == NoSymbol)
739 		ksname = "NoSymbol";
740 	else if (!(ksname = XKeysymToString(keysym)))
741 		ksname = "(no name)";
742 
743 	return ksname;
744 }
745 
746 static BOOL
is_modifier(uint8 scancode)747 is_modifier(uint8 scancode)
748 {
749 	switch (scancode)
750 	{
751 		case SCANCODE_CHAR_LSHIFT:
752 		case SCANCODE_CHAR_RSHIFT:
753 		case SCANCODE_CHAR_LCTRL:
754 		case SCANCODE_CHAR_RCTRL:
755 		case SCANCODE_CHAR_LALT:
756 		case SCANCODE_CHAR_RALT:
757 		case SCANCODE_CHAR_LWIN:
758 		case SCANCODE_CHAR_RWIN:
759 		case SCANCODE_CHAR_NUMLOCK:
760 			return True;
761 		default:
762 			break;
763 	}
764 	return False;
765 }
766 
767 void
save_remote_modifiers(RDPCLIENT * This,uint8 scancode)768 save_remote_modifiers(RDPCLIENT * This, uint8 scancode)
769 {
770 	if (is_modifier(scancode))
771 		return;
772 
773 	This->xkeymap.saved_remote_modifier_state = This->xkeymap.remote_modifier_state;
774 }
775 
776 void
restore_remote_modifiers(RDPCLIENT * This,uint32 ev_time,uint8 scancode)777 restore_remote_modifiers(RDPCLIENT * This, uint32 ev_time, uint8 scancode)
778 {
779 	key_translation dummy;
780 
781 	if (is_modifier(scancode))
782 		return;
783 
784 	dummy.scancode = 0;
785 	dummy.modifiers = This->xkeymap.saved_remote_modifier_state;
786 	ensure_remote_modifiers(This, ev_time, dummy);
787 }
788 
789 void
ensure_remote_modifiers(RDPCLIENT * This,uint32 ev_time,key_translation tr)790 ensure_remote_modifiers(RDPCLIENT * This, uint32 ev_time, key_translation tr)
791 {
792 	/* If this key is a modifier, do nothing */
793 	if (is_modifier(tr.scancode))
794 		return;
795 
796 	if (!This->numlock_sync)
797 	{
798 		/* NumLock */
799 		if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
800 		    != MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapNumLockMask))
801 		{
802 			/* The remote modifier state is not correct */
803 			uint16 new_remote_state;
804 
805 			if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
806 			{
807 				DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
808 				new_remote_state = KBD_FLAG_NUMLOCK;
809 				This->xkeymap.remote_modifier_state = MapNumLockMask;
810 			}
811 			else
812 			{
813 				DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
814 				new_remote_state = 0;
815 				This->xkeymap.remote_modifier_state = 0;
816 			}
817 
818 			rdp_send_input(This, 0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
819 		}
820 	}
821 
822 
823 	/* Shift. Left shift and right shift are treated as equal; either is fine. */
824 	if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
825 	    != MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapShiftMask))
826 	{
827 		/* The remote modifier state is not correct */
828 		if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
829 		{
830 			/* Needs left shift. Send down. */
831 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
832 		}
833 		else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
834 		{
835 			/* Needs right shift. Send down. */
836 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
837 		}
838 		else
839 		{
840 			/* Should not use this modifier. Send up for shift currently pressed. */
841 			if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapLeftShiftMask))
842 				/* Left shift is down */
843 				rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
844 			else
845 				/* Right shift is down */
846 				rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
847 		}
848 	}
849 
850 	/* AltGr */
851 	if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
852 	    != MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapAltGrMask))
853 	{
854 		/* The remote modifier state is not correct */
855 		if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
856 		{
857 			/* Needs this modifier. Send down. */
858 			rdp_send_scancode(This, ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
859 		}
860 		else
861 		{
862 			/* Should not use this modifier. Send up. */
863 			rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
864 		}
865 	}
866 
867 
868 }
869 
870 
871 unsigned int
read_keyboard_state(RDPCLIENT * This)872 read_keyboard_state(RDPCLIENT * This)
873 {
874 #ifdef RDP2VNC
875 	return 0;
876 #else
877 	unsigned int state;
878 	Window wdummy;
879 	int dummy;
880 
881 	XQueryPointer(This->display, This->wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
882 	return state;
883 #endif
884 }
885 
886 
887 uint16
ui_get_numlock_state(RDPCLIENT * This,unsigned int state)888 ui_get_numlock_state(RDPCLIENT * This, unsigned int state)
889 {
890 	uint16 numlock_state = 0;
891 
892 	if (get_key_state(This, state, XK_Num_Lock))
893 		numlock_state = KBD_FLAG_NUMLOCK;
894 
895 	return numlock_state;
896 }
897 
898 
899 void
reset_modifier_keys(RDPCLIENT * This)900 reset_modifier_keys(RDPCLIENT * This)
901 {
902 	unsigned int state = read_keyboard_state(This);
903 
904 	/* reset keys */
905 	uint32 ev_time;
906 	ev_time = time(NULL);
907 
908 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapLeftShiftMask)
909 	    && !get_key_state(This, state, XK_Shift_L))
910 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
911 
912 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapRightShiftMask)
913 	    && !get_key_state(This, state, XK_Shift_R))
914 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
915 
916 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapLeftCtrlMask)
917 	    && !get_key_state(This, state, XK_Control_L))
918 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
919 
920 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapRightCtrlMask)
921 	    && !get_key_state(This, state, XK_Control_R))
922 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
923 
924 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapLeftAltMask) && !get_key_state(This, state, XK_Alt_L))
925 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
926 
927 	if (MASK_HAS_BITS(This->xkeymap.remote_modifier_state, MapRightAltMask) &&
928 	    !get_key_state(This, state, XK_Alt_R) && !get_key_state(This, state, XK_Mode_switch)
929 	    && !get_key_state(This, state, XK_ISO_Level3_Shift))
930 		rdp_send_scancode(This, ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
931 
932 	reset_winkey(This, ev_time);
933 
934 	if (This->numlock_sync)
935 		rdp_send_input(This, ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(This, state), 0);
936 }
937 
938 
939 static void
update_modifier_state(RDPCLIENT * This,uint8 scancode,BOOL pressed)940 update_modifier_state(RDPCLIENT * This, uint8 scancode, BOOL pressed)
941 {
942 #ifdef WITH_DEBUG_KBD
943 	uint16 old_modifier_state;
944 
945 	old_modifier_state = This->xkeymap.remote_modifier_state;
946 #endif
947 
948 	switch (scancode)
949 	{
950 		case SCANCODE_CHAR_LSHIFT:
951 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapLeftShiftMask, pressed);
952 			break;
953 		case SCANCODE_CHAR_RSHIFT:
954 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapRightShiftMask, pressed);
955 			break;
956 		case SCANCODE_CHAR_LCTRL:
957 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapLeftCtrlMask, pressed);
958 			break;
959 		case SCANCODE_CHAR_RCTRL:
960 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapRightCtrlMask, pressed);
961 			break;
962 		case SCANCODE_CHAR_LALT:
963 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapLeftAltMask, pressed);
964 			break;
965 		case SCANCODE_CHAR_RALT:
966 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapRightAltMask, pressed);
967 			break;
968 		case SCANCODE_CHAR_LWIN:
969 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapLeftWinMask, pressed);
970 			break;
971 		case SCANCODE_CHAR_RWIN:
972 			MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state, MapRightWinMask, pressed);
973 			break;
974 		case SCANCODE_CHAR_NUMLOCK:
975 			/* KeyReleases for NumLocks are sent immediately. Toggle the
976 			   modifier state only on Keypress */
977 			if (pressed && !This->numlock_sync)
978 			{
979 				BOOL newNumLockState;
980 				newNumLockState =
981 					(MASK_HAS_BITS
982 					 (This->xkeymap.remote_modifier_state, MapNumLockMask) == False);
983 				MASK_CHANGE_BIT(This->xkeymap.remote_modifier_state,
984 						MapNumLockMask, newNumLockState);
985 			}
986 	}
987 
988 #ifdef WITH_DEBUG_KBD
989 	if (old_modifier_state != This->xkeymap.remote_modifier_state)
990 	{
991 		DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
992 			   old_modifier_state, pressed));
993 		DEBUG_KBD(("After updating modifier_state:0x%x\n", This->xkeymap.remote_modifier_state));
994 	}
995 #endif
996 
997 }
998 
999 /* Send keyboard input */
1000 void
rdp_send_scancode(RDPCLIENT * This,uint32 time,uint16 flags,uint8 scancode)1001 rdp_send_scancode(RDPCLIENT * This, uint32 time, uint16 flags, uint8 scancode)
1002 {
1003 	update_modifier_state(This, scancode, !(flags & RDP_KEYRELEASE));
1004 
1005 	if (scancode & SCANCODE_EXTENDED)
1006 	{
1007 		DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1008 			   scancode & ~SCANCODE_EXTENDED, flags));
1009 		rdp_send_input(This, time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1010 			       scancode & ~SCANCODE_EXTENDED, 0);
1011 	}
1012 	else
1013 	{
1014 		DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1015 		rdp_send_input(This, time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1016 	}
1017 }
1018