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