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 
66 extern void
67 CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
68 
69 enum {
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 
82 const 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 
126 const 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  */
157 const 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 
163 const 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 
192 typedef 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 
198 darwinKeyboardInfo keyInfo;
199 pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
200 
201 static void
DarwinChangeKeyboardControl(DeviceIntPtr device,KeybdCtrl * ctrl)202 DarwinChangeKeyboardControl(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  */
217 static void
DarwinBuildModifierMaps(darwinKeyboardInfo * info)218 DarwinBuildModifierMaps(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  */
318 void
DarwinKeyboardInit(DeviceIntPtr pDev)319 DarwinKeyboardInit(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  */
336 static void
DarwinKeyboardSetRepeat(DeviceIntPtr pDev,int initialKeyRepeatValue,int keyRepeatValue)337 DarwinKeyboardSetRepeat(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 
391 void
DarwinKeyboardReloadHandler(void)392 DarwinKeyboardReloadHandler(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  */
504 int
DarwinModifierNXKeyToNXKeycode(int key,int side)505 DarwinModifierNXKeyToNXKeycode(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  */
520 int
DarwinModifierNXKeycodeToNXKey(unsigned char keycode,int * outSide)521 DarwinModifierNXKeycodeToNXKey(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  */
548 int
DarwinModifierNXMaskToNXKey(int mask)549 DarwinModifierNXMaskToNXKey(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  */
615 int
DarwinModifierNXKeyToNXMask(int key)616 DarwinModifierNXKeyToNXMask(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  */
677 int
DarwinModifierStringToNXMask(const char * str,int separatelr)678 DarwinModifierStringToNXMask(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 
735 static KeySym
make_dead_key(KeySym in)736 make_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 
746 static Bool
QuartzReadSystemKeymap(darwinKeyboardInfo * info)747 QuartzReadSystemKeymap(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 
869 Bool
QuartsResyncKeymap(Bool sendDDXEvent)870 QuartsResyncKeymap(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