Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xquartz / quartzKeyboard.c
CommitLineData
a09e091a
JB
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
740static inline UniChar
741macroman2ucs(unsigned char c)
742{
743 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
744 by creating single element CFStringRefs then extracting the
745 first character. */
746
747 static const unsigned short table[128] = {
748 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc,
749 0xe1,
750 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9,
751 0xe8,
752 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1,
753 0xf3,
754 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb,
755 0xfc,
756 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6,
757 0xdf,
758 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6,
759 0xd8,
760 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202,
761 0x2211,
762 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6,
763 0xf8,
764 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206,
765 0xab,
766 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152,
767 0x153,
768 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7,
769 0x25ca,
770 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01,
771 0xfb02,
772 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca,
773 0xc1,
774 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3,
775 0xd4,
776 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6,
777 0x2dc,
778 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db,
779 0x2c7,
780 };
781
782 if (c < 128) return c;
783 else return table[c - 128];
784}
785
786static KeySym
787make_dead_key(KeySym in)
788{
789 int i;
790
791 for (i = 0; i < sizeof(dead_keys) / sizeof(dead_keys[0]); i++)
792 if (dead_keys[i].normal == in) return dead_keys[i].dead;
793
794 return in;
795}
796
797static Bool
798QuartzReadSystemKeymap(darwinKeyboardInfo *info)
799{
800#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
801 KeyboardLayoutRef key_layout;
802 int is_uchr = 1;
803#endif
804 const void *chr_data = NULL;
805 int num_keycodes = NUM_KEYCODES;
806 UInt32 keyboard_type = LMGetKbdType();
807 int i, j;
808 OSStatus err;
809 KeySym *k;
810 CFDataRef currentKeyLayoutDataRef = NULL;
811
812#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
813 TISInputSourceRef currentKeyLayoutRef =
814 TISCopyCurrentKeyboardLayoutInputSource();
815
816 if (currentKeyLayoutRef) {
817 currentKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(
818 currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData);
819 if (currentKeyLayoutDataRef)
820 chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
821 }
822#endif
823
824#ifdef __clang__
825#pragma clang diagnostic push
826#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty
827#endif
828
829#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
830 if (chr_data == NULL) {
831#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
832 ErrorF(
833 "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");
834 ErrorF(
835 "X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n",
836 (unsigned)keyboard_type, currentKeyLayoutRef,
837 currentKeyLayoutDataRef, chr_data);
838#endif
839
840 KLGetCurrentKeyboardLayout(&key_layout);
841 KLGetKeyboardLayoutProperty(key_layout, kKLuchrData, &chr_data);
842
843#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
844 if (chr_data != NULL) {
845 ErrorF(
846 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
847 }
848#endif
849 }
850
851 if (chr_data == NULL) {
852 ErrorF(
853 "X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
854 ErrorF(
855 "If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n");
856 KLGetKeyboardLayoutProperty(key_layout, kKLKCHRData, &chr_data);
857 is_uchr = 0;
858 num_keycodes = 128;
859
860#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
861 if (chr_data != NULL) {
862 ErrorF(
863 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
864 }
865#endif
866 }
867#endif
868
869#ifdef __clang__
870#pragma clang diagnostic pop
871#endif
872
873#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
874 if (currentKeyLayoutRef)
875 CFRelease(currentKeyLayoutRef);
876#endif
877
878 if (chr_data == NULL) {
879 ErrorF("Couldn't get uchr or kchr resource\n");
880 return FALSE;
881 }
882
883 /* Scan the keycode range for the Unicode character that each
884 key produces in the four shift states. Then convert that to
885 an X11 keysym (which may just the bit that says "this is
886 Unicode" if it can't find the real symbol.) */
887
888 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
889 must be used instead. */
890
891 for (i = 0; i < num_keycodes; i++) {
892 static const int mods[4] = {
893 0, MOD_SHIFT, MOD_OPTION,
894 MOD_OPTION | MOD_SHIFT
895 };
896
897 k = info->keyMap + i * GLYPHS_PER_KEY;
898
899 for (j = 0; j < 4; j++) {
900#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
901 if (is_uchr) {
902#endif
903 UniChar s[8];
904 UniCharCount len;
905 UInt32 dead_key_state = 0, extra_dead = 0;
906
907 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
908 mods[j] >> 8, keyboard_type, 0,
909 &dead_key_state, 8, &len, s);
910 if (err != noErr) continue;
911
912 if (len == 0 && dead_key_state != 0) {
913 /* Found a dead key. Work out which one it is, but
914 remembering that it's dead. */
915 err = UCKeyTranslate(chr_data, i, kUCKeyActionDown,
916 mods[j] >> 8, keyboard_type,
917 kUCKeyTranslateNoDeadKeysMask,
918 &extra_dead, 8, &len, s);
919 if (err != noErr) continue;
920 }
921
922 /* Not sure why 0x0010 is there.
923 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
924 */
925 if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
926 k[j] = ucs2keysym(s[0]);
927 if (dead_key_state != 0) k[j] = make_dead_key(k[j]);
928 }
929#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
930 }
931 else { // kchr
932 UInt32 c, state = 0, state2 = 0;
933 UInt16 code;
934
935 code = i | mods[j];
936
937#ifdef __clang__
938#pragma clang diagnostic push
939#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate
940#endif
941
942 c = KeyTranslate(chr_data, code, &state);
943
944 /* Dead keys are only processed on key-down, so ask
945 to translate those events. When we find a dead key,
946 translating the matching key up event will give
947 us the actual dead character. */
948
949 if (state != 0)
950 c = KeyTranslate(chr_data, code | 128, &state2);
951
952#ifdef __clang__
953#pragma clang diagnostic pop
954#endif
955
956 /* Characters seem to be in MacRoman encoding. */
957
958 if (c != 0 && c != 0x0010) {
959 k[j] = ucs2keysym(macroman2ucs(c & 255));
960
961 if (state != 0) k[j] = make_dead_key(k[j]);
962 }
963 }
964#endif
965 }
966
967 if (k[3] == k[2]) k[3] = NoSymbol;
968 if (k[1] == k[0]) k[1] = NoSymbol;
969 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
970 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
971 }
972
973#if HACK_MISSING
974 /* Fix up some things that are normally missing.. */
975
976 for (i = 0; i < sizeof(known_keys) / sizeof(known_keys[0]); i++) {
977 k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
978
979 if (k[0] == NoSymbol && k[1] == NoSymbol
980 && k[2] == NoSymbol && k[3] == NoSymbol)
981 k[0] = known_keys[i].keysym;
982 }
983#endif
984
985#if HACK_KEYPAD
986 /* And some more things. We find the right symbols for the numeric
987 keypad, but not the KP_ keysyms. So try to convert known keycodes. */
988 for (i = 0; i < sizeof(known_numeric_keys) / sizeof(known_numeric_keys[0]);
989 i++) {
990 k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
991
992 if (k[0] == known_numeric_keys[i].normal)
993 k[0] = known_numeric_keys[i].keypad;
994 }
995#endif
996
997#if HACK_BLACKLIST
998 for (i = 0; i < sizeof(keycode_blacklist) / sizeof(keycode_blacklist[0]);
999 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}