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