xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

quartzKeyboard.c (29927B)


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