1 /* darwin-old-keymap.c -- ugly code we need to keep around for now
3 Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved.
5 The code to parse the Darwin keymap is derived from dumpkeymap.c
6 by Eric Sunshine, which includes the following copyright:
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 "darwin-keyboard.h"
37 #include <drivers/event_status_driver.h>
38 #include <IOKit/hidsystem/ev_keymap.h>
39 #include <architecture/byte_order.h> // For the NXSwap*
41 #define XK_TECHNICAL // needed to get XK_Escape
45 static FILE *fref = NULL;
46 static char *inBuffer = NULL;
48 // FIXME: It would be nice to support some of the extra keys in XF86keysym.h,
49 // at least the volume controls that now ship on every Apple keyboard.
51 #define UK(a) NoSymbol // unknown symbol
53 static KeySym const next_to_x[256] = {
54 NoSymbol, NoSymbol, NoSymbol, XK_KP_Enter,
55 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
56 XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
57 NoSymbol, XK_Return, NoSymbol, NoSymbol,
58 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
59 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
60 NoSymbol, NoSymbol, NoSymbol, XK_Escape,
61 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
62 XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
63 XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
64 XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
65 XK_comma, XK_minus, XK_period, XK_slash,
66 XK_0, XK_1, XK_2, XK_3,
67 XK_4, XK_5, XK_6, XK_7,
68 XK_8, XK_9, XK_colon, XK_semicolon,
69 XK_less, XK_equal, XK_greater, XK_question,
70 XK_at, XK_A, XK_B, XK_C,
71 XK_D, XK_E, XK_F, XK_G,
72 XK_H, XK_I, XK_J, XK_K,
73 XK_L, XK_M, XK_N, XK_O,
74 XK_P, XK_Q, XK_R, XK_S,
75 XK_T, XK_U, XK_V, XK_W,
76 XK_X, XK_Y, XK_Z, XK_bracketleft,
77 XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore,
78 XK_grave, XK_a, XK_b, XK_c,
79 XK_d, XK_e, XK_f, XK_g,
80 XK_h, XK_i, XK_j, XK_k,
81 XK_l, XK_m, XK_n, XK_o,
82 XK_p, XK_q, XK_r, XK_s,
83 XK_t, XK_u, XK_v, XK_w,
84 XK_x, XK_y, XK_z, XK_braceleft,
85 XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace,
87 NoSymbol, XK_Agrave, XK_Aacute, XK_Acircumflex,
88 XK_Atilde, XK_Adiaeresis, XK_Aring, XK_Ccedilla,
89 XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
90 XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
92 XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
93 XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_Ugrave,
94 XK_Uacute, XK_Ucircumflex, XK_Udiaeresis, XK_Yacute,
95 XK_THORN, XK_mu, XK_multiply, XK_division,
97 XK_copyright, XK_exclamdown, XK_cent, XK_sterling,
98 UK(fraction), XK_yen, UK(fhook), XK_section,
99 XK_currency, XK_rightsinglequotemark,
100 XK_leftdoublequotemark,
103 XK_rightanglebracket,
104 UK(filigature), UK(flligature),
106 XK_registered, XK_endash, XK_dagger, XK_doubledagger,
107 XK_periodcentered,XK_brokenbar, XK_paragraph, UK(bullet),
108 XK_singlelowquotemark,
109 XK_doublelowquotemark,
110 XK_rightdoublequotemark,
112 XK_ellipsis, UK(permille), XK_notsign, XK_questiondown,
114 XK_onesuperior, XK_dead_grave, XK_dead_acute, XK_dead_circumflex,
115 XK_dead_tilde, XK_dead_macron, XK_dead_breve, XK_dead_abovedot,
117 XK_twosuperior, XK_dead_abovering,
121 XK_dead_ogonek, XK_dead_caron,
123 XK_emdash, XK_plusminus, XK_onequarter, XK_onehalf,
125 XK_agrave, XK_aacute, XK_acircumflex,
126 XK_atilde, XK_adiaeresis, XK_aring, XK_ccedilla,
127 XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
129 XK_igrave, XK_AE, XK_iacute, XK_ordfeminine,
130 XK_icircumflex, XK_idiaeresis, XK_eth, XK_ntilde,
131 XK_Lstroke, XK_Ooblique, XK_OE, XK_masculine,
132 XK_ograve, XK_oacute, XK_ocircumflex, XK_otilde,
134 XK_odiaeresis, XK_ae, XK_ugrave, XK_uacute,
135 XK_ucircumflex, XK_idotless, XK_udiaeresis, XK_ygrave,
136 XK_lstroke, XK_ooblique, XK_oe, XK_ssharp,
137 XK_thorn, XK_ydiaeresis, NoSymbol, NoSymbol,
140 #define MIN_SYMBOL 0xAC
141 static KeySym const symbol_to_x[] = {
142 XK_Left, XK_Up, XK_Right, XK_Down
144 int const NUM_SYMBOL = sizeof(symbol_to_x) / sizeof(symbol_to_x[0]);
146 #define MIN_FUNCKEY 0x20
147 static KeySym const funckey_to_x[] = {
148 XK_F1, XK_F2, XK_F3, XK_F4,
149 XK_F5, XK_F6, XK_F7, XK_F8,
150 XK_F9, XK_F10, XK_F11, XK_F12,
151 XK_Insert, XK_Delete, XK_Home, XK_End,
152 XK_Page_Up, XK_Page_Down, XK_F13, XK_F14,
155 int const NUM_FUNCKEY = sizeof(funckey_to_x) / sizeof(funckey_to_x[0]);
162 static darwinKeyPad_t const normal_to_keypad[] = {
173 { XK_equal, XK_KP_Equal },
174 { XK_asterisk, XK_KP_Multiply },
175 { XK_plus, XK_KP_Add },
176 { XK_comma, XK_KP_Separator },
177 { XK_minus, XK_KP_Subtract },
178 { XK_period, XK_KP_Decimal },
179 { XK_slash, XK_KP_Divide }
181 int const NUM_KEYPAD = sizeof(normal_to_keypad) / sizeof(normal_to_keypad[0]);
184 //-----------------------------------------------------------------------------
185 // Data Stream Object
186 // Can be configured to treat embedded "numbers" as being composed of
187 // either 1, 2, or 4 bytes, apiece.
188 //-----------------------------------------------------------------------------
189 typedef struct _DataStream
191 unsigned char const *data;
192 unsigned char const *data_end;
193 short number_size; // Size in bytes of a "number" in the stream.
196 static DataStream* new_data_stream( unsigned char const* data, int size )
198 DataStream* s = (DataStream*)xalloc( sizeof(DataStream) );
200 s->data_end = data + size;
201 s->number_size = 1; // Default to byte-sized numbers.
205 static void destroy_data_stream( DataStream* s )
210 static unsigned char get_byte( DataStream* s )
212 assert(s->data + 1 <= s->data_end);
216 static short get_word( DataStream* s )
219 assert(s->data + 2 <= s->data_end);
222 return ((hi << 8) | lo);
225 static int get_dword( DataStream* s )
228 assert(s->data + 4 <= s->data_end);
233 return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
236 static int get_number( DataStream* s )
238 switch (s->number_size) {
239 case 4: return get_dword(s);
240 case 2: return get_word(s);
241 default: return get_byte(s);
246 //-----------------------------------------------------------------------------
247 // Utility functions to help parse Darwin keymap
248 //-----------------------------------------------------------------------------
252 * Calculate number of bits set in the modifier mask.
254 static short bits_set( short mask )
258 for ( ; mask != 0; mask >>= 1)
259 if ((mask & 0x01) != 0)
265 * parse_next_char_code
266 * Read the next character code from the Darwin keymapping
267 * and write it to the X keymap.
269 static void parse_next_char_code(
273 const short charSet = get_number(s);
274 const short charCode = get_number(s);
276 if (charSet == 0) { // ascii character
277 if (charCode >= 0 && charCode < 256)
278 *k = next_to_x[charCode];
279 } else if (charSet == 0x01) { // symbol character
280 if (charCode >= MIN_SYMBOL &&
281 charCode <= MIN_SYMBOL + NUM_SYMBOL)
282 *k = symbol_to_x[charCode - MIN_SYMBOL];
283 } else if (charSet == 0xFE) { // function key
284 if (charCode >= MIN_FUNCKEY &&
285 charCode <= MIN_FUNCKEY + NUM_FUNCKEY)
286 *k = funckey_to_x[charCode - MIN_FUNCKEY];
291 * DarwinReadKeymapFile
292 * Read the appropriate keymapping from a keymapping file.
294 static Bool _DarwinReadKeymapFile(
295 NXKeyMapping *keyMap)
298 NXEventSystemDevice info[20];
299 int interface = 0, handler_id = 0;
300 int map_interface, map_handler_id, map_size = 0;
301 unsigned int i, size;
309 filename = DarwinFindLibraryFile (darwinKeymapFile, "Keyboards");
310 if (filename == NULL) {
311 FatalError("Could not find keymapping file %s.\n", darwinKeymapFile);
315 fref = fopen( filename, "rb" );
319 ErrorF("Unable to open keymapping file '%s' (errno %d).\n",
320 darwinKeymapFile, errno);
323 if (fstat(fileno(fref), &st) == -1) {
324 ErrorF("Could not stat keymapping file '%s' (errno %d).\n",
325 darwinKeymapFile, errno);
329 // check to make sure we don't crash later
330 if (st.st_size <= 16*sizeof(int)) {
331 ErrorF("Keymapping file '%s' is invalid (too small).\n",
336 inBuffer = (char*) xalloc( st.st_size );
337 bufferEnd = (int *) (inBuffer + st.st_size);
338 if (fread(inBuffer, st.st_size, 1, fref) != 1) {
339 ErrorF("Could not read %qd bytes from keymapping file '%s' (errno %d).\n",
340 st.st_size, darwinKeymapFile, errno);
344 if (strncmp( inBuffer, "KYM1", 4 ) == 0) {
346 } else if (strncmp( inBuffer, "KYMP", 4 ) == 0) {
347 ErrorF("Keymapping file '%s' is intended for use with the original NeXT keyboards and cannot be used by XDarwin.\n", darwinKeymapFile);
350 ErrorF("Keymapping file '%s' has a bad magic number and cannot be used by XDarwin.\n", darwinKeymapFile);
354 // find the keyboard interface and handler id
356 NXEventSystemInfoType info_type;
358 size = sizeof( info ) / sizeof( int );
359 hid = NXOpenEventStatus ();
360 info_type = NXEventSystemInfo (hid, NX_EVS_DEVICE_INFO,
361 (int *) info, &size);
362 NXCloseEventStatus (hid);
364 ErrorF("Error reading event status driver info.\n");
368 size = size * sizeof( int ) / sizeof( info[0] );
369 for( i = 0; i < size; i++) {
370 if (info[i].dev_type == NX_EVS_DEVICE_TYPE_KEYBOARD) {
371 Bool hasInterface = FALSE;
372 Bool hasMatch = FALSE;
374 interface = info[i].interface;
375 handler_id = info[i].id;
377 // Find an appropriate keymapping:
378 // The first time we try to match both interface and handler_id.
379 // If we can't match both, we take the first match for interface.
384 while (km.intP+3 < bufferEnd) {
385 map_interface = NXSwapBigIntToHost(*(km.intP++));
386 map_handler_id = NXSwapBigIntToHost(*(km.intP++));
387 map_size = NXSwapBigIntToHost(*(km.intP++));
388 if (map_interface == interface) {
389 if (map_handler_id == handler_id || hasInterface) {
396 km.charP += map_size;
398 } while (hasInterface && !hasMatch);
401 // fill in NXKeyMapping structure
402 keyMap->size = map_size;
403 keyMap->mapping = (char*) xalloc(map_size);
404 memcpy(keyMap->mapping, km.charP, map_size);
407 } // if dev_id == keyboard device
408 } // foreach info struct
410 // The keymapping file didn't match any of the info structs
411 // returned by NXEventSystemInfo.
412 ErrorF("Keymapping file '%s' did not contain appropriate keyboard interface.\n", darwinKeymapFile);
416 static Bool DarwinReadKeymapFile(NXKeyMapping *keyMap)
420 ret = _DarwinReadKeymapFile (keyMap);
422 if (inBuffer != NULL)
430 int DarwinParseKeymapFile (darwin_keyboard_info *info)
432 short numMods, numKeys, numPadKeys = 0;
434 DataStream *keyMapStream;
435 unsigned char const *numPadStart = 0;
440 if (darwinKeymapFile == NULL)
443 haveKeymap = DarwinReadKeymapFile(&keyMap);
445 ErrorF("Reverting to system keymapping.\n");
449 keyMapStream = new_data_stream( (unsigned char const*)keyMap.mapping,
452 // check the type of map
453 if (get_word(keyMapStream)) {
454 keyMapStream->number_size = 2;
455 ErrorF("Current 16-bit keymapping may not be interpreted correctly.\n");
458 // Compute the modifier map and
459 // insert X modifier KeySyms into keyboard map.
460 // Store modifier keycodes in modifierKeycodes.
461 numMods = get_number(keyMapStream);
462 while (numMods-- > 0) {
463 int left = 1; // first keycode is left
464 short const charCode = get_number(keyMapStream);
465 short numKeyCodes = get_number(keyMapStream);
467 // This is just a marker, not a real modifier.
468 // Store numeric keypad keys for later.
469 if (charCode == NX_MODIFIERKEY_NUMERICPAD) {
470 numPadStart = keyMapStream->data;
471 numPadKeys = numKeyCodes;
474 while (numKeyCodes-- > 0) {
475 const short keyCode = get_number(keyMapStream);
476 if (charCode != NX_MODIFIERKEY_NUMERICPAD) {
478 case NX_MODIFIERKEY_ALPHALOCK:
479 info->key_map[keyCode * GLYPHS_PER_KEY] = XK_Caps_Lock;
481 case NX_MODIFIERKEY_SHIFT:
482 info->key_map[keyCode * GLYPHS_PER_KEY] =
483 (left ? XK_Shift_L : XK_Shift_R);
485 case NX_MODIFIERKEY_CONTROL:
486 info->key_map[keyCode * GLYPHS_PER_KEY] =
487 (left ? XK_Control_L : XK_Control_R);
489 case NX_MODIFIERKEY_ALTERNATE:
490 info->key_map[keyCode * GLYPHS_PER_KEY] =
491 (left ? XK_Alt_L : XK_Alt_R);
493 case NX_MODIFIERKEY_COMMAND:
494 info->key_map[keyCode * GLYPHS_PER_KEY] =
495 (left ? XK_Meta_L : XK_Meta_R);
497 case NX_MODIFIERKEY_SECONDARYFN:
498 info->key_map[keyCode * GLYPHS_PER_KEY] =
499 (left ? XK_Control_L : XK_Control_R);
501 case NX_MODIFIERKEY_HELP:
502 info->key_map[keyCode * GLYPHS_PER_KEY] = XK_Help;
510 // Convert the Darwin keyboard map to an X keyboard map.
511 // A key can have a different character code for each combination of
512 // modifiers. We currently ignore all modifier combinations except
513 // those with Shift, AlphaLock, and Alt.
514 numKeys = get_number(keyMapStream);
515 for (i = 0, k = info->key_map; i < numKeys; i++, k += GLYPHS_PER_KEY) {
516 short const charGenMask = get_number(keyMapStream);
517 if (charGenMask != 0xFF) { // is key bound?
518 short numKeyCodes = 1 << bits_set(charGenMask);
520 // Record unmodified case
521 parse_next_char_code( keyMapStream, k );
524 // If AlphaLock and Shift modifiers produce different codes,
525 // we record the Shift case since X handles AlphaLock.
526 if (charGenMask & 0x01) { // AlphaLock
527 parse_next_char_code( keyMapStream, k+1 );
531 if (charGenMask & 0x02) { // Shift
532 parse_next_char_code( keyMapStream, k+1 );
535 if (charGenMask & 0x01) { // Shift-AlphaLock
536 get_number(keyMapStream); get_number(keyMapStream);
541 // Skip the Control cases
542 if (charGenMask & 0x04) { // Control
543 get_number(keyMapStream); get_number(keyMapStream);
546 if (charGenMask & 0x01) { // Control-AlphaLock
547 get_number(keyMapStream); get_number(keyMapStream);
551 if (charGenMask & 0x02) { // Control-Shift
552 get_number(keyMapStream); get_number(keyMapStream);
555 if (charGenMask & 0x01) { // Shift-Control-AlphaLock
556 get_number(keyMapStream); get_number(keyMapStream);
563 if (charGenMask & 0x08) { // Alt
564 parse_next_char_code( keyMapStream, k+2 );
567 if (charGenMask & 0x01) { // Alt-AlphaLock
568 parse_next_char_code( keyMapStream, k+3 );
572 if (charGenMask & 0x02) { // Alt-Shift
573 parse_next_char_code( keyMapStream, k+3 );
576 if (charGenMask & 0x01) { // Alt-Shift-AlphaLock
577 get_number(keyMapStream); get_number(keyMapStream);
583 while (numKeyCodes-- > 0) {
584 get_number(keyMapStream); get_number(keyMapStream);
587 if (k[3] == k[2]) k[3] = NoSymbol;
588 if (k[2] == k[1]) k[2] = NoSymbol;
589 if (k[1] == k[0]) k[1] = NoSymbol;
590 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
594 // Now we have to go back through the list of keycodes that are on the
595 // numeric keypad and update the X keymap.
596 keyMapStream->data = numPadStart;
597 while(numPadKeys-- > 0) {
598 const short keyCode = get_number(keyMapStream);
599 k = &info->key_map[keyCode * GLYPHS_PER_KEY];
600 for (i = 0; i < NUM_KEYPAD; i++) {
601 if (*k == normal_to_keypad[i].normalSym) {
602 k[0] = normal_to_keypad[i].keypadSym;
608 // free Darwin keyboard map
609 destroy_data_stream( keyMapStream );
610 xfree( keyMap.mapping );