]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkkeys-quartz.c
Turn the private #define for the group-shifting modifier into API
[~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                         p[j] = gdk_unicode_to_keyval (uc);
363                     }
364                 }
365
366               if (p[3] == p[2])
367                 p[3] = 0;
368               if (p[2] == p[1])
369                 p[2] = 0;
370               if (p[1] == p[0])
371                 p[1] = 0;
372               if (p[0] == p[2] && 
373                   p[1] == p[3])
374                 p[2] = p[3] = 0;
375             }
376         }
377       /* unicode keyboard layout */
378       else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
379         { 
380           /* Get chr data */
381           KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
382 #endif
383           
384           for (i = 0; i < NUM_KEYCODES; i++) 
385             {
386               int j;
387               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
388               UniChar chars[4];
389               UniCharCount nChars;
390
391               p = keyval_array + i * KEYVALS_PER_KEYCODE;
392
393               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
394                 {
395                   UInt32 state = 0;
396                   OSStatus err;
397                   UInt16 key_code;
398                   UniChar uc;
399                   
400                   key_code = modifiers[j] | i;
401                   err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
402                                         (modifiers[j] >> 8) & 0xFF,
403                                         LMGetKbdType(),
404                                         0,
405                                         &state, 4, &nChars, chars);
406
407
408                   /* FIXME: Theoretically, we can get multiple UTF-16 values;
409                    * we should convert them to proper unicode and figure
410                    * out whether there are really keyboard layouts that
411                    * give us more than one character for one keypress. */
412                   if (err == noErr && nChars == 1)
413                     {
414                       int k;
415                       gboolean found = FALSE;
416
417                       /* A few <Shift><Option>keys return two
418                        * characters, the first of which is U+00a0,
419                        * which isn't interesting; so we return the
420                        * second. More sophisticated handling is the
421                        * job of a GtkIMContext.
422                        *
423                        * If state isn't zero, it means that it's a
424                        * dead key of some sort. Some of those are
425                        * enumerated in the special_ucs_table with the
426                        * high nibble set to f to push it into the
427                        * private use range. Here we do the same.
428                        */
429                       if (state != 0)
430                         chars[nChars - 1] |= 0xf000;
431                       uc = chars[nChars - 1];
432
433                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
434                         {
435                           if (special_ucs_table[k].ucs_value == uc)
436                             {
437                               p[j] = special_ucs_table[k].keyval;
438                               found = TRUE;
439                               break;
440                             }
441                         }
442
443                       /* Special-case shift-tab since GTK+ expects
444                        * GDK_KEY_ISO_Left_Tab for that.
445                        */
446                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
447                         p[j] = GDK_KEY_ISO_Left_Tab;
448
449                       if (!found)
450                         p[j] = gdk_unicode_to_keyval (uc);
451                     }
452                 }
453
454               if (p[3] == p[2])
455                 p[3] = 0;
456               if (p[2] == p[1])
457                 p[2] = 0;
458               if (p[1] == p[0])
459                 p[1] = 0;
460               if (p[0] == p[2] && 
461                   p[1] == p[3])
462                 p[2] = p[3] = 0;
463             }
464 #ifndef __LP64__
465         }
466       else
467         {
468           g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
469                    " - not supported right now");
470         }
471 #endif
472
473       for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
474         {
475           p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
476
477           if (p[0] == 0 && p[1] == 0 && 
478               p[2] == 0 && p[3] == 0)
479             p[0] = known_keys[i].keyval;
480         }
481
482       for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
483         {
484           p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
485
486           if (p[0] == known_numeric_keys[i].normal_keyval)
487             p[0] = known_numeric_keys[i].keypad_keyval;
488         }
489       
490       if (current_layout)
491         g_signal_emit_by_name (default_keymap, "keys_changed");
492
493       current_layout = new_layout;
494     }
495 }
496
497 static PangoDirection
498 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
499 {
500   return PANGO_DIRECTION_NEUTRAL;
501 }
502
503 static gboolean
504 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
505 {
506   /* FIXME: Can we implement this? */
507   return FALSE;
508 }
509
510 static gboolean
511 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
512 {
513   /* FIXME: Implement this. */
514   return FALSE;
515 }
516
517 static gboolean
518 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
519 {
520   /* FIXME: Implement this. */
521   return FALSE;
522 }
523
524 static gboolean
525 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
526                                           guint          keyval,
527                                           GdkKeymapKey **keys,
528                                           gint          *n_keys)
529 {
530   GArray *keys_array;
531   int i;
532
533   maybe_update_keymap ();
534
535   *n_keys = 0;
536   keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
537
538   for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
539     {
540       GdkKeymapKey key;
541
542       if (keyval_array[i] != keyval)
543         continue;
544
545       (*n_keys)++;
546
547       key.keycode = i / KEYVALS_PER_KEYCODE;
548       key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
549       key.level = i % 2;
550
551       g_array_append_val (keys_array, key);
552     }
553
554   *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
555   
556   return *n_keys > 0;;
557 }
558
559 static gboolean
560 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
561                                            guint          hardware_keycode,
562                                            GdkKeymapKey **keys,
563                                            guint        **keyvals,
564                                            gint          *n_entries)
565 {
566   GArray *keys_array, *keyvals_array;
567   int i;
568   guint *p;
569
570   maybe_update_keymap ();
571
572   *n_entries = 0;
573
574   if (hardware_keycode > NUM_KEYCODES)
575     return FALSE;
576
577   if (keys)
578     keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
579   else
580     keys_array = NULL;
581
582   if (keyvals)
583     keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
584   else
585     keyvals_array = NULL;
586
587   p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
588   
589   for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
590     {
591       if (!p[i])
592         continue;
593
594       (*n_entries)++;
595       
596       if (keyvals_array)
597         g_array_append_val (keyvals_array, p[i]);
598
599       if (keys_array)
600         {
601           GdkKeymapKey key;
602
603           key.keycode = hardware_keycode;
604           key.group = i >= 2;
605           key.level = i % 2;
606
607           g_array_append_val (keys_array, key);
608         }
609     }
610   
611   if (keys)
612     *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
613
614   if (keyvals)
615     *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
616
617   return *n_entries > 0;
618 }
619
620 static guint
621 gdk_quartz_keymap_lookup_key (GdkKeymap          *keymap,
622                               const GdkKeymapKey *key)
623 {
624   /* FIXME: Implement */
625
626   return 0;
627 }
628
629 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
630
631 static guint
632 translate_keysym (guint           hardware_keycode,
633                   gint            group,
634                   GdkModifierType state,
635                   gint           *effective_group,
636                   gint           *effective_level)
637 {
638   gint level;
639   guint tmp_keyval;
640
641   level = (state & GDK_SHIFT_MASK) ? 1 : 0;
642
643   if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
644       (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
645     group = 0;
646
647   if (!GET_KEYVAL (hardware_keycode, group, level) &&
648       GET_KEYVAL (hardware_keycode, group, 0))
649     level = 0;
650
651   tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
652
653   if (state & GDK_LOCK_MASK)
654     {
655       guint upper = gdk_keyval_to_upper (tmp_keyval);
656       if (upper != tmp_keyval)
657         tmp_keyval = upper;
658     }
659
660   if (effective_group)
661     *effective_group = group;
662   if (effective_level)
663     *effective_level = level;
664
665   return tmp_keyval;
666 }
667
668 static gboolean
669 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap       *keymap,
670                                             guint            hardware_keycode,
671                                             GdkModifierType  state,
672                                             gint             group,
673                                             guint           *keyval,
674                                             gint            *effective_group,
675                                             gint            *level,
676                                             GdkModifierType *consumed_modifiers)
677 {
678   guint tmp_keyval;
679   GdkModifierType bit;
680   guint tmp_modifiers = 0;
681
682   maybe_update_keymap ();
683
684   if (keyval)
685     *keyval = 0;
686   if (effective_group)
687     *effective_group = 0;
688   if (level)
689     *level = 0;
690   if (consumed_modifiers)
691     *consumed_modifiers = 0;
692
693   if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
694     return FALSE;
695
696   /* Check if modifiers modify the keyval */
697   for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1)
698     {
699       if (translate_keysym (hardware_keycode,
700                             (bit == GDK_MOD1_MASK) ? 0 : group,
701                             state & ~bit,
702                             NULL, NULL) !=
703           translate_keysym (hardware_keycode,
704                             (bit == GDK_MOD1_MASK) ? 1 : group,
705                             state | bit,
706                             NULL, NULL))
707         tmp_modifiers |= bit;
708     }
709
710   tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
711
712   if (consumed_modifiers)
713     *consumed_modifiers = tmp_modifiers;
714
715   if (keyval)
716     *keyval = tmp_keyval; 
717
718   return TRUE;
719 }
720
721 static void
722 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
723                                          GdkModifierType *state)
724 {
725   if (*state & GDK_MOD2_MASK)
726     *state |= GDK_META_MASK;
727 }
728
729 static gboolean
730 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
731                                          GdkModifierType *state)
732 {
733   if (*state & GDK_META_MASK)
734     *state |= GDK_MOD2_MASK;
735
736   return TRUE;
737 }
738
739 static GdkModifierType
740 gdk_quartz_keymap_get_modifier_mask (GdkKeymap         *keymap,
741                                      GdkModifierIntent  intent)
742 {
743   switch (intent)
744     {
745     case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR:
746       return GDK_MOD2_MASK;
747
748     case GDK_MODIFIER_INTENT_CONTEXT_MENU:
749       return GDK_CONTROL_MASK;
750
751     case GDK_MODIFIER_INTENT_EXTEND_SELECTION:
752       return GDK_SHIFT_MASK;
753
754     case GDK_MODIFIER_INTENT_MODIFY_SELECTION:
755       return GDK_MOD2_MASK;
756
757     case GDK_MODIFIER_INTENT_NO_TEXT_INPUT:
758       return GDK_MOD2_MASK | GDK_CONTROL_MASK;
759
760     case GDK_MODIFIER_INTENT_SHIFT_GROUP:
761       return GDK_MOD1_MASK;
762
763     default:
764       g_return_val_if_reached (0);
765     }
766 }
767
768 /* What sort of key event is this? Returns one of
769  * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
770  */
771 GdkEventType
772 _gdk_quartz_keys_event_type (NSEvent *event)
773 {
774   unsigned short keycode;
775   unsigned int flags;
776   int i;
777   
778   switch ([event type])
779     {
780     case NSKeyDown:
781       return GDK_KEY_PRESS;
782     case NSKeyUp:
783       return GDK_KEY_RELEASE;
784     case NSFlagsChanged:
785       break;
786     default:
787       g_assert_not_reached ();
788     }
789   
790   /* For flags-changed events, we have to find the special key that caused the
791    * event, and see if it's in the modifier mask. */
792   keycode = [event keyCode];
793   flags = [event modifierFlags];
794   
795   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
796     {
797       if (known_keys[i].keycode == keycode)
798         {
799           if (flags & known_keys[i].modmask)
800             return GDK_KEY_PRESS;
801           else
802             return GDK_KEY_RELEASE;
803         }
804     }
805   
806   /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
807    * events for no good reason. Ignore them! */
808   return GDK_NOTHING;
809 }
810
811 gboolean
812 _gdk_quartz_keys_is_modifier (guint keycode)
813 {
814   gint i;
815   
816   for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
817     {
818       if (known_keys[i].modmask == 0)
819         break;
820
821       if (known_keys[i].keycode == keycode)
822         return TRUE;
823     }
824
825   return FALSE;
826 }
827
828 static void
829 gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
830 {
831 }
832
833 static void
834 gdk_quartz_keymap_finalize (GObject *object)
835 {
836   G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
837 }
838
839 static void
840 gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
841 {
842   GObjectClass *object_class = G_OBJECT_CLASS (klass);
843   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
844
845   object_class->finalize = gdk_quartz_keymap_finalize;
846
847   keymap_class->get_direction = gdk_quartz_keymap_get_direction;
848   keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
849   keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
850   keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
851   keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
852   keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
853   keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
854   keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
855   keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
856   keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
857   keymap_class->get_modifier_mask = gdk_quartz_keymap_get_modifier_mask;
858 }