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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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