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