1 /* darwin-old-keymap.c -- ugly code we need to keep around for now
2 
3    Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved.
4 
5    The code to parse the Darwin keymap is derived from dumpkeymap.c
6    by Eric Sunshine, which includes the following copyright:
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 #include "darwin.h"
34 #include "darwin-keyboard.h"
35 #include <errno.h>
36 #include <sys/stat.h>
37 #include <drivers/event_status_driver.h>
38 #include <IOKit/hidsystem/ev_keymap.h>
39 #include <architecture/byte_order.h>  // For the NXSwap*
40 
41 #define XK_TECHNICAL		// needed to get XK_Escape
42 #define XK_PUBLISHING
43 #include "keysym.h"
44 
45 static  FILE *fref = NULL;
46 static  char *inBuffer = NULL;
47 
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.
50 
51 #define UK(a)           NoSymbol	// unknown symbol
52 
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,
86 // 128
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,
91 // 144
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,
96 // 160
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,
101 							XK_guillemotleft,
102 	XK_leftanglebracket,
103 			XK_rightanglebracket,
104 					UK(filigature),	UK(flligature),
105 // 176
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,
111 							XK_guillemotright,
112 	XK_ellipsis,	UK(permille),	XK_notsign,	XK_questiondown,
113 // 192
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,
116 	XK_dead_diaeresis,
117 			XK_twosuperior,	XK_dead_abovering,
118 							XK_dead_cedilla,
119 	XK_threesuperior,
120 			XK_dead_doubleacute,
121 					XK_dead_ogonek,	XK_dead_caron,
122 // 208
123 	XK_emdash,	XK_plusminus,	XK_onequarter,	XK_onehalf,
124 	XK_threequarters,
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,
128 // 224
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,
133 // 240
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,
138   };
139 
140 #define MIN_SYMBOL		0xAC
141 static KeySym const symbol_to_x[] = {
142     XK_Left,        XK_Up,          XK_Right,      XK_Down
143   };
144 int const NUM_SYMBOL = sizeof(symbol_to_x) / sizeof(symbol_to_x[0]);
145 
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,
153     XK_F15
154   };
155 int const NUM_FUNCKEY = sizeof(funckey_to_x) / sizeof(funckey_to_x[0]);
156 
157 typedef struct {
158     KeySym		normalSym;
159     KeySym		keypadSym;
160 } darwinKeyPad_t;
161 
162 static darwinKeyPad_t const normal_to_keypad[] = {
163     { XK_0,         XK_KP_0 },
164     { XK_1,         XK_KP_1 },
165     { XK_2,         XK_KP_2 },
166     { XK_3,         XK_KP_3 },
167     { XK_4,         XK_KP_4 },
168     { XK_5,         XK_KP_5 },
169     { XK_6,         XK_KP_6 },
170     { XK_7,         XK_KP_7 },
171     { XK_8,         XK_KP_8 },
172     { XK_9,         XK_KP_9 },
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 }
180 };
181 int const NUM_KEYPAD = sizeof(normal_to_keypad) / sizeof(normal_to_keypad[0]);
182 
183 
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
190 {
191     unsigned char const *data;
192     unsigned char const *data_end;
193     short number_size;  // Size in bytes of a "number" in the stream.
194 } DataStream;
195 
new_data_stream(unsigned char const * data,int size)196 static DataStream* new_data_stream( unsigned char const* data, int size )
197 {
198     DataStream* s = (DataStream*)xalloc( sizeof(DataStream) );
199     s->data = data;
200     s->data_end = data + size;
201     s->number_size = 1; // Default to byte-sized numbers.
202     return s;
203 }
204 
destroy_data_stream(DataStream * s)205 static void destroy_data_stream( DataStream* s )
206 {
207     xfree(s);
208 }
209 
get_byte(DataStream * s)210 static unsigned char get_byte( DataStream* s )
211 {
212     assert(s->data + 1 <= s->data_end);
213     return *s->data++;
214 }
215 
get_word(DataStream * s)216 static short get_word( DataStream* s )
217 {
218     short hi, lo;
219     assert(s->data + 2 <= s->data_end);
220     hi = *s->data++;
221     lo = *s->data++;
222     return ((hi << 8) | lo);
223 }
224 
get_dword(DataStream * s)225 static int get_dword( DataStream* s )
226 {
227     int b1, b2, b3, b4;
228     assert(s->data + 4 <= s->data_end);
229     b4 = *s->data++;
230     b3 = *s->data++;
231     b2 = *s->data++;
232     b1 = *s->data++;
233     return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
234 }
235 
get_number(DataStream * s)236 static int get_number( DataStream* s )
237 {
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);
242     }
243 }
244 
245 
246 //-----------------------------------------------------------------------------
247 // Utility functions to help parse Darwin keymap
248 //-----------------------------------------------------------------------------
249 
250 /*
251  * bits_set
252  *      Calculate number of bits set in the modifier mask.
253  */
bits_set(short mask)254 static short bits_set( short mask )
255 {
256     short n = 0;
257 
258     for ( ; mask != 0; mask >>= 1)
259         if ((mask & 0x01) != 0)
260             n++;
261     return n;
262 }
263 
264 /*
265  * parse_next_char_code
266  *      Read the next character code from the Darwin keymapping
267  *      and write it to the X keymap.
268  */
parse_next_char_code(DataStream * s,KeySym * k)269 static void parse_next_char_code(
270     DataStream  *s,
271     KeySym      *k )
272 {
273     const short charSet = get_number(s);
274     const short charCode = get_number(s);
275 
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];
287     }
288 }
289 
290 /*
291  * DarwinReadKeymapFile
292  *      Read the appropriate keymapping from a keymapping file.
293  */
_DarwinReadKeymapFile(NXKeyMapping * keyMap)294 static Bool _DarwinReadKeymapFile(
295     NXKeyMapping        *keyMap)
296 {
297     struct stat         st;
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;
302     int                 *bufferEnd;
303     union km_tag {
304         int             *intP;
305         char            *charP;
306     } km;
307     char *filename;
308 
309     filename = DarwinFindLibraryFile (darwinKeymapFile, "Keyboards");
310     if (filename == NULL) {
311 	FatalError("Could not find keymapping file %s.\n", darwinKeymapFile);
312 	return FALSE;
313     }
314 
315     fref = fopen( filename, "rb" );
316     xfree (filename);
317 
318     if (fref == NULL) {
319         ErrorF("Unable to open keymapping file '%s' (errno %d).\n",
320                darwinKeymapFile, errno);
321         return FALSE;
322     }
323     if (fstat(fileno(fref), &st) == -1) {
324         ErrorF("Could not stat keymapping file '%s' (errno %d).\n",
325                darwinKeymapFile, errno);
326         return FALSE;
327     }
328 
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",
332                darwinKeymapFile);
333         return FALSE;
334     }
335 
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);
341         return FALSE;
342     }
343 
344     if (strncmp( inBuffer, "KYM1", 4 ) == 0) {
345         // Magic number OK.
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);
348         return FALSE;
349     } else {
350         ErrorF("Keymapping file '%s' has a bad magic number and cannot be used by XDarwin.\n", darwinKeymapFile);
351         return FALSE;
352     }
353 
354     // find the keyboard interface and handler id
355     {NXEventHandle hid;
356      NXEventSystemInfoType info_type;
357 
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);
363      if (!info_type) {
364 	 ErrorF("Error reading event status driver info.\n");
365 	 return FALSE;
366      }}
367 
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;
373 
374             interface = info[i].interface;
375             handler_id = info[i].id;
376 
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.
380 
381             do {
382                 km.charP = inBuffer;
383                 km.intP++;
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) {
390                             hasMatch = TRUE;
391                             break;
392                         } else {
393                             hasInterface = TRUE;
394                         }
395                     }
396                     km.charP += map_size;
397                 }
398             } while (hasInterface && !hasMatch);
399 
400             if (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);
405                 return TRUE;
406             }
407         } // if dev_id == keyboard device
408     } // foreach info struct
409 
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);
413     return FALSE;
414 }
415 
DarwinReadKeymapFile(NXKeyMapping * keyMap)416 static Bool DarwinReadKeymapFile(NXKeyMapping *keyMap)
417 {
418     Bool ret;
419 
420     ret = _DarwinReadKeymapFile (keyMap);
421 
422     if (inBuffer != NULL)
423 	xfree (inBuffer);
424     if (fref != NULL)
425 	fclose (fref);
426 
427     return ret;
428 }
429 
DarwinParseKeymapFile(darwin_keyboard_info * info)430 int DarwinParseKeymapFile (darwin_keyboard_info *info)
431 {
432     short numMods, numKeys, numPadKeys = 0;
433     NXKeyMapping keyMap;
434     DataStream *keyMapStream;
435     unsigned char const *numPadStart = 0;
436     Bool haveKeymap;
437     int i;
438     KeySym *k;
439 
440     if (darwinKeymapFile == NULL)
441 	return FALSE;
442 
443     haveKeymap = DarwinReadKeymapFile(&keyMap);
444     if (!haveKeymap) {
445 	ErrorF("Reverting to system keymapping.\n");
446 	return FALSE;
447     }
448 
449     keyMapStream = new_data_stream( (unsigned char const*)keyMap.mapping,
450                                     keyMap.size );
451 
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");
456     }
457 
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);
466 
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;
472         }
473 
474         while (numKeyCodes-- > 0) {
475             const short keyCode = get_number(keyMapStream);
476             if (charCode != NX_MODIFIERKEY_NUMERICPAD) {
477                 switch (charCode) {
478                     case NX_MODIFIERKEY_ALPHALOCK:
479                         info->key_map[keyCode * GLYPHS_PER_KEY] = XK_Caps_Lock;
480                         break;
481                     case NX_MODIFIERKEY_SHIFT:
482                         info->key_map[keyCode * GLYPHS_PER_KEY] =
483                                 (left ? XK_Shift_L : XK_Shift_R);
484                         break;
485                     case NX_MODIFIERKEY_CONTROL:
486                         info->key_map[keyCode * GLYPHS_PER_KEY] =
487                                 (left ? XK_Control_L : XK_Control_R);
488                         break;
489                     case NX_MODIFIERKEY_ALTERNATE:
490                         info->key_map[keyCode * GLYPHS_PER_KEY] =
491                                 (left ? XK_Alt_L : XK_Alt_R);
492                         break;
493                     case NX_MODIFIERKEY_COMMAND:
494                         info->key_map[keyCode * GLYPHS_PER_KEY] =
495                                 (left ? XK_Meta_L : XK_Meta_R);
496                         break;
497                     case NX_MODIFIERKEY_SECONDARYFN:
498                         info->key_map[keyCode * GLYPHS_PER_KEY] =
499                                 (left ? XK_Control_L : XK_Control_R);
500                         break;
501                     case NX_MODIFIERKEY_HELP:
502                         info->key_map[keyCode * GLYPHS_PER_KEY] = XK_Help;
503                         break;
504                 }
505             }
506             left = 0;
507         }
508     }
509 
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);
519 
520             // Record unmodified case
521             parse_next_char_code( keyMapStream, k );
522             numKeyCodes--;
523 
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 );
528                 numKeyCodes--;
529             }
530 
531             if (charGenMask & 0x02) {		// Shift
532                 parse_next_char_code( keyMapStream, k+1 );
533                 numKeyCodes--;
534 
535                 if (charGenMask & 0x01) {	// Shift-AlphaLock
536                     get_number(keyMapStream); get_number(keyMapStream);
537                     numKeyCodes--;
538                 }
539             }
540 
541             // Skip the Control cases
542             if (charGenMask & 0x04) {		// Control
543                 get_number(keyMapStream); get_number(keyMapStream);
544                 numKeyCodes--;
545 
546                 if (charGenMask & 0x01) {	// Control-AlphaLock
547                     get_number(keyMapStream); get_number(keyMapStream);
548                     numKeyCodes--;
549                 }
550 
551                 if (charGenMask & 0x02) {	// Control-Shift
552                     get_number(keyMapStream); get_number(keyMapStream);
553                     numKeyCodes--;
554 
555                     if (charGenMask & 0x01) {	// Shift-Control-AlphaLock
556                         get_number(keyMapStream); get_number(keyMapStream);
557                         numKeyCodes--;
558                     }
559                 }
560             }
561 
562             // Process Alt cases
563             if (charGenMask & 0x08) {		// Alt
564                 parse_next_char_code( keyMapStream, k+2 );
565                 numKeyCodes--;
566 
567                 if (charGenMask & 0x01) {	// Alt-AlphaLock
568                     parse_next_char_code( keyMapStream, k+3 );
569                     numKeyCodes--;
570                 }
571 
572                 if (charGenMask & 0x02) {	// Alt-Shift
573                     parse_next_char_code( keyMapStream, k+3 );
574                     numKeyCodes--;
575 
576                     if (charGenMask & 0x01) {	// Alt-Shift-AlphaLock
577                         get_number(keyMapStream); get_number(keyMapStream);
578                         numKeyCodes--;
579                     }
580                 }
581             }
582 
583             while (numKeyCodes-- > 0) {
584                 get_number(keyMapStream); get_number(keyMapStream);
585             }
586 
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;
591         }
592     }
593 
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;
603                 break;
604             }
605         }
606     }
607 
608     // free Darwin keyboard map
609     destroy_data_stream( keyMapStream );
610     xfree( keyMap.mapping );
611 
612     return TRUE;
613 }
614