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