quartzKeyboard.c revision c8548ba8
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 735/* 736 * LegalModifier 737 * This allows the ddx layer to prevent some keys from being remapped 738 * as modifier keys. 739 */ 740Bool 741LegalModifier(unsigned int key, DeviceIntPtr pDev) 742{ 743 return 1; 744} 745 746static KeySym 747make_dead_key(KeySym in) 748{ 749 int i; 750 751 for (i = 0; i < ARRAY_SIZE(dead_keys); i++) 752 if (dead_keys[i].normal == in) return dead_keys[i].dead; 753 754 return in; 755} 756 757static Bool 758QuartzReadSystemKeymap(darwinKeyboardInfo *info) 759{ 760 __block const void *chr_data = NULL; 761 int num_keycodes = NUM_KEYCODES; 762 __block UInt32 keyboard_type; 763 int i, j; 764 OSStatus err; 765 KeySym *k; 766 767 dispatch_block_t getKeyboardData = ^{ 768 keyboard_type = LMGetKbdType(); 769 770 TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource(); 771 772 if (currentKeyLayoutRef) { 773 CFDataRef currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(currentKeyLayoutRef, 774 kTISPropertyUnicodeKeyLayoutData); 775 if (currentKeyLayoutDataRef) 776 chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef); 777 778 CFRelease(currentKeyLayoutRef); 779 } 780 }; 781 782 /* This is an ugly ant-pattern, but it is more expedient to address the problem right now. */ 783 if (pthread_main_np()) { 784 getKeyboardData(); 785 } else { 786 dispatch_sync(dispatch_get_main_queue(), getKeyboardData); 787 } 788 789 if (chr_data == NULL) { 790 ErrorF("Couldn't get uchr or kchr resource\n"); 791 return FALSE; 792 } 793 794 /* Scan the keycode range for the Unicode character that each 795 key produces in the four shift states. Then convert that to 796 an X11 keysym (which may just the bit that says "this is 797 Unicode" if it can't find the real symbol.) */ 798 799 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate 800 must be used instead. */ 801 802 for (i = 0; i < num_keycodes; i++) { 803 static const int mods[4] = { 804 0, MOD_SHIFT, MOD_OPTION, 805 MOD_OPTION | MOD_SHIFT 806 }; 807 808 k = info->keyMap + i * GLYPHS_PER_KEY; 809 810 for (j = 0; j < 4; j++) { 811 UniChar s[8]; 812 UniCharCount len; 813 UInt32 dead_key_state = 0, extra_dead = 0; 814 815 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 816 mods[j] >> 8, keyboard_type, 0, 817 &dead_key_state, 8, &len, s); 818 if (err != noErr) continue; 819 820 if (len == 0 && dead_key_state != 0) { 821 /* Found a dead key. Work out which one it is, but 822 remembering that it's dead. */ 823 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 824 mods[j] >> 8, keyboard_type, 825 kUCKeyTranslateNoDeadKeysMask, 826 &extra_dead, 8, &len, s); 827 if (err != noErr) continue; 828 } 829 830 /* Not sure why 0x0010 is there. 831 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ... 832 */ 833 if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { 834 k[j] = ucs2keysym(s[0]); 835 if (dead_key_state != 0) k[j] = make_dead_key(k[j]); 836 } 837 } 838 839 if (k[3] == k[2]) k[3] = NoSymbol; 840 if (k[1] == k[0]) k[1] = NoSymbol; 841 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; 842 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; 843 } 844 845#if HACK_MISSING 846 /* Fix up some things that are normally missing.. */ 847 848 for (i = 0; i < ARRAY_SIZE(known_keys); i++) { 849 k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; 850 851 if (k[0] == NoSymbol && k[1] == NoSymbol 852 && k[2] == NoSymbol && k[3] == NoSymbol) 853 k[0] = known_keys[i].keysym; 854 } 855#endif 856 857#if HACK_KEYPAD 858 /* And some more things. We find the right symbols for the numeric 859 keypad, but not the KP_ keysyms. So try to convert known keycodes. */ 860 for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) { 861 k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; 862 863 if (k[0] == known_numeric_keys[i].normal) 864 k[0] = known_numeric_keys[i].keypad; 865 } 866#endif 867 868#if HACK_BLACKLIST 869 for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) { 870 k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; 871 k[0] = k[1] = k[2] = k[3] = NoSymbol; 872 } 873#endif 874 875 DarwinBuildModifierMaps(info); 876 877 return TRUE; 878} 879 880Bool 881QuartsResyncKeymap(Bool sendDDXEvent) 882{ 883 Bool retval; 884 /* Update keyInfo */ 885 pthread_mutex_lock(&keyInfo_mutex); 886 memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); 887 retval = QuartzReadSystemKeymap(&keyInfo); 888 pthread_mutex_unlock(&keyInfo_mutex); 889 890 /* Tell server thread to deal with new keyInfo */ 891 if (sendDDXEvent) 892 DarwinSendDDXEvent(kXquartzReloadKeymap, 0); 893 894 return retval; 895} 896