1/* 2 quartzKeyboard.c: Keyboard support for Xquartz 3 4 Copyright (c) 2003-2012 Apple Inc. 5 Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved. 6 Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. 7 8 Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com> 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in the 18 documentation and/or other materials provided with the distribution. 19 3. The name of the author may not be used to endorse or promote products 20 derived from this software without specific prior written permission. 21 22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 25 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include "sanitizedCarbon.h" 35 36#ifdef HAVE_DIX_CONFIG_H 37#include <dix-config.h> 38#endif 39 40#define HACK_MISSING 1 41#define HACK_KEYPAD 1 42#define HACK_BLACKLIST 1 43 44#include <unistd.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <errno.h> 48#include <sys/stat.h> 49 50#include "quartz.h" 51#include "darwin.h" 52#include "darwinEvents.h" 53 54#include "quartzKeyboard.h" 55 56#include "X11Application.h" 57 58#include <assert.h> 59#include <pthread.h> 60 61#include "xkbsrv.h" 62#include "exevents.h" 63#include "X11/keysym.h" 64#include "keysym2ucs.h" 65 66extern void 67CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); 68 69enum { 70 MOD_COMMAND = 256, 71 MOD_SHIFT = 512, 72 MOD_OPTION = 2048, 73 MOD_CONTROL = 4096, 74}; 75 76#define UKEYSYM(u) ((u) | 0x01000000) 77 78#if HACK_MISSING 79/* Table of keycode->keysym mappings we use to fallback on for important 80 keys that are often not in the Unicode mapping. */ 81 82const static struct { 83 unsigned short keycode; 84 KeySym keysym; 85} known_keys[] = { 86 { 55, XK_Meta_L }, 87 { 56, XK_Shift_L }, 88 { 57, XK_Caps_Lock }, 89 { 58, XK_Alt_L }, 90 { 59, XK_Control_L }, 91 92 { 60, XK_Shift_R }, 93 { 61, XK_Alt_R }, 94 { 62, XK_Control_R }, 95 { 63, XK_Meta_R }, 96 97 { 110, XK_Menu }, 98 99 { 122, XK_F1 }, 100 { 120, XK_F2 }, 101 { 99, XK_F3 }, 102 { 118, XK_F4 }, 103 { 96, XK_F5 }, 104 { 97, XK_F6 }, 105 { 98, XK_F7 }, 106 { 100, XK_F8 }, 107 { 101, XK_F9 }, 108 { 109, XK_F10 }, 109 { 103, XK_F11 }, 110 { 111, XK_F12 }, 111 { 105, XK_F13 }, 112 { 107, XK_F14 }, 113 { 113, XK_F15 }, 114 { 106, XK_F16 }, 115 { 64, XK_F17 }, 116 { 79, XK_F18 }, 117 { 80, XK_F19 }, 118 { 90, XK_F20 }, 119}; 120#endif 121 122#if HACK_KEYPAD 123/* Table of keycode->old,new-keysym mappings we use to fixup the numeric 124 keypad entries. */ 125 126const static struct { 127 unsigned short keycode; 128 KeySym normal, keypad; 129} known_numeric_keys[] = { 130 { 65, XK_period, XK_KP_Decimal }, 131 { 67, XK_asterisk, XK_KP_Multiply }, 132 { 69, XK_plus, XK_KP_Add }, 133 { 75, XK_slash, XK_KP_Divide }, 134 { 76, 0x01000003, XK_KP_Enter }, 135 { 78, XK_minus, XK_KP_Subtract }, 136 { 81, XK_equal, XK_KP_Equal }, 137 { 82, XK_0, XK_KP_0 }, 138 { 83, XK_1, XK_KP_1 }, 139 { 84, XK_2, XK_KP_2 }, 140 { 85, XK_3, XK_KP_3 }, 141 { 86, XK_4, XK_KP_4 }, 142 { 87, XK_5, XK_KP_5 }, 143 { 88, XK_6, XK_KP_6 }, 144 { 89, XK_7, XK_KP_7 }, 145 { 91, XK_8, XK_KP_8 }, 146 { 92, XK_9, XK_KP_9 }, 147}; 148#endif 149 150#if HACK_BLACKLIST 151/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow 152 * http://xquartz.macosforge.org/trac/ticket/295 153 * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html 154 * 155 * legacy Mac keycodes for arrow keys that shift-modify to math symbols 156 */ 157const static unsigned short keycode_blacklist[] = { 66, 70, 72, 77 }; 158#endif 159 160/* Table mapping normal keysyms to their dead equivalents. 161 FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ 162 163const static struct { 164 KeySym normal, dead; 165} dead_keys[] = { 166 { XK_grave, XK_dead_grave }, 167 { XK_apostrophe, XK_dead_acute }, /* US:"=" on a Czech keyboard */ 168 { XK_acute, XK_dead_acute }, 169 { UKEYSYM(0x384), XK_dead_acute }, /* US:";" on a Greek keyboard */ 170 // {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */ 171 { XK_asciicircum, XK_dead_circumflex }, 172 { UKEYSYM(0x2c6), XK_dead_circumflex }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ 173 { XK_asciitilde, XK_dead_tilde }, 174 { UKEYSYM(0x2dc), XK_dead_tilde }, /* SMALL TILDE */ 175 { XK_macron, XK_dead_macron }, 176 { XK_breve, XK_dead_breve }, 177 { XK_abovedot, XK_dead_abovedot }, 178 { XK_diaeresis, XK_dead_diaeresis }, 179 { UKEYSYM(0x2da), XK_dead_abovering }, /* DOT ABOVE */ 180 { XK_doubleacute, XK_dead_doubleacute }, 181 { XK_caron, XK_dead_caron }, 182 { XK_cedilla, XK_dead_cedilla }, 183 { XK_ogonek, XK_dead_ogonek }, 184 { UKEYSYM(0x269), XK_dead_iota }, /* LATIN SMALL LETTER IOTA */ 185 { UKEYSYM(0x2ec), XK_dead_voiced_sound }, /* MODIFIER LETTER VOICING */ 186 /* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ 187 { UKEYSYM(0x323), XK_dead_belowdot }, /* COMBINING DOT BELOW */ 188 { UKEYSYM(0x309), XK_dead_hook }, /* COMBINING HOOK ABOVE */ 189 { UKEYSYM(0x31b), XK_dead_horn }, /* COMBINING HORN */ 190}; 191 192typedef struct darwinKeyboardInfo_struct { 193 CARD8 modMap[MAP_LENGTH]; 194 KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; 195 unsigned char modifierKeycodes[32][2]; 196} darwinKeyboardInfo; 197 198darwinKeyboardInfo keyInfo; 199pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER; 200 201static void 202DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) 203{ 204 // FIXME: to be implemented 205 // keyclick, bell volume / pitch, autorepead, LED's 206} 207 208//----------------------------------------------------------------------------- 209// Utility functions to help parse Darwin keymap 210//----------------------------------------------------------------------------- 211 212/* 213 * DarwinBuildModifierMaps 214 * Use the keyMap field of keyboard info structure to populate 215 * the modMap and modifierKeycodes fields. 216 */ 217static void 218DarwinBuildModifierMaps(darwinKeyboardInfo *info) 219{ 220 int i; 221 KeySym *k; 222 223 memset(info->modMap, NoSymbol, sizeof(info->modMap)); 224 memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes)); 225 226 for (i = 0; i < NUM_KEYCODES; i++) { 227 k = info->keyMap + i * GLYPHS_PER_KEY; 228 229 switch (*k) { 230 case XK_Shift_L: 231 info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; 232 info->modMap[MIN_KEYCODE + i] = ShiftMask; 233 break; 234 235 case XK_Shift_R: 236#ifdef NX_MODIFIERKEY_RSHIFT 237 info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i; 238#else 239 info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; 240#endif 241 info->modMap[MIN_KEYCODE + i] = ShiftMask; 242 break; 243 244 case XK_Control_L: 245 info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; 246 info->modMap[MIN_KEYCODE + i] = ControlMask; 247 break; 248 249 case XK_Control_R: 250#ifdef NX_MODIFIERKEY_RCONTROL 251 info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i; 252#else 253 info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; 254#endif 255 info->modMap[MIN_KEYCODE + i] = ControlMask; 256 break; 257 258 case XK_Caps_Lock: 259 info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i; 260 info->modMap[MIN_KEYCODE + i] = LockMask; 261 break; 262 263 case XK_Alt_L: 264 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 265 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 266 if (!XQuartzOptionSendsAlt) 267 *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. 268 break; 269 270 case XK_Alt_R: 271#ifdef NX_MODIFIERKEY_RALTERNATE 272 info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; 273#else 274 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 275#endif 276 if (!XQuartzOptionSendsAlt) 277 *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. 278 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 279 break; 280 281 case XK_Mode_switch: 282 ErrorF( 283 "DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n"); 284 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 285#ifdef NX_MODIFIERKEY_RALTERNATE 286 info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; 287#endif 288 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 289 break; 290 291 case XK_Meta_L: 292 info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; 293 info->modMap[MIN_KEYCODE + i] = Mod2Mask; 294 break; 295 296 case XK_Meta_R: 297#ifdef NX_MODIFIERKEY_RCOMMAND 298 info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i; 299#else 300 info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; 301#endif 302 info->modMap[MIN_KEYCODE + i] = Mod2Mask; 303 break; 304 305 case XK_Num_Lock: 306 info->modMap[MIN_KEYCODE + i] = Mod3Mask; 307 break; 308 } 309 } 310} 311 312/* 313 * DarwinKeyboardInit 314 * Get the Darwin keyboard map and compute an equivalent 315 * X keyboard map and modifier map. Set the new keyboard 316 * device structure. 317 */ 318void 319DarwinKeyboardInit(DeviceIntPtr pDev) 320{ 321 // Open a shared connection to the HID System. 322 // Note that the Event Status Driver is really just a wrapper 323 // for a kIOHIDParamConnectType connection. 324 assert(darwinParamConnect = NXOpenEventStatus()); 325 326 InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl); 327 328 DarwinKeyboardReloadHandler(); 329 330 CopyKeyClass(pDev, inputInfo.keyboard); 331} 332 333/* Set the repeat rates based on global preferences and keycodes for modifiers. 334 * Precondition: Has the keyInfo_mutex lock. 335 */ 336static void 337DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, 338 int keyRepeatValue) 339{ 340 if (initialKeyRepeatValue == 300000) { // off 341 /* Turn off repeats globally */ 342 XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff); 343 } 344 else { 345 int i; 346 XkbControlsPtr ctrl; 347 XkbControlsRec old; 348 349 /* Turn on repeats globally */ 350 XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); 351 352 /* Setup the bit mask for individual key repeats */ 353 ctrl = pDev->key->xkbInfo->desc->ctrls; 354 old = *ctrl; 355 356 ctrl->repeat_delay = initialKeyRepeatValue * 15; 357 ctrl->repeat_interval = keyRepeatValue * 15; 358 359 /* Turn off key-repeat for modifier keys, on for others */ 360 /* First set them all on */ 361 for (i = 0; i < XkbPerKeyBitArraySize; i++) 362 ctrl->per_key_repeat[i] = -1; 363 364 /* Now turn off the modifiers */ 365 for (i = 0; i < 32; i++) { 366 unsigned char keycode; 367 368 keycode = keyInfo.modifierKeycodes[i][0]; 369 if (keycode) 370 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); 371 372 keycode = keyInfo.modifierKeycodes[i][1]; 373 if (keycode) 374 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); 375 } 376 377 /* Hurray for data duplication */ 378 if (pDev->kbdfeed) 379 memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, 380 XkbPerKeyBitArraySize); 381 382 //ErrorF("per_key_repeat =\n"); 383 //for(i=0; i < XkbPerKeyBitArraySize; i++) 384 // ErrorF("%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n"); 385 386 /* And now we notify the puppies about the changes */ 387 XkbDDXChangeControls(pDev, &old, ctrl); 388 } 389} 390 391void 392DarwinKeyboardReloadHandler(void) 393{ 394 KeySymsRec keySyms; 395 CFIndex initialKeyRepeatValue, keyRepeatValue; 396 BOOL ok; 397 DeviceIntPtr pDev; 398 const char *xmodmap = PROJECTROOT "/bin/xmodmap"; 399 const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap"; 400 const char *homedir = getenv("HOME"); 401 char usermodmap[PATH_MAX], cmd[PATH_MAX]; 402 403 DEBUG_LOG("DarwinKeyboardReloadHandler\n"); 404 405 /* Get our key repeat settings from GlobalPreferences */ 406 (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); 407 408 initialKeyRepeatValue = 409 CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), 410 CFSTR(".GlobalPreferences"), &ok); 411 if (!ok) 412 initialKeyRepeatValue = 35; 413 414 keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR( 415 "KeyRepeat"), 416 CFSTR( 417 ".GlobalPreferences"), 418 &ok); 419 if (!ok) 420 keyRepeatValue = 6; 421 422 pthread_mutex_lock(&keyInfo_mutex); 423 { 424 /* Initialize our keySyms */ 425 keySyms.map = keyInfo.keyMap; 426 keySyms.mapWidth = GLYPHS_PER_KEY; 427 keySyms.minKeyCode = MIN_KEYCODE; 428 keySyms.maxKeyCode = MAX_KEYCODE; 429 430 // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap 431 /* Apply the mappings to darwinKeyboard */ 432 XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode, 433 keySyms.maxKeyCode - keySyms.minKeyCode + 1, 434 keyInfo.modMap, serverClient); 435 DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, 436 keyRepeatValue); 437 438 /* Apply the mappings to the core keyboard */ 439 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { 440 if ((pDev->coreEvents || 441 pDev == inputInfo.keyboard) && pDev->key) { 442 XkbApplyMappingChange( 443 pDev, &keySyms, keySyms.minKeyCode, 444 keySyms.maxKeyCode - 445 keySyms.minKeyCode + 1, 446 keyInfo.modMap, serverClient); 447 DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, 448 keyRepeatValue); 449 } 450 } 451 } pthread_mutex_unlock(&keyInfo_mutex); 452 453 /* Modify with xmodmap */ 454 if (access(xmodmap, F_OK) == 0) { 455 /* Check for system .Xmodmap */ 456 if (access(sysmodmap, F_OK) == 0) { 457 if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap, 458 sysmodmap) < sizeof(cmd)) { 459 X11ApplicationLaunchClient(cmd); 460 } 461 else { 462 ErrorF( 463 "X11.app: Unable to create / execute xmodmap command line"); 464 } 465 } 466 467 /* Check for user's local .Xmodmap */ 468 if ((homedir != NULL) && 469 (snprintf(usermodmap, sizeof(usermodmap), "%s/.Xmodmap", 470 homedir) < sizeof(usermodmap))) { 471 if (access(usermodmap, F_OK) == 0) { 472 if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap, 473 usermodmap) < sizeof(cmd)) { 474 X11ApplicationLaunchClient(cmd); 475 } 476 else { 477 ErrorF( 478 "X11.app: Unable to create / execute xmodmap command line"); 479 } 480 } 481 } 482 else { 483 ErrorF("X11.app: Unable to determine path to user's .Xmodmap"); 484 } 485 } 486} 487 488//----------------------------------------------------------------------------- 489// Modifier translation functions 490// 491// There are three different ways to specify a Mac modifier key: 492// keycode - specifies hardware key, read from keymapping 493// key - NX_MODIFIERKEY_*, really an index 494// mask - NX_*MASK, mask for modifier flags in event record 495// Left and right side have different keycodes but the same key and mask. 496//----------------------------------------------------------------------------- 497 498/* 499 * DarwinModifierNXKeyToNXKeycode 500 * Return the keycode for an NX_MODIFIERKEY_* modifier. 501 * side = 0 for left or 1 for right. 502 * Returns 0 if key+side is not a known modifier. 503 */ 504int 505DarwinModifierNXKeyToNXKeycode(int key, int side) 506{ 507 int retval; 508 pthread_mutex_lock(&keyInfo_mutex); 509 retval = keyInfo.modifierKeycodes[key][side]; 510 pthread_mutex_unlock(&keyInfo_mutex); 511 512 return retval; 513} 514 515/* 516 * DarwinModifierNXKeycodeToNXKey 517 * Returns -1 if keycode+side is not a modifier key 518 * outSide may be NULL, else it gets 0 for left and 1 for right. 519 */ 520int 521DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) 522{ 523 int key, side; 524 525 keycode += MIN_KEYCODE; 526 527 // search modifierKeycodes for this keycode+side 528 pthread_mutex_lock(&keyInfo_mutex); 529 for (key = 0; key < NX_NUMMODIFIERS; key++) { 530 for (side = 0; side <= 1; side++) { 531 if (keyInfo.modifierKeycodes[key][side] == keycode) break; 532 } 533 } 534 pthread_mutex_unlock(&keyInfo_mutex); 535 536 if (key == NX_NUMMODIFIERS) { 537 return -1; 538 } 539 if (outSide) *outSide = side; 540 541 return key; 542} 543 544/* 545 * DarwinModifierNXMaskToNXKey 546 * Returns -1 if mask is not a known modifier mask. 547 */ 548int 549DarwinModifierNXMaskToNXKey(int mask) 550{ 551 switch (mask) { 552 case NX_ALPHASHIFTMASK: 553 return NX_MODIFIERKEY_ALPHALOCK; 554 555 case NX_SHIFTMASK: 556 return NX_MODIFIERKEY_SHIFT; 557 558#ifdef NX_DEVICELSHIFTKEYMASK 559 case NX_DEVICELSHIFTKEYMASK: 560 return NX_MODIFIERKEY_SHIFT; 561 562 case NX_DEVICERSHIFTKEYMASK: 563 return NX_MODIFIERKEY_RSHIFT; 564 565#endif 566 case NX_CONTROLMASK: 567 return NX_MODIFIERKEY_CONTROL; 568 569#ifdef NX_DEVICELCTLKEYMASK 570 case NX_DEVICELCTLKEYMASK: 571 return NX_MODIFIERKEY_CONTROL; 572 573 case NX_DEVICERCTLKEYMASK: 574 return NX_MODIFIERKEY_RCONTROL; 575 576#endif 577 case NX_ALTERNATEMASK: 578 return NX_MODIFIERKEY_ALTERNATE; 579 580#ifdef NX_DEVICELALTKEYMASK 581 case NX_DEVICELALTKEYMASK: 582 return NX_MODIFIERKEY_ALTERNATE; 583 584 case NX_DEVICERALTKEYMASK: 585 return NX_MODIFIERKEY_RALTERNATE; 586 587#endif 588 case NX_COMMANDMASK: 589 return NX_MODIFIERKEY_COMMAND; 590 591#ifdef NX_DEVICELCMDKEYMASK 592 case NX_DEVICELCMDKEYMASK: 593 return NX_MODIFIERKEY_COMMAND; 594 595 case NX_DEVICERCMDKEYMASK: 596 return NX_MODIFIERKEY_RCOMMAND; 597 598#endif 599 case NX_NUMERICPADMASK: 600 return NX_MODIFIERKEY_NUMERICPAD; 601 602 case NX_HELPMASK: 603 return NX_MODIFIERKEY_HELP; 604 605 case NX_SECONDARYFNMASK: 606 return NX_MODIFIERKEY_SECONDARYFN; 607 } 608 return -1; 609} 610 611/* 612 * DarwinModifierNXKeyToNXMask 613 * Returns 0 if key is not a known modifier key. 614 */ 615int 616DarwinModifierNXKeyToNXMask(int key) 617{ 618 switch (key) { 619 case NX_MODIFIERKEY_ALPHALOCK: 620 return NX_ALPHASHIFTMASK; 621 622#ifdef NX_DEVICELSHIFTKEYMASK 623 case NX_MODIFIERKEY_SHIFT: 624 return NX_DEVICELSHIFTKEYMASK; 625 626 case NX_MODIFIERKEY_RSHIFT: 627 return NX_DEVICERSHIFTKEYMASK; 628 629 case NX_MODIFIERKEY_CONTROL: 630 return NX_DEVICELCTLKEYMASK; 631 632 case NX_MODIFIERKEY_RCONTROL: 633 return NX_DEVICERCTLKEYMASK; 634 635 case NX_MODIFIERKEY_ALTERNATE: 636 return NX_DEVICELALTKEYMASK; 637 638 case NX_MODIFIERKEY_RALTERNATE: 639 return NX_DEVICERALTKEYMASK; 640 641 case NX_MODIFIERKEY_COMMAND: 642 return NX_DEVICELCMDKEYMASK; 643 644 case NX_MODIFIERKEY_RCOMMAND: 645 return NX_DEVICERCMDKEYMASK; 646 647#else 648 case NX_MODIFIERKEY_SHIFT: 649 return NX_SHIFTMASK; 650 651 case NX_MODIFIERKEY_CONTROL: 652 return NX_CONTROLMASK; 653 654 case NX_MODIFIERKEY_ALTERNATE: 655 return NX_ALTERNATEMASK; 656 657 case NX_MODIFIERKEY_COMMAND: 658 return NX_COMMANDMASK; 659 660#endif 661 case NX_MODIFIERKEY_NUMERICPAD: 662 return NX_NUMERICPADMASK; 663 664 case NX_MODIFIERKEY_HELP: 665 return NX_HELPMASK; 666 667 case NX_MODIFIERKEY_SECONDARYFN: 668 return NX_SECONDARYFNMASK; 669 } 670 return 0; 671} 672 673/* 674 * DarwinModifierStringToNXMask 675 * Returns 0 if string is not a known modifier. 676 */ 677int 678DarwinModifierStringToNXMask(const char *str, int separatelr) 679{ 680#ifdef NX_DEVICELSHIFTKEYMASK 681 if (separatelr) { 682 if (!strcasecmp(str, 683 "shift")) return NX_DEVICELSHIFTKEYMASK | 684 NX_DEVICERSHIFTKEYMASK; 685 if (!strcasecmp(str, 686 "control")) return NX_DEVICELCTLKEYMASK | 687 NX_DEVICERCTLKEYMASK; 688 if (!strcasecmp(str, 689 "option")) return NX_DEVICELALTKEYMASK | 690 NX_DEVICERALTKEYMASK; 691 if (!strcasecmp(str, 692 "alt")) return NX_DEVICELALTKEYMASK | 693 NX_DEVICERALTKEYMASK; 694 if (!strcasecmp(str, 695 "command")) return NX_DEVICELCMDKEYMASK | 696 NX_DEVICERCMDKEYMASK; 697 if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK; 698 if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK; 699 if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK; 700 if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK; 701 if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK; 702 if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK; 703 if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK; 704 if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK; 705 if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK; 706 if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK; 707 } 708 else { 709#endif 710 if (!strcasecmp(str, "shift")) return NX_SHIFTMASK; 711 if (!strcasecmp(str, "control")) return NX_CONTROLMASK; 712 if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK; 713 if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK; 714 if (!strcasecmp(str, "command")) return NX_COMMANDMASK; 715 if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK; 716 if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK; 717 if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK; 718 if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK; 719 if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK; 720 if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK; 721 if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK; 722 if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK; 723 if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK; 724 if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK; 725#ifdef NX_DEVICELSHIFTKEYMASK 726} 727#endif 728 if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK; 729 if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK; 730 if (!strcasecmp(str, "help")) return NX_HELPMASK; 731 if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK; 732 return 0; 733} 734 735static KeySym 736make_dead_key(KeySym in) 737{ 738 int i; 739 740 for (i = 0; i < ARRAY_SIZE(dead_keys); i++) 741 if (dead_keys[i].normal == in) return dead_keys[i].dead; 742 743 return in; 744} 745 746static Bool 747QuartzReadSystemKeymap(darwinKeyboardInfo *info) 748{ 749 __block const void *chr_data = NULL; 750 int num_keycodes = NUM_KEYCODES; 751 __block UInt32 keyboard_type; 752 int i, j; 753 OSStatus err; 754 KeySym *k; 755 756 dispatch_block_t getKeyboardData = ^{ 757 keyboard_type = LMGetKbdType(); 758 759 TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource(); 760 761 if (currentKeyLayoutRef) { 762 CFDataRef currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(currentKeyLayoutRef, 763 kTISPropertyUnicodeKeyLayoutData); 764 if (currentKeyLayoutDataRef) 765 chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef); 766 767 CFRelease(currentKeyLayoutRef); 768 } 769 }; 770 771 /* This is an ugly ant-pattern, but it is more expedient to address the problem right now. */ 772 if (pthread_main_np()) { 773 getKeyboardData(); 774 } else { 775 dispatch_sync(dispatch_get_main_queue(), getKeyboardData); 776 } 777 778 if (chr_data == NULL) { 779 ErrorF("Couldn't get uchr or kchr resource\n"); 780 return FALSE; 781 } 782 783 /* Scan the keycode range for the Unicode character that each 784 key produces in the four shift states. Then convert that to 785 an X11 keysym (which may just the bit that says "this is 786 Unicode" if it can't find the real symbol.) */ 787 788 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate 789 must be used instead. */ 790 791 for (i = 0; i < num_keycodes; i++) { 792 static const int mods[4] = { 793 0, MOD_SHIFT, MOD_OPTION, 794 MOD_OPTION | MOD_SHIFT 795 }; 796 797 k = info->keyMap + i * GLYPHS_PER_KEY; 798 799 for (j = 0; j < 4; j++) { 800 UniChar s[8]; 801 UniCharCount len; 802 UInt32 dead_key_state = 0, extra_dead = 0; 803 804 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 805 mods[j] >> 8, keyboard_type, 0, 806 &dead_key_state, 8, &len, s); 807 if (err != noErr) continue; 808 809 if (len == 0 && dead_key_state != 0) { 810 /* Found a dead key. Work out which one it is, but 811 remembering that it's dead. */ 812 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 813 mods[j] >> 8, keyboard_type, 814 kUCKeyTranslateNoDeadKeysMask, 815 &extra_dead, 8, &len, s); 816 if (err != noErr) continue; 817 } 818 819 /* Not sure why 0x0010 is there. 820 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ... 821 */ 822 if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { 823 k[j] = ucs2keysym(s[0]); 824 if (dead_key_state != 0) k[j] = make_dead_key(k[j]); 825 } 826 } 827 828 if (k[3] == k[2]) k[3] = NoSymbol; 829 if (k[1] == k[0]) k[1] = NoSymbol; 830 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; 831 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; 832 } 833 834#if HACK_MISSING 835 /* Fix up some things that are normally missing.. */ 836 837 for (i = 0; i < ARRAY_SIZE(known_keys); i++) { 838 k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; 839 840 if (k[0] == NoSymbol && k[1] == NoSymbol 841 && k[2] == NoSymbol && k[3] == NoSymbol) 842 k[0] = known_keys[i].keysym; 843 } 844#endif 845 846#if HACK_KEYPAD 847 /* And some more things. We find the right symbols for the numeric 848 keypad, but not the KP_ keysyms. So try to convert known keycodes. */ 849 for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) { 850 k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; 851 852 if (k[0] == known_numeric_keys[i].normal) 853 k[0] = known_numeric_keys[i].keypad; 854 } 855#endif 856 857#if HACK_BLACKLIST 858 for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) { 859 k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; 860 k[0] = k[1] = k[2] = k[3] = NoSymbol; 861 } 862#endif 863 864 DarwinBuildModifierMaps(info); 865 866 return TRUE; 867} 868 869Bool 870QuartsResyncKeymap(Bool sendDDXEvent) 871{ 872 Bool retval; 873 /* Update keyInfo */ 874 pthread_mutex_lock(&keyInfo_mutex); 875 memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); 876 retval = QuartzReadSystemKeymap(&keyInfo); 877 pthread_mutex_unlock(&keyInfo_mutex); 878 879 /* Tell server thread to deal with new keyInfo */ 880 if (sendDDXEvent) 881 DarwinSendDDXEvent(kXquartzReloadKeymap, 0); 882 883 return retval; 884} 885