]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkkeys-quartz.c
70c9596bd67ecbc695a8a71c104668ef96796a69
[~andy/gtk] / gdk / quartz / gdkkeys-quartz.c
1 /* gdkkeys-quartz.c
2  *
3  * Copyright (C) 2000 Red Hat, Inc.
4  * Copyright (C) 2005 Imendio AB
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /* Some parts of this code come from quartzKeyboard.c,
22  * from the Apple X11 Server.
23  *
24  * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
25  *
26  *  Permission is hereby granted, free of charge, to any person
27  *  obtaining a copy of this software and associated documentation files
28  *  (the "Software"), to deal in the Software without restriction,
29  *  including without limitation the rights to use, copy, modify, merge,
30  *  publish, distribute, sublicense, and/or sell copies of the Software,
31  *  and to permit persons to whom the Software is furnished to do so,
32  *  subject to the following conditions:
33  *
34  *  The above copyright notice and this permission notice shall be
35  *  included in all copies or substantial portions of the Software.
36  *
37  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
40  *  NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
41  *  HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
42  *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
44  *  DEALINGS IN THE SOFTWARE.
45  *
46  *  Except as contained in this notice, the name(s) of the above
47  *  copyright holders shall not be used in advertising or otherwise to
48  *  promote the sale, use or other dealings in this Software without
49  *  prior written authorization.
50  */
51
52 #include "config.h"
53
54 #include <Carbon/Carbon.h>
55 #include <AppKit/NSEvent.h>
56 #include "gdk.h"
57 #include "gdkquartzkeys.h"
58 #include "gdkkeysprivate.h"
59 #include "gdkkeysyms.h"
60
61 #define NUM_KEYCODES 128
62 #define KEYVALS_PER_KEYCODE 4
63
64 static GdkKeymap *default_keymap = NULL;
65
66 struct _GdkQuartzKeymap
67 {
68   GdkKeymap keymap;
69 };
70
71 struct _GdkQuartzKeymapClass
72 {
73   GdkKeymapClass keymap_class;
74 };
75
76 G_DEFINE_TYPE (GdkQuartzKeymap, gdk_quartz_keymap, GDK_TYPE_KEYMAP)
77
78 GdkKeymap *
79 _gdk_quartz_display_get_keymap (GdkDisplay *display)
80 {
81   if (default_keymap == NULL)
82     default_keymap = g_object_new (gdk_quartz_keymap_get_type (), NULL);
83
84   return default_keymap;
85 }
86
87 /* Note: we could check only if building against the 10.5 SDK instead, but
88  * that would make non-xml layouts not work in 32-bit which would be a quite
89  * bad regression. This way, old unsupported layouts will just not work in
90  * 64-bit.
91  */
92 #ifdef __LP64__
93 static TISInputSourceRef current_layout = NULL;
94 #else
95 static KeyboardLayoutRef current_layout = NULL;
96 #endif
97
98 /* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
99  * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
100  */
101 static guint *keyval_array = NULL;
102
103 static inline UniChar
104 macroman2ucs (unsigned char c)
105 {
106   /* Precalculated table mapping MacRoman-128 to Unicode. Generated
107      by creating single element CFStringRefs then extracting the
108      first character. */
109   
110   static const unsigned short table[128] = {
111     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
112     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
113     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
114     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
115     0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
116     0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
117     0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
118     0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
119     0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
120     0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
121     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
122     0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
123     0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
124     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
125     0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
126     0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
127   };
128
129   if (c < 128)
130     return c;
131   else
132     return table[c - 128];
133 }
134
135 const static struct {
136   guint keycode;
137   guint keyval;
138   unsigned int modmask; /* So we can tell when a mod key is pressed/released */
139 } known_keys[] = {
140   {  54, GDK_KEY_Meta_R,    NSCommandKeyMask },
141   {  55, GDK_KEY_Meta_L,    NSCommandKeyMask },
142   {  56, GDK_KEY_Shift_L,   NSShiftKeyMask },
143   {  57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
144   {  58, GDK_KEY_Alt_L,     NSAlternateKeyMask },
145   {  59, GDK_KEY_Control_L, NSControlKeyMask },
146   {  60, GDK_KEY_Shift_R,   NSShiftKeyMask },
147   {  61, GDK_KEY_Alt_R,     NSAlternateKeyMask },
148   {  62, GDK_KEY_Control_R, NSControlKeyMask },
149   { 122, GDK_KEY_F1, 0 },
150   { 120, GDK_KEY_F2, 0 },
151   {  99, GDK_KEY_F3, 0 },
152   { 118, GDK_KEY_F4, 0 },
153   {  96, GDK_KEY_F5, 0 },
154   {  97, GDK_KEY_F6, 0 },
155   {  98, GDK_KEY_F7, 0 },
156   { 100, GDK_KEY_F8, 0 },
157   { 101, GDK_KEY_F9, 0 },
158   { 109, GDK_KEY_F10, 0 },
159   { 103, GDK_KEY_F11, 0 },
160   { 111, GDK_KEY_F12, 0 },
161   { 105, GDK_KEY_F13, 0 },
162   { 107, GDK_KEY_F14, 0 },
163   { 113, GDK_KEY_F15, 0 },
164   { 106, GDK_KEY_F16, 0 }
165 };
166
167 const static struct {
168   guint keycode;
169   guint normal_keyval, keypad_keyval;
170 } known_numeric_keys[] = {
171   { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
172   { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
173   { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
174   { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
175   { 76, 0x01000003, GDK_KEY_KP_Enter },
176   { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
177   { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
178   { 82, GDK_KEY_0, GDK_KEY_KP_0 },
179   { 83, GDK_KEY_1, GDK_KEY_KP_1 },
180   { 84, GDK_KEY_2, GDK_KEY_KP_2 },
181   { 85, GDK_KEY_3, GDK_KEY_KP_3 },
182   { 86, GDK_KEY_4, GDK_KEY_KP_4 },
183   { 87, GDK_KEY_5, GDK_KEY_KP_5 },
184   { 88, GDK_KEY_6, GDK_KEY_KP_6 },
185   { 89, GDK_KEY_7, GDK_KEY_KP_7 },
186   { 91, GDK_KEY_8, GDK_KEY_KP_8 },
187   { 92, GDK_KEY_9, GDK_KEY_KP_9 }
188 };
189
190 /* These values aren't covered by gdk_unicode_to_keyval */
191 const static struct {
192   gunichar ucs_value;
193   guint keyval;
194 } special_ucs_table [] = {
195   { 0x0001, GDK_KEY_Home },
196   { 0x0003, GDK_KEY_Return },
197   { 0x0004, GDK_KEY_End },
198   { 0x0008, GDK_KEY_BackSpace },
199   { 0x0009, GDK_KEY_Tab },
200   { 0x000b, GDK_KEY_Page_Up },
201   { 0x000c, GDK_KEY_Page_Down },
202   { 0x000d, GDK_KEY_Return },
203   { 0x001b, GDK_KEY_Escape },
204   { 0x001c, GDK_KEY_Left },
205   { 0x001d, GDK_KEY_Right },
206   { 0x001e, GDK_KEY_Up },
207   { 0x001f, GDK_KEY_Down },
208   { 0x007f, GDK_KEY_Delete },
209   { 0xf027, GDK_KEY_dead_acute },
210   { 0xf060, GDK_KEY_dead_grave },
211   { 0xf300, GDK_KEY_dead_grave },
212   { 0xf0b4, GDK_KEY_dead_acute },
213   { 0xf301, GDK_KEY_dead_acute },
214   { 0xf385, GDK_KEY_dead_acute },
215   { 0xf05e, GDK_KEY_dead_circumflex },
216   { 0xf2c6, GDK_KEY_dead_circumflex },
217   { 0xf302, GDK_KEY_dead_circumflex },
218   { 0xf07e, GDK_KEY_dead_tilde },
219   { 0xf303, GDK_KEY_dead_tilde },
220   { 0xf342, GDK_KEY_dead_perispomeni },
221   { 0xf0af, GDK_KEY_dead_macron },
222   { 0xf304, GDK_KEY_dead_macron },
223   { 0xf2d8, GDK_KEY_dead_breve },
224   { 0xf306, GDK_KEY_dead_breve },
225   { 0xf2d9, GDK_KEY_dead_abovedot },
226   { 0xf307, GDK_KEY_dead_abovedot },
227   { 0xf0a8, GDK_KEY_dead_diaeresis },
228   { 0xf308, GDK_KEY_dead_diaeresis },
229   { 0xf2da, GDK_KEY_dead_abovering },
230   { 0xf30A, GDK_KEY_dead_abovering },
231   { 0xf022, GDK_KEY_dead_doubleacute },
232   { 0xf2dd, GDK_KEY_dead_doubleacute },
233   { 0xf30B, GDK_KEY_dead_doubleacute },
234   { 0xf2c7, GDK_KEY_dead_caron },
235   { 0xf30C, GDK_KEY_dead_caron },
236   { 0xf0be, GDK_KEY_dead_cedilla },
237   { 0xf327, GDK_KEY_dead_cedilla },
238   { 0xf2db, GDK_KEY_dead_ogonek },
239   { 0xf328, GDK_KEY_dead_ogonek },
240   { 0xfe5d, GDK_KEY_dead_iota },
241   { 0xf323, GDK_KEY_dead_belowdot },
242   { 0xf309, GDK_KEY_dead_hook },
243   { 0xf31B, GDK_KEY_dead_horn },
244   { 0xf02d, GDK_KEY_dead_stroke },
245   { 0xf335, GDK_KEY_dead_stroke },
246   { 0xf336, GDK_KEY_dead_stroke },
247   { 0xf313, GDK_KEY_dead_abovecomma },
248   /*  { 0xf313, GDK_KEY_dead_psili }, */
249   { 0xf314, GDK_KEY_dead_abovereversedcomma },
250   /*  { 0xf314, GDK_KEY_dead_dasia }, */
251   { 0xf30F, GDK_KEY_dead_doublegrave },
252   { 0xf325, GDK_KEY_dead_belowring },
253   { 0xf2cd, GDK_KEY_dead_belowmacron },
254   { 0xf331, GDK_KEY_dead_belowmacron },
255   { 0xf32D, GDK_KEY_dead_belowcircumflex },
256   { 0xf330, GDK_KEY_dead_belowtilde },
257   { 0xf32E, GDK_KEY_dead_belowbreve },
258   { 0xf324, GDK_KEY_dead_belowdiaeresis },
259   { 0xf311, GDK_KEY_dead_invertedbreve },
260   { 0xf02c, GDK_KEY_dead_belowcomma },
261   { 0xf326, GDK_KEY_dead_belowcomma }
262 };
263
264 static void
265 maybe_update_keymap (void)
266 {
267   const void *chr_data = NULL;
268
269 #ifdef __LP64__
270   TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
271   CFDataRef layout_data_ref;
272
273 #else
274   KeyboardLayoutRef new_layout;
275   KeyboardLayoutKind layout_kind;
276
277   KLGetCurrentKeyboardLayout (&new_layout);
278 #endif
279
280   if (new_layout != current_layout)
281     {
282       guint *p;
283       int i;
284
285       g_free (keyval_array);
286       keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
287
288 #ifdef __LP64__
289       layout_data_ref = (CFDataRef) TISGetInputSourceProperty
290         (new_layout, kTISPropertyUnicodeKeyLayoutData);
291
292       if (layout_data_ref)
293         chr_data = CFDataGetBytePtr (layout_data_ref);
294
295       if (chr_data == NULL)
296         {
297           g_error ("cannot get keyboard layout data");
298           return;
299         }
300 #else
301       /* Get the layout kind */
302       KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
303
304       /* 8-bit-only keyabord layout */
305       if (layout_kind == kKLKCHRKind)
306         { 
307           /* Get chr data */
308           KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
309           
310           for (i = 0; i < NUM_KEYCODES; i++) 
311             {
312               int j;
313               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
314
315               p = keyval_array + i * KEYVALS_PER_KEYCODE;
316               
317               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
318                 {
319                   UInt32 c, state = 0;
320                   UInt16 key_code;
321                   UniChar uc;
322                   
323                   key_code = modifiers[j] | i;
324                   c = KeyTranslate (chr_data, key_code, &state);
325
326                   if (state != 0)
327                     {
328                       UInt32 state2 = 0;
329                       c = KeyTranslate (chr_data, key_code | 128, &state2);
330                     }
331
332                   if (c != 0 && c != 0x10)
333                     {
334                       int k;
335                       gboolean found = FALSE;
336
337                       /* FIXME: some keyboard layouts (e.g. Russian) use
338                        * a different 8-bit character set. We should
339                        * check for this. Not a serious problem, because
340                        * most (all?) of these layouts also have a
341                        * uchr version. 
342                        */
343                       uc = macroman2ucs (c);
344
345                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
346                         {
347                           if (special_ucs_table[k].ucs_value == uc)
348                             {
349                               p[j] = special_ucs_table[k].keyval;
350                               found = TRUE;
351                               break;
352                             }
353                         }
354                       
355                       /* Special-case shift-tab since GTK+ expects
356                        * GDK_KEY_ISO_Left_Tab for that.
357                        */
358                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
359                         p[j] = GDK_KEY_ISO_Left_Tab;
360
361                       if (!found)
362                         {
363                           guint tmp;
364                           
365                           tmp = gdk_unicode_to_keyval (uc);
366                           if (tmp != (uc | 0x01000000))
367                             p[j] = tmp;
368                           else
369                             p[j] = 0;
370                         }
371                     }
372                 }
373               
374               if (p[3] == p[2])
375                 p[3] = 0;
376               if (p[2] == p[1])
377                 p[2] = 0;
378               if (p[1] == p[0])
379                 p[1] = 0;
380               if (p[0] == p[2] && 
381                   p[1] == p[3])
382                 p[2] = p[3] = 0;
383             }
384         }
385       /* unicode keyboard layout */
386       else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
387         { 
388           /* Get chr data */
389           KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
390 #endif
391           
392           for (i = 0; i < NUM_KEYCODES; i++) 
393             {
394               int j;
395               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
396               UniChar chars[4];
397               UniCharCount nChars;
398
399               p = keyval_array + i * KEYVALS_PER_KEYCODE;
400
401               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
402                 {
403                   UInt32 state = 0;
404                   OSStatus err;
405                   UInt16 key_code;
406                   UniChar uc;
407                   
408                   key_code = modifiers[j] | i;
409                   err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
410                                         (modifiers[j] >> 8) & 0xFF,
411                                         LMGetKbdType(),
412                                         0,
413                                         &state, 4, &nChars, chars);
414
415
416                   /* FIXME: Theoretically, we can get multiple UTF-16 values;
417                    * we should convert them to proper unicode and figure
418                    * out whether there are really keyboard layouts that
419                    * give us more than one character for one keypress. */
420                   if (err == noErr && nChars == 1)
421                     {
422                       int k;
423                       gboolean found = FALSE;
424
425                       /* A few <Shift><Option>keys return two
426                        * characters, the first of which is U+00a0,
427                        * which isn't interesting; so we return the
428                        * second. More sophisticated handling is the
429                        * job of a GtkIMContext.
430                        *
431                        * If state isn't zero, it means that it's a
432                        * dead key of some sort. Some of those are
433                        * enumerated in the special_ucs_table with the
434                        * high nibble set to f to push it into the
435                        * private use range. Here we do the same.
436                        */
437                       if (state != 0)
438                         chars[nChars - 1] |= 0xf000;
439                       uc = chars[nChars - 1];
440
441                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
442                         {
443                           if (special_ucs_table[k].ucs_value == uc)
444                             {
445                               p[j] = special_ucs_table[k].keyval;
446                               found = TRUE;
447                               break;
448                             }
449                         }
450
451                       /* Special-case shift-tab since GTK+ expects
452                        * GDK_KEY_ISO_Left_Tab for that.
453                        */
454                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
455                         p[j] = GDK_KEY_ISO_Left_Tab;
456                       
457                       if (!found)
458                         {
459                           guint tmp;
460                           
461                           tmp = gdk_unicode_to_keyval (uc);
462                           if (tmp != (uc | 0x01000000))
463                             p[j] = tmp;
464                           else
465                             p[j] = 0;
466                         }
467                     }
468                 }
469               
470               if (p[3] == p[2])
471                 p[3] = 0;
472               if (p[2] == p[1])
473                 p[2] = 0;
474               if (p[1] == p[0])
475                 p[1] = 0;
476               if (p[0] == p[2] && 
477                   p[1] == p[3])
478                 p[2] = p[3] = 0;
479             }
480 #ifndef __LP64__
481         }
482       else
483         {
484           g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
485                    " - not supported right now");
486         }
487 #endif
488
489       for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
490         {
491           p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
492
493           if (p[0] == 0 && p[1] == 0 && 
494               p[2] == 0 && p[3] == 0)
495             p[0] = known_keys[i].keyval;
496         }
497
498       for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
499         {
500           p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
501
502           if (p[0] == known_numeric_keys[i].normal_keyval)
503             p[0] = known_numeric_keys[i].keypad_keyval;
504         }
505       
506       if (current_layout)
507         g_signal_emit_by_name (default_keymap, "keys_changed");
508
509       current_layout = new_layout;
510     }
511 }
512
513 static PangoDirection
514 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
515 {
516   return PANGO_DIRECTION_NEUTRAL;
517 }
518
519 static gboolean
520 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
521 {
522   /* FIXME: Can we implement this? */
523   return FALSE;
524 }
525
526 static gboolean
527 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
528 {
529   /* FIXME: Implement this. */
530   return FALSE;
531 }
532
533 static gboolean
534 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
535 {
536   /* FIXME: Implement this. */
537   return FALSE;
538 }
539
540 static gboolean
541 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
542                                           guint          keyval,
543                                           GdkKeymapKey **keys,
544                                           gint          *n_keys)
545 {
546   GArray *keys_array;
547   int i;
548
549   maybe_update_keymap ();
550
551   *n_keys = 0;
552   keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
553
554   for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
555     {
556       GdkKeymapKey key;
557
558       if (keyval_array[i] != keyval)
559         continue;
560
561       (*n_keys)++;
562
563       key.keycode = i / KEYVALS_PER_KEYCODE;
564       key.group = 0;
565       key.level = i % KEYVALS_PER_KEYCODE;
566
567       g_array_append_val (keys_array, key);
568     }
569
570   *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
571   
572   return *n_keys > 0;;
573 }
574
575 static gboolean
576 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
577                                            guint          hardware_keycode,
578                                            GdkKeymapKey **keys,
579                                            guint        **keyvals,
580                                            gint          *n_entries)
581 {
582   GArray *keys_array, *keyvals_array;
583   int i;
584   guint *p;
585
586   maybe_update_keymap ();
587
588   *n_entries = 0;
589
590   if (hardware_keycode > NUM_KEYCODES)
591     return FALSE;
592
593   if (keys)
594     keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
595   else
596     keys_array = NULL;
597
598   if (keyvals)
599     keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
600   else
601     keyvals_array = NULL;
602
603   p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
604   
605   for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
606     {
607       if (!p[i])
608         continue;
609
610       (*n_entries)++;
611       
612       if (keyvals_array)
613         g_array_append_val (keyvals_array, p[i]);
614
615       if (keys_array)
616         {
617           GdkKeymapKey key;
618
619           key.keycode = hardware_keycode;
620           key.group = i / 2;
621           key.level = i % 2;
622
623           g_array_append_val (keys_array, key);
624         }
625     }
626   
627   if (keys)
628     *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
629
630   if (keyvals)
631     *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
632
633   return *n_entries > 0;
634 }
635
636 static guint
637 gdk_quartz_keymap_lookup_key (GdkKeymap          *keymap,
638                               const GdkKeymapKey *key)
639 {
640   /* FIXME: Implement */
641
642   return 0;
643 }
644
645 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
646
647 static guint
648 translate_keysym (guint           hardware_keycode,
649                   gint            group,
650                   GdkModifierType state,
651                   gint           *effective_group,
652                   gint           *effective_level)
653 {
654   gint level;
655   guint tmp_keyval;
656
657   level = (state & GDK_SHIFT_MASK) ? 1 : 0;
658
659   if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
660       (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
661     group = 0;
662
663   if (!GET_KEYVAL (hardware_keycode, group, level) &&
664       GET_KEYVAL (hardware_keycode, group, 0))
665     level = 0;
666
667   tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
668
669   if (state & GDK_LOCK_MASK)
670     {
671       guint upper = gdk_keyval_to_upper (tmp_keyval);
672       if (upper != tmp_keyval)
673         tmp_keyval = upper;
674     }
675
676   return tmp_keyval;
677 }
678
679 static gboolean
680 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap       *keymap,
681                                             guint            hardware_keycode,
682                                             GdkModifierType  state,
683                                             gint             group,
684                                             guint           *keyval,
685                                             gint            *effective_group,
686                                             gint            *level,
687                                             GdkModifierType *consumed_modifiers)
688 {
689   guint tmp_keyval;
690   GdkModifierType bit;
691   guint tmp_modifiers = 0;
692
693   maybe_update_keymap ();
694
695   if (keyval)
696     *keyval = 0;
697   if (effective_group)
698     *effective_group = 0;
699   if (level)
700     *level = 0;
701   if (consumed_modifiers)
702     *consumed_modifiers = 0;
703
704   if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
705     return FALSE;
706   
707   /* Check if shift or capslock modify the keyval */
708   for (bit = GDK_SHIFT_MASK; bit < GDK_CONTROL_MASK; bit <<= 1)
709     {
710       if (translate_keysym (hardware_keycode, group, state & ~bit, NULL, NULL) !=
711           translate_keysym (hardware_keycode, group, state | bit, NULL, NULL))
712         tmp_modifiers |= bit;
713     }
714
715   tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
716
717   if (consumed_modifiers)
718     *consumed_modifiers = tmp_modifiers;
719
720   if (keyval)
721     *keyval = tmp_keyval; 
722
723   return TRUE;
724 }
725
726 static void
727 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
728                                          GdkModifierType *state)
729 {
730   /* FIXME: For now, we've mimiced the Windows backend. */
731 }
732
733 static gboolean
734 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
735                                          GdkModifierType *state)
736 {
737   /* FIXME: For now, we've mimiced the Windows backend. */
738   return TRUE;
739 }
740
741 /* What sort of key event is this? Returns one of
742  * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
743  */
744 GdkEventType
745 _gdk_quartz_keys_event_type (NSEvent *event)
746 {
747   unsigned short keycode;
748   unsigned int flags;
749   int i;
750   
751   switch ([event type])
752     {
753     case NSKeyDown:
754       return GDK_KEY_PRESS;
755     case NSKeyUp:
756       return GDK_KEY_RELEASE;
757     case NSFlagsChanged:
758       break;
759     default:
760       g_assert_not_reached ();
761     }
762   
763   /* For flags-changed events, we have to find the special key that caused the
764    * event, and see if it's in the modifier mask. */
765   keycode = [event keyCode];
766   flags = [event modifierFlags];
767   
768   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
769     {
770       if (known_keys[i].keycode == keycode)
771         {
772           if (flags & known_keys[i].modmask)
773             return GDK_KEY_PRESS;
774           else
775             return GDK_KEY_RELEASE;
776         }
777     }
778   
779   /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
780    * events for no good reason. Ignore them! */
781   return GDK_NOTHING;
782 }
783
784 gboolean
785 _gdk_quartz_keys_is_modifier (guint keycode)
786 {
787   gint i;
788   
789   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
790     {
791       if (known_keys[i].modmask == 0)
792         break;
793
794       if (known_keys[i].keycode == keycode)
795         return TRUE;
796     }
797
798   return FALSE;
799 }
800
801 static void
802 gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
803 {
804 }
805
806 static void
807 gdk_quartz_keymap_finalize (GObject *object)
808 {
809   G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
810 }
811
812 static void
813 gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
814 {
815   GObjectClass *object_class = G_OBJECT_CLASS (klass);
816   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
817
818   object_class->finalize = gdk_quartz_keymap_finalize;
819
820   keymap_class->get_direction = gdk_quartz_keymap_get_direction;
821   keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
822   keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
823   keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
824   keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
825   keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
826   keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
827   keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
828   keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
829   keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
830 }