14642e01fSmrg/*
24642e01fSmrg   quartzKeyboard.c: Keyboard support for Xquartz
34642e01fSmrg
435c4bbdfSmrg   Copyright (c) 2003-2012 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.
3235c4bbdfSmrg */
334642e01fSmrg
344642e01fSmrg#include "sanitizedCarbon.h"
354642e01fSmrg
364642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
374642e01fSmrg#include <dix-config.h>
384642e01fSmrg#endif
394642e01fSmrg
4035c4bbdfSmrg#define HACK_MISSING   1
4135c4bbdfSmrg#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
506747b715Smrg#include "quartz.h"
514642e01fSmrg#include "darwin.h"
526747b715Smrg#include "darwinEvents.h"
534642e01fSmrg
544642e01fSmrg#include "quartzKeyboard.h"
554642e01fSmrg
566747b715Smrg#include "X11Application.h"
576747b715Smrg
584642e01fSmrg#include <assert.h>
594642e01fSmrg#include <pthread.h>
604642e01fSmrg
614642e01fSmrg#include "xkbsrv.h"
624642e01fSmrg#include "exevents.h"
634642e01fSmrg#include "X11/keysym.h"
644642e01fSmrg#include "keysym2ucs.h"
654642e01fSmrg
666747b715Smrgextern void
676747b715SmrgCopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
686747b715Smrg
694642e01fSmrgenum {
704642e01fSmrg    MOD_COMMAND = 256,
714642e01fSmrg    MOD_SHIFT = 512,
724642e01fSmrg    MOD_OPTION = 2048,
734642e01fSmrg    MOD_CONTROL = 4096,
744642e01fSmrg};
754642e01fSmrg
764642e01fSmrg#define UKEYSYM(u) ((u) | 0x01000000)
774642e01fSmrg
786747b715Smrg#if HACK_MISSING
794642e01fSmrg/* Table of keycode->keysym mappings we use to fallback on for important
804642e01fSmrg   keys that are often not in the Unicode mapping. */
814642e01fSmrg
824642e01fSmrgconst static struct {
834642e01fSmrg    unsigned short keycode;
844642e01fSmrg    KeySym keysym;
854642e01fSmrg} known_keys[] = {
8635c4bbdfSmrg    { 55,  XK_Meta_L        },
8735c4bbdfSmrg    { 56,  XK_Shift_L       },
8835c4bbdfSmrg    { 57,  XK_Caps_Lock     },
8935c4bbdfSmrg    { 58,  XK_Alt_L         },
9035c4bbdfSmrg    { 59,  XK_Control_L     },
9135c4bbdfSmrg
9235c4bbdfSmrg    { 60,  XK_Shift_R       },
9335c4bbdfSmrg    { 61,  XK_Alt_R         },
9435c4bbdfSmrg    { 62,  XK_Control_R     },
9535c4bbdfSmrg    { 63,  XK_Meta_R        },
9635c4bbdfSmrg
97c8548ba8Smrg    { 110, XK_Menu          },
98c8548ba8Smrg
9935c4bbdfSmrg    { 122, XK_F1            },
10035c4bbdfSmrg    { 120, XK_F2            },
10135c4bbdfSmrg    { 99,  XK_F3            },
10235c4bbdfSmrg    { 118, XK_F4            },
10335c4bbdfSmrg    { 96,  XK_F5            },
10435c4bbdfSmrg    { 97,  XK_F6            },
10535c4bbdfSmrg    { 98,  XK_F7            },
10635c4bbdfSmrg    { 100, XK_F8            },
10735c4bbdfSmrg    { 101, XK_F9            },
10835c4bbdfSmrg    { 109, XK_F10           },
10935c4bbdfSmrg    { 103, XK_F11           },
11035c4bbdfSmrg    { 111, XK_F12           },
11135c4bbdfSmrg    { 105, XK_F13           },
11235c4bbdfSmrg    { 107, XK_F14           },
11335c4bbdfSmrg    { 113, XK_F15           },
114c8548ba8Smrg    { 106, XK_F16           },
115c8548ba8Smrg    { 64,  XK_F17           },
116c8548ba8Smrg    { 79,  XK_F18           },
117c8548ba8Smrg    { 80,  XK_F19           },
118c8548ba8Smrg    { 90,  XK_F20           },
1194642e01fSmrg};
1206747b715Smrg#endif
1214642e01fSmrg
1226747b715Smrg#if HACK_KEYPAD
1234642e01fSmrg/* Table of keycode->old,new-keysym mappings we use to fixup the numeric
1244642e01fSmrg   keypad entries. */
1254642e01fSmrg
1264642e01fSmrgconst static struct {
1274642e01fSmrg    unsigned short keycode;
1284642e01fSmrg    KeySym normal, keypad;
1294642e01fSmrg} known_numeric_keys[] = {
13035c4bbdfSmrg    { 65, XK_period,   XK_KP_Decimal                              },
13135c4bbdfSmrg    { 67, XK_asterisk, XK_KP_Multiply                             },
13235c4bbdfSmrg    { 69, XK_plus,     XK_KP_Add                                  },
13335c4bbdfSmrg    { 75, XK_slash,    XK_KP_Divide                               },
13435c4bbdfSmrg    { 76, 0x01000003,  XK_KP_Enter                                },
13535c4bbdfSmrg    { 78, XK_minus,    XK_KP_Subtract                             },
13635c4bbdfSmrg    { 81, XK_equal,    XK_KP_Equal                                },
13735c4bbdfSmrg    { 82, XK_0,        XK_KP_0                                    },
13835c4bbdfSmrg    { 83, XK_1,        XK_KP_1                                    },
13935c4bbdfSmrg    { 84, XK_2,        XK_KP_2                                    },
14035c4bbdfSmrg    { 85, XK_3,        XK_KP_3                                    },
14135c4bbdfSmrg    { 86, XK_4,        XK_KP_4                                    },
14235c4bbdfSmrg    { 87, XK_5,        XK_KP_5                                    },
14335c4bbdfSmrg    { 88, XK_6,        XK_KP_6                                    },
14435c4bbdfSmrg    { 89, XK_7,        XK_KP_7                                    },
14535c4bbdfSmrg    { 91, XK_8,        XK_KP_8                                    },
14635c4bbdfSmrg    { 92, XK_9,        XK_KP_9                                    },
1474642e01fSmrg};
1486747b715Smrg#endif
1496747b715Smrg
1506747b715Smrg#if HACK_BLACKLIST
1516747b715Smrg/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow
1526747b715Smrg * http://xquartz.macosforge.org/trac/ticket/295
1536747b715Smrg * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html
1546747b715Smrg *
1556747b715Smrg * legacy Mac keycodes for arrow keys that shift-modify to math symbols
1566747b715Smrg */
15735c4bbdfSmrgconst static unsigned short keycode_blacklist[] = { 66, 70, 72, 77 };
1586747b715Smrg#endif
1594642e01fSmrg
1604642e01fSmrg/* Table mapping normal keysyms to their dead equivalents.
1614642e01fSmrg   FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
1624642e01fSmrg
1634642e01fSmrgconst static struct {
1644642e01fSmrg    KeySym normal, dead;
1654642e01fSmrg} dead_keys[] = {
16635c4bbdfSmrg    { XK_grave,       XK_dead_grave                                },
16735c4bbdfSmrg    { XK_apostrophe,  XK_dead_acute                                }, /* US:"=" on a Czech keyboard */
16835c4bbdfSmrg    { XK_acute,       XK_dead_acute                                },
16935c4bbdfSmrg    { UKEYSYM(0x384), XK_dead_acute                                }, /* US:";" on a Greek keyboard */
17035c4bbdfSmrg    //    {XK_Greek_accentdieresis, XK_dead_diaeresis},   /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */
17135c4bbdfSmrg    { XK_asciicircum, XK_dead_circumflex                           },
17235c4bbdfSmrg    { UKEYSYM(0x2c6), XK_dead_circumflex                           }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
17335c4bbdfSmrg    { XK_asciitilde,  XK_dead_tilde                                },
17435c4bbdfSmrg    { UKEYSYM(0x2dc), XK_dead_tilde                                }, /* SMALL TILDE */
17535c4bbdfSmrg    { XK_macron,      XK_dead_macron                               },
17635c4bbdfSmrg    { XK_breve,       XK_dead_breve                                },
17735c4bbdfSmrg    { XK_abovedot,    XK_dead_abovedot                             },
17835c4bbdfSmrg    { XK_diaeresis,   XK_dead_diaeresis                            },
17935c4bbdfSmrg    { UKEYSYM(0x2da), XK_dead_abovering                            }, /* DOT ABOVE */
18035c4bbdfSmrg    { XK_doubleacute, XK_dead_doubleacute                          },
18135c4bbdfSmrg    { XK_caron,       XK_dead_caron                                },
18235c4bbdfSmrg    { XK_cedilla,     XK_dead_cedilla                              },
18335c4bbdfSmrg    { XK_ogonek,      XK_dead_ogonek                               },
18435c4bbdfSmrg    { UKEYSYM(0x269), XK_dead_iota                                 }, /* LATIN SMALL LETTER IOTA */
18535c4bbdfSmrg    { UKEYSYM(0x2ec), XK_dead_voiced_sound                         }, /* MODIFIER LETTER VOICING */
18635c4bbdfSmrg    /*  {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
18735c4bbdfSmrg    { UKEYSYM(0x323), XK_dead_belowdot                             }, /* COMBINING DOT BELOW */
18835c4bbdfSmrg    { UKEYSYM(0x309), XK_dead_hook                                 }, /* COMBINING HOOK ABOVE */
18935c4bbdfSmrg    { UKEYSYM(0x31b), XK_dead_horn                                 }, /* COMBINING HORN */
1904642e01fSmrg};
1914642e01fSmrg
1926747b715Smrgtypedef struct darwinKeyboardInfo_struct {
1936747b715Smrg    CARD8 modMap[MAP_LENGTH];
1946747b715Smrg    KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY];
1956747b715Smrg    unsigned char modifierKeycodes[32][2];
1966747b715Smrg} darwinKeyboardInfo;
1976747b715Smrg
1984642e01fSmrgdarwinKeyboardInfo keyInfo;
1994642e01fSmrgpthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
2004642e01fSmrg
20135c4bbdfSmrgstatic void
20235c4bbdfSmrgDarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl)
20335c4bbdfSmrg{
2044642e01fSmrg    // FIXME: to be implemented
2054642e01fSmrg    // keyclick, bell volume / pitch, autorepead, LED's
2064642e01fSmrg}
2074642e01fSmrg
2084642e01fSmrg//-----------------------------------------------------------------------------
2094642e01fSmrg// Utility functions to help parse Darwin keymap
2104642e01fSmrg//-----------------------------------------------------------------------------
2114642e01fSmrg
2124642e01fSmrg/*
2134642e01fSmrg * DarwinBuildModifierMaps
2144642e01fSmrg *      Use the keyMap field of keyboard info structure to populate
2154642e01fSmrg *      the modMap and modifierKeycodes fields.
2164642e01fSmrg */
21735c4bbdfSmrgstatic void
21835c4bbdfSmrgDarwinBuildModifierMaps(darwinKeyboardInfo *info)
21935c4bbdfSmrg{
2204642e01fSmrg    int i;
2214642e01fSmrg    KeySym *k;
2224642e01fSmrg
2234642e01fSmrg    memset(info->modMap, NoSymbol, sizeof(info->modMap));
2244642e01fSmrg    memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes));
2254642e01fSmrg
2264642e01fSmrg    for (i = 0; i < NUM_KEYCODES; i++) {
2274642e01fSmrg        k = info->keyMap + i * GLYPHS_PER_KEY;
2284642e01fSmrg
2294642e01fSmrg        switch (*k) {
23035c4bbdfSmrg        case XK_Shift_L:
23135c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
23235c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = ShiftMask;
23335c4bbdfSmrg            break;
2344642e01fSmrg
23535c4bbdfSmrg        case XK_Shift_R:
2364642e01fSmrg#ifdef NX_MODIFIERKEY_RSHIFT
23735c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i;
2384642e01fSmrg#else
23935c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
2404642e01fSmrg#endif
24135c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = ShiftMask;
24235c4bbdfSmrg            break;
2434642e01fSmrg
24435c4bbdfSmrg        case XK_Control_L:
24535c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
24635c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = ControlMask;
24735c4bbdfSmrg            break;
2484642e01fSmrg
24935c4bbdfSmrg        case XK_Control_R:
2504642e01fSmrg#ifdef NX_MODIFIERKEY_RCONTROL
25135c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i;
2524642e01fSmrg#else
25335c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
2544642e01fSmrg#endif
25535c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = ControlMask;
25635c4bbdfSmrg            break;
25735c4bbdfSmrg
25835c4bbdfSmrg        case XK_Caps_Lock:
25935c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
26035c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = LockMask;
26135c4bbdfSmrg            break;
26235c4bbdfSmrg
26335c4bbdfSmrg        case XK_Alt_L:
26435c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
26535c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod1Mask;
26635c4bbdfSmrg            if (!XQuartzOptionSendsAlt)
26735c4bbdfSmrg                *k = XK_Mode_switch;     // Yes, this is ugly.  This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
26835c4bbdfSmrg            break;
26935c4bbdfSmrg
27035c4bbdfSmrg        case XK_Alt_R:
2714642e01fSmrg#ifdef NX_MODIFIERKEY_RALTERNATE
27235c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
2734642e01fSmrg#else
27435c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
2754642e01fSmrg#endif
27635c4bbdfSmrg            if (!XQuartzOptionSendsAlt)
27735c4bbdfSmrg                *k = XK_Mode_switch;     // Yes, this is ugly.  This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
27835c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod1Mask;
27935c4bbdfSmrg            break;
28035c4bbdfSmrg
28135c4bbdfSmrg        case XK_Mode_switch:
28235c4bbdfSmrg            ErrorF(
28335c4bbdfSmrg                "DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n");
28435c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
2856747b715Smrg#ifdef NX_MODIFIERKEY_RALTERNATE
28635c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
2876747b715Smrg#endif
28835c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod1Mask;
28935c4bbdfSmrg            break;
2904642e01fSmrg
29135c4bbdfSmrg        case XK_Meta_L:
29235c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
29335c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod2Mask;
29435c4bbdfSmrg            break;
2954642e01fSmrg
29635c4bbdfSmrg        case XK_Meta_R:
2974642e01fSmrg#ifdef NX_MODIFIERKEY_RCOMMAND
29835c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i;
2994642e01fSmrg#else
30035c4bbdfSmrg            info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
3014642e01fSmrg#endif
30235c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod2Mask;
30335c4bbdfSmrg            break;
3044642e01fSmrg
30535c4bbdfSmrg        case XK_Num_Lock:
30635c4bbdfSmrg            info->modMap[MIN_KEYCODE + i] = Mod3Mask;
30735c4bbdfSmrg            break;
3084642e01fSmrg        }
3094642e01fSmrg    }
3104642e01fSmrg}
3114642e01fSmrg
3124642e01fSmrg/*
3134642e01fSmrg * DarwinKeyboardInit
3144642e01fSmrg *      Get the Darwin keyboard map and compute an equivalent
3154642e01fSmrg *      X keyboard map and modifier map. Set the new keyboard
3164642e01fSmrg *      device structure.
3174642e01fSmrg */
31835c4bbdfSmrgvoid
31935c4bbdfSmrgDarwinKeyboardInit(DeviceIntPtr pDev)
32035c4bbdfSmrg{
3214642e01fSmrg    // Open a shared connection to the HID System.
3224642e01fSmrg    // Note that the Event Status Driver is really just a wrapper
3234642e01fSmrg    // for a kIOHIDParamConnectType connection.
3244642e01fSmrg    assert(darwinParamConnect = NXOpenEventStatus());
3254642e01fSmrg
3266747b715Smrg    InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl);
3274642e01fSmrg
3286747b715Smrg    DarwinKeyboardReloadHandler();
3294642e01fSmrg
3306747b715Smrg    CopyKeyClass(pDev, inputInfo.keyboard);
3316747b715Smrg}
3324642e01fSmrg
3336747b715Smrg/* Set the repeat rates based on global preferences and keycodes for modifiers.
3346747b715Smrg * Precondition: Has the keyInfo_mutex lock.
3356747b715Smrg */
33635c4bbdfSmrgstatic void
33735c4bbdfSmrgDarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue,
33835c4bbdfSmrg                        int keyRepeatValue)
33935c4bbdfSmrg{
34035c4bbdfSmrg    if (initialKeyRepeatValue == 300000) { // off
3416747b715Smrg        /* Turn off repeats globally */
3424642e01fSmrg        XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff);
34335c4bbdfSmrg    }
34435c4bbdfSmrg    else {
3456747b715Smrg        int i;
34635c4bbdfSmrg        XkbControlsPtr ctrl;
34735c4bbdfSmrg        XkbControlsRec old;
3484642e01fSmrg
3496747b715Smrg        /* Turn on repeats globally */
3504642e01fSmrg        XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
35135c4bbdfSmrg
3526747b715Smrg        /* Setup the bit mask for individual key repeats */
3536747b715Smrg        ctrl = pDev->key->xkbInfo->desc->ctrls;
35435c4bbdfSmrg        old = *ctrl;
35535c4bbdfSmrg
3566747b715Smrg        ctrl->repeat_delay = initialKeyRepeatValue * 15;
3576747b715Smrg        ctrl->repeat_interval = keyRepeatValue * 15;
3586747b715Smrg
3596747b715Smrg        /* Turn off key-repeat for modifier keys, on for others */
3606747b715Smrg        /* First set them all on */
36135c4bbdfSmrg        for (i = 0; i < XkbPerKeyBitArraySize; i++)
3626747b715Smrg            ctrl->per_key_repeat[i] = -1;
3636747b715Smrg
3646747b715Smrg        /* Now turn off the modifiers */
36535c4bbdfSmrg        for (i = 0; i < 32; i++) {
3666747b715Smrg            unsigned char keycode;
36735c4bbdfSmrg
3686747b715Smrg            keycode = keyInfo.modifierKeycodes[i][0];
36935c4bbdfSmrg            if (keycode)
3706747b715Smrg                ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
3716747b715Smrg
3726747b715Smrg            keycode = keyInfo.modifierKeycodes[i][1];
37335c4bbdfSmrg            if (keycode)
3746747b715Smrg                ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
3756747b715Smrg        }
3766747b715Smrg
3776747b715Smrg        /* Hurray for data duplication */
3786747b715Smrg        if (pDev->kbdfeed)
37935c4bbdfSmrg            memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat,
38035c4bbdfSmrg                   XkbPerKeyBitArraySize);
3814642e01fSmrg
38235c4bbdfSmrg        //ErrorF("per_key_repeat =\n");
3836747b715Smrg        //for(i=0; i < XkbPerKeyBitArraySize; i++)
38435c4bbdfSmrg        //    ErrorF("%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n");
3856747b715Smrg
3866747b715Smrg        /* And now we notify the puppies about the changes */
3876747b715Smrg        XkbDDXChangeControls(pDev, &old, ctrl);
3886747b715Smrg    }
3894642e01fSmrg}
3904642e01fSmrg
39135c4bbdfSmrgvoid
39235c4bbdfSmrgDarwinKeyboardReloadHandler(void)
39335c4bbdfSmrg{
3944642e01fSmrg    KeySymsRec keySyms;
3956747b715Smrg    CFIndex initialKeyRepeatValue, keyRepeatValue;
3966747b715Smrg    BOOL ok;
3976747b715Smrg    DeviceIntPtr pDev;
3986747b715Smrg    const char *xmodmap = PROJECTROOT "/bin/xmodmap";
3996747b715Smrg    const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap";
4006747b715Smrg    const char *homedir = getenv("HOME");
4016747b715Smrg    char usermodmap[PATH_MAX], cmd[PATH_MAX];
4024642e01fSmrg
4034642e01fSmrg    DEBUG_LOG("DarwinKeyboardReloadHandler\n");
4044642e01fSmrg
4056747b715Smrg    /* Get our key repeat settings from GlobalPreferences */
4066747b715Smrg    (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
40735c4bbdfSmrg
40835c4bbdfSmrg    initialKeyRepeatValue =
40935c4bbdfSmrg        CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"),
41035c4bbdfSmrg                                        CFSTR(".GlobalPreferences"), &ok);
41135c4bbdfSmrg    if (!ok)
4126747b715Smrg        initialKeyRepeatValue = 35;
41335c4bbdfSmrg
41435c4bbdfSmrg    keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR(
41535c4bbdfSmrg                                                         "KeyRepeat"),
41635c4bbdfSmrg                                                     CFSTR(
41735c4bbdfSmrg                                                         ".GlobalPreferences"),
41835c4bbdfSmrg                                                     &ok);
41935c4bbdfSmrg    if (!ok)
4206747b715Smrg        keyRepeatValue = 6;
42135c4bbdfSmrg
42235c4bbdfSmrg    pthread_mutex_lock(&keyInfo_mutex);
42335c4bbdfSmrg    {
4246747b715Smrg        /* Initialize our keySyms */
4256747b715Smrg        keySyms.map = keyInfo.keyMap;
42635c4bbdfSmrg        keySyms.mapWidth = GLYPHS_PER_KEY;
4276747b715Smrg        keySyms.minKeyCode = MIN_KEYCODE;
4286747b715Smrg        keySyms.maxKeyCode = MAX_KEYCODE;
4296747b715Smrg
43035c4bbdfSmrg        // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap
4316747b715Smrg        /* Apply the mappings to darwinKeyboard */
4326747b715Smrg        XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode,
4336747b715Smrg                              keySyms.maxKeyCode - keySyms.minKeyCode + 1,
4346747b715Smrg                              keyInfo.modMap, serverClient);
43535c4bbdfSmrg        DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue,
43635c4bbdfSmrg                                keyRepeatValue);
4376747b715Smrg
4386747b715Smrg        /* Apply the mappings to the core keyboard */
4396747b715Smrg        for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
44035c4bbdfSmrg            if ((pDev->coreEvents ||
44135c4bbdfSmrg                 pDev == inputInfo.keyboard) && pDev->key) {
44235c4bbdfSmrg                XkbApplyMappingChange(
44335c4bbdfSmrg                    pDev, &keySyms, keySyms.minKeyCode,
44435c4bbdfSmrg                    keySyms.maxKeyCode -
44535c4bbdfSmrg                    keySyms.minKeyCode + 1,
44635c4bbdfSmrg                    keyInfo.modMap, serverClient);
44735c4bbdfSmrg                DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue,
44835c4bbdfSmrg                                        keyRepeatValue);
4496747b715Smrg            }
4506747b715Smrg        }
4516747b715Smrg    } pthread_mutex_unlock(&keyInfo_mutex);
4526747b715Smrg
4536747b715Smrg    /* Modify with xmodmap */
4546747b715Smrg    if (access(xmodmap, F_OK) == 0) {
4556747b715Smrg        /* Check for system .Xmodmap */
4566747b715Smrg        if (access(sysmodmap, F_OK) == 0) {
45735c4bbdfSmrg            if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap,
45835c4bbdfSmrg                         sysmodmap) < sizeof(cmd)) {
4596747b715Smrg                X11ApplicationLaunchClient(cmd);
46035c4bbdfSmrg            }
46135c4bbdfSmrg            else {
46235c4bbdfSmrg                ErrorF(
46335c4bbdfSmrg                    "X11.app: Unable to create / execute xmodmap command line");
4646747b715Smrg            }
4656747b715Smrg        }
4666747b715Smrg
4676747b715Smrg        /* Check for user's local .Xmodmap */
46835c4bbdfSmrg        if ((homedir != NULL) &&
46935c4bbdfSmrg            (snprintf(usermodmap, sizeof(usermodmap), "%s/.Xmodmap",
47035c4bbdfSmrg                      homedir) < sizeof(usermodmap))) {
4716747b715Smrg            if (access(usermodmap, F_OK) == 0) {
47235c4bbdfSmrg                if (snprintf(cmd, sizeof(cmd), "%s %s", xmodmap,
47335c4bbdfSmrg                             usermodmap) < sizeof(cmd)) {
4746747b715Smrg                    X11ApplicationLaunchClient(cmd);
47535c4bbdfSmrg                }
47635c4bbdfSmrg                else {
47735c4bbdfSmrg                    ErrorF(
47835c4bbdfSmrg                        "X11.app: Unable to create / execute xmodmap command line");
4796747b715Smrg                }
4806747b715Smrg            }
48135c4bbdfSmrg        }
48235c4bbdfSmrg        else {
4836747b715Smrg            ErrorF("X11.app: Unable to determine path to user's .Xmodmap");
4846747b715Smrg        }
4856747b715Smrg    }
4864642e01fSmrg}
4874642e01fSmrg
4884642e01fSmrg//-----------------------------------------------------------------------------
4894642e01fSmrg// Modifier translation functions
4904642e01fSmrg//
4914642e01fSmrg// There are three different ways to specify a Mac modifier key:
4924642e01fSmrg// keycode - specifies hardware key, read from keymapping
4934642e01fSmrg// key     - NX_MODIFIERKEY_*, really an index
4944642e01fSmrg// mask    - NX_*MASK, mask for modifier flags in event record
4954642e01fSmrg// Left and right side have different keycodes but the same key and mask.
4964642e01fSmrg//-----------------------------------------------------------------------------
4974642e01fSmrg
4984642e01fSmrg/*
4994642e01fSmrg * DarwinModifierNXKeyToNXKeycode
5004642e01fSmrg *      Return the keycode for an NX_MODIFIERKEY_* modifier.
5014642e01fSmrg *      side = 0 for left or 1 for right.
5024642e01fSmrg *      Returns 0 if key+side is not a known modifier.
5034642e01fSmrg */
50435c4bbdfSmrgint
50535c4bbdfSmrgDarwinModifierNXKeyToNXKeycode(int key, int side)
50635c4bbdfSmrg{
5074642e01fSmrg    int retval;
5084642e01fSmrg    pthread_mutex_lock(&keyInfo_mutex);
5094642e01fSmrg    retval = keyInfo.modifierKeycodes[key][side];
5104642e01fSmrg    pthread_mutex_unlock(&keyInfo_mutex);
5114642e01fSmrg
5124642e01fSmrg    return retval;
5134642e01fSmrg}
5144642e01fSmrg
5154642e01fSmrg/*
5164642e01fSmrg * DarwinModifierNXKeycodeToNXKey
5174642e01fSmrg *      Returns -1 if keycode+side is not a modifier key
5184642e01fSmrg *      outSide may be NULL, else it gets 0 for left and 1 for right.
5194642e01fSmrg */
52035c4bbdfSmrgint
52135c4bbdfSmrgDarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide)
52235c4bbdfSmrg{
5234642e01fSmrg    int key, side;
5244642e01fSmrg
5254642e01fSmrg    keycode += MIN_KEYCODE;
5266747b715Smrg
5274642e01fSmrg    // search modifierKeycodes for this keycode+side
5286747b715Smrg    pthread_mutex_lock(&keyInfo_mutex);
5294642e01fSmrg    for (key = 0; key < NX_NUMMODIFIERS; key++) {
5304642e01fSmrg        for (side = 0; side <= 1; side++) {
5314642e01fSmrg            if (keyInfo.modifierKeycodes[key][side] == keycode) break;
5324642e01fSmrg        }
5334642e01fSmrg    }
5346747b715Smrg    pthread_mutex_unlock(&keyInfo_mutex);
5356747b715Smrg
5364642e01fSmrg    if (key == NX_NUMMODIFIERS) {
5374642e01fSmrg        return -1;
5384642e01fSmrg    }
5394642e01fSmrg    if (outSide) *outSide = side;
5404642e01fSmrg
5414642e01fSmrg    return key;
5424642e01fSmrg}
5434642e01fSmrg
5444642e01fSmrg/*
5454642e01fSmrg * DarwinModifierNXMaskToNXKey
5464642e01fSmrg *      Returns -1 if mask is not a known modifier mask.
5474642e01fSmrg */
54835c4bbdfSmrgint
54935c4bbdfSmrgDarwinModifierNXMaskToNXKey(int mask)
55035c4bbdfSmrg{
5514642e01fSmrg    switch (mask) {
55235c4bbdfSmrg    case NX_ALPHASHIFTMASK:
55335c4bbdfSmrg        return NX_MODIFIERKEY_ALPHALOCK;
55435c4bbdfSmrg
55535c4bbdfSmrg    case NX_SHIFTMASK:
55635c4bbdfSmrg        return NX_MODIFIERKEY_SHIFT;
55735c4bbdfSmrg
5584642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
55935c4bbdfSmrg    case NX_DEVICELSHIFTKEYMASK:
56035c4bbdfSmrg        return NX_MODIFIERKEY_SHIFT;
56135c4bbdfSmrg
56235c4bbdfSmrg    case NX_DEVICERSHIFTKEYMASK:
56335c4bbdfSmrg        return NX_MODIFIERKEY_RSHIFT;
56435c4bbdfSmrg
5654642e01fSmrg#endif
56635c4bbdfSmrg    case NX_CONTROLMASK:
56735c4bbdfSmrg        return NX_MODIFIERKEY_CONTROL;
56835c4bbdfSmrg
5694642e01fSmrg#ifdef NX_DEVICELCTLKEYMASK
57035c4bbdfSmrg    case NX_DEVICELCTLKEYMASK:
57135c4bbdfSmrg        return NX_MODIFIERKEY_CONTROL;
57235c4bbdfSmrg
57335c4bbdfSmrg    case NX_DEVICERCTLKEYMASK:
57435c4bbdfSmrg        return NX_MODIFIERKEY_RCONTROL;
57535c4bbdfSmrg
5764642e01fSmrg#endif
57735c4bbdfSmrg    case NX_ALTERNATEMASK:
57835c4bbdfSmrg        return NX_MODIFIERKEY_ALTERNATE;
57935c4bbdfSmrg
5804642e01fSmrg#ifdef NX_DEVICELALTKEYMASK
58135c4bbdfSmrg    case NX_DEVICELALTKEYMASK:
58235c4bbdfSmrg        return NX_MODIFIERKEY_ALTERNATE;
58335c4bbdfSmrg
58435c4bbdfSmrg    case NX_DEVICERALTKEYMASK:
58535c4bbdfSmrg        return NX_MODIFIERKEY_RALTERNATE;
58635c4bbdfSmrg
5874642e01fSmrg#endif
58835c4bbdfSmrg    case NX_COMMANDMASK:
58935c4bbdfSmrg        return NX_MODIFIERKEY_COMMAND;
59035c4bbdfSmrg
5914642e01fSmrg#ifdef NX_DEVICELCMDKEYMASK
59235c4bbdfSmrg    case NX_DEVICELCMDKEYMASK:
59335c4bbdfSmrg        return NX_MODIFIERKEY_COMMAND;
59435c4bbdfSmrg
59535c4bbdfSmrg    case NX_DEVICERCMDKEYMASK:
59635c4bbdfSmrg        return NX_MODIFIERKEY_RCOMMAND;
59735c4bbdfSmrg
5984642e01fSmrg#endif
59935c4bbdfSmrg    case NX_NUMERICPADMASK:
60035c4bbdfSmrg        return NX_MODIFIERKEY_NUMERICPAD;
60135c4bbdfSmrg
60235c4bbdfSmrg    case NX_HELPMASK:
60335c4bbdfSmrg        return NX_MODIFIERKEY_HELP;
60435c4bbdfSmrg
60535c4bbdfSmrg    case NX_SECONDARYFNMASK:
60635c4bbdfSmrg        return NX_MODIFIERKEY_SECONDARYFN;
6074642e01fSmrg    }
6084642e01fSmrg    return -1;
6094642e01fSmrg}
6104642e01fSmrg
6114642e01fSmrg/*
6124642e01fSmrg * DarwinModifierNXKeyToNXMask
6134642e01fSmrg *      Returns 0 if key is not a known modifier key.
6144642e01fSmrg */
61535c4bbdfSmrgint
61635c4bbdfSmrgDarwinModifierNXKeyToNXMask(int key)
61735c4bbdfSmrg{
6184642e01fSmrg    switch (key) {
61935c4bbdfSmrg    case NX_MODIFIERKEY_ALPHALOCK:
62035c4bbdfSmrg        return NX_ALPHASHIFTMASK;
62135c4bbdfSmrg
6224642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
62335c4bbdfSmrg    case NX_MODIFIERKEY_SHIFT:
62435c4bbdfSmrg        return NX_DEVICELSHIFTKEYMASK;
62535c4bbdfSmrg
62635c4bbdfSmrg    case NX_MODIFIERKEY_RSHIFT:
62735c4bbdfSmrg        return NX_DEVICERSHIFTKEYMASK;
62835c4bbdfSmrg
62935c4bbdfSmrg    case NX_MODIFIERKEY_CONTROL:
63035c4bbdfSmrg        return NX_DEVICELCTLKEYMASK;
63135c4bbdfSmrg
63235c4bbdfSmrg    case NX_MODIFIERKEY_RCONTROL:
63335c4bbdfSmrg        return NX_DEVICERCTLKEYMASK;
63435c4bbdfSmrg
63535c4bbdfSmrg    case NX_MODIFIERKEY_ALTERNATE:
63635c4bbdfSmrg        return NX_DEVICELALTKEYMASK;
63735c4bbdfSmrg
63835c4bbdfSmrg    case NX_MODIFIERKEY_RALTERNATE:
63935c4bbdfSmrg        return NX_DEVICERALTKEYMASK;
64035c4bbdfSmrg
64135c4bbdfSmrg    case NX_MODIFIERKEY_COMMAND:
64235c4bbdfSmrg        return NX_DEVICELCMDKEYMASK;
64335c4bbdfSmrg
64435c4bbdfSmrg    case NX_MODIFIERKEY_RCOMMAND:
64535c4bbdfSmrg        return NX_DEVICERCMDKEYMASK;
64635c4bbdfSmrg
6474642e01fSmrg#else
64835c4bbdfSmrg    case NX_MODIFIERKEY_SHIFT:
64935c4bbdfSmrg        return NX_SHIFTMASK;
65035c4bbdfSmrg
65135c4bbdfSmrg    case NX_MODIFIERKEY_CONTROL:
65235c4bbdfSmrg        return NX_CONTROLMASK;
65335c4bbdfSmrg
65435c4bbdfSmrg    case NX_MODIFIERKEY_ALTERNATE:
65535c4bbdfSmrg        return NX_ALTERNATEMASK;
65635c4bbdfSmrg
65735c4bbdfSmrg    case NX_MODIFIERKEY_COMMAND:
65835c4bbdfSmrg        return NX_COMMANDMASK;
65935c4bbdfSmrg
66035c4bbdfSmrg#endif
66135c4bbdfSmrg    case NX_MODIFIERKEY_NUMERICPAD:
66235c4bbdfSmrg        return NX_NUMERICPADMASK;
66335c4bbdfSmrg
66435c4bbdfSmrg    case NX_MODIFIERKEY_HELP:
66535c4bbdfSmrg        return NX_HELPMASK;
66635c4bbdfSmrg
66735c4bbdfSmrg    case NX_MODIFIERKEY_SECONDARYFN:
66835c4bbdfSmrg        return NX_SECONDARYFNMASK;
6694642e01fSmrg    }
6704642e01fSmrg    return 0;
6714642e01fSmrg}
6724642e01fSmrg
6734642e01fSmrg/*
6744642e01fSmrg * DarwinModifierStringToNXMask
6754642e01fSmrg *      Returns 0 if string is not a known modifier.
6764642e01fSmrg */
67735c4bbdfSmrgint
67835c4bbdfSmrgDarwinModifierStringToNXMask(const char *str, int separatelr)
67935c4bbdfSmrg{
6804642e01fSmrg#ifdef NX_DEVICELSHIFTKEYMASK
68135c4bbdfSmrg    if (separatelr) {
68235c4bbdfSmrg        if (!strcasecmp(str,
68335c4bbdfSmrg                        "shift")) return NX_DEVICELSHIFTKEYMASK |
68435c4bbdfSmrg                   NX_DEVICERSHIFTKEYMASK;
68535c4bbdfSmrg        if (!strcasecmp(str,
68635c4bbdfSmrg                        "control")) return NX_DEVICELCTLKEYMASK |
68735c4bbdfSmrg                   NX_DEVICERCTLKEYMASK;
68835c4bbdfSmrg        if (!strcasecmp(str,
68935c4bbdfSmrg                        "option")) return NX_DEVICELALTKEYMASK |
69035c4bbdfSmrg                   NX_DEVICERALTKEYMASK;
69135c4bbdfSmrg        if (!strcasecmp(str,
69235c4bbdfSmrg                        "alt")) return NX_DEVICELALTKEYMASK |
69335c4bbdfSmrg                   NX_DEVICERALTKEYMASK;
69435c4bbdfSmrg        if (!strcasecmp(str,
69535c4bbdfSmrg                        "command")) return NX_DEVICELCMDKEYMASK |
69635c4bbdfSmrg                   NX_DEVICERCMDKEYMASK;
69735c4bbdfSmrg        if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK;
69835c4bbdfSmrg        if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK;
6994642e01fSmrg        if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK;
7004642e01fSmrg        if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK;
70135c4bbdfSmrg        if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK;
70235c4bbdfSmrg        if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK;
70335c4bbdfSmrg        if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK;
70435c4bbdfSmrg        if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK;
7054642e01fSmrg        if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK;
7064642e01fSmrg        if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK;
7074642e01fSmrg    }
70835c4bbdfSmrg    else {
7094642e01fSmrg#endif
71035c4bbdfSmrg    if (!strcasecmp(str, "shift")) return NX_SHIFTMASK;
71135c4bbdfSmrg    if (!strcasecmp(str, "control")) return NX_CONTROLMASK;
71235c4bbdfSmrg    if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK;
71335c4bbdfSmrg    if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK;
71435c4bbdfSmrg    if (!strcasecmp(str, "command")) return NX_COMMANDMASK;
71535c4bbdfSmrg    if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK;
71635c4bbdfSmrg    if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK;
71735c4bbdfSmrg    if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK;
71835c4bbdfSmrg    if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK;
71935c4bbdfSmrg    if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK;
72035c4bbdfSmrg    if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK;
72135c4bbdfSmrg    if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK;
72235c4bbdfSmrg    if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK;
72335c4bbdfSmrg    if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK;
72435c4bbdfSmrg    if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK;
72535c4bbdfSmrg#ifdef NX_DEVICELSHIFTKEYMASK
72635c4bbdfSmrg}
72735c4bbdfSmrg#endif
72835c4bbdfSmrg    if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK;
72935c4bbdfSmrg    if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK;
73035c4bbdfSmrg    if (!strcasecmp(str, "help")) return NX_HELPMASK;
73135c4bbdfSmrg    if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK;
7324642e01fSmrg    return 0;
7334642e01fSmrg}
7344642e01fSmrg
73535c4bbdfSmrgstatic KeySym
73635c4bbdfSmrgmake_dead_key(KeySym in)
73735c4bbdfSmrg{
7384642e01fSmrg    int i;
7394642e01fSmrg
7401b5d61b8Smrg    for (i = 0; i < ARRAY_SIZE(dead_keys); i++)
7414642e01fSmrg        if (dead_keys[i].normal == in) return dead_keys[i].dead;
7424642e01fSmrg
7434642e01fSmrg    return in;
7444642e01fSmrg}
7454642e01fSmrg
74635c4bbdfSmrgstatic Bool
74735c4bbdfSmrgQuartzReadSystemKeymap(darwinKeyboardInfo *info)
74835c4bbdfSmrg{
749c8548ba8Smrg    __block const void *chr_data = NULL;
7504642e01fSmrg    int num_keycodes = NUM_KEYCODES;
751c8548ba8Smrg    __block UInt32 keyboard_type;
7524642e01fSmrg    int i, j;
7534642e01fSmrg    OSStatus err;
7544642e01fSmrg    KeySym *k;
7554642e01fSmrg
756c8548ba8Smrg    dispatch_block_t getKeyboardData = ^{
757c8548ba8Smrg        keyboard_type = LMGetKbdType();
75835c4bbdfSmrg
759c8548ba8Smrg        TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource();
7604642e01fSmrg
761c8548ba8Smrg        if (currentKeyLayoutRef) {
762c8548ba8Smrg            CFDataRef currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(currentKeyLayoutRef,
763c8548ba8Smrg                                                                                     kTISPropertyUnicodeKeyLayoutData);
764c8548ba8Smrg            if (currentKeyLayoutDataRef)
765c8548ba8Smrg                chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
7664642e01fSmrg
767c8548ba8Smrg            CFRelease(currentKeyLayoutRef);
7684642e01fSmrg        }
769c8548ba8Smrg    };
7704642e01fSmrg
771c8548ba8Smrg    /* This is an ugly ant-pattern, but it is more expedient to address the problem right now. */
772c8548ba8Smrg    if (pthread_main_np()) {
773c8548ba8Smrg        getKeyboardData();
774c8548ba8Smrg    } else {
775c8548ba8Smrg        dispatch_sync(dispatch_get_main_queue(), getKeyboardData);
7764642e01fSmrg    }
77735c4bbdfSmrg
7784642e01fSmrg    if (chr_data == NULL) {
77935c4bbdfSmrg        ErrorF("Couldn't get uchr or kchr resource\n");
78035c4bbdfSmrg        return FALSE;
7814642e01fSmrg    }
78235c4bbdfSmrg
7834642e01fSmrg    /* Scan the keycode range for the Unicode character that each
7844642e01fSmrg       key produces in the four shift states. Then convert that to
7854642e01fSmrg       an X11 keysym (which may just the bit that says "this is
7864642e01fSmrg       Unicode" if it can't find the real symbol.) */
78735c4bbdfSmrg
7884642e01fSmrg    /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
7894642e01fSmrg       must be used instead. */
7904642e01fSmrg
7914642e01fSmrg    for (i = 0; i < num_keycodes; i++) {
79235c4bbdfSmrg        static const int mods[4] = {
79335c4bbdfSmrg            0, MOD_SHIFT, MOD_OPTION,
79435c4bbdfSmrg            MOD_OPTION | MOD_SHIFT
79535c4bbdfSmrg        };
7964642e01fSmrg
7974642e01fSmrg        k = info->keyMap + i * GLYPHS_PER_KEY;
7984642e01fSmrg
7994642e01fSmrg        for (j = 0; j < 4; j++) {
80035c4bbdfSmrg            UniChar s[8];
80135c4bbdfSmrg            UniCharCount len;
80235c4bbdfSmrg            UInt32 dead_key_state = 0, extra_dead = 0;
80335c4bbdfSmrg
80435c4bbdfSmrg            err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
80535c4bbdfSmrg                                 mods[j] >> 8, keyboard_type, 0,
80635c4bbdfSmrg                                 &dead_key_state, 8, &len, s);
80735c4bbdfSmrg            if (err != noErr) continue;
80835c4bbdfSmrg
80935c4bbdfSmrg            if (len == 0 && dead_key_state != 0) {
81035c4bbdfSmrg                /* Found a dead key. Work out which one it is, but
81135c4bbdfSmrg                   remembering that it's dead. */
81235c4bbdfSmrg                err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
81335c4bbdfSmrg                                     mods[j] >> 8, keyboard_type,
81435c4bbdfSmrg                                     kUCKeyTranslateNoDeadKeysMask,
81535c4bbdfSmrg                                     &extra_dead, 8, &len, s);
8164642e01fSmrg                if (err != noErr) continue;
81735c4bbdfSmrg            }
8184642e01fSmrg
81935c4bbdfSmrg            /* Not sure why 0x0010 is there.
82035c4bbdfSmrg             * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
82135c4bbdfSmrg             */
82235c4bbdfSmrg            if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
82335c4bbdfSmrg                k[j] = ucs2keysym(s[0]);
82435c4bbdfSmrg                if (dead_key_state != 0) k[j] = make_dead_key(k[j]);
82535c4bbdfSmrg            }
8264642e01fSmrg        }
8276747b715Smrg
8284642e01fSmrg        if (k[3] == k[2]) k[3] = NoSymbol;
8294642e01fSmrg        if (k[1] == k[0]) k[1] = NoSymbol;
8304642e01fSmrg        if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
8316747b715Smrg        if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
8324642e01fSmrg    }
8334642e01fSmrg
8346747b715Smrg#if HACK_MISSING
8354642e01fSmrg    /* Fix up some things that are normally missing.. */
83635c4bbdfSmrg
8371b5d61b8Smrg    for (i = 0; i < ARRAY_SIZE(known_keys); i++) {
8386747b715Smrg        k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
83935c4bbdfSmrg
84035c4bbdfSmrg        if (k[0] == NoSymbol && k[1] == NoSymbol
8416747b715Smrg            && k[2] == NoSymbol && k[3] == NoSymbol)
8426747b715Smrg            k[0] = known_keys[i].keysym;
8434642e01fSmrg    }
8446747b715Smrg#endif
84535c4bbdfSmrg
8466747b715Smrg#if HACK_KEYPAD
8474642e01fSmrg    /* And some more things. We find the right symbols for the numeric
84835c4bbdfSmrg       keypad, but not the KP_ keysyms. So try to convert known keycodes. */
8491b5d61b8Smrg    for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) {
8506747b715Smrg        k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
85135c4bbdfSmrg
8526747b715Smrg        if (k[0] == known_numeric_keys[i].normal)
8536747b715Smrg            k[0] = known_numeric_keys[i].keypad;
8544642e01fSmrg    }
8556747b715Smrg#endif
85635c4bbdfSmrg
8576747b715Smrg#if HACK_BLACKLIST
8581b5d61b8Smrg    for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) {
8596747b715Smrg        k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY;
8606747b715Smrg        k[0] = k[1] = k[2] = k[3] = NoSymbol;
8616747b715Smrg    }
8626747b715Smrg#endif
8636747b715Smrg
8646747b715Smrg    DarwinBuildModifierMaps(info);
8654642e01fSmrg
8664642e01fSmrg    return TRUE;
8674642e01fSmrg}
8686747b715Smrg
86935c4bbdfSmrgBool
87035c4bbdfSmrgQuartsResyncKeymap(Bool sendDDXEvent)
87135c4bbdfSmrg{
8726747b715Smrg    Bool retval;
8736747b715Smrg    /* Update keyInfo */
8746747b715Smrg    pthread_mutex_lock(&keyInfo_mutex);
8756747b715Smrg    memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap));
8766747b715Smrg    retval = QuartzReadSystemKeymap(&keyInfo);
8776747b715Smrg    pthread_mutex_unlock(&keyInfo_mutex);
8786747b715Smrg
8796747b715Smrg    /* Tell server thread to deal with new keyInfo */
88035c4bbdfSmrg    if (sendDDXEvent)
8816747b715Smrg        DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
8826747b715Smrg
8836747b715Smrg    return retval;
8846747b715Smrg}
885