]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkkeys-quartz.c
81765f41c42113b4409108da264e61ee60a5841d
[~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 "gdkkeysprivate.h"
58 #include "gdkkeysyms.h"
59
60 #define NUM_KEYCODES 128
61 #define KEYVALS_PER_KEYCODE 4
62
63 static GdkKeymap *default_keymap = NULL;
64
65
66 #define GDK_TYPE_QUARTZ_KEYMAP              (gdk_quartz_keymap_get_type ())
67 #define GDK_QUARTZ_KEYMAP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymap))
68 #define GDK_QUARTZ_KEYMAP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
69 #define GDK_IS_QUARTZ_KEYMAP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_KEYMAP))
70 #define GDK_IS_QUARTZ_KEYMAP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_KEYMAP))
71 #define GDK_QUARTZ_KEYMAP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
72
73 typedef struct _GdkQuartzKeymap GdkQuartzKeymap;
74 typedef struct _GdkQuartzKeymapClass GdkQuartzKeymapClass;
75
76 struct _GdkQuartzKeymap
77 {
78   GdkKeymap keymap;
79 };
80
81 struct _GdkQuartzKeymapClass
82 {
83   GdkKeymapClass keymap_class;
84 };
85
86 G_DEFINE_TYPE (GdkQuartzKeymap, _gdk_quartz_keymap, GDK_TYPE_KEYMAP)
87
88 GdkKeymap *
89 _gdk_quartz_display_get_keymap (GdkDisplay *display)
90 {
91   if (default_keymap == NULL)
92     default_keymap = g_object_new (_gdk_quartz_keymap_get_type (), NULL);
93
94   return default_keymap;
95 }
96
97 /* Note: we could check only if building against the 10.5 SDK instead, but
98  * that would make non-xml layouts not work in 32-bit which would be a quite
99  * bad regression. This way, old unsupported layouts will just not work in
100  * 64-bit.
101  */
102 #ifdef __LP64__
103 static TISInputSourceRef current_layout = NULL;
104 #else
105 static KeyboardLayoutRef current_layout = NULL;
106 #endif
107
108 /* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
109  * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
110  */
111 static guint *keyval_array = NULL;
112
113 static inline UniChar
114 macroman2ucs (unsigned char c)
115 {
116   /* Precalculated table mapping MacRoman-128 to Unicode. Generated
117      by creating single element CFStringRefs then extracting the
118      first character. */
119   
120   static const unsigned short table[128] = {
121     0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
122     0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
123     0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
124     0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
125     0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
126     0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
127     0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
128     0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
129     0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
130     0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
131     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
132     0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
133     0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
134     0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
135     0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
136     0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
137   };
138
139   if (c < 128)
140     return c;
141   else
142     return table[c - 128];
143 }
144
145 const static struct {
146   guint keycode;
147   guint keyval;
148   unsigned int modmask; /* So we can tell when a mod key is pressed/released */
149 } known_keys[] = {
150   {  54, GDK_KEY_Meta_R,    NSCommandKeyMask },
151   {  55, GDK_KEY_Meta_L,    NSCommandKeyMask },
152   {  56, GDK_KEY_Shift_L,   NSShiftKeyMask },
153   {  57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
154   {  58, GDK_KEY_Alt_L,     NSAlternateKeyMask },
155   {  59, GDK_KEY_Control_L, NSControlKeyMask },
156   {  60, GDK_KEY_Shift_R,   NSShiftKeyMask },
157   {  61, GDK_KEY_Alt_R,     NSAlternateKeyMask },
158   {  62, GDK_KEY_Control_R, NSControlKeyMask },
159   { 122, GDK_KEY_F1, 0 },
160   { 120, GDK_KEY_F2, 0 },
161   {  99, GDK_KEY_F3, 0 },
162   { 118, GDK_KEY_F4, 0 },
163   {  96, GDK_KEY_F5, 0 },
164   {  97, GDK_KEY_F6, 0 },
165   {  98, GDK_KEY_F7, 0 },
166   { 100, GDK_KEY_F8, 0 },
167   { 101, GDK_KEY_F9, 0 },
168   { 109, GDK_KEY_F10, 0 },
169   { 103, GDK_KEY_F11, 0 },
170   { 111, GDK_KEY_F12, 0 },
171   { 105, GDK_KEY_F13, 0 },
172   { 107, GDK_KEY_F14, 0 },
173   { 113, GDK_KEY_F15, 0 },
174   { 106, GDK_KEY_F16, 0 }
175 };
176
177 const static struct {
178   guint keycode;
179   guint normal_keyval, keypad_keyval;
180 } known_numeric_keys[] = {
181   { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
182   { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
183   { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
184   { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
185   { 76, 0x01000003, GDK_KEY_KP_Enter },
186   { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
187   { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
188   { 82, GDK_KEY_0, GDK_KEY_KP_0 },
189   { 83, GDK_KEY_1, GDK_KEY_KP_1 },
190   { 84, GDK_KEY_2, GDK_KEY_KP_2 },
191   { 85, GDK_KEY_3, GDK_KEY_KP_3 },
192   { 86, GDK_KEY_4, GDK_KEY_KP_4 },
193   { 87, GDK_KEY_5, GDK_KEY_KP_5 },
194   { 88, GDK_KEY_6, GDK_KEY_KP_6 },
195   { 89, GDK_KEY_7, GDK_KEY_KP_7 },
196   { 91, GDK_KEY_8, GDK_KEY_KP_8 },
197   { 92, GDK_KEY_9, GDK_KEY_KP_9 }
198 };
199
200 /* These values aren't covered by gdk_unicode_to_keyval */
201 const static struct {
202   gunichar ucs_value;
203   guint keyval;
204 } special_ucs_table [] = {
205   { 0x0001, GDK_KEY_Home },
206   { 0x0003, GDK_KEY_Return },
207   { 0x0004, GDK_KEY_End },
208   { 0x0008, GDK_KEY_BackSpace },
209   { 0x0009, GDK_KEY_Tab },
210   { 0x000b, GDK_KEY_Page_Up },
211   { 0x000c, GDK_KEY_Page_Down },
212   { 0x000d, GDK_KEY_Return },
213   { 0x001b, GDK_KEY_Escape },
214   { 0x001c, GDK_KEY_Left },
215   { 0x001d, GDK_KEY_Right },
216   { 0x001e, GDK_KEY_Up },
217   { 0x001f, GDK_KEY_Down },
218   { 0x007f, GDK_KEY_Delete }
219 };
220
221 static void
222 maybe_update_keymap (void)
223 {
224   const void *chr_data = NULL;
225
226 #ifdef __LP64__
227   TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
228   CFDataRef layout_data_ref;
229
230 #else
231   KeyboardLayoutRef new_layout;
232   KeyboardLayoutKind layout_kind;
233
234   KLGetCurrentKeyboardLayout (&new_layout);
235 #endif
236
237   if (new_layout != current_layout)
238     {
239       guint *p;
240       int i;
241
242       g_free (keyval_array);
243       keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
244
245 #ifdef __LP64__
246       layout_data_ref = (CFDataRef) TISGetInputSourceProperty
247         (new_layout, kTISPropertyUnicodeKeyLayoutData);
248
249       if (layout_data_ref)
250         chr_data = CFDataGetBytePtr (layout_data_ref);
251
252       if (chr_data == NULL)
253         {
254           g_error ("cannot get keyboard layout data");
255           return;
256         }
257 #else
258       /* Get the layout kind */
259       KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
260
261       /* 8-bit-only keyabord layout */
262       if (layout_kind == kKLKCHRKind)
263         { 
264           /* Get chr data */
265           KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
266           
267           for (i = 0; i < NUM_KEYCODES; i++) 
268             {
269               int j;
270               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
271
272               p = keyval_array + i * KEYVALS_PER_KEYCODE;
273               
274               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
275                 {
276                   UInt32 c, state = 0;
277                   UInt16 key_code;
278                   UniChar uc;
279                   
280                   key_code = modifiers[j] | i;
281                   c = KeyTranslate (chr_data, key_code, &state);
282
283                   if (state != 0)
284                     {
285                       UInt32 state2 = 0;
286                       c = KeyTranslate (chr_data, key_code | 128, &state2);
287                     }
288
289                   if (c != 0 && c != 0x10)
290                     {
291                       int k;
292                       gboolean found = FALSE;
293
294                       /* FIXME: some keyboard layouts (e.g. Russian) use
295                        * a different 8-bit character set. We should
296                        * check for this. Not a serious problem, because
297                        * most (all?) of these layouts also have a
298                        * uchr version. 
299                        */
300                       uc = macroman2ucs (c);
301
302                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
303                         {
304                           if (special_ucs_table[k].ucs_value == uc)
305                             {
306                               p[j] = special_ucs_table[k].keyval;
307                               found = TRUE;
308                               break;
309                             }
310                         }
311                       
312                       /* Special-case shift-tab since GTK+ expects
313                        * GDK_KEY_ISO_Left_Tab for that.
314                        */
315                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
316                         p[j] = GDK_KEY_ISO_Left_Tab;
317
318                       if (!found)
319                         {
320                           guint tmp;
321                           
322                           tmp = gdk_unicode_to_keyval (uc);
323                           if (tmp != (uc | 0x01000000))
324                             p[j] = tmp;
325                           else
326                             p[j] = 0;
327                         }
328                     }
329                 }
330               
331               if (p[3] == p[2])
332                 p[3] = 0;
333               if (p[2] == p[1])
334                 p[2] = 0;
335               if (p[1] == p[0])
336                 p[1] = 0;
337               if (p[0] == p[2] && 
338                   p[1] == p[3])
339                 p[2] = p[3] = 0;
340             }
341         }
342       /* unicode keyboard layout */
343       else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
344         { 
345           /* Get chr data */
346           KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
347 #endif
348           
349           for (i = 0; i < NUM_KEYCODES; i++) 
350             {
351               int j;
352               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
353               UniChar chars[4];
354               UniCharCount nChars;
355
356               p = keyval_array + i * KEYVALS_PER_KEYCODE;
357
358               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
359                 {
360                   UInt32 state = 0;
361                   OSStatus err;
362                   UInt16 key_code;
363                   UniChar uc;
364                   
365                   key_code = modifiers[j] | i;
366                   err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
367                                         (modifiers[j] >> 8) & 0xFF,
368                                         LMGetKbdType(),
369                                         kUCKeyTranslateNoDeadKeysMask,
370                                         &state, 4, &nChars, chars);
371
372
373                   /* FIXME: Theoretically, we can get multiple UTF-16 values;
374                    * we should convert them to proper unicode and figure
375                    * out whether there are really keyboard layouts that
376                    * give us more than one character for one keypress. */
377                   if (err == noErr && nChars == 1)
378                     {
379                       int k;
380                       gboolean found = FALSE;
381                       
382                       uc = chars[0];
383
384                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
385                         {
386                           if (special_ucs_table[k].ucs_value == uc)
387                             {
388                               p[j] = special_ucs_table[k].keyval;
389                               found = TRUE;
390                               break;
391                             }
392                         }
393
394                       /* Special-case shift-tab since GTK+ expects
395                        * GDK_KEY_ISO_Left_Tab for that.
396                        */
397                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
398                         p[j] = GDK_KEY_ISO_Left_Tab;
399                       
400                       if (!found)
401                         {
402                           guint tmp;
403                           
404                           tmp = gdk_unicode_to_keyval (uc);
405                           if (tmp != (uc | 0x01000000))
406                             p[j] = tmp;
407                           else
408                             p[j] = 0;
409                         }
410                     }
411                 }
412               
413               if (p[3] == p[2])
414                 p[3] = 0;
415               if (p[2] == p[1])
416                 p[2] = 0;
417               if (p[1] == p[0])
418                 p[1] = 0;
419               if (p[0] == p[2] && 
420                   p[1] == p[3])
421                 p[2] = p[3] = 0;
422             }
423 #ifndef __LP64__
424         }
425       else
426         {
427           g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
428                    " - not supported right now");
429         }
430 #endif
431
432       for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
433         {
434           p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
435
436           if (p[0] == 0 && p[1] == 0 && 
437               p[2] == 0 && p[3] == 0)
438             p[0] = known_keys[i].keyval;
439         }
440
441       for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
442         {
443           p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
444
445           if (p[0] == known_numeric_keys[i].normal_keyval)
446             p[0] = known_numeric_keys[i].keypad_keyval;
447         }
448       
449       if (current_layout)
450         g_signal_emit_by_name (default_keymap, "keys_changed");
451
452       current_layout = new_layout;
453     }
454 }
455
456 GdkKeymap *
457 gdk_keymap_get_for_display (GdkDisplay *display)
458 {
459   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
460
461   if (default_keymap == NULL)
462     default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
463
464   return default_keymap;
465 }
466
467 static PangoDirection
468 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
469 {
470   return PANGO_DIRECTION_NEUTRAL;
471 }
472
473 static gboolean
474 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
475 {
476   /* FIXME: Can we implement this? */
477   return FALSE;
478 }
479
480 static gboolean
481 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
482 {
483   /* FIXME: Implement this. */
484   return FALSE;
485 }
486
487 static gboolean
488 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
489 {
490   /* FIXME: Implement this. */
491   return FALSE;
492 }
493
494 static gboolean
495 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
496                                           guint          keyval,
497                                           GdkKeymapKey **keys,
498                                           gint          *n_keys)
499 {
500   GArray *keys_array;
501   int i;
502
503   maybe_update_keymap ();
504
505   *n_keys = 0;
506   keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
507
508   for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
509     {
510       GdkKeymapKey key;
511
512       if (keyval_array[i] != keyval)
513         continue;
514
515       (*n_keys)++;
516
517       key.keycode = i / KEYVALS_PER_KEYCODE;
518       key.group = 0;
519       key.level = i % KEYVALS_PER_KEYCODE;
520
521       g_array_append_val (keys_array, key);
522     }
523
524   *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
525   
526   return *n_keys > 0;;
527 }
528
529 static gboolean
530 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
531                                            guint          hardware_keycode,
532                                            GdkKeymapKey **keys,
533                                            guint        **keyvals,
534                                            gint          *n_entries)
535 {
536   GArray *keys_array, *keyvals_array;
537   int i;
538   guint *p;
539
540   maybe_update_keymap ();
541
542   *n_entries = 0;
543
544   if (hardware_keycode > NUM_KEYCODES)
545     return FALSE;
546
547   if (keys)
548     keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
549   else
550     keys_array = NULL;
551
552   if (keyvals)
553     keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
554   else
555     keyvals_array = NULL;
556
557   p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
558   
559   for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
560     {
561       if (!p[i])
562         continue;
563
564       (*n_entries)++;
565       
566       if (keyvals_array)
567         g_array_append_val (keyvals_array, p[i]);
568
569       if (keys_array)
570         {
571           GdkKeymapKey key;
572
573           key.keycode = hardware_keycode;
574           key.group = i / 2;
575           key.level = i % 2;
576
577           g_array_append_val (keys_array, key);
578         }
579     }
580   
581   if (keys)
582     *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
583
584   if (keyvals)
585     *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
586
587   return *n_entries > 0;
588 }
589
590 static guint
591 gdk_quartz_keymap_lookup_key (GdkKeymap          *keymap,
592                               const GdkKeymapKey *key)
593 {
594   /* FIXME: Implement */
595
596   return 0;
597 }
598
599 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
600
601 static guint
602 translate_keysym (guint           hardware_keycode,
603                   gint            group,
604                   GdkModifierType state,
605                   gint           *effective_group,
606                   gint           *effective_level)
607 {
608   gint level;
609   guint tmp_keyval;
610
611   level = (state & GDK_SHIFT_MASK) ? 1 : 0;
612
613   if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
614       (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
615     group = 0;
616
617   if (!GET_KEYVAL (hardware_keycode, group, level) &&
618       GET_KEYVAL (hardware_keycode, group, 0))
619     level = 0;
620
621   tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
622
623   if (state & GDK_LOCK_MASK)
624     {
625       guint upper = gdk_keyval_to_upper (tmp_keyval);
626       if (upper != tmp_keyval)
627         tmp_keyval = upper;
628     }
629
630   return tmp_keyval;
631 }
632
633 static gboolean
634 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap       *keymap,
635                                             guint            hardware_keycode,
636                                             GdkModifierType  state,
637                                             gint             group,
638                                             guint           *keyval,
639                                             gint            *effective_group,
640                                             gint            *level,
641                                             GdkModifierType *consumed_modifiers)
642 {
643   guint tmp_keyval;
644   GdkModifierType bit;
645   guint tmp_modifiers = 0;
646
647   maybe_update_keymap ();
648
649   if (keyval)
650     *keyval = 0;
651   if (effective_group)
652     *effective_group = 0;
653   if (level)
654     *level = 0;
655   if (consumed_modifiers)
656     *consumed_modifiers = 0;
657
658   if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
659     return FALSE;
660   
661   /* Check if shift or capslock modify the keyval */
662   for (bit = GDK_SHIFT_MASK; bit < GDK_CONTROL_MASK; bit <<= 1)
663     {
664       if (translate_keysym (hardware_keycode, group, state & ~bit, NULL, NULL) !=
665           translate_keysym (hardware_keycode, group, state | bit, NULL, NULL))
666         tmp_modifiers |= bit;
667     }
668
669   tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
670
671   if (consumed_modifiers)
672     *consumed_modifiers = tmp_modifiers;
673
674   if (keyval)
675     *keyval = tmp_keyval; 
676
677   return TRUE;
678 }
679
680 static void
681 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
682                                          GdkModifierType *state)
683 {
684   /* FIXME: For now, we've mimiced the Windows backend. */
685 }
686
687 static gboolean
688 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
689                                          GdkModifierType *state)
690 {
691   /* FIXME: For now, we've mimiced the Windows backend. */
692   return TRUE;
693 }
694
695 /* What sort of key event is this? Returns one of
696  * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
697  */
698 GdkEventType
699 _gdk_quartz_keys_event_type (NSEvent *event)
700 {
701   unsigned short keycode;
702   unsigned int flags;
703   int i;
704   
705   switch ([event type])
706     {
707     case NSKeyDown:
708       return GDK_KEY_PRESS;
709     case NSKeyUp:
710       return GDK_KEY_RELEASE;
711     case NSFlagsChanged:
712       break;
713     default:
714       g_assert_not_reached ();
715     }
716   
717   /* For flags-changed events, we have to find the special key that caused the
718    * event, and see if it's in the modifier mask. */
719   keycode = [event keyCode];
720   flags = [event modifierFlags];
721   
722   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
723     {
724       if (known_keys[i].keycode == keycode)
725         {
726           if (flags & known_keys[i].modmask)
727             return GDK_KEY_PRESS;
728           else
729             return GDK_KEY_RELEASE;
730         }
731     }
732   
733   /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
734    * events for no good reason. Ignore them! */
735   return GDK_NOTHING;
736 }
737
738 gboolean
739 _gdk_quartz_keys_is_modifier (guint keycode)
740 {
741   gint i;
742   
743   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
744     {
745       if (known_keys[i].modmask == 0)
746         break;
747
748       if (known_keys[i].keycode == keycode)
749         return TRUE;
750     }
751
752   return FALSE;
753 }
754
755 static void
756 _gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
757 {
758 }
759
760 static void
761 _gdk_quartz_keymap_finalize (GObject *object)
762 {
763   G_OBJECT_CLASS (_gdk_quartz_keymap_parent_class)->finalize (object);
764 }
765
766 static void
767 _gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
768 {
769   GObjectClass *object_class = G_OBJECT_CLASS (klass);
770   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
771
772   object_class->finalize = _gdk_quartz_keymap_finalize;
773
774   keymap_class->get_direction = gdk_quartz_keymap_get_direction;
775   keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
776   keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
777   keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
778   keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
779   keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
780   keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
781   keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
782   keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
783   keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
784 }