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