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