Partially fix 1702760: stop compiler warning about valuenodedynamiclistinsertsmart...
[synfig.git] / synfig-osx / trunk / launcher / darwin-old-keymap.c
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
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
205 static void destroy_data_stream( DataStream* s )
206 {
207     xfree(s);
208 }
209
210 static unsigned char get_byte( DataStream* s )
211 {
212     assert(s->data + 1 <= s->data_end);
213     return *s->data++;
214 }
215
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
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
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  */
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  */
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  */
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
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
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 }