4 Code to build a keymap using the Carbon Keyboard Layout API,
5 which is supported on Mac OS X 10.2 and newer.
7 Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
9 Permission is hereby granted, free of charge, to any person
10 obtaining a copy of this software and associated documentation files
11 (the "Software"), to deal in the Software without restriction,
12 including without limitation the rights to use, copy, modify, merge,
13 publish, distribute, sublicense, and/or sell copies of the Software,
14 and to permit persons to whom the Software is furnished to do so,
15 subject to the following conditions:
17 The above copyright notice and this permission notice shall be
18 included in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
24 HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
29 Except as contained in this notice, the name(s) of the above
30 copyright holders shall not be used in advertising or otherwise to
31 promote the sale, use or other dealings in this Software without
32 prior written authorization.
35 #ifdef HAVE_XORG_CONFIG_H
36 #include <xorg-config.h>
38 #include "quartzCommon.h"
40 #include <CoreServices/CoreServices.h>
41 #include <Carbon/Carbon.h>
43 #include "darwinKeyboard.h"
44 #include "X11/keysym.h"
45 #include "keysym2ucs.h"
49 #define HACK_MISSING 1
59 #define UKEYSYM(u) ((u) | 0x01000000)
61 /* Table of keycode->keysym mappings we use to fallback on for important
62 keys that are often not in the Unicode mapping. */
65 unsigned short keycode
;
96 /* Table of keycode->old,new-keysym mappings we use to fixup the numeric
100 unsigned short keycode
;
101 KeySym normal
, keypad
;
102 } known_numeric_keys
[] = {
103 {65, XK_period
, XK_KP_Decimal
},
104 {67, XK_asterisk
, XK_KP_Multiply
},
105 {69, XK_plus
, XK_KP_Add
},
106 {75, XK_slash
, XK_KP_Divide
},
107 {76, 0x01000003, XK_KP_Enter
},
108 {78, XK_minus
, XK_KP_Subtract
},
109 {81, XK_equal
, XK_KP_Equal
},
122 /* Table mapping normal keysyms to their dead equivalents.
123 FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
125 const static struct {
128 {XK_grave
, XK_dead_grave
},
129 {XK_acute
, XK_dead_acute
},
130 {XK_asciicircum
, XK_dead_circumflex
},
131 {UKEYSYM (0x2c6), XK_dead_circumflex
}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
132 {XK_asciitilde
, XK_dead_tilde
},
133 {UKEYSYM (0x2dc), XK_dead_tilde
}, /* SMALL TILDE */
134 {XK_macron
, XK_dead_macron
},
135 {XK_breve
, XK_dead_breve
},
136 {XK_abovedot
, XK_dead_abovedot
},
137 {XK_diaeresis
, XK_dead_diaeresis
},
138 {UKEYSYM (0x2da), XK_dead_abovering
}, /* DOT ABOVE */
139 {XK_doubleacute
, XK_dead_doubleacute
},
140 {XK_caron
, XK_dead_caron
},
141 {XK_cedilla
, XK_dead_cedilla
},
142 {XK_ogonek
, XK_dead_ogonek
},
143 {UKEYSYM (0x269), XK_dead_iota
}, /* LATIN SMALL LETTER IOTA */
144 {UKEYSYM (0x2ec), XK_dead_voiced_sound
}, /* MODIFIER LETTER VOICING */
145 /* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
146 {UKEYSYM (0x323), XK_dead_belowdot
}, /* COMBINING DOT BELOW */
147 {UKEYSYM (0x309), XK_dead_hook
}, /* COMBINING HOOK ABOVE */
148 {UKEYSYM (0x31b), XK_dead_horn
}, /* COMBINING HORN */
152 DarwinModeSystemKeymapSeed (void)
154 static unsigned int seed
;
156 static KeyboardLayoutRef last_key_layout
;
157 KeyboardLayoutRef key_layout
;
159 KLGetCurrentKeyboardLayout (&key_layout
);
161 if (key_layout
!= last_key_layout
)
164 last_key_layout
= key_layout
;
169 static inline UniChar
170 macroman2ucs (unsigned char c
)
172 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
173 by creating single element CFStringRefs then extracting the
176 static const unsigned short table
[128] = {
177 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
178 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
179 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
180 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
181 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
182 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
183 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
184 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
185 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
186 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
187 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
188 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
189 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
190 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
191 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
192 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
198 return table
[c
- 128];
202 make_dead_key (KeySym in
)
206 for (i
= 0; i
< sizeof (dead_keys
) / sizeof (dead_keys
[0]); i
++)
208 if (dead_keys
[i
].normal
== in
)
209 return dead_keys
[i
].dead
;
216 DarwinModeReadSystemKeymap (darwinKeyboardInfo
*info
)
218 KeyboardLayoutRef key_layout
;
219 const void *chr_data
;
220 int num_keycodes
= NUM_KEYCODES
;
221 UInt32 keyboard_type
= 0;
226 KLGetCurrentKeyboardLayout (&key_layout
);
227 KLGetKeyboardLayoutProperty (key_layout
, kKLuchrData
, &chr_data
);
229 if (chr_data
!= NULL
)
232 keyboard_type
= LMGetKbdType ();
236 KLGetKeyboardLayoutProperty (key_layout
, kKLKCHRData
, &chr_data
);
238 if (chr_data
== NULL
)
240 ErrorF ( "Couldn't get uchr or kchr resource\n");
249 /* Scan the keycode range for the Unicode character that each
250 key produces in the four shift states. Then convert that to
251 an X11 keysym (which may just the bit that says "this is
252 Unicode" if it can't find the real symbol.) */
254 for (i
= 0; i
< num_keycodes
; i
++)
256 static const int mods
[4] = {0, MOD_SHIFT
, MOD_OPTION
,
257 MOD_OPTION
| MOD_SHIFT
};
259 k
= info
->keyMap
+ i
* GLYPHS_PER_KEY
;
261 for (j
= 0; j
< 4; j
++)
267 UInt32 dead_key_state
, extra_dead
;
270 err
= UCKeyTranslate (chr_data
, i
, kUCKeyActionDown
,
271 mods
[j
] >> 8, keyboard_type
, 0,
272 &dead_key_state
, 8, &len
, s
);
276 if (len
== 0 && dead_key_state
!= 0)
278 /* Found a dead key. Work out which one it is, but
279 remembering that it's dead. */
282 err
= UCKeyTranslate (chr_data
, i
, kUCKeyActionDown
,
283 mods
[j
] >> 8, keyboard_type
,
284 kUCKeyTranslateNoDeadKeysMask
,
285 &extra_dead
, 8, &len
, s
);
290 if (len
> 0 && s
[0] != 0x0010)
292 k
[j
] = ucs2keysym (s
[0]);
294 if (dead_key_state
!= 0)
295 k
[j
] = make_dead_key (k
[j
]);
304 c
= KeyTranslate (chr_data
, code
, &state
);
306 /* Dead keys are only processed on key-down, so ask
307 to translate those events. When we find a dead key,
308 translating the matching key up event will give
309 us the actual dead character. */
314 c
= KeyTranslate (chr_data
, code
| 128, &state2
);
317 /* Characters seem to be in MacRoman encoding. */
319 if (c
!= 0 && c
!= 0x0010)
321 k
[j
] = ucs2keysym (macroman2ucs (c
& 255));
324 k
[j
] = make_dead_key (k
[j
]);
335 if (k
[0] == k
[2] && k
[1] == k
[3])
336 k
[2] = k
[3] = NoSymbol
;
339 /* Fix up some things that are normally missing.. */
343 for (i
= 0; i
< sizeof (known_keys
) / sizeof (known_keys
[0]); i
++)
345 k
= info
->keyMap
+ known_keys
[i
].keycode
* GLYPHS_PER_KEY
;
347 if (k
[0] == NoSymbol
&& k
[1] == NoSymbol
348 && k
[2] == NoSymbol
&& k
[3] == NoSymbol
)
350 k
[0] = known_keys
[i
].keysym
;
355 /* And some more things. We find the right symbols for the numeric
356 keypad, but not the KP_ keysyms. So try to convert known keycodes. */
360 for (i
= 0; i
< sizeof (known_numeric_keys
)
361 / sizeof (known_numeric_keys
[0]); i
++)
363 k
= info
->keyMap
+ known_numeric_keys
[i
].keycode
* GLYPHS_PER_KEY
;
365 if (k
[0] == known_numeric_keys
[i
].normal
)
367 k
[0] = known_numeric_keys
[i
].keypad
;
375 #else /* !HAS_KL_API */
378 DarwinModeSystemKeymapSeed (void)
384 DarwinModeReadSystemKeymap (darwinKeyboardInfo
*info
)
389 #endif /* HAS_KL_API */