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