]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkkeys-quartz.c
quartz: make function keys work (again?)
[~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 } modifier_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 };
150
151 const static struct {
152   guint keycode;
153   guint keyval;
154 } function_keys[] = {
155   { 122, GDK_KEY_F1 },
156   { 120, GDK_KEY_F2 },
157   {  99, GDK_KEY_F3 },
158   { 118, GDK_KEY_F4 },
159   {  96, GDK_KEY_F5 },
160   {  97, GDK_KEY_F6 },
161   {  98, GDK_KEY_F7 },
162   { 100, GDK_KEY_F8 },
163   { 101, GDK_KEY_F9 },
164   { 109, GDK_KEY_F10 },
165   { 103, GDK_KEY_F11 },
166   { 111, GDK_KEY_F12 },
167   { 105, GDK_KEY_F13 },
168   { 107, GDK_KEY_F14 },
169   { 113, GDK_KEY_F15 },
170   { 106, GDK_KEY_F16 }
171 };
172
173 const static struct {
174   guint keycode;
175   guint normal_keyval, keypad_keyval;
176 } known_numeric_keys[] = {
177   { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
178   { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
179   { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
180   { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
181   { 76, 0x01000003, GDK_KEY_KP_Enter },
182   { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
183   { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
184   { 82, GDK_KEY_0, GDK_KEY_KP_0 },
185   { 83, GDK_KEY_1, GDK_KEY_KP_1 },
186   { 84, GDK_KEY_2, GDK_KEY_KP_2 },
187   { 85, GDK_KEY_3, GDK_KEY_KP_3 },
188   { 86, GDK_KEY_4, GDK_KEY_KP_4 },
189   { 87, GDK_KEY_5, GDK_KEY_KP_5 },
190   { 88, GDK_KEY_6, GDK_KEY_KP_6 },
191   { 89, GDK_KEY_7, GDK_KEY_KP_7 },
192   { 91, GDK_KEY_8, GDK_KEY_KP_8 },
193   { 92, GDK_KEY_9, GDK_KEY_KP_9 }
194 };
195
196 /* These values aren't covered by gdk_unicode_to_keyval */
197 const static struct {
198   gunichar ucs_value;
199   guint keyval;
200 } special_ucs_table [] = {
201   { 0x0001, GDK_KEY_Home },
202   { 0x0003, GDK_KEY_Return },
203   { 0x0004, GDK_KEY_End },
204   { 0x0008, GDK_KEY_BackSpace },
205   { 0x0009, GDK_KEY_Tab },
206   { 0x000b, GDK_KEY_Page_Up },
207   { 0x000c, GDK_KEY_Page_Down },
208   { 0x000d, GDK_KEY_Return },
209   { 0x001b, GDK_KEY_Escape },
210   { 0x001c, GDK_KEY_Left },
211   { 0x001d, GDK_KEY_Right },
212   { 0x001e, GDK_KEY_Up },
213   { 0x001f, GDK_KEY_Down },
214   { 0x007f, GDK_KEY_Delete },
215   { 0xf027, GDK_KEY_dead_acute },
216   { 0xf060, GDK_KEY_dead_grave },
217   { 0xf300, GDK_KEY_dead_grave },
218   { 0xf0b4, GDK_KEY_dead_acute },
219   { 0xf301, GDK_KEY_dead_acute },
220   { 0xf385, GDK_KEY_dead_acute },
221   { 0xf05e, GDK_KEY_dead_circumflex },
222   { 0xf2c6, GDK_KEY_dead_circumflex },
223   { 0xf302, GDK_KEY_dead_circumflex },
224   { 0xf07e, GDK_KEY_dead_tilde },
225   { 0xf303, GDK_KEY_dead_tilde },
226   { 0xf342, GDK_KEY_dead_perispomeni },
227   { 0xf0af, GDK_KEY_dead_macron },
228   { 0xf304, GDK_KEY_dead_macron },
229   { 0xf2d8, GDK_KEY_dead_breve },
230   { 0xf306, GDK_KEY_dead_breve },
231   { 0xf2d9, GDK_KEY_dead_abovedot },
232   { 0xf307, GDK_KEY_dead_abovedot },
233   { 0xf0a8, GDK_KEY_dead_diaeresis },
234   { 0xf308, GDK_KEY_dead_diaeresis },
235   { 0xf2da, GDK_KEY_dead_abovering },
236   { 0xf30A, GDK_KEY_dead_abovering },
237   { 0xf022, GDK_KEY_dead_doubleacute },
238   { 0xf2dd, GDK_KEY_dead_doubleacute },
239   { 0xf30B, GDK_KEY_dead_doubleacute },
240   { 0xf2c7, GDK_KEY_dead_caron },
241   { 0xf30C, GDK_KEY_dead_caron },
242   { 0xf0be, GDK_KEY_dead_cedilla },
243   { 0xf327, GDK_KEY_dead_cedilla },
244   { 0xf2db, GDK_KEY_dead_ogonek },
245   { 0xf328, GDK_KEY_dead_ogonek },
246   { 0xfe5d, GDK_KEY_dead_iota },
247   { 0xf323, GDK_KEY_dead_belowdot },
248   { 0xf309, GDK_KEY_dead_hook },
249   { 0xf31B, GDK_KEY_dead_horn },
250   { 0xf02d, GDK_KEY_dead_stroke },
251   { 0xf335, GDK_KEY_dead_stroke },
252   { 0xf336, GDK_KEY_dead_stroke },
253   { 0xf313, GDK_KEY_dead_abovecomma },
254   /*  { 0xf313, GDK_KEY_dead_psili }, */
255   { 0xf314, GDK_KEY_dead_abovereversedcomma },
256   /*  { 0xf314, GDK_KEY_dead_dasia }, */
257   { 0xf30F, GDK_KEY_dead_doublegrave },
258   { 0xf325, GDK_KEY_dead_belowring },
259   { 0xf2cd, GDK_KEY_dead_belowmacron },
260   { 0xf331, GDK_KEY_dead_belowmacron },
261   { 0xf32D, GDK_KEY_dead_belowcircumflex },
262   { 0xf330, GDK_KEY_dead_belowtilde },
263   { 0xf32E, GDK_KEY_dead_belowbreve },
264   { 0xf324, GDK_KEY_dead_belowdiaeresis },
265   { 0xf311, GDK_KEY_dead_invertedbreve },
266   { 0xf02c, GDK_KEY_dead_belowcomma },
267   { 0xf326, GDK_KEY_dead_belowcomma }
268 };
269
270 static void
271 maybe_update_keymap (void)
272 {
273   const void *chr_data = NULL;
274
275 #ifdef __LP64__
276   TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
277   CFDataRef layout_data_ref;
278
279 #else
280   KeyboardLayoutRef new_layout;
281   KeyboardLayoutKind layout_kind;
282
283   KLGetCurrentKeyboardLayout (&new_layout);
284 #endif
285
286   if (new_layout != current_layout)
287     {
288       guint *p;
289       int i;
290
291       g_free (keyval_array);
292       keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
293
294 #ifdef __LP64__
295       layout_data_ref = (CFDataRef) TISGetInputSourceProperty
296         (new_layout, kTISPropertyUnicodeKeyLayoutData);
297
298       if (layout_data_ref)
299         chr_data = CFDataGetBytePtr (layout_data_ref);
300
301       if (chr_data == NULL)
302         {
303           g_error ("cannot get keyboard layout data");
304           return;
305         }
306 #else
307       /* Get the layout kind */
308       KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
309
310       /* 8-bit-only keyabord layout */
311       if (layout_kind == kKLKCHRKind)
312         { 
313           /* Get chr data */
314           KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
315           
316           for (i = 0; i < NUM_KEYCODES; i++) 
317             {
318               int j;
319               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
320
321               p = keyval_array + i * KEYVALS_PER_KEYCODE;
322               
323               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
324                 {
325                   UInt32 c, state = 0;
326                   UInt16 key_code;
327                   UniChar uc;
328                   
329                   key_code = modifiers[j] | i;
330                   c = KeyTranslate (chr_data, key_code, &state);
331
332                   if (state != 0)
333                     {
334                       UInt32 state2 = 0;
335                       c = KeyTranslate (chr_data, key_code | 128, &state2);
336                     }
337
338                   if (c != 0 && c != 0x10)
339                     {
340                       int k;
341                       gboolean found = FALSE;
342
343                       /* FIXME: some keyboard layouts (e.g. Russian) use
344                        * a different 8-bit character set. We should
345                        * check for this. Not a serious problem, because
346                        * most (all?) of these layouts also have a
347                        * uchr version. 
348                        */
349                       uc = macroman2ucs (c);
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_KEY_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                         p[j] = gdk_unicode_to_keyval (uc);
369                     }
370                 }
371
372               if (p[3] == p[2])
373                 p[3] = 0;
374               if (p[2] == p[1])
375                 p[2] = 0;
376               if (p[1] == p[0])
377                 p[1] = 0;
378               if (p[0] == p[2] && 
379                   p[1] == p[3])
380                 p[2] = p[3] = 0;
381             }
382         }
383       /* unicode keyboard layout */
384       else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
385         { 
386           /* Get chr data */
387           KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
388 #endif
389           
390           for (i = 0; i < NUM_KEYCODES; i++) 
391             {
392               int j;
393               UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
394               UniChar chars[4];
395               UniCharCount nChars;
396
397               p = keyval_array + i * KEYVALS_PER_KEYCODE;
398
399               for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
400                 {
401                   UInt32 state = 0;
402                   OSStatus err;
403                   UInt16 key_code;
404                   UniChar uc;
405                   
406                   key_code = modifiers[j] | i;
407                   err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
408                                         (modifiers[j] >> 8) & 0xFF,
409                                         LMGetKbdType(),
410                                         0,
411                                         &state, 4, &nChars, chars);
412
413                   /* FIXME: Theoretically, we can get multiple UTF-16 values;
414                    * we should convert them to proper unicode and figure
415                    * out whether there are really keyboard layouts that
416                    * give us more than one character for one keypress. */
417                   if (err == noErr && nChars == 1)
418                     {
419                       int k;
420                       gboolean found = FALSE;
421
422                       /* A few <Shift><Option>keys return two
423                        * characters, the first of which is U+00a0,
424                        * which isn't interesting; so we return the
425                        * second. More sophisticated handling is the
426                        * job of a GtkIMContext.
427                        *
428                        * If state isn't zero, it means that it's a
429                        * dead key of some sort. Some of those are
430                        * enumerated in the special_ucs_table with the
431                        * high nibble set to f to push it into the
432                        * private use range. Here we do the same.
433                        */
434                       if (state != 0)
435                         chars[nChars - 1] |= 0xf000;
436                       uc = chars[nChars - 1];
437
438                       for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
439                         {
440                           if (special_ucs_table[k].ucs_value == uc)
441                             {
442                               p[j] = special_ucs_table[k].keyval;
443                               found = TRUE;
444                               break;
445                             }
446                         }
447
448                       /* Special-case shift-tab since GTK+ expects
449                        * GDK_KEY_ISO_Left_Tab for that.
450                        */
451                       if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
452                         p[j] = GDK_KEY_ISO_Left_Tab;
453
454                       if (!found)
455                         p[j] = gdk_unicode_to_keyval (uc);
456                     }
457                 }
458
459               if (p[3] == p[2])
460                 p[3] = 0;
461               if (p[2] == p[1])
462                 p[2] = 0;
463               if (p[1] == p[0])
464                 p[1] = 0;
465               if (p[0] == p[2] && 
466                   p[1] == p[3])
467                 p[2] = p[3] = 0;
468             }
469 #ifndef __LP64__
470         }
471       else
472         {
473           g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
474                    " - not supported right now");
475         }
476 #endif
477
478       for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
479         {
480           p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
481
482           if (p[0] == 0 && p[1] == 0 && 
483               p[2] == 0 && p[3] == 0)
484             p[0] = modifier_keys[i].keyval;
485         }
486
487       for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
488         {
489           p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
490
491           p[0] = function_keys[i].keyval;
492           p[1] = p[2] = p[3] = 0;
493         }
494
495       for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
496         {
497           p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
498
499           if (p[0] == known_numeric_keys[i].normal_keyval)
500             p[0] = known_numeric_keys[i].keypad_keyval;
501         }
502       
503       if (current_layout)
504         g_signal_emit_by_name (default_keymap, "keys_changed");
505
506       current_layout = new_layout;
507     }
508 }
509
510 static PangoDirection
511 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
512 {
513   return PANGO_DIRECTION_NEUTRAL;
514 }
515
516 static gboolean
517 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
518 {
519   /* FIXME: Can we implement this? */
520   return FALSE;
521 }
522
523 static gboolean
524 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
525 {
526   /* FIXME: Implement this. */
527   return FALSE;
528 }
529
530 static gboolean
531 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
532 {
533   /* FIXME: Implement this. */
534   return FALSE;
535 }
536
537 static gboolean
538 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
539                                           guint          keyval,
540                                           GdkKeymapKey **keys,
541                                           gint          *n_keys)
542 {
543   GArray *keys_array;
544   int i;
545
546   maybe_update_keymap ();
547
548   *n_keys = 0;
549   keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
550
551   for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
552     {
553       GdkKeymapKey key;
554
555       if (keyval_array[i] != keyval)
556         continue;
557
558       (*n_keys)++;
559
560       key.keycode = i / KEYVALS_PER_KEYCODE;
561       key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
562       key.level = i % 2;
563
564       g_array_append_val (keys_array, key);
565     }
566
567   *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
568   
569   return *n_keys > 0;;
570 }
571
572 static gboolean
573 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
574                                            guint          hardware_keycode,
575                                            GdkKeymapKey **keys,
576                                            guint        **keyvals,
577                                            gint          *n_entries)
578 {
579   GArray *keys_array, *keyvals_array;
580   int i;
581   guint *p;
582
583   maybe_update_keymap ();
584
585   *n_entries = 0;
586
587   if (hardware_keycode > NUM_KEYCODES)
588     return FALSE;
589
590   if (keys)
591     keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
592   else
593     keys_array = NULL;
594
595   if (keyvals)
596     keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
597   else
598     keyvals_array = NULL;
599
600   p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
601   
602   for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
603     {
604       if (!p[i])
605         continue;
606
607       (*n_entries)++;
608       
609       if (keyvals_array)
610         g_array_append_val (keyvals_array, p[i]);
611
612       if (keys_array)
613         {
614           GdkKeymapKey key;
615
616           key.keycode = hardware_keycode;
617           key.group = i >= 2;
618           key.level = i % 2;
619
620           g_array_append_val (keys_array, key);
621         }
622     }
623   
624   if (keys)
625     *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
626
627   if (keyvals)
628     *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
629
630   return *n_entries > 0;
631 }
632
633 static guint
634 gdk_quartz_keymap_lookup_key (GdkKeymap          *keymap,
635                               const GdkKeymapKey *key)
636 {
637   /* FIXME: Implement */
638
639   return 0;
640 }
641
642 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
643
644 static guint
645 translate_keysym (guint           hardware_keycode,
646                   gint            group,
647                   GdkModifierType state,
648                   gint           *effective_group,
649                   gint           *effective_level)
650 {
651   gint level;
652   guint tmp_keyval;
653
654   level = (state & GDK_SHIFT_MASK) ? 1 : 0;
655
656   if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
657       (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
658     group = 0;
659
660   if (!GET_KEYVAL (hardware_keycode, group, level) &&
661       GET_KEYVAL (hardware_keycode, group, 0))
662     level = 0;
663
664   tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
665
666   if (state & GDK_LOCK_MASK)
667     {
668       guint upper = gdk_keyval_to_upper (tmp_keyval);
669       if (upper != tmp_keyval)
670         tmp_keyval = upper;
671     }
672
673   if (effective_group)
674     *effective_group = group;
675   if (effective_level)
676     *effective_level = level;
677
678   return tmp_keyval;
679 }
680
681 static gboolean
682 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap       *keymap,
683                                             guint            hardware_keycode,
684                                             GdkModifierType  state,
685                                             gint             group,
686                                             guint           *keyval,
687                                             gint            *effective_group,
688                                             gint            *level,
689                                             GdkModifierType *consumed_modifiers)
690 {
691   guint tmp_keyval;
692   GdkModifierType bit;
693   guint tmp_modifiers = 0;
694
695   maybe_update_keymap ();
696
697   if (keyval)
698     *keyval = 0;
699   if (effective_group)
700     *effective_group = 0;
701   if (level)
702     *level = 0;
703   if (consumed_modifiers)
704     *consumed_modifiers = 0;
705
706   if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
707     return FALSE;
708
709   /* Check if modifiers modify the keyval */
710   for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1)
711     {
712       if (translate_keysym (hardware_keycode,
713                             (bit == GDK_MOD1_MASK) ? 0 : group,
714                             state & ~bit,
715                             NULL, NULL) !=
716           translate_keysym (hardware_keycode,
717                             (bit == GDK_MOD1_MASK) ? 1 : group,
718                             state | bit,
719                             NULL, NULL))
720         tmp_modifiers |= bit;
721     }
722
723   tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
724
725   if (consumed_modifiers)
726     *consumed_modifiers = tmp_modifiers;
727
728   if (keyval)
729     *keyval = tmp_keyval; 
730
731   return TRUE;
732 }
733
734 static void
735 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
736                                          GdkModifierType *state)
737 {
738   if (*state & GDK_MOD2_MASK)
739     *state |= GDK_META_MASK;
740 }
741
742 static gboolean
743 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
744                                          GdkModifierType *state)
745 {
746   if (*state & GDK_META_MASK)
747     *state |= GDK_MOD2_MASK;
748
749   return TRUE;
750 }
751
752 static GdkModifierType
753 gdk_quartz_keymap_get_modifier_mask (GdkKeymap         *keymap,
754                                      GdkModifierIntent  intent)
755 {
756   switch (intent)
757     {
758     case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR:
759       return GDK_MOD2_MASK;
760
761     case GDK_MODIFIER_INTENT_CONTEXT_MENU:
762       return GDK_CONTROL_MASK;
763
764     case GDK_MODIFIER_INTENT_EXTEND_SELECTION:
765       return GDK_SHIFT_MASK;
766
767     case GDK_MODIFIER_INTENT_MODIFY_SELECTION:
768       return GDK_MOD2_MASK;
769
770     case GDK_MODIFIER_INTENT_NO_TEXT_INPUT:
771       return GDK_MOD2_MASK | GDK_CONTROL_MASK;
772
773     case GDK_MODIFIER_INTENT_SHIFT_GROUP:
774       return GDK_MOD1_MASK;
775
776     default:
777       g_return_val_if_reached (0);
778     }
779 }
780
781 /* What sort of key event is this? Returns one of
782  * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
783  */
784 GdkEventType
785 _gdk_quartz_keys_event_type (NSEvent *event)
786 {
787   unsigned short keycode;
788   unsigned int flags;
789   int i;
790   
791   switch ([event type])
792     {
793     case NSKeyDown:
794       return GDK_KEY_PRESS;
795     case NSKeyUp:
796       return GDK_KEY_RELEASE;
797     case NSFlagsChanged:
798       break;
799     default:
800       g_assert_not_reached ();
801     }
802   
803   /* For flags-changed events, we have to find the special key that caused the
804    * event, and see if it's in the modifier mask. */
805   keycode = [event keyCode];
806   flags = [event modifierFlags];
807   
808   for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
809     {
810       if (modifier_keys[i].keycode == keycode)
811         {
812           if (flags & modifier_keys[i].modmask)
813             return GDK_KEY_PRESS;
814           else
815             return GDK_KEY_RELEASE;
816         }
817     }
818   
819   /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
820    * events for no good reason. Ignore them! */
821   return GDK_NOTHING;
822 }
823
824 gboolean
825 _gdk_quartz_keys_is_modifier (guint keycode)
826 {
827   gint i;
828   
829   for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
830     {
831       if (modifier_keys[i].modmask == 0)
832         break;
833
834       if (modifier_keys[i].keycode == keycode)
835         return TRUE;
836     }
837
838   return FALSE;
839 }
840
841 static void
842 gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
843 {
844 }
845
846 static void
847 gdk_quartz_keymap_finalize (GObject *object)
848 {
849   G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
850 }
851
852 static void
853 gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
854 {
855   GObjectClass *object_class = G_OBJECT_CLASS (klass);
856   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
857
858   object_class->finalize = gdk_quartz_keymap_finalize;
859
860   keymap_class->get_direction = gdk_quartz_keymap_get_direction;
861   keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
862   keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
863   keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
864   keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
865   keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
866   keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
867   keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
868   keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
869   keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
870   keymap_class->get_modifier_mask = gdk_quartz_keymap_get_modifier_mask;
871 }