2 quartzKeyboard.c: Keyboard support for Xquartz
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.
8 Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com>
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
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.
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.
34 #include "sanitizedCarbon.h"
36 #ifdef HAVE_DIX_CONFIG_H
37 #include <dix-config.h>
40 #define HACK_MISSING 1
42 #define HACK_BLACKLIST 1
49 #include <AvailabilityMacros.h>
53 #include "darwinEvents.h"
55 #include "quartzKeyboard.h"
57 #include "X11Application.h"
64 #include "X11/keysym.h"
65 #include "keysym2ucs.h"
68 CopyKeyClass(DeviceIntPtr device
, DeviceIntPtr master
);
77 #define UKEYSYM(u) ((u) | 0x01000000)
80 /* Table of keycode->keysym mappings we use to fallback on for important
81 keys that are often not in the Unicode mapping. */
84 unsigned short keycode
;
117 /* Table of keycode->old,new-keysym mappings we use to fixup the numeric
120 const 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
},
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
149 * legacy Mac keycodes for arrow keys that shift-modify to math symbols
151 const static unsigned short keycode_blacklist
[] = { 66, 70, 72, 77 };
154 /* Table mapping normal keysyms to their dead equivalents.
155 FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
157 const static struct {
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 */
186 typedef struct darwinKeyboardInfo_struct
{
187 CARD8 modMap
[MAP_LENGTH
];
188 KeySym keyMap
[MAP_LENGTH
* GLYPHS_PER_KEY
];
189 unsigned char modifierKeycodes
[32][2];
190 } darwinKeyboardInfo
;
192 darwinKeyboardInfo keyInfo
;
193 pthread_mutex_t keyInfo_mutex
= PTHREAD_MUTEX_INITIALIZER
;
196 DarwinChangeKeyboardControl(DeviceIntPtr device
, KeybdCtrl
*ctrl
)
198 // FIXME: to be implemented
199 // keyclick, bell volume / pitch, autorepead, LED's
202 //-----------------------------------------------------------------------------
203 // Utility functions to help parse Darwin keymap
204 //-----------------------------------------------------------------------------
207 * DarwinBuildModifierMaps
208 * Use the keyMap field of keyboard info structure to populate
209 * the modMap and modifierKeycodes fields.
212 DarwinBuildModifierMaps(darwinKeyboardInfo
*info
)
217 memset(info
->modMap
, NoSymbol
, sizeof(info
->modMap
));
218 memset(info
->modifierKeycodes
, 0, sizeof(info
->modifierKeycodes
));
220 for (i
= 0; i
< NUM_KEYCODES
; i
++) {
221 k
= info
->keyMap
+ i
* GLYPHS_PER_KEY
;
225 info
->modifierKeycodes
[NX_MODIFIERKEY_SHIFT
][0] = i
;
226 info
->modMap
[MIN_KEYCODE
+ i
] = ShiftMask
;
230 #ifdef NX_MODIFIERKEY_RSHIFT
231 info
->modifierKeycodes
[NX_MODIFIERKEY_RSHIFT
][0] = i
;
233 info
->modifierKeycodes
[NX_MODIFIERKEY_SHIFT
][0] = i
;
235 info
->modMap
[MIN_KEYCODE
+ i
] = ShiftMask
;
239 info
->modifierKeycodes
[NX_MODIFIERKEY_CONTROL
][0] = i
;
240 info
->modMap
[MIN_KEYCODE
+ i
] = ControlMask
;
244 #ifdef NX_MODIFIERKEY_RCONTROL
245 info
->modifierKeycodes
[NX_MODIFIERKEY_RCONTROL
][0] = i
;
247 info
->modifierKeycodes
[NX_MODIFIERKEY_CONTROL
][0] = i
;
249 info
->modMap
[MIN_KEYCODE
+ i
] = ControlMask
;
253 info
->modifierKeycodes
[NX_MODIFIERKEY_ALPHALOCK
][0] = i
;
254 info
->modMap
[MIN_KEYCODE
+ i
] = LockMask
;
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.
265 #ifdef NX_MODIFIERKEY_RALTERNATE
266 info
->modifierKeycodes
[NX_MODIFIERKEY_RALTERNATE
][0] = i
;
268 info
->modifierKeycodes
[NX_MODIFIERKEY_ALTERNATE
][0] = i
;
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
;
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
;
282 info
->modMap
[MIN_KEYCODE
+ i
] = Mod1Mask
;
286 info
->modifierKeycodes
[NX_MODIFIERKEY_COMMAND
][0] = i
;
287 info
->modMap
[MIN_KEYCODE
+ i
] = Mod2Mask
;
291 #ifdef NX_MODIFIERKEY_RCOMMAND
292 info
->modifierKeycodes
[NX_MODIFIERKEY_RCOMMAND
][0] = i
;
294 info
->modifierKeycodes
[NX_MODIFIERKEY_COMMAND
][0] = i
;
296 info
->modMap
[MIN_KEYCODE
+ i
] = Mod2Mask
;
300 info
->modMap
[MIN_KEYCODE
+ i
] = Mod3Mask
;
308 * Get the Darwin keyboard map and compute an equivalent
309 * X keyboard map and modifier map. Set the new keyboard
313 DarwinKeyboardInit(DeviceIntPtr pDev
)
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());
320 InitKeyboardDeviceStruct(pDev
, NULL
, NULL
, DarwinChangeKeyboardControl
);
322 DarwinKeyboardReloadHandler();
324 CopyKeyClass(pDev
, inputInfo
.keyboard
);
327 /* Set the repeat rates based on global preferences and keycodes for modifiers.
328 * Precondition: Has the keyInfo_mutex lock.
331 DarwinKeyboardSetRepeat(DeviceIntPtr pDev
, int initialKeyRepeatValue
,
334 if (initialKeyRepeatValue
== 300000) { // off
335 /* Turn off repeats globally */
336 XkbSetRepeatKeys(pDev
, -1, AutoRepeatModeOff
);
343 /* Turn on repeats globally */
344 XkbSetRepeatKeys(pDev
, -1, AutoRepeatModeOn
);
346 /* Setup the bit mask for individual key repeats */
347 ctrl
= pDev
->key
->xkbInfo
->desc
->ctrls
;
350 ctrl
->repeat_delay
= initialKeyRepeatValue
* 15;
351 ctrl
->repeat_interval
= keyRepeatValue
* 15;
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;
358 /* Now turn off the modifiers */
359 for (i
= 0; i
< 32; i
++) {
360 unsigned char keycode
;
362 keycode
= keyInfo
.modifierKeycodes
[i
][0];
364 ClearBit(ctrl
->per_key_repeat
, keycode
+ MIN_KEYCODE
);
366 keycode
= keyInfo
.modifierKeycodes
[i
][1];
368 ClearBit(ctrl
->per_key_repeat
, keycode
+ MIN_KEYCODE
);
371 /* Hurray for data duplication */
373 memcpy(pDev
->kbdfeed
->ctrl
.autoRepeats
, ctrl
->per_key_repeat
,
374 XkbPerKeyBitArraySize
);
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");
380 /* And now we notify the puppies about the changes */
381 XkbDDXChangeControls(pDev
, &old
, ctrl
);
386 DarwinKeyboardReloadHandler(void)
389 CFIndex initialKeyRepeatValue
, keyRepeatValue
;
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
];
397 DEBUG_LOG("DarwinKeyboardReloadHandler\n");
399 /* Get our key repeat settings from GlobalPreferences */
400 (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
402 initialKeyRepeatValue
=
403 CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"),
404 CFSTR(".GlobalPreferences"), &ok
);
406 initialKeyRepeatValue
= 35;
408 keyRepeatValue
= CFPreferencesGetAppIntegerValue(CFSTR(
411 ".GlobalPreferences"),
416 pthread_mutex_lock(&keyInfo_mutex
);
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
;
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
,
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
,
439 keySyms
.minKeyCode
+ 1,
440 keyInfo
.modMap
, serverClient
);
441 DarwinKeyboardSetRepeat(pDev
, initialKeyRepeatValue
,
445 } pthread_mutex_unlock(&keyInfo_mutex
);
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
);
457 "X11.app: Unable to create / execute xmodmap command line");
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
);
472 "X11.app: Unable to create / execute xmodmap command line");
477 ErrorF("X11.app: Unable to determine path to user's .Xmodmap");
482 //-----------------------------------------------------------------------------
483 // Modifier translation functions
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 //-----------------------------------------------------------------------------
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.
499 DarwinModifierNXKeyToNXKeycode(int key
, int side
)
502 pthread_mutex_lock(&keyInfo_mutex
);
503 retval
= keyInfo
.modifierKeycodes
[key
][side
];
504 pthread_mutex_unlock(&keyInfo_mutex
);
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.
515 DarwinModifierNXKeycodeToNXKey(unsigned char keycode
, int *outSide
)
519 keycode
+= MIN_KEYCODE
;
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;
528 pthread_mutex_unlock(&keyInfo_mutex
);
530 if (key
== NX_NUMMODIFIERS
) {
533 if (outSide
) *outSide
= side
;
539 * DarwinModifierNXMaskToNXKey
540 * Returns -1 if mask is not a known modifier mask.
543 DarwinModifierNXMaskToNXKey(int mask
)
546 case NX_ALPHASHIFTMASK
:
547 return NX_MODIFIERKEY_ALPHALOCK
;
550 return NX_MODIFIERKEY_SHIFT
;
552 #ifdef NX_DEVICELSHIFTKEYMASK
553 case NX_DEVICELSHIFTKEYMASK
:
554 return NX_MODIFIERKEY_SHIFT
;
556 case NX_DEVICERSHIFTKEYMASK
:
557 return NX_MODIFIERKEY_RSHIFT
;
561 return NX_MODIFIERKEY_CONTROL
;
563 #ifdef NX_DEVICELCTLKEYMASK
564 case NX_DEVICELCTLKEYMASK
:
565 return NX_MODIFIERKEY_CONTROL
;
567 case NX_DEVICERCTLKEYMASK
:
568 return NX_MODIFIERKEY_RCONTROL
;
571 case NX_ALTERNATEMASK
:
572 return NX_MODIFIERKEY_ALTERNATE
;
574 #ifdef NX_DEVICELALTKEYMASK
575 case NX_DEVICELALTKEYMASK
:
576 return NX_MODIFIERKEY_ALTERNATE
;
578 case NX_DEVICERALTKEYMASK
:
579 return NX_MODIFIERKEY_RALTERNATE
;
583 return NX_MODIFIERKEY_COMMAND
;
585 #ifdef NX_DEVICELCMDKEYMASK
586 case NX_DEVICELCMDKEYMASK
:
587 return NX_MODIFIERKEY_COMMAND
;
589 case NX_DEVICERCMDKEYMASK
:
590 return NX_MODIFIERKEY_RCOMMAND
;
593 case NX_NUMERICPADMASK
:
594 return NX_MODIFIERKEY_NUMERICPAD
;
597 return NX_MODIFIERKEY_HELP
;
599 case NX_SECONDARYFNMASK
:
600 return NX_MODIFIERKEY_SECONDARYFN
;
606 * DarwinModifierNXKeyToNXMask
607 * Returns 0 if key is not a known modifier key.
610 DarwinModifierNXKeyToNXMask(int key
)
613 case NX_MODIFIERKEY_ALPHALOCK
:
614 return NX_ALPHASHIFTMASK
;
616 #ifdef NX_DEVICELSHIFTKEYMASK
617 case NX_MODIFIERKEY_SHIFT
:
618 return NX_DEVICELSHIFTKEYMASK
;
620 case NX_MODIFIERKEY_RSHIFT
:
621 return NX_DEVICERSHIFTKEYMASK
;
623 case NX_MODIFIERKEY_CONTROL
:
624 return NX_DEVICELCTLKEYMASK
;
626 case NX_MODIFIERKEY_RCONTROL
:
627 return NX_DEVICERCTLKEYMASK
;
629 case NX_MODIFIERKEY_ALTERNATE
:
630 return NX_DEVICELALTKEYMASK
;
632 case NX_MODIFIERKEY_RALTERNATE
:
633 return NX_DEVICERALTKEYMASK
;
635 case NX_MODIFIERKEY_COMMAND
:
636 return NX_DEVICELCMDKEYMASK
;
638 case NX_MODIFIERKEY_RCOMMAND
:
639 return NX_DEVICERCMDKEYMASK
;
642 case NX_MODIFIERKEY_SHIFT
:
645 case NX_MODIFIERKEY_CONTROL
:
646 return NX_CONTROLMASK
;
648 case NX_MODIFIERKEY_ALTERNATE
:
649 return NX_ALTERNATEMASK
;
651 case NX_MODIFIERKEY_COMMAND
:
652 return NX_COMMANDMASK
;
655 case NX_MODIFIERKEY_NUMERICPAD
:
656 return NX_NUMERICPADMASK
;
658 case NX_MODIFIERKEY_HELP
:
661 case NX_MODIFIERKEY_SECONDARYFN
:
662 return NX_SECONDARYFNMASK
;
668 * DarwinModifierStringToNXMask
669 * Returns 0 if string is not a known modifier.
672 DarwinModifierStringToNXMask(const char *str
, int separatelr
)
674 #ifdef NX_DEVICELSHIFTKEYMASK
677 "shift")) return NX_DEVICELSHIFTKEYMASK
|
678 NX_DEVICERSHIFTKEYMASK
;
680 "control")) return NX_DEVICELCTLKEYMASK
|
681 NX_DEVICERCTLKEYMASK
;
683 "option")) return NX_DEVICELALTKEYMASK
|
684 NX_DEVICERALTKEYMASK
;
686 "alt")) return NX_DEVICELALTKEYMASK
|
687 NX_DEVICERALTKEYMASK
;
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
;
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
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
;
731 * This allows the ddx layer to prevent some keys from being remapped
735 LegalModifier(unsigned int key
, DeviceIntPtr pDev
)
740 static inline UniChar
741 macroman2ucs(unsigned char c
)
743 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
744 by creating single element CFStringRefs then extracting the
747 static const unsigned short table
[128] = {
748 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc,
750 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9,
752 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1,
754 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb,
756 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6,
758 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6,
760 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202,
762 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6,
764 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206,
766 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152,
768 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7,
770 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01,
772 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca,
774 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3,
776 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6,
778 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db,
782 if (c
< 128) return c
;
783 else return table
[c
- 128];
787 make_dead_key(KeySym in
)
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
;
798 QuartzReadSystemKeymap(darwinKeyboardInfo
*info
)
800 #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
801 KeyboardLayoutRef key_layout
;
804 const void *chr_data
= NULL
;
805 int num_keycodes
= NUM_KEYCODES
;
806 UInt32 keyboard_type
= LMGetKbdType();
810 CFDataRef currentKeyLayoutDataRef
= NULL
;
812 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
813 TISInputSourceRef currentKeyLayoutRef
=
814 TISCopyCurrentKeyboardLayoutInputSource();
816 if (currentKeyLayoutRef
) {
817 currentKeyLayoutDataRef
= (CFDataRef
)TISGetInputSourceProperty(
818 currentKeyLayoutRef
, kTISPropertyUnicodeKeyLayoutData
);
819 if (currentKeyLayoutDataRef
)
820 chr_data
= CFDataGetBytePtr(currentKeyLayoutDataRef
);
825 #pragma clang diagnostic push
826 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty
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
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");
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
);
840 KLGetCurrentKeyboardLayout(&key_layout
);
841 KLGetKeyboardLayoutProperty(key_layout
, kKLuchrData
, &chr_data
);
843 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
844 if (chr_data
!= NULL
) {
846 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
851 if (chr_data
== NULL
) {
853 "X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
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
);
860 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
861 if (chr_data
!= NULL
) {
863 "X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
870 #pragma clang diagnostic pop
873 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
874 if (currentKeyLayoutRef
)
875 CFRelease(currentKeyLayoutRef
);
878 if (chr_data
== NULL
) {
879 ErrorF("Couldn't get uchr or kchr resource\n");
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.) */
888 /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
889 must be used instead. */
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
897 k
= info
->keyMap
+ i
* GLYPHS_PER_KEY
;
899 for (j
= 0; j
< 4; j
++) {
900 #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
905 UInt32 dead_key_state
= 0, extra_dead
= 0;
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;
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;
922 /* Not sure why 0x0010 is there.
923 * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
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
]);
929 #if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
932 UInt32 c
, state
= 0, state2
= 0;
938 #pragma clang diagnostic push
939 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate
942 c
= KeyTranslate(chr_data
, code
, &state
);
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. */
950 c
= KeyTranslate(chr_data
, code
| 128, &state2
);
953 #pragma clang diagnostic pop
956 /* Characters seem to be in MacRoman encoding. */
958 if (c
!= 0 && c
!= 0x0010) {
959 k
[j
] = ucs2keysym(macroman2ucs(c
& 255));
961 if (state
!= 0) k
[j
] = make_dead_key(k
[j
]);
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
;
974 /* Fix up some things that are normally missing.. */
976 for (i
= 0; i
< sizeof(known_keys
) / sizeof(known_keys
[0]); i
++) {
977 k
= info
->keyMap
+ known_keys
[i
].keycode
* GLYPHS_PER_KEY
;
979 if (k
[0] == NoSymbol
&& k
[1] == NoSymbol
980 && k
[2] == NoSymbol
&& k
[3] == NoSymbol
)
981 k
[0] = known_keys
[i
].keysym
;
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]);
990 k
= info
->keyMap
+ known_numeric_keys
[i
].keycode
* GLYPHS_PER_KEY
;
992 if (k
[0] == known_numeric_keys
[i
].normal
)
993 k
[0] = known_numeric_keys
[i
].keypad
;
998 for (i
= 0; i
< sizeof(keycode_blacklist
) / sizeof(keycode_blacklist
[0]);
1000 k
= info
->keyMap
+ keycode_blacklist
[i
] * GLYPHS_PER_KEY
;
1001 k
[0] = k
[1] = k
[2] = k
[3] = NoSymbol
;
1005 DarwinBuildModifierMaps(info
);
1011 QuartsResyncKeymap(Bool sendDDXEvent
)
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
);
1020 /* Tell server thread to deal with new keyInfo */
1022 DarwinSendDDXEvent(kXquartzReloadKeymap
, 0);