quartzKeyboard.c revision 6747b715
14642e01fSmrg/*
24642e01fSmrg   quartzKeyboard.c: Keyboard support for Xquartz
34642e01fSmrg
44642e01fSmrg   Copyright (c) 2003-2008 Apple Inc.
54642e01fSmrg   Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved.
64642e01fSmrg   Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved.
74642e01fSmrg
84642e01fSmrg   Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com>
94642e01fSmrg   All rights reserved.
104642e01fSmrg
114642e01fSmrg   Redistribution and use in source and binary forms, with or without
124642e01fSmrg   modification, are permitted provided that the following conditions are met:
134642e01fSmrg
144642e01fSmrg     1. Redistributions of source code must retain the above copyright
154642e01fSmrg        notice, this list of conditions and the following disclaimer.
164642e01fSmrg     2. Redistributions in binary form must reproduce the above copyright
174642e01fSmrg        notice, this list of conditions and the following disclaimer in the
184642e01fSmrg        documentation and/or other materials provided with the distribution.
194642e01fSmrg     3. The name of the author may not be used to endorse or promote products
204642e01fSmrg        derived from this software without specific prior written permission.
214642e01fSmrg
224642e01fSmrg   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
234642e01fSmrg   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
244642e01fSmrg   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
254642e01fSmrg   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
264642e01fSmrg   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
274642e01fSmrg   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
284642e01fSmrg   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
294642e01fSmrg   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
304642e01fSmrg   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
314642e01fSmrg   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
324642e01fSmrg*/
334642e01fSmrg
344642e01fSmrg#include "sanitizedCarbon.h"
354642e01fSmrg
364642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
374642e01fSmrg#include <dix-config.h>
384642e01fSmrg#endif
394642e01fSmrg
404642e01fSmrg#define HACK_MISSING 1
414642e01fSmrg#define HACK_KEYPAD 1
426747b715Smrg#define HACK_BLACKLIST 1
434642e01fSmrg
446747b715Smrg#include <unistd.h>
454642e01fSmrg#include <stdio.h>
464642e01fSmrg#include <stdlib.h>
474642e01fSmrg#include <errno.h>
484642e01fSmrg#include <sys/stat.h>
494642e01fSmrg#include <AvailabilityMacros.h>
504642e01fSmrg
516747b715Smrg#include "quartz.h"
524642e01fSmrg#include "darwin.h"
536747b715Smrg#include "darwinEvents.h"
544642e01fSmrg
554642e01fSmrg#include "quartzKeyboard.h"
564642e01fSmrg#include "quartzAudio.h"
574642e01fSmrg
586747b715Smrg#include "X11Application.h"
596747b715Smrg
604642e01fSmrg#include "threadSafety.h"
614642e01fSmrg
624642e01fSmrg#ifdef NDEBUG
634642e01fSmrg#undef NDEBUG
644642e01fSmrg#include <assert.h>
654642e01fSmrg#define NDEBUG 1
664642e01fSmrg#else
674642e01fSmrg#include <assert.h>
684642e01fSmrg#endif
694642e01fSmrg#include <pthread.h>
704642e01fSmrg
714642e01fSmrg#include "xkbsrv.h"
724642e01fSmrg#include "exevents.h"
734642e01fSmrg#include "X11/keysym.h"
744642e01fSmrg#include "keysym2ucs.h"
754642e01fSmrg
766747b715Smrgextern void
776747b715SmrgCopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
786747b715Smrg
794642e01fSmrgenum {
804642e01fSmrg    MOD_COMMAND = 256,
814642e01fSmrg    MOD_SHIFT = 512,
824642e01fSmrg    MOD_OPTION = 2048,
834642e01fSmrg    MOD_CONTROL = 4096,
844642e01fSmrg};
854642e01fSmrg
864642e01fSmrg#define UKEYSYM(u) ((u) | 0x01000000)
874642e01fSmrg
886747b715Smrg#if HACK_MISSING
894642e01fSmrg/* Table of keycode->keysym mappings we use to fallback on for important
904642e01fSmrg   keys that are often not in the Unicode mapping. */
914642e01fSmrg
924642e01fSmrgconst static struct {
934642e01fSmrg    unsigned short keycode;
944642e01fSmrg    KeySym keysym;
954642e01fSmrg} known_keys[] = {
964642e01fSmrg    {55,  XK_Meta_L},
974642e01fSmrg    {56,  XK_Shift_L},
984642e01fSmrg    {57,  XK_Caps_Lock},
994642e01fSmrg    {58,  XK_Alt_L},
1004642e01fSmrg    {59,  XK_Control_L},
1014642e01fSmrg
1024642e01fSmrg    {60,  XK_Shift_R},
1034642e01fSmrg    {61,  XK_Alt_R},
1044642e01fSmrg    {62,  XK_Control_R},
1054642e01fSmrg    {63,  XK_Meta_R},
1064642e01fSmrg
1074642e01fSmrg    {122, XK_F1},
1084642e01fSmrg    {120, XK_F2},
1094642e01fSmrg    {99,  XK_F3},
1104642e01fSmrg    {118, XK_F4},
1114642e01fSmrg    {96,  XK_F5},
1124642e01fSmrg    {97,  XK_F6},
1134642e01fSmrg    {98,  XK_F7},
1144642e01fSmrg    {100, XK_F8},
1154642e01fSmrg    {101, XK_F9},
1164642e01fSmrg    {109, XK_F10},
1174642e01fSmrg    {103, XK_F11},
1184642e01fSmrg    {111, XK_F12},
1194642e01fSmrg    {105, XK_F13},
1204642e01fSmrg    {107, XK_F14},
1214642e01fSmrg    {113, XK_F15},
1224642e01fSmrg};
1236747b715Smrg#endif
1244642e01fSmrg
1256747b715Smrg#if HACK_KEYPAD
1264642e01fSmrg/* Table of keycode->old,new-keysym mappings we use to fixup the numeric
1274642e01fSmrg   keypad entries. */
1284642e01fSmrg
1294642e01fSmrgconst static struct {
1304642e01fSmrg    unsigned short keycode;
1314642e01fSmrg    KeySym normal, keypad;
1324642e01fSmrg} known_numeric_keys[] = {
1334642e01fSmrg    {65, XK_period, XK_KP_Decimal},
1344642e01fSmrg    {67, XK_asterisk, XK_KP_Multiply},
1354642e01fSmrg    {69, XK_plus, XK_KP_Add},
1364642e01fSmrg    {75, XK_slash, XK_KP_Divide},
1374642e01fSmrg    {76, 0x01000003, XK_KP_Enter},
1384642e01fSmrg    {78, XK_minus, XK_KP_Subtract},
1394642e01fSmrg    {81, XK_equal, XK_KP_Equal},
1404642e01fSmrg    {82, XK_0, XK_KP_0},
1414642e01fSmrg    {83, XK_1, XK_KP_1},
1424642e01fSmrg    {84, XK_2, XK_KP_2},
1434642e01fSmrg    {85, XK_3, XK_KP_3},
1444642e01fSmrg    {86, XK_4, XK_KP_4},
1454642e01fSmrg    {87, XK_5, XK_KP_5},
1464642e01fSmrg    {88, XK_6, XK_KP_6},
1474642e01fSmrg    {89, XK_7, XK_KP_7},
1484642e01fSmrg    {91, XK_8, XK_KP_8},
1494642e01fSmrg    {92, XK_9, XK_KP_9},
1504642e01fSmrg};
1516747b715Smrg#endif
1526747b715Smrg
1536747b715Smrg#if HACK_BLACKLIST
1546747b715Smrg/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow
1556747b715Smrg * http://xquartz.macosforge.org/trac/ticket/295
1566747b715Smrg * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html
1576747b715Smrg *
1586747b715Smrg * legacy Mac keycodes for arrow keys that shift-modify to math symbols
1596747b715Smrg */
1606747b715Smrgconst static unsigned short keycode_blacklist[] = {66, 70, 72, 77};
1616747b715Smrg#endif
1624642e01fSmrg
1634642e01fSmrg/* Table mapping normal keysyms to their dead equivalents.
1644642e01fSmrg   FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
1654642e01fSmrg
1664642e01fSmrgconst static struct {
1674642e01fSmrg    KeySym normal, dead;
1684642e01fSmrg} dead_keys[] = {
1694642e01fSmrg    {XK_grave, XK_dead_grave},
1704642e01fSmrg    {XK_apostrophe, XK_dead_acute},             /* US:"=" on a Czech keyboard */
1714642e01fSmrg    {XK_acute, XK_dead_acute},
1724642e01fSmrg    {UKEYSYM (0x384), XK_dead_acute},           /* US:";" on a Greek keyboard */
1736747b715Smrg//    {XK_Greek_accentdieresis, XK_dead_diaeresis},   /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */
1744642e01fSmrg    {XK_asciicircum, XK_dead_circumflex},
1754642e01fSmrg    {UKEYSYM (0x2c6), XK_dead_circumflex},	/* MODIFIER LETTER CIRCUMFLEX ACCENT */
1764642e01fSmrg    {XK_asciitilde, XK_dead_tilde},
1774642e01fSmrg    {UKEYSYM (0x2dc), XK_dead_tilde},		/* SMALL TILDE */
1784642e01fSmrg    {XK_macron, XK_dead_macron},
1794642e01fSmrg    {XK_breve, XK_dead_breve},
1804642e01fSmrg    {XK_abovedot, XK_dead_abovedot},
1814642e01fSmrg    {XK_diaeresis, XK_dead_diaeresis},
1824642e01fSmrg    {UKEYSYM (0x2da), XK_dead_abovering},	/* DOT ABOVE */
1834642e01fSmrg    {XK_doubleacute, XK_dead_doubleacute},
1844642e01fSmrg    {XK_caron, XK_dead_caron},
1854642e01fSmrg    {XK_cedilla, XK_dead_cedilla},
1864642e01fSmrg    {XK_ogonek, XK_dead_ogonek},
1874642e01fSmrg    {UKEYSYM (0x269), XK_dead_iota},		/* LATIN SMALL LETTER IOTA */
1884642e01fSmrg    {UKEYSYM (0x2ec), XK_dead_voiced_sound},	/* MODIFIER LETTER VOICING */
1894642e01fSmrg/*  {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
1904642e01fSmrg    {UKEYSYM (0x323), XK_dead_belowdot},	/* COMBINING DOT BELOW */
1914642e01fSmrg    {UKEYSYM (0x309), XK_dead_hook}, 		/* COMBINING HOOK ABOVE */
1924642e01fSmrg    {UKEYSYM (0x31b), XK_dead_horn},		/* COMBINING HORN */
1934642e01fSmrg};
1944642e01fSmrg
1956747b715Smrgtypedef struct darwinKeyboardInfo_struct {
1966747b715Smrg    CARD8 modMap[MAP_LENGTH];
1976747b715Smrg    KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY];
1986747b715Smrg    unsigned char modifierKeycodes[32][2];
1996747b715Smrg} darwinKeyboardInfo;
2006747b715Smrg
2014642e01fSmrgdarwinKeyboardInfo keyInfo;
2024642e01fSmrgpthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
2034642e01fSmrg
2044642e01fSmrgstatic void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) {
2054642e01fSmrg    // FIXME: to be implemented
2064642e01fSmrg    // keyclick, bell volume / pitch, autorepead, LED's
2074642e01fSmrg}
2084642e01fSmrg
2094642e01fSmrg//-----------------------------------------------------------------------------
2104642e01fSmrg// Utility functions to help parse Darwin keymap
2114642e01fSmrg//-----------------------------------------------------------------------------
2124642e01fSmrg
2134642e01fSmrg/*
2144642e01fSmrg * DarwinBuildModifierMaps
2154642e01fSmrg *      Use the keyMap field of keyboard info structure to populate
2164642e01fSmrg *      the modMap and modifierKeycodes fields.
2174642e01fSmrg */
2184642e01fSmrgstatic void DarwinBuildModifierMaps(darwinKeyboardInfo *info) {
2194642e01fSmrg    int i;
2204642e01fSmrg    KeySym *k;
2214642e01fSmrg
2224642e01fSmrg    memset(info->modMap, NoSymbol, sizeof(info->modMap));
2234642e01fSmrg    memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes));
2244642e01fSmrg
2254642e01fSmrg    for (i = 0; i < NUM_KEYCODES; i++) {
2264642e01fSmrg        k = info->keyMap + i * GLYPHS_PER_KEY;
2274642e01fSmrg
2284642e01fSmrg        switch (*k) {
2294642e01fSmrg            case XK_Shift_L:
2304642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
2314642e01fSmrg                info->modMap[MIN_KEYCODE + i] = ShiftMask;
2324642e01fSmrg                break;
2334642e01fSmrg
2344642e01fSmrg            case XK_Shift_R:
2354642e01fSmrg#ifdef NX_MODIFIERKEY_RSHIFT
2364642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i;
2374642e01fSmrg#else
2384642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
2394642e01fSmrg#endif
2404642e01fSmrg                info->modMap[MIN_KEYCODE + i] = ShiftMask;
2414642e01fSmrg                break;
2424642e01fSmrg
2434642e01fSmrg            case XK_Control_L:
2444642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
2454642e01fSmrg                info->modMap[MIN_KEYCODE + i] = ControlMask;
2464642e01fSmrg                break;
2474642e01fSmrg
2484642e01fSmrg            case XK_Control_R:
2494642e01fSmrg#ifdef NX_MODIFIERKEY_RCONTROL
2504642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i;
2514642e01fSmrg#else
2524642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
2534642e01fSmrg#endif
2544642e01fSmrg                info->modMap[MIN_KEYCODE + i] = ControlMask;
2554642e01fSmrg                break;
2564642e01fSmrg
2574642e01fSmrg            case XK_Caps_Lock:
2584642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
2594642e01fSmrg                info->modMap[MIN_KEYCODE + i] = LockMask;
2604642e01fSmrg                break;
2614642e01fSmrg
2624642e01fSmrg            case XK_Alt_L:
2634642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
2644642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod1Mask;
2656747b715Smrg                if(!XQuartzOptionSendsAlt)
2666747b715Smrg                    *k = XK_Mode_switch; // Yes, this is ugly.  This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
2674642e01fSmrg                break;
2684642e01fSmrg
2694642e01fSmrg            case XK_Alt_R:
2704642e01fSmrg#ifdef NX_MODIFIERKEY_RALTERNATE
2714642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
2724642e01fSmrg#else
2734642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
2744642e01fSmrg#endif
2756747b715Smrg                if(!XQuartzOptionSendsAlt)
2766747b715Smrg                    *k = XK_Mode_switch; // Yes, this is ugly.  This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
2774642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod1Mask;
2784642e01fSmrg                break;
2794642e01fSmrg
2804642e01fSmrg            case XK_Mode_switch:
2816747b715Smrg                ErrorF("DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n");
2826747b715Smrg                info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
2836747b715Smrg#ifdef NX_MODIFIERKEY_RALTERNATE
2846747b715Smrg                info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
2856747b715Smrg#endif
2864642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod1Mask;
2874642e01fSmrg                break;
2884642e01fSmrg
2894642e01fSmrg            case XK_Meta_L:
2904642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
2914642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod2Mask;
2924642e01fSmrg                break;
2934642e01fSmrg
2944642e01fSmrg            case XK_Meta_R:
2954642e01fSmrg#ifdef NX_MODIFIERKEY_RCOMMAND
2964642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i;
2974642e01fSmrg#else
2984642e01fSmrg                info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
2994642e01fSmrg#endif
3004642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod2Mask;
3014642e01fSmrg                break;
3024642e01fSmrg
3034642e01fSmrg            case XK_Num_Lock:
3044642e01fSmrg                info->modMap[MIN_KEYCODE + i] = Mod3Mask;
3054642e01fSmrg                break;
3064642e01fSmrg        }
3074642e01fSmrg    }
3084642e01fSmrg}
3094642e01fSmrg
3104642e01fSmrg/*
3114642e01fSmrg * DarwinKeyboardInit
3124642e01fSmrg *      Get the Darwin keyboard map and compute an equivalent
3134642e01fSmrg *      X keyboard map and modifier map. Set the new keyboard
3144642e01fSmrg *      device structure.
3154642e01fSmrg */
3164642e01fSmrgvoid DarwinKeyboardInit(DeviceIntPtr pDev) {
3174642e01fSmrg    // Open a shared connection to the HID System.
3184642e01fSmrg    // Note that the Event Status Driver is really just a wrapper
3194642e01fSmrg    // for a kIOHIDParamConnectType connection.
3204642e01fSmrg    assert(darwinParamConnect = NXOpenEventStatus());
3214642e01fSmrg
3226747b715Smrg    InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl);
3234642e01fSmrg
3246747b715Smrg    DarwinKeyboardReloadHandler();
3254642e01fSmrg
3266747b715Smrg    CopyKeyClass(pDev, inputInfo.keyboard);
3276747b715Smrg}
3284642e01fSmrg
3296747b715Smrg/* Set the repeat rates based on global preferences and keycodes for modifiers.
3306747b715Smrg * Precondition: Has the keyInfo_mutex lock.
3316747b715Smrg */
3326747b715Smrgstatic void DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, int keyRepeatValue) {
3336747b715Smrg    if(initialKeyRepeatValue == 300000) { // off
3346747b715Smrg        /* Turn off repeats globally */
3354642e01fSmrg        XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff);
3364642e01fSmrg    } else {
3376747b715Smrg        int i;
3386747b715Smrg        XkbControlsPtr      ctrl;
3396747b715Smrg        XkbControlsRec      old;
3404642e01fSmrg
3416747b715Smrg        /* Turn on repeats globally */
3424642e01fSmrg        XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
3436747b715Smrg
3446747b715Smrg        /* Setup the bit mask for individual key repeats */
3456747b715Smrg        ctrl = pDev->key->xkbInfo->desc->ctrls;
3466747b715Smrg        old= *ctrl;
3476747b715Smrg
3486747b715Smrg        ctrl->repeat_delay = initialKeyRepeatValue * 15;
3496747b715Smrg        ctrl->repeat_interval = keyRepeatValue * 15;
3506747b715Smrg
3516747b715Smrg        /* Turn off key-repeat for modifier keys, on for others */
3526747b715Smrg        /* First set them all on */
3536747b715Smrg        for(i=0; i < XkbPerKeyBitArraySize; i++)
3546747b715Smrg            ctrl->per_key_repeat[i] = -1;
3556747b715Smrg
3566747b715Smrg        /* Now turn off the modifiers */
3576747b715Smrg        for(i=0; i < 32; i++) {
3586747b715Smrg            unsigned char keycode;
3596747b715Smrg
3606747b715Smrg            keycode = keyInfo.modifierKeycodes[i][0];
3616747b715Smrg            if(keycode)
3626747b715Smrg                ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
3636747b715Smrg
3646747b715Smrg            keycode = keyInfo.modifierKeycodes[i][1];
3656747b715Smrg            if(keycode)
3666747b715Smrg                ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
3676747b715Smrg        }
3686747b715Smrg
3696747b715Smrg        /* Hurray for data duplication */
3706747b715Smrg        if (pDev->kbdfeed)
3716747b715Smrg            memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, XkbPerKeyBitArraySize);
3724642e01fSmrg
3736747b715Smrg        //fprintf(stderr, "per_key_repeat =\n");
3746747b715Smrg        //for(i=0; i < XkbPerKeyBitArraySize; i++)
3756747b715Smrg        //    fprintf(stderr, "%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n");
3766747b715Smrg
3776747b715Smrg        /* And now we notify the puppies about the changes */
3786747b715Smrg        XkbDDXChangeControls(pDev, &old, ctrl);
3796747b715Smrg    }
3804642e01fSmrg}
3814642e01fSmrg
3826747b715Smrgvoid DarwinKeyboardReloadHandler(void) {
3834642e01fSmrg    KeySymsRec keySyms;
3846747b715Smrg    CFIndex initialKeyRepeatValue, keyRepeatValue;
3856747b715Smrg    BOOL ok;
3866747b715Smrg    DeviceIntPtr pDev;
3876747b715Smrg    const char *xmodmap = PROJECTROOT "/bin/xmodmap";
3886747b715Smrg    const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap";
3896747b715Smrg    const char *homedir = getenv("HOME");
3906747b715Smrg    char usermodmap[PATH_MAX], cmd[PATH_MAX];
3914642e01fSmrg
3924642e01fSmrg    DEBUG_LOG("DarwinKeyboardReloadHandler\n");
3934642e01fSmrg
3946747b715Smrg    /* Get our key repeat settings from GlobalPreferences */
3956747b715Smrg    (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
3966747b715Smrg
3976747b715Smrg    initialKeyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
3986747b715Smrg    if(!ok)
3996747b715Smrg        initialKeyRepeatValue = 35;
4006747b715Smrg
4016747b715Smrg    keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
4026747b715Smrg    if(!ok)
4036747b715Smrg        keyRepeatValue = 6;
4046747b715Smrg
4056747b715Smrg    pthread_mutex_lock(&keyInfo_mutex); {
4066747b715Smrg        /* Initialize our keySyms */
4076747b715Smrg        keySyms.map = keyInfo.keyMap;
4086747b715Smrg        keySyms.mapWidth   = GLYPHS_PER_KEY;
4096747b715Smrg        keySyms.minKeyCode = MIN_KEYCODE;
4106747b715Smrg        keySyms.maxKeyCode = MAX_KEYCODE;
4116747b715Smrg
4126747b715Smrg	// TODO: We should build the entire XkbDescRec and use XkbCopyKeymap
4136747b715Smrg        /* Apply the mappings to darwinKeyboard */
4146747b715Smrg        XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode,
4156747b715Smrg                              keySyms.maxKeyCode - keySyms.minKeyCode + 1,
4166747b715Smrg                              keyInfo.modMap, serverClient);
4176747b715Smrg        DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, keyRepeatValue);
4186747b715Smrg
4196747b715Smrg        /* Apply the mappings to the core keyboard */
4206747b715Smrg        for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
4216747b715Smrg            if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
4226747b715Smrg                XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode,
4236747b715Smrg                                      keySyms.maxKeyCode - keySyms.minKeyCode + 1,
4246747b715Smrg                                      keyInfo.modMap, serverClient);
4256747b715Smrg                DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, keyRepeatValue);
4266747b715Smrg            }
4276747b715Smrg        }
4286747b715Smrg    } pthread_mutex_unlock(&keyInfo_mutex);
4296747b715Smrg
4306747b715Smrg    /* Modify with xmodmap */
4316747b715Smrg    if (access(xmodmap, F_OK) == 0) {
4326747b715Smrg        /* Check for system .Xmodmap */
4336747b715Smrg        if (access(sysmodmap, F_OK) == 0) {
4346747b715Smrg            if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap) < sizeof(cmd)) {
4356747b715Smrg                X11ApplicationLaunchClient(cmd);
4366747b715Smrg            } else {
4376747b715Smrg                ErrorF("X11.app: Unable to create / execute xmodmap command line");
4386747b715Smrg            }
4396747b715Smrg        }
4406747b715Smrg
4416747b715Smrg        /* Check for user's local .Xmodmap */
4426747b715Smrg        if ((homedir != NULL) && (snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir) < sizeof(usermodmap))) {
4436747b715Smrg            if (access(usermodmap, F_OK) == 0) {
4446747b715Smrg                if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap) < sizeof(cmd)) {
4456747b715Smrg                    X11ApplicationLaunchClient(cmd);
4466747b715Smrg                } else {
4476747b715Smrg                    ErrorF("X11.app: Unable to create / execute xmodmap command line");
4486747b715Smrg                }
4496747b715Smrg            }
4506747b715Smrg        } else {
4516747b715Smrg            ErrorF("X11.app: Unable to determine path to user's .Xmodmap");
4526747b715Smrg        }
4536747b715Smrg    }
4544642e01fSmrg}
4554642e01fSmrg
4564642e01fSmrg//-----------------------------------------------------------------------------
4574642e01fSmrg// Modifier translation functions
4584642e01fSmrg//
4594642e01fSmrg// There are three different ways to specify a Mac modifier key:
4604642e01fSmrg// keycode - specifies hardware key, read from keymapping
4614642e01fSmrg// key     - NX_MODIFIERKEY_*, really an index
4624642e01fSmrg// mask    - NX_*MASK, mask for modifier flags in event record
4634642e01fSmrg// Left and right side have different keycodes but the same key and mask.
4644642e01fSmrg//-----------------------------------------------------------------------------
4654642e01fSmrg
4664642e01fSmrg/*
4674642e01fSmrg * DarwinModifierNXKeyToNXKeycode
4684642e01fSmrg *      Return the keycode for an NX_MODIFIERKEY_* modifier.
4694642e01fSmrg *      side = 0 for left or 1 for right.
4704642e01fSmrg *      Returns 0 if key+side is not a known modifier.
4714642e01fSmrg */
4724642e01fSmrgint DarwinModifierNXKeyToNXKeycode(int key, int side) {
4734642e01fSmrg    int retval;
4744642e01fSmrg    pthread_mutex_lock(&keyInfo_mutex);
4754642e01fSmrg    retval = keyInfo.modifierKeycodes[key][side];
4764642e01fSmrg    pthread_mutex_unlock(&keyInfo_mutex);
4774642e01fSmrg
4784642e01fSmrg    return retval;
4794642e01fSmrg}
4804642e01fSmrg
4814642e01fSmrg/*
4824642e01fSmrg * DarwinModifierNXKeycodeToNXKey
4834642e01fSmrg *      Returns -1 if keycode+side is not a modifier key
4844642e01fSmrg *      outSide may be NULL, else it gets 0 for left and 1 for right.
4854642e01fSmrg */
4864642e01fSmrgint DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) {
4874642e01fSmrg    int key, side;
4884642e01fSmrg
4894642e01fSmrg    keycode += MIN_KEYCODE;
4906747b715Smrg
4914642e01fSmrg    // search modifierKeycodes for this keycode+side
4926747b715Smrg    pthread_mutex_lock(&keyInfo_mutex);
4934642e01fSmrg    for (key = 0; key < NX_NUMMODIFIERS; key++) {
4944642e01fSmrg        for (side = 0; side <= 1; side++) {
4954642e01fSmrg            if (keyInfo.modifierKeycodes[key][side] == keycode) break;
4964642e01fSmrg        }
4974642e01fSmrg    }
4986747b715Smrg    pthread_mutex_unlock(&keyInfo_mutex);
4996747b715Smrg
5004642e01fSmrg    if (key == NX_NUMMODIFIERS) {
5014642e01fSmrg        return -1;
5024642e01fSmrg    }
5034642e01fSmrg    if (outSide) *outSide = side;
5044642e01fSmrg
5054642e01fSmrg    return key;
5064642e01fSmrg}
5074642e01fSmrg
5084642e01fSmrg/*
5094642e01fSmrg * DarwinModifierNXMaskToNXKey
5104642e01fSmrg *      Returns -1 if mask is not a known modifier mask.
5114642e01fSmrg */
5124642e01fSmrgint DarwinModifierNXMaskToNXKey(int mask) {
5134642e01fSmrg    switch (mask) {
5144642e01fSmrg        case NX_ALPHASHIFTMASK:       return NX_MODIFIERKEY_ALPHALOCK;
5154642e01fSmrg        case NX_SHIFTMASK:            return NX_MODIFIERKEY_SHIFT;
5164642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
5174642e01fSmrg        case NX_DEVICELSHIFTKEYMASK:  return NX_MODIFIERKEY_SHIFT;
5184642e01fSmrg        case NX_DEVICERSHIFTKEYMASK:  return NX_MODIFIERKEY_RSHIFT;
5194642e01fSmrg#endif
5204642e01fSmrg        case NX_CONTROLMASK:          return NX_MODIFIERKEY_CONTROL;
5214642e01fSmrg#ifdef NX_DEVICELCTLKEYMASK
5224642e01fSmrg        case NX_DEVICELCTLKEYMASK:    return NX_MODIFIERKEY_CONTROL;
5234642e01fSmrg        case NX_DEVICERCTLKEYMASK:    return NX_MODIFIERKEY_RCONTROL;
5244642e01fSmrg#endif
5254642e01fSmrg        case NX_ALTERNATEMASK:        return NX_MODIFIERKEY_ALTERNATE;
5264642e01fSmrg#ifdef NX_DEVICELALTKEYMASK
5274642e01fSmrg        case NX_DEVICELALTKEYMASK:    return NX_MODIFIERKEY_ALTERNATE;
5284642e01fSmrg        case NX_DEVICERALTKEYMASK:    return NX_MODIFIERKEY_RALTERNATE;
5294642e01fSmrg#endif
5304642e01fSmrg        case NX_COMMANDMASK:          return NX_MODIFIERKEY_COMMAND;
5314642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
5324642e01fSmrg        case NX_DEVICELCMDKEYMASK:    return NX_MODIFIERKEY_COMMAND;
5334642e01fSmrg        case NX_DEVICERCMDKEYMASK:    return NX_MODIFIERKEY_RCOMMAND;
5344642e01fSmrg#endif
5354642e01fSmrg        case NX_NUMERICPADMASK:       return NX_MODIFIERKEY_NUMERICPAD;
5364642e01fSmrg        case NX_HELPMASK:             return NX_MODIFIERKEY_HELP;
5374642e01fSmrg        case NX_SECONDARYFNMASK:      return NX_MODIFIERKEY_SECONDARYFN;
5384642e01fSmrg    }
5394642e01fSmrg    return -1;
5404642e01fSmrg}
5414642e01fSmrg
5424642e01fSmrg/*
5434642e01fSmrg * DarwinModifierNXKeyToNXMask
5444642e01fSmrg *      Returns 0 if key is not a known modifier key.
5454642e01fSmrg */
5464642e01fSmrgint DarwinModifierNXKeyToNXMask(int key) {
5474642e01fSmrg    switch (key) {
5484642e01fSmrg        case NX_MODIFIERKEY_ALPHALOCK:   return NX_ALPHASHIFTMASK;
5494642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
5504642e01fSmrg        case NX_MODIFIERKEY_SHIFT:       return NX_DEVICELSHIFTKEYMASK;
5514642e01fSmrg        case NX_MODIFIERKEY_RSHIFT:      return NX_DEVICERSHIFTKEYMASK;
5524642e01fSmrg        case NX_MODIFIERKEY_CONTROL:     return NX_DEVICELCTLKEYMASK;
5534642e01fSmrg        case NX_MODIFIERKEY_RCONTROL:    return NX_DEVICERCTLKEYMASK;
5544642e01fSmrg        case NX_MODIFIERKEY_ALTERNATE:   return NX_DEVICELALTKEYMASK;
5554642e01fSmrg        case NX_MODIFIERKEY_RALTERNATE:  return NX_DEVICERALTKEYMASK;
5564642e01fSmrg        case NX_MODIFIERKEY_COMMAND:     return NX_DEVICELCMDKEYMASK;
5574642e01fSmrg        case NX_MODIFIERKEY_RCOMMAND:    return NX_DEVICERCMDKEYMASK;
5584642e01fSmrg#else
5594642e01fSmrg        case NX_MODIFIERKEY_SHIFT:       return NX_SHIFTMASK;
5604642e01fSmrg        case NX_MODIFIERKEY_CONTROL:     return NX_CONTROLMASK;
5614642e01fSmrg        case NX_MODIFIERKEY_ALTERNATE:   return NX_ALTERNATEMASK;
5624642e01fSmrg        case NX_MODIFIERKEY_COMMAND:     return NX_COMMANDMASK;
5634642e01fSmrg#endif
5644642e01fSmrg        case NX_MODIFIERKEY_NUMERICPAD:  return NX_NUMERICPADMASK;
5654642e01fSmrg        case NX_MODIFIERKEY_HELP:        return NX_HELPMASK;
5664642e01fSmrg        case NX_MODIFIERKEY_SECONDARYFN: return NX_SECONDARYFNMASK;
5674642e01fSmrg    }
5684642e01fSmrg    return 0;
5694642e01fSmrg}
5704642e01fSmrg
5714642e01fSmrg/*
5724642e01fSmrg * DarwinModifierStringToNXMask
5734642e01fSmrg *      Returns 0 if string is not a known modifier.
5744642e01fSmrg */
5754642e01fSmrgint DarwinModifierStringToNXMask(const char *str, int separatelr) {
5764642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
5774642e01fSmrg    if(separatelr) {
5784642e01fSmrg        if (!strcasecmp(str, "shift"))    return NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK;
5794642e01fSmrg        if (!strcasecmp(str, "control"))  return NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK;
5804642e01fSmrg        if (!strcasecmp(str, "option"))   return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
5814642e01fSmrg        if (!strcasecmp(str, "alt"))   return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
5824642e01fSmrg        if (!strcasecmp(str, "command"))  return NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK;
5834642e01fSmrg        if (!strcasecmp(str, "lshift"))   return NX_DEVICELSHIFTKEYMASK;
5844642e01fSmrg        if (!strcasecmp(str, "rshift"))   return NX_DEVICERSHIFTKEYMASK;
5854642e01fSmrg        if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK;
5864642e01fSmrg        if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK;
5874642e01fSmrg        if (!strcasecmp(str, "loption"))  return NX_DEVICELALTKEYMASK;
5884642e01fSmrg        if (!strcasecmp(str, "roption"))  return NX_DEVICERALTKEYMASK;
5894642e01fSmrg        if (!strcasecmp(str, "lalt"))  return NX_DEVICELALTKEYMASK;
5904642e01fSmrg        if (!strcasecmp(str, "ralt"))  return NX_DEVICERALTKEYMASK;
5914642e01fSmrg        if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK;
5924642e01fSmrg        if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK;
5934642e01fSmrg    } else {
5944642e01fSmrg#endif
5954642e01fSmrg        if (!strcasecmp(str, "shift"))    return NX_SHIFTMASK;
5964642e01fSmrg        if (!strcasecmp(str, "control"))  return NX_CONTROLMASK;
5974642e01fSmrg        if (!strcasecmp(str, "option"))   return NX_ALTERNATEMASK;
5984642e01fSmrg        if (!strcasecmp(str, "alt"))   return NX_ALTERNATEMASK;
5994642e01fSmrg        if (!strcasecmp(str, "command"))  return NX_COMMANDMASK;
6004642e01fSmrg        if (!strcasecmp(str, "lshift"))   return NX_SHIFTMASK;
6014642e01fSmrg        if (!strcasecmp(str, "rshift"))   return NX_SHIFTMASK;
6024642e01fSmrg        if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK;
6034642e01fSmrg        if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK;
6044642e01fSmrg        if (!strcasecmp(str, "loption"))  return NX_ALTERNATEMASK;
6054642e01fSmrg        if (!strcasecmp(str, "roption"))  return NX_ALTERNATEMASK;
6064642e01fSmrg        if (!strcasecmp(str, "lalt"))  return NX_ALTERNATEMASK;
6074642e01fSmrg        if (!strcasecmp(str, "ralt"))  return NX_ALTERNATEMASK;
6084642e01fSmrg        if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK;
6094642e01fSmrg        if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK;
6104642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
6114642e01fSmrg    }
6124642e01fSmrg#endif
6134642e01fSmrg    if (!strcasecmp(str, "lock"))     return NX_ALPHASHIFTMASK;
6144642e01fSmrg    if (!strcasecmp(str, "fn"))       return NX_SECONDARYFNMASK;
6154642e01fSmrg    if (!strcasecmp(str, "help"))     return NX_HELPMASK;
6164642e01fSmrg    if (!strcasecmp(str, "numlock"))  return NX_NUMERICPADMASK;
6174642e01fSmrg    return 0;
6184642e01fSmrg}
6194642e01fSmrg
6204642e01fSmrg/*
6214642e01fSmrg * LegalModifier
6224642e01fSmrg *      This allows the ddx layer to prevent some keys from being remapped
6234642e01fSmrg *      as modifier keys.
6244642e01fSmrg */
6254642e01fSmrgBool LegalModifier(unsigned int key, DeviceIntPtr pDev)
6264642e01fSmrg{
6274642e01fSmrg    return 1;
6284642e01fSmrg}
6294642e01fSmrg
6304642e01fSmrgstatic inline UniChar macroman2ucs(unsigned char c) {
6314642e01fSmrg    /* Precalculated table mapping MacRoman-128 to Unicode. Generated
6324642e01fSmrg       by creating single element CFStringRefs then extracting the
6334642e01fSmrg       first character. */
6344642e01fSmrg
6354642e01fSmrg    static const unsigned short table[128] = {
6364642e01fSmrg        0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
6374642e01fSmrg        0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
6384642e01fSmrg        0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
6394642e01fSmrg        0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
6404642e01fSmrg        0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
6414642e01fSmrg        0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
6424642e01fSmrg        0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
6434642e01fSmrg        0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
6444642e01fSmrg        0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
6454642e01fSmrg        0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
6464642e01fSmrg        0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
6474642e01fSmrg        0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
6484642e01fSmrg        0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
6494642e01fSmrg        0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
6504642e01fSmrg        0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
6514642e01fSmrg        0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
6524642e01fSmrg    };
6534642e01fSmrg
6544642e01fSmrg    if (c < 128) return c;
6554642e01fSmrg    else         return table[c - 128];
6564642e01fSmrg}
6574642e01fSmrg
6584642e01fSmrgstatic KeySym make_dead_key(KeySym in) {
6594642e01fSmrg    int i;
6604642e01fSmrg
6614642e01fSmrg    for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++)
6624642e01fSmrg        if (dead_keys[i].normal == in) return dead_keys[i].dead;
6634642e01fSmrg
6644642e01fSmrg    return in;
6654642e01fSmrg}
6664642e01fSmrg
6676747b715Smrgstatic Bool QuartzReadSystemKeymap(darwinKeyboardInfo *info) {
6684642e01fSmrg#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
6694642e01fSmrg    KeyboardLayoutRef key_layout;
6704642e01fSmrg    int is_uchr = 1;
6714642e01fSmrg#endif
6724642e01fSmrg    const void *chr_data = NULL;
6734642e01fSmrg    int num_keycodes = NUM_KEYCODES;
6744642e01fSmrg    UInt32 keyboard_type = LMGetKbdType();
6754642e01fSmrg    int i, j;
6764642e01fSmrg    OSStatus err;
6774642e01fSmrg    KeySym *k;
6784642e01fSmrg    CFDataRef currentKeyLayoutDataRef = NULL;
6794642e01fSmrg
6804642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
6814642e01fSmrg    TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource();
6824642e01fSmrg
6834642e01fSmrg    if (currentKeyLayoutRef) {
6844642e01fSmrg      currentKeyLayoutDataRef = (CFDataRef )TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData);
6854642e01fSmrg      if (currentKeyLayoutDataRef)
6864642e01fSmrg          chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
6874642e01fSmrg    }
6884642e01fSmrg#endif
6894642e01fSmrg
6904642e01fSmrg#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
6914642e01fSmrg    if (chr_data == NULL) {
6924642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
6934642e01fSmrg        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");
6944642e01fSmrg        ErrorF("X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n",
6954642e01fSmrg               (unsigned)keyboard_type, currentKeyLayoutRef, currentKeyLayoutDataRef, chr_data);
6964642e01fSmrg#endif
6974642e01fSmrg
6984642e01fSmrg        KLGetCurrentKeyboardLayout (&key_layout);
6994642e01fSmrg        KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data);
7004642e01fSmrg
7014642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
7024642e01fSmrg        if(chr_data != NULL) {
7034642e01fSmrg            ErrorF("X11.app: Fallback succeeded, but this is still a bug.  Please report the above information.\n");
7044642e01fSmrg        }
7054642e01fSmrg#endif
7064642e01fSmrg    }
7074642e01fSmrg
7084642e01fSmrg    if (chr_data == NULL) {
7094642e01fSmrg        ErrorF("X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
7104642e01fSmrg        ErrorF("If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n");
7114642e01fSmrg        KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data);
7124642e01fSmrg        is_uchr = 0;
7134642e01fSmrg        num_keycodes = 128;
7144642e01fSmrg
7154642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
7164642e01fSmrg        if(chr_data != NULL) {
7174642e01fSmrg            ErrorF("X11.app: Fallback succeeded, but this is still a bug.  Please report the above information.\n");
7184642e01fSmrg        }
7194642e01fSmrg#endif
7204642e01fSmrg    }
7214642e01fSmrg#endif
7224642e01fSmrg
7234642e01fSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
7244642e01fSmrg    if(currentKeyLayoutRef)
7254642e01fSmrg        CFRelease(currentKeyLayoutRef);
7264642e01fSmrg#endif
7274642e01fSmrg
7284642e01fSmrg    if (chr_data == NULL) {
7294642e01fSmrg      ErrorF ( "Couldn't get uchr or kchr resource\n");
7304642e01fSmrg      return FALSE;
7314642e01fSmrg    }
7324642e01fSmrg
7334642e01fSmrg    /* Scan the keycode range for the Unicode character that each
7344642e01fSmrg       key produces in the four shift states. Then convert that to
7354642e01fSmrg       an X11 keysym (which may just the bit that says "this is
7364642e01fSmrg       Unicode" if it can't find the real symbol.) */
7374642e01fSmrg
7384642e01fSmrg    /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
7394642e01fSmrg       must be used instead. */
7404642e01fSmrg
7414642e01fSmrg    for (i = 0; i < num_keycodes; i++) {
7424642e01fSmrg        static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION,
7434642e01fSmrg                                    MOD_OPTION | MOD_SHIFT};
7444642e01fSmrg
7454642e01fSmrg        k = info->keyMap + i * GLYPHS_PER_KEY;
7464642e01fSmrg
7474642e01fSmrg        for (j = 0; j < 4; j++) {
7484642e01fSmrg#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
7494642e01fSmrg            if (is_uchr)  {
7504642e01fSmrg#endif
7514642e01fSmrg                UniChar s[8];
7524642e01fSmrg                UniCharCount len;
7534642e01fSmrg                UInt32 dead_key_state = 0, extra_dead = 0;
7544642e01fSmrg
7554642e01fSmrg                err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
7564642e01fSmrg                                      mods[j] >> 8, keyboard_type, 0,
7574642e01fSmrg                                      &dead_key_state, 8, &len, s);
7584642e01fSmrg                if (err != noErr) continue;
7594642e01fSmrg
7604642e01fSmrg                if (len == 0 && dead_key_state != 0) {
7614642e01fSmrg                    /* Found a dead key. Work out which one it is, but
7624642e01fSmrg                       remembering that it's dead. */
7634642e01fSmrg                    err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
7644642e01fSmrg                                          mods[j] >> 8, keyboard_type,
7654642e01fSmrg                                          kUCKeyTranslateNoDeadKeysMask,
7664642e01fSmrg                                          &extra_dead, 8, &len, s);
7674642e01fSmrg                    if (err != noErr) continue;
7684642e01fSmrg                }
7694642e01fSmrg
7706747b715Smrg                /* Not sure why 0x0010 is there.
7716747b715Smrg                 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
7726747b715Smrg                 */
7736747b715Smrg                if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
7744642e01fSmrg                    k[j] = ucs2keysym (s[0]);
7754642e01fSmrg                    if (dead_key_state != 0) k[j] = make_dead_key (k[j]);
7764642e01fSmrg                }
7774642e01fSmrg#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
7784642e01fSmrg            } else { // kchr
7794642e01fSmrg	      UInt32 c, state = 0, state2 = 0;
7804642e01fSmrg                UInt16 code;
7814642e01fSmrg
7824642e01fSmrg                code = i | mods[j];
7834642e01fSmrg                c = KeyTranslate (chr_data, code, &state);
7844642e01fSmrg
7854642e01fSmrg                /* Dead keys are only processed on key-down, so ask
7864642e01fSmrg                   to translate those events. When we find a dead key,
7874642e01fSmrg                   translating the matching key up event will give
7884642e01fSmrg                   us the actual dead character. */
7894642e01fSmrg
7904642e01fSmrg                if (state != 0)
7914642e01fSmrg                    c = KeyTranslate (chr_data, code | 128, &state2);
7924642e01fSmrg
7934642e01fSmrg                /* Characters seem to be in MacRoman encoding. */
7944642e01fSmrg
7954642e01fSmrg                if (c != 0 && c != 0x0010) {
7964642e01fSmrg                    k[j] = ucs2keysym (macroman2ucs (c & 255));
7974642e01fSmrg
7984642e01fSmrg                    if (state != 0) k[j] = make_dead_key (k[j]);
7994642e01fSmrg                }
8004642e01fSmrg            }
8014642e01fSmrg#endif
8024642e01fSmrg        }
8036747b715Smrg
8044642e01fSmrg        if (k[3] == k[2]) k[3] = NoSymbol;
8054642e01fSmrg        if (k[1] == k[0]) k[1] = NoSymbol;
8064642e01fSmrg        if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
8076747b715Smrg        if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
8084642e01fSmrg    }
8094642e01fSmrg
8106747b715Smrg#if HACK_MISSING
8114642e01fSmrg    /* Fix up some things that are normally missing.. */
8126747b715Smrg
8136747b715Smrg    for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) {
8146747b715Smrg        k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
8156747b715Smrg
8166747b715Smrg        if (   k[0] == NoSymbol && k[1] == NoSymbol
8176747b715Smrg            && k[2] == NoSymbol && k[3] == NoSymbol)
8186747b715Smrg            k[0] = known_keys[i].keysym;
8194642e01fSmrg    }
8206747b715Smrg#endif
8216747b715Smrg
8226747b715Smrg#if HACK_KEYPAD
8234642e01fSmrg    /* And some more things. We find the right symbols for the numeric
8246747b715Smrg     keypad, but not the KP_ keysyms. So try to convert known keycodes. */
8256747b715Smrg    for (i = 0; i < sizeof (known_numeric_keys) / sizeof (known_numeric_keys[0]); i++) {
8266747b715Smrg        k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
8276747b715Smrg
8286747b715Smrg        if (k[0] == known_numeric_keys[i].normal)
8296747b715Smrg            k[0] = known_numeric_keys[i].keypad;
8304642e01fSmrg    }
8316747b715Smrg#endif
8326747b715Smrg
8336747b715Smrg#if HACK_BLACKLIST
8346747b715Smrg    for (i = 0; i < sizeof (keycode_blacklist) / sizeof (keycode_blacklist[0]); i++) {
8356747b715Smrg        k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY;
8366747b715Smrg        k[0] = k[1] = k[2] = k[3] = NoSymbol;
8376747b715Smrg    }
8386747b715Smrg#endif
8396747b715Smrg
8406747b715Smrg    DarwinBuildModifierMaps(info);
8414642e01fSmrg
8424642e01fSmrg    return TRUE;
8434642e01fSmrg}
8446747b715Smrg
8456747b715SmrgBool QuartsResyncKeymap(Bool sendDDXEvent) {
8466747b715Smrg    Bool retval;
8476747b715Smrg    /* Update keyInfo */
8486747b715Smrg    pthread_mutex_lock(&keyInfo_mutex);
8496747b715Smrg    memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap));
8506747b715Smrg    retval = QuartzReadSystemKeymap(&keyInfo);
8516747b715Smrg    pthread_mutex_unlock(&keyInfo_mutex);
8526747b715Smrg
8536747b715Smrg    /* Tell server thread to deal with new keyInfo */
8546747b715Smrg    if(sendDDXEvent)
8556747b715Smrg        DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
8566747b715Smrg
8576747b715Smrg    return retval;
8586747b715Smrg}
859