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 /*
736 * LegalModifier
737 * This allows the ddx layer to prevent some keys from being remapped
738 * as modifier keys.
739 */
740 Bool
LegalModifier(unsigned int key,DeviceIntPtr pDev)741 LegalModifier(unsigned int key, DeviceIntPtr pDev)
742 {
743 return 1;
744 }
745
746 static KeySym
make_dead_key(KeySym in)747 make_dead_key(KeySym in)
748 {
749 int i;
750
751 for (i = 0; i < ARRAY_SIZE(dead_keys); i++)
752 if (dead_keys[i].normal == in) return dead_keys[i].dead;
753
754 return in;
755 }
756
757 static Bool
QuartzReadSystemKeymap(darwinKeyboardInfo * info)758 QuartzReadSystemKeymap(darwinKeyboardInfo *info)
759 {
760 __block const void *chr_data = NULL;
761 int num_keycodes = NUM_KEYCODES;
762 __block UInt32 keyboard_type;
763 int i, j;
764 OSStatus err;
765 KeySym *k;
766
767 dispatch_block_t getKeyboardData = ^{
768 keyboard_type = LMGetKbdType();
769
770 TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource();
771
772 if (currentKeyLayoutRef) {
773 CFDataRef currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(currentKeyLayoutRef,
774 kTISPropertyUnicodeKeyLayoutData);
775 if (currentKeyLayoutDataRef)
776 chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
777
778 CFRelease(currentKeyLayoutRef);
779 }
780 };
781
782 /* This is an ugly ant-pattern, but it is more expedient to address the problem right now. */
783 if (pthread_main_np()) {
784 getKeyboardData();
785 } else {
786 dispatch_sync(dispatch_get_main_queue(), getKeyboardData);
787 }
788
789 if (chr_data == NULL) {
790 ErrorF("Couldn't get uchr or kchr resource\n");
791 return FALSE;
792 }
793
794 /* Scan the keycode range for the Unicode character that each
795 key produces in the four shift states. Then convert that to
796 an X11 keysym (which may just the bit that says "this is
797 Unicode" if it can't find the real symbol.) */
798
799 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
800 must be used instead. */
801
802 for (i = 0; i < num_keycodes; i++) {
803 static const int mods[4] = {
804 0, MOD_SHIFT, MOD_OPTION,
805 MOD_OPTION | MOD_SHIFT
806 };
807
808 k = info->keyMap + i * GLYPHS_PER_KEY;
809
810 for (j = 0; j < 4; j++) {
811 UniChar s[8];
812 UniCharCount len;
813 UInt32 dead_key_state = 0, extra_dead = 0;
814
815 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
816 mods[j] >> 8, keyboard_type, 0,
817 &dead_key_state, 8, &len, s);
818 if (err != noErr) continue;
819
820 if (len == 0 && dead_key_state != 0) {
821 /* Found a dead key. Work out which one it is, but
822 remembering that it's dead. */
823 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
824 mods[j] >> 8, keyboard_type,
825 kUCKeyTranslateNoDeadKeysMask,
826 &extra_dead, 8, &len, s);
827 if (err != noErr) continue;
828 }
829
830 /* Not sure why 0x0010 is there.
831 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
832 */
833 if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
834 k[j] = ucs2keysym(s[0]);
835 if (dead_key_state != 0) k[j] = make_dead_key(k[j]);
836 }
837 }
838
839 if (k[3] == k[2]) k[3] = NoSymbol;
840 if (k[1] == k[0]) k[1] = NoSymbol;
841 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
842 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
843 }
844
845 #if HACK_MISSING
846 /* Fix up some things that are normally missing.. */
847
848 for (i = 0; i < ARRAY_SIZE(known_keys); i++) {
849 k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
850
851 if (k[0] == NoSymbol && k[1] == NoSymbol
852 && k[2] == NoSymbol && k[3] == NoSymbol)
853 k[0] = known_keys[i].keysym;
854 }
855 #endif
856
857 #if HACK_KEYPAD
858 /* And some more things. We find the right symbols for the numeric
859 keypad, but not the KP_ keysyms. So try to convert known keycodes. */
860 for (i = 0; i < ARRAY_SIZE(known_numeric_keys); i++) {
861 k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
862
863 if (k[0] == known_numeric_keys[i].normal)
864 k[0] = known_numeric_keys[i].keypad;
865 }
866 #endif
867
868 #if HACK_BLACKLIST
869 for (i = 0; i < ARRAY_SIZE(keycode_blacklist); i++) {
870 k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY;
871 k[0] = k[1] = k[2] = k[3] = NoSymbol;
872 }
873 #endif
874
875 DarwinBuildModifierMaps(info);
876
877 return TRUE;
878 }
879
880 Bool
QuartsResyncKeymap(Bool sendDDXEvent)881 QuartsResyncKeymap(Bool sendDDXEvent)
882 {
883 Bool retval;
884 /* Update keyInfo */
885 pthread_mutex_lock(&keyInfo_mutex);
886 memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap));
887 retval = QuartzReadSystemKeymap(&keyInfo);
888 pthread_mutex_unlock(&keyInfo_mutex);
889
890 /* Tell server thread to deal with new keyInfo */
891 if (sendDDXEvent)
892 DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
893
894 return retval;
895 }
896