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