quartzKeyboard.c revision 1b5d61b8
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#include <AvailabilityMacros.h> 50 51#include "quartz.h" 52#include "darwin.h" 53#include "darwinEvents.h" 54 55#include "quartzKeyboard.h" 56 57#include "X11Application.h" 58 59#include <assert.h> 60#include <pthread.h> 61 62#include "xkbsrv.h" 63#include "exevents.h" 64#include "X11/keysym.h" 65#include "keysym2ucs.h" 66 67extern void 68CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); 69 70enum { 71 MOD_COMMAND = 256, 72 MOD_SHIFT = 512, 73 MOD_OPTION = 2048, 74 MOD_CONTROL = 4096, 75}; 76 77#define UKEYSYM(u) ((u) | 0x01000000) 78 79#if HACK_MISSING 80/* Table of keycode->keysym mappings we use to fallback on for important 81 keys that are often not in the Unicode mapping. */ 82 83const static struct { 84 unsigned short keycode; 85 KeySym keysym; 86} known_keys[] = { 87 { 55, XK_Meta_L }, 88 { 56, XK_Shift_L }, 89 { 57, XK_Caps_Lock }, 90 { 58, XK_Alt_L }, 91 { 59, XK_Control_L }, 92 93 { 60, XK_Shift_R }, 94 { 61, XK_Alt_R }, 95 { 62, XK_Control_R }, 96 { 63, XK_Meta_R }, 97 98 { 122, XK_F1 }, 99 { 120, XK_F2 }, 100 { 99, XK_F3 }, 101 { 118, XK_F4 }, 102 { 96, XK_F5 }, 103 { 97, XK_F6 }, 104 { 98, XK_F7 }, 105 { 100, XK_F8 }, 106 { 101, XK_F9 }, 107 { 109, XK_F10 }, 108 { 103, XK_F11 }, 109 { 111, XK_F12 }, 110 { 105, XK_F13 }, 111 { 107, XK_F14 }, 112 { 113, XK_F15 }, 113}; 114#endif 115 116#if HACK_KEYPAD 117/* Table of keycode->old,new-keysym mappings we use to fixup the numeric 118 keypad entries. */ 119 120const static struct { 121 unsigned short keycode; 122 KeySym normal, keypad; 123} known_numeric_keys[] = { 124 { 65, XK_period, XK_KP_Decimal }, 125 { 67, XK_asterisk, XK_KP_Multiply }, 126 { 69, XK_plus, XK_KP_Add }, 127 { 75, XK_slash, XK_KP_Divide }, 128 { 76, 0x01000003, XK_KP_Enter }, 129 { 78, XK_minus, XK_KP_Subtract }, 130 { 81, XK_equal, XK_KP_Equal }, 131 { 82, XK_0, XK_KP_0 }, 132 { 83, XK_1, XK_KP_1 }, 133 { 84, XK_2, XK_KP_2 }, 134 { 85, XK_3, XK_KP_3 }, 135 { 86, XK_4, XK_KP_4 }, 136 { 87, XK_5, XK_KP_5 }, 137 { 88, XK_6, XK_KP_6 }, 138 { 89, XK_7, XK_KP_7 }, 139 { 91, XK_8, XK_KP_8 }, 140 { 92, XK_9, XK_KP_9 }, 141}; 142#endif 143 144#if HACK_BLACKLIST 145/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow 146 * http://xquartz.macosforge.org/trac/ticket/295 147 * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html 148 * 149 * legacy Mac keycodes for arrow keys that shift-modify to math symbols 150 */ 151const static unsigned short keycode_blacklist[] = { 66, 70, 72, 77 }; 152#endif 153 154/* Table mapping normal keysyms to their dead equivalents. 155 FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ 156 157const static struct { 158 KeySym normal, dead; 159} dead_keys[] = { 160 { XK_grave, XK_dead_grave }, 161 { XK_apostrophe, XK_dead_acute }, /* US:"=" on a Czech keyboard */ 162 { XK_acute, XK_dead_acute }, 163 { UKEYSYM(0x384), XK_dead_acute }, /* US:";" on a Greek keyboard */ 164 // {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */ 165 { XK_asciicircum, XK_dead_circumflex }, 166 { UKEYSYM(0x2c6), XK_dead_circumflex }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ 167 { XK_asciitilde, XK_dead_tilde }, 168 { UKEYSYM(0x2dc), XK_dead_tilde }, /* SMALL TILDE */ 169 { XK_macron, XK_dead_macron }, 170 { XK_breve, XK_dead_breve }, 171 { XK_abovedot, XK_dead_abovedot }, 172 { XK_diaeresis, XK_dead_diaeresis }, 173 { UKEYSYM(0x2da), XK_dead_abovering }, /* DOT ABOVE */ 174 { XK_doubleacute, XK_dead_doubleacute }, 175 { XK_caron, XK_dead_caron }, 176 { XK_cedilla, XK_dead_cedilla }, 177 { XK_ogonek, XK_dead_ogonek }, 178 { UKEYSYM(0x269), XK_dead_iota }, /* LATIN SMALL LETTER IOTA */ 179 { UKEYSYM(0x2ec), XK_dead_voiced_sound }, /* MODIFIER LETTER VOICING */ 180 /* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ 181 { UKEYSYM(0x323), XK_dead_belowdot }, /* COMBINING DOT BELOW */ 182 { UKEYSYM(0x309), XK_dead_hook }, /* COMBINING HOOK ABOVE */ 183 { UKEYSYM(0x31b), XK_dead_horn }, /* COMBINING HORN */ 184}; 185 186typedef struct darwinKeyboardInfo_struct { 187 CARD8 modMap[MAP_LENGTH]; 188 KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; 189 unsigned char modifierKeycodes[32][2]; 190} darwinKeyboardInfo; 191 192darwinKeyboardInfo keyInfo; 193pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER; 194 195static void 196DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) 197{ 198 // FIXME: to be implemented 199 // keyclick, bell volume / pitch, autorepead, LED's 200} 201 202//----------------------------------------------------------------------------- 203// Utility functions to help parse Darwin keymap 204//----------------------------------------------------------------------------- 205 206/* 207 * DarwinBuildModifierMaps 208 * Use the keyMap field of keyboard info structure to populate 209 * the modMap and modifierKeycodes fields. 210 */ 211static void 212DarwinBuildModifierMaps(darwinKeyboardInfo *info) 213{ 214 int i; 215 KeySym *k; 216 217 memset(info->modMap, NoSymbol, sizeof(info->modMap)); 218 memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes)); 219 220 for (i = 0; i < NUM_KEYCODES; i++) { 221 k = info->keyMap + i * GLYPHS_PER_KEY; 222 223 switch (*k) { 224 case XK_Shift_L: 225 info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; 226 info->modMap[MIN_KEYCODE + i] = ShiftMask; 227 break; 228 229 case XK_Shift_R: 230#ifdef NX_MODIFIERKEY_RSHIFT 231 info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i; 232#else 233 info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; 234#endif 235 info->modMap[MIN_KEYCODE + i] = ShiftMask; 236 break; 237 238 case XK_Control_L: 239 info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; 240 info->modMap[MIN_KEYCODE + i] = ControlMask; 241 break; 242 243 case XK_Control_R: 244#ifdef NX_MODIFIERKEY_RCONTROL 245 info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i; 246#else 247 info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; 248#endif 249 info->modMap[MIN_KEYCODE + i] = ControlMask; 250 break; 251 252 case XK_Caps_Lock: 253 info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i; 254 info->modMap[MIN_KEYCODE + i] = LockMask; 255 break; 256 257 case XK_Alt_L: 258 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 259 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 260 if (!XQuartzOptionSendsAlt) 261 *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. 262 break; 263 264 case XK_Alt_R: 265#ifdef NX_MODIFIERKEY_RALTERNATE 266 info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; 267#else 268 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 269#endif 270 if (!XQuartzOptionSendsAlt) 271 *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. 272 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 273 break; 274 275 case XK_Mode_switch: 276 ErrorF( 277 "DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n"); 278 info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; 279#ifdef NX_MODIFIERKEY_RALTERNATE 280 info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; 281#endif 282 info->modMap[MIN_KEYCODE + i] = Mod1Mask; 283 break; 284 285 case XK_Meta_L: 286 info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; 287 info->modMap[MIN_KEYCODE + i] = Mod2Mask; 288 break; 289 290 case XK_Meta_R: 291#ifdef NX_MODIFIERKEY_RCOMMAND 292 info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i; 293#else 294 info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; 295#endif 296 info->modMap[MIN_KEYCODE + i] = Mod2Mask; 297 break; 298 299 case XK_Num_Lock: 300 info->modMap[MIN_KEYCODE + i] = Mod3Mask; 301 break; 302 } 303 } 304} 305 306/* 307 * DarwinKeyboardInit 308 * Get the Darwin keyboard map and compute an equivalent 309 * X keyboard map and modifier map. Set the new keyboard 310 * device structure. 311 */ 312void 313DarwinKeyboardInit(DeviceIntPtr pDev) 314{ 315 // Open a shared connection to the HID System. 316 // Note that the Event Status Driver is really just a wrapper 317 // for a kIOHIDParamConnectType connection. 318 assert(darwinParamConnect = NXOpenEventStatus()); 319 320 InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl); 321 322 DarwinKeyboardReloadHandler(); 323 324 CopyKeyClass(pDev, inputInfo.keyboard); 325} 326 327/* Set the repeat rates based on global preferences and keycodes for modifiers. 328 * Precondition: Has the keyInfo_mutex lock. 329 */ 330static void 331DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, 332 int keyRepeatValue) 333{ 334 if (initialKeyRepeatValue == 300000) { // off 335 /* Turn off repeats globally */ 336 XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff); 337 } 338 else { 339 int i; 340 XkbControlsPtr ctrl; 341 XkbControlsRec old; 342 343 /* Turn on repeats globally */ 344 XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); 345 346 /* Setup the bit mask for individual key repeats */ 347 ctrl = pDev->key->xkbInfo->desc->ctrls; 348 old = *ctrl; 349 350 ctrl->repeat_delay = initialKeyRepeatValue * 15; 351 ctrl->repeat_interval = keyRepeatValue * 15; 352 353 /* Turn off key-repeat for modifier keys, on for others */ 354 /* First set them all on */ 355 for (i = 0; i < XkbPerKeyBitArraySize; i++) 356 ctrl->per_key_repeat[i] = -1; 357 358 /* Now turn off the modifiers */ 359 for (i = 0; i < 32; i++) { 360 unsigned char keycode; 361 362 keycode = keyInfo.modifierKeycodes[i][0]; 363 if (keycode) 364 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); 365 366 keycode = keyInfo.modifierKeycodes[i][1]; 367 if (keycode) 368 ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); 369 } 370 371 /* Hurray for data duplication */ 372 if (pDev->kbdfeed) 373 memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, 374 XkbPerKeyBitArraySize); 375 376 //ErrorF("per_key_repeat =\n"); 377 //for(i=0; i < XkbPerKeyBitArraySize; i++) 378 // ErrorF("%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n"); 379 380 /* And now we notify the puppies about the changes */ 381 XkbDDXChangeControls(pDev, &old, ctrl); 382 } 383} 384 385void 386DarwinKeyboardReloadHandler(void) 387{ 388 KeySymsRec keySyms; 389 CFIndex initialKeyRepeatValue, keyRepeatValue; 390 BOOL ok; 391 DeviceIntPtr pDev; 392 const char *xmodmap = PROJECTROOT "/bin/xmodmap"; 393 const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap"; 394 const char *homedir = getenv("HOME"); 395 char usermodmap[PATH_MAX], cmd[PATH_MAX]; 396 397 DEBUG_LOG("DarwinKeyboardReloadHandler\n"); 398 399 /* Get our key repeat settings from GlobalPreferences */ 400 (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); 401 402 initialKeyRepeatValue = 403 CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), 404 CFSTR(".GlobalPreferences"), &ok); 405 if (!ok) 406 initialKeyRepeatValue = 35; 407 408 keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR( 409 "KeyRepeat"), 410 CFSTR( 411 ".GlobalPreferences"), 412 &ok); 413 if (!ok) 414 keyRepeatValue = 6; 415 416 pthread_mutex_lock(&keyInfo_mutex); 417 { 418 /* Initialize our keySyms */ 419 keySyms.map = keyInfo.keyMap; 420 keySyms.mapWidth = GLYPHS_PER_KEY; 421 keySyms.minKeyCode = MIN_KEYCODE; 422 keySyms.maxKeyCode = MAX_KEYCODE; 423 424 // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap 425 /* Apply the mappings to darwinKeyboard */ 426 XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode, 427 keySyms.maxKeyCode - keySyms.minKeyCode + 1, 428 keyInfo.modMap, serverClient); 429 DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, 430 keyRepeatValue); 431 432 /* Apply the mappings to the core keyboard */ 433 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { 434 if ((pDev->coreEvents || 435 pDev == inputInfo.keyboard) && pDev->key) { 436 XkbApplyMappingChange( 437 pDev, &keySyms, keySyms.minKeyCode, 438 keySyms.maxKeyCode - 439 keySyms.minKeyCode + 1, 440 keyInfo.modMap, serverClient); 441 DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, 442 keyRepeatValue); 443 } 444 } 445 } pthread_mutex_unlock(&keyInfo_mutex); 446 447 /* Modify with xmodmap */ 448 if (access(xmodmap, F_OK) == 0) { 449 /* Check for system .Xmodmap */ 450 if (access(sysmodmap, F_OK) == 0) { 451 if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap, 452 sysmodmap) < sizeof(cmd)) { 453 X11ApplicationLaunchClient(cmd); 454 } 455 else { 456 ErrorF( 457 "X11.app: Unable to create / execute xmodmap command line"); 458 } 459 } 460 461 /* Check for user's local .Xmodmap */ 462 if ((homedir != NULL) && 463 (snprintf(usermodmap, sizeof(usermodmap), "%s/.Xmodmap", 464 homedir) < sizeof(usermodmap))) { 465 if (access(usermodmap, F_OK) == 0) { 466 if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap, 467 usermodmap) < sizeof(cmd)) { 468 X11ApplicationLaunchClient(cmd); 469 } 470 else { 471 ErrorF( 472 "X11.app: Unable to create / execute xmodmap command line"); 473 } 474 } 475 } 476 else { 477 ErrorF("X11.app: Unable to determine path to user's .Xmodmap"); 478 } 479 } 480} 481 482//----------------------------------------------------------------------------- 483// Modifier translation functions 484// 485// There are three different ways to specify a Mac modifier key: 486// keycode - specifies hardware key, read from keymapping 487// key - NX_MODIFIERKEY_*, really an index 488// mask - NX_*MASK, mask for modifier flags in event record 489// Left and right side have different keycodes but the same key and mask. 490//----------------------------------------------------------------------------- 491 492/* 493 * DarwinModifierNXKeyToNXKeycode 494 * Return the keycode for an NX_MODIFIERKEY_* modifier. 495 * side = 0 for left or 1 for right. 496 * Returns 0 if key+side is not a known modifier. 497 */ 498int 499DarwinModifierNXKeyToNXKeycode(int key, int side) 500{ 501 int retval; 502 pthread_mutex_lock(&keyInfo_mutex); 503 retval = keyInfo.modifierKeycodes[key][side]; 504 pthread_mutex_unlock(&keyInfo_mutex); 505 506 return retval; 507} 508 509/* 510 * DarwinModifierNXKeycodeToNXKey 511 * Returns -1 if keycode+side is not a modifier key 512 * outSide may be NULL, else it gets 0 for left and 1 for right. 513 */ 514int 515DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) 516{ 517 int key, side; 518 519 keycode += MIN_KEYCODE; 520 521 // search modifierKeycodes for this keycode+side 522 pthread_mutex_lock(&keyInfo_mutex); 523 for (key = 0; key < NX_NUMMODIFIERS; key++) { 524 for (side = 0; side <= 1; side++) { 525 if (keyInfo.modifierKeycodes[key][side] == keycode) break; 526 } 527 } 528 pthread_mutex_unlock(&keyInfo_mutex); 529 530 if (key == NX_NUMMODIFIERS) { 531 return -1; 532 } 533 if (outSide) *outSide = side; 534 535 return key; 536} 537 538/* 539 * DarwinModifierNXMaskToNXKey 540 * Returns -1 if mask is not a known modifier mask. 541 */ 542int 543DarwinModifierNXMaskToNXKey(int mask) 544{ 545 switch (mask) { 546 case NX_ALPHASHIFTMASK: 547 return NX_MODIFIERKEY_ALPHALOCK; 548 549 case NX_SHIFTMASK: 550 return NX_MODIFIERKEY_SHIFT; 551 552#ifdef NX_DEVICELSHIFTKEYMASK 553 case NX_DEVICELSHIFTKEYMASK: 554 return NX_MODIFIERKEY_SHIFT; 555 556 case NX_DEVICERSHIFTKEYMASK: 557 return NX_MODIFIERKEY_RSHIFT; 558 559#endif 560 case NX_CONTROLMASK: 561 return NX_MODIFIERKEY_CONTROL; 562 563#ifdef NX_DEVICELCTLKEYMASK 564 case NX_DEVICELCTLKEYMASK: 565 return NX_MODIFIERKEY_CONTROL; 566 567 case NX_DEVICERCTLKEYMASK: 568 return NX_MODIFIERKEY_RCONTROL; 569 570#endif 571 case NX_ALTERNATEMASK: 572 return NX_MODIFIERKEY_ALTERNATE; 573 574#ifdef NX_DEVICELALTKEYMASK 575 case NX_DEVICELALTKEYMASK: 576 return NX_MODIFIERKEY_ALTERNATE; 577 578 case NX_DEVICERALTKEYMASK: 579 return NX_MODIFIERKEY_RALTERNATE; 580 581#endif 582 case NX_COMMANDMASK: 583 return NX_MODIFIERKEY_COMMAND; 584 585#ifdef NX_DEVICELCMDKEYMASK 586 case NX_DEVICELCMDKEYMASK: 587 return NX_MODIFIERKEY_COMMAND; 588 589 case NX_DEVICERCMDKEYMASK: 590 return NX_MODIFIERKEY_RCOMMAND; 591 592#endif 593 case NX_NUMERICPADMASK: 594 return NX_MODIFIERKEY_NUMERICPAD; 595 596 case NX_HELPMASK: 597 return NX_MODIFIERKEY_HELP; 598 599 case NX_SECONDARYFNMASK: 600 return NX_MODIFIERKEY_SECONDARYFN; 601 } 602 return -1; 603} 604 605/* 606 * DarwinModifierNXKeyToNXMask 607 * Returns 0 if key is not a known modifier key. 608 */ 609int 610DarwinModifierNXKeyToNXMask(int key) 611{ 612 switch (key) { 613 case NX_MODIFIERKEY_ALPHALOCK: 614 return NX_ALPHASHIFTMASK; 615 616#ifdef NX_DEVICELSHIFTKEYMASK 617 case NX_MODIFIERKEY_SHIFT: 618 return NX_DEVICELSHIFTKEYMASK; 619 620 case NX_MODIFIERKEY_RSHIFT: 621 return NX_DEVICERSHIFTKEYMASK; 622 623 case NX_MODIFIERKEY_CONTROL: 624 return NX_DEVICELCTLKEYMASK; 625 626 case NX_MODIFIERKEY_RCONTROL: 627 return NX_DEVICERCTLKEYMASK; 628 629 case NX_MODIFIERKEY_ALTERNATE: 630 return NX_DEVICELALTKEYMASK; 631 632 case NX_MODIFIERKEY_RALTERNATE: 633 return NX_DEVICERALTKEYMASK; 634 635 case NX_MODIFIERKEY_COMMAND: 636 return NX_DEVICELCMDKEYMASK; 637 638 case NX_MODIFIERKEY_RCOMMAND: 639 return NX_DEVICERCMDKEYMASK; 640 641#else 642 case NX_MODIFIERKEY_SHIFT: 643 return NX_SHIFTMASK; 644 645 case NX_MODIFIERKEY_CONTROL: 646 return NX_CONTROLMASK; 647 648 case NX_MODIFIERKEY_ALTERNATE: 649 return NX_ALTERNATEMASK; 650 651 case NX_MODIFIERKEY_COMMAND: 652 return NX_COMMANDMASK; 653 654#endif 655 case NX_MODIFIERKEY_NUMERICPAD: 656 return NX_NUMERICPADMASK; 657 658 case NX_MODIFIERKEY_HELP: 659 return NX_HELPMASK; 660 661 case NX_MODIFIERKEY_SECONDARYFN: 662 return NX_SECONDARYFNMASK; 663 } 664 return 0; 665} 666 667/* 668 * DarwinModifierStringToNXMask 669 * Returns 0 if string is not a known modifier. 670 */ 671int 672DarwinModifierStringToNXMask(const char *str, int separatelr) 673{ 674#ifdef NX_DEVICELSHIFTKEYMASK 675 if (separatelr) { 676 if (!strcasecmp(str, 677 "shift")) return NX_DEVICELSHIFTKEYMASK | 678 NX_DEVICERSHIFTKEYMASK; 679 if (!strcasecmp(str, 680 "control")) return NX_DEVICELCTLKEYMASK | 681 NX_DEVICERCTLKEYMASK; 682 if (!strcasecmp(str, 683 "option")) return NX_DEVICELALTKEYMASK | 684 NX_DEVICERALTKEYMASK; 685 if (!strcasecmp(str, 686 "alt")) return NX_DEVICELALTKEYMASK | 687 NX_DEVICERALTKEYMASK; 688 if (!strcasecmp(str, 689 "command")) return NX_DEVICELCMDKEYMASK | 690 NX_DEVICERCMDKEYMASK; 691 if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK; 692 if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK; 693 if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK; 694 if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK; 695 if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK; 696 if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK; 697 if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK; 698 if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK; 699 if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK; 700 if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK; 701 } 702 else { 703#endif 704 if (!strcasecmp(str, "shift")) return NX_SHIFTMASK; 705 if (!strcasecmp(str, "control")) return NX_CONTROLMASK; 706 if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK; 707 if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK; 708 if (!strcasecmp(str, "command")) return NX_COMMANDMASK; 709 if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK; 710 if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK; 711 if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK; 712 if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK; 713 if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK; 714 if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK; 715 if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK; 716 if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK; 717 if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK; 718 if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK; 719#ifdef NX_DEVICELSHIFTKEYMASK 720} 721#endif 722 if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK; 723 if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK; 724 if (!strcasecmp(str, "help")) return NX_HELPMASK; 725 if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK; 726 return 0; 727} 728 729/* 730 * LegalModifier 731 * This allows the ddx layer to prevent some keys from being remapped 732 * as modifier keys. 733 */ 734Bool 735LegalModifier(unsigned int key, DeviceIntPtr pDev) 736{ 737 return 1; 738} 739 740#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 741static inline UniChar 742macroman2ucs(unsigned char c) 743{ 744 /* Precalculated table mapping MacRoman-128 to Unicode. Generated 745 by creating single element CFStringRefs then extracting the 746 first character. */ 747 748 static const unsigned short table[128] = { 749 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 750 0xe1, 751 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 752 0xe8, 753 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 754 0xf3, 755 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 756 0xfc, 757 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 758 0xdf, 759 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 760 0xd8, 761 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 762 0x2211, 763 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 764 0xf8, 765 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 766 0xab, 767 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 768 0x153, 769 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 770 0x25ca, 771 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 772 0xfb02, 773 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 774 0xc1, 775 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 776 0xd4, 777 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 778 0x2dc, 779 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 780 0x2c7, 781 }; 782 783 if (c < 128) return c; 784 else return table[c - 128]; 785} 786#endif 787 788static KeySym 789make_dead_key(KeySym in) 790{ 791 int i; 792 793 for (i = 0; i < ARRAY_SIZE(dead_keys); i++) 794 if (dead_keys[i].normal == in) return dead_keys[i].dead; 795 796 return in; 797} 798 799static Bool 800QuartzReadSystemKeymap(darwinKeyboardInfo *info) 801{ 802#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 803 KeyboardLayoutRef key_layout; 804 int is_uchr = 1; 805#endif 806 const void *chr_data = NULL; 807 int num_keycodes = NUM_KEYCODES; 808 UInt32 keyboard_type = LMGetKbdType(); 809 int i, j; 810 OSStatus err; 811 KeySym *k; 812 CFDataRef currentKeyLayoutDataRef = NULL; 813 814#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 815 TISInputSourceRef currentKeyLayoutRef = 816 TISCopyCurrentKeyboardLayoutInputSource(); 817 818 if (currentKeyLayoutRef) { 819 currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty( 820 currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData); 821 if (currentKeyLayoutDataRef) 822 chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef); 823 } 824#endif 825 826#ifdef __clang__ 827#pragma clang diagnostic push 828#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty 829#endif 830 831#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 832 if (chr_data == NULL) { 833#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 834 ErrorF( 835 "X11.app: Error detected in determining keyboard layout. If you are using an Apple-provided keyboard layout, please report this error at http://xquartz.macosforge.org and http://bugreport.apple.com\n"); 836 ErrorF( 837 "X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n", 838 (unsigned)keyboard_type, currentKeyLayoutRef, 839 currentKeyLayoutDataRef, chr_data); 840#endif 841 842 KLGetCurrentKeyboardLayout(&key_layout); 843 KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data); 844 845#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 846 if (chr_data != NULL) { 847 ErrorF( 848 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n"); 849 } 850#endif 851 } 852 853 if (chr_data == NULL) { 854 ErrorF( 855 "X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n"); 856 ErrorF( 857 "If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n"); 858 KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data); 859 is_uchr = 0; 860 num_keycodes = 128; 861 862#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 863 if (chr_data != NULL) { 864 ErrorF( 865 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n"); 866 } 867#endif 868 } 869#endif 870 871#ifdef __clang__ 872#pragma clang diagnostic pop 873#endif 874 875#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 876 if (currentKeyLayoutRef) 877 CFRelease(currentKeyLayoutRef); 878#endif 879 880 if (chr_data == NULL) { 881 ErrorF("Couldn't get uchr or kchr resource\n"); 882 return FALSE; 883 } 884 885 /* Scan the keycode range for the Unicode character that each 886 key produces in the four shift states. Then convert that to 887 an X11 keysym (which may just the bit that says "this is 888 Unicode" if it can't find the real symbol.) */ 889 890 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate 891 must be used instead. */ 892 893 for (i = 0; i < num_keycodes; i++) { 894 static const int mods[4] = { 895 0, MOD_SHIFT, MOD_OPTION, 896 MOD_OPTION | MOD_SHIFT 897 }; 898 899 k = info->keyMap + i * GLYPHS_PER_KEY; 900 901 for (j = 0; j < 4; j++) { 902#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 903 if (is_uchr) { 904#endif 905 UniChar s[8]; 906 UniCharCount len; 907 UInt32 dead_key_state = 0, extra_dead = 0; 908 909 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 910 mods[j] >> 8, keyboard_type, 0, 911 &dead_key_state, 8, &len, s); 912 if (err != noErr) continue; 913 914 if (len == 0 && dead_key_state != 0) { 915 /* Found a dead key. Work out which one it is, but 916 remembering that it's dead. */ 917 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown, 918 mods[j] >> 8, keyboard_type, 919 kUCKeyTranslateNoDeadKeysMask, 920 &extra_dead, 8, &len, s); 921 if (err != noErr) continue; 922 } 923 924 /* Not sure why 0x0010 is there. 925 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ... 926 */ 927 if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { 928 k[j] = ucs2keysym(s[0]); 929 if (dead_key_state != 0) k[j] = make_dead_key(k[j]); 930 } 931#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 932 } 933 else { // kchr 934 UInt32 c, state = 0, state2 = 0; 935 UInt16 code; 936 937 code = i | mods[j]; 938 939#ifdef __clang__ 940#pragma clang diagnostic push 941#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate 942#endif 943 944 c = KeyTranslate(chr_data, code, &state); 945 946 /* Dead keys are only processed on key-down, so ask 947 to translate those events. When we find a dead key, 948 translating the matching key up event will give 949 us the actual dead character. */ 950 951 if (state != 0) 952 c = KeyTranslate(chr_data, code | 128, &state2); 953 954#ifdef __clang__ 955#pragma clang diagnostic pop 956#endif 957 958 /* Characters seem to be in MacRoman encoding. */ 959 960 if (c != 0 && c != 0x0010) { 961 k[j] = ucs2keysym(macroman2ucs(c & 255)); 962 963 if (state != 0) k[j] = make_dead_key(k[j]); 964 } 965 } 966#endif 967 } 968 969 if (k[3] == k[2]) k[3] = NoSymbol; 970 if (k[1] == k[0]) k[1] = NoSymbol; 971 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; 972 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; 973 } 974 975#if HACK_MISSING 976 /* Fix up some things that are normally missing.. */ 977 978 for (i = 0; i < ARRAY_SIZE(known_keys); i++) { 979 k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; 980 981 if (k[0] == NoSymbol && k[1] == NoSymbol 982 && k[2] == NoSymbol && k[3] == NoSymbol) 983 k[0] = known_keys[i].keysym; 984 } 985#endif 986 987#if HACK_KEYPAD 988 /* And some more things. We find the right symbols for the numeric 989 keypad, but not the KP_ keysyms. So try to convert known keycodes. */ 990 for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) { 991 k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; 992 993 if (k[0] == known_numeric_keys[i].normal) 994 k[0] = known_numeric_keys[i].keypad; 995 } 996#endif 997 998#if HACK_BLACKLIST 999 for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) { 1000 k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; 1001 k[0] = k[1] = k[2] = k[3] = NoSymbol; 1002 } 1003#endif 1004 1005 DarwinBuildModifierMaps(info); 1006 1007 return TRUE; 1008} 1009 1010Bool 1011QuartsResyncKeymap(Bool sendDDXEvent) 1012{ 1013 Bool retval; 1014 /* Update keyInfo */ 1015 pthread_mutex_lock(&keyInfo_mutex); 1016 memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); 1017 retval = QuartzReadSystemKeymap(&keyInfo); 1018 pthread_mutex_unlock(&keyInfo_mutex); 1019 1020 /* Tell server thread to deal with new keyInfo */ 1021 if (sendDDXEvent) 1022 DarwinSendDDXEvent(kXquartzReloadKeymap, 0); 1023 1024 return retval; 1025} 1026