3 * Copyright (C) 2000 Red Hat, Inc.
4 * Copyright (C) 2005 Imendio AB
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.
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.
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.
21 /* Some parts of this code come from quartzKeyboard.c,
22 * from the Apple X11 Server.
24 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
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:
34 * The above copyright notice and this permission notice shall be
35 * included in all copies or substantial portions of the Software.
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.
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.
54 #include <Carbon/Carbon.h>
55 #include <AppKit/NSEvent.h>
57 #include "gdkquartzkeys.h"
58 #include "gdkkeysprivate.h"
59 #include "gdkkeysyms.h"
61 #define NUM_KEYCODES 128
62 #define KEYVALS_PER_KEYCODE 4
64 static GdkKeymap *default_keymap = NULL;
66 struct _GdkQuartzKeymap
71 struct _GdkQuartzKeymapClass
73 GdkKeymapClass keymap_class;
76 G_DEFINE_TYPE (GdkQuartzKeymap, gdk_quartz_keymap, GDK_TYPE_KEYMAP)
79 _gdk_quartz_display_get_keymap (GdkDisplay *display)
81 if (default_keymap == NULL)
82 default_keymap = g_object_new (gdk_quartz_keymap_get_type (), NULL);
84 return default_keymap;
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
93 static TISInputSourceRef current_layout = NULL;
95 static KeyboardLayoutRef current_layout = NULL;
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);
101 static guint *keyval_array = NULL;
103 static inline UniChar
104 macroman2ucs (unsigned char c)
106 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
107 by creating single element CFStringRefs then extracting the
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
132 return table[c - 128];
135 const static struct {
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 }
151 const static struct {
154 } function_keys[] = {
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 },
173 const static struct {
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 }
196 /* These values aren't covered by gdk_unicode_to_keyval */
197 const static struct {
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 }
271 maybe_update_keymap (void)
273 const void *chr_data = NULL;
276 TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
277 CFDataRef layout_data_ref;
280 KeyboardLayoutRef new_layout;
281 KeyboardLayoutKind layout_kind;
283 KLGetCurrentKeyboardLayout (&new_layout);
286 if (new_layout != current_layout)
291 g_free (keyval_array);
292 keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
295 layout_data_ref = (CFDataRef) TISGetInputSourceProperty
296 (new_layout, kTISPropertyUnicodeKeyLayoutData);
299 chr_data = CFDataGetBytePtr (layout_data_ref);
301 if (chr_data == NULL)
303 g_error ("cannot get keyboard layout data");
307 /* Get the layout kind */
308 KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
310 /* 8-bit-only keyabord layout */
311 if (layout_kind == kKLKCHRKind)
314 KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
316 for (i = 0; i < NUM_KEYCODES; i++)
319 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
321 p = keyval_array + i * KEYVALS_PER_KEYCODE;
323 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
329 key_code = modifiers[j] | i;
330 c = KeyTranslate (chr_data, key_code, &state);
335 c = KeyTranslate (chr_data, key_code | 128, &state2);
338 if (c != 0 && c != 0x10)
341 gboolean found = FALSE;
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
349 uc = macroman2ucs (c);
351 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
353 if (special_ucs_table[k].ucs_value == uc)
355 p[j] = special_ucs_table[k].keyval;
361 /* Special-case shift-tab since GTK+ expects
362 * GDK_KEY_ISO_Left_Tab for that.
364 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
365 p[j] = GDK_KEY_ISO_Left_Tab;
368 p[j] = gdk_unicode_to_keyval (uc);
383 /* unicode keyboard layout */
384 else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
387 KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
390 for (i = 0; i < NUM_KEYCODES; i++)
393 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
397 p = keyval_array + i * KEYVALS_PER_KEYCODE;
399 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
406 key_code = modifiers[j] | i;
407 err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
408 (modifiers[j] >> 8) & 0xFF,
411 &state, 4, &nChars, chars);
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)
420 gboolean found = FALSE;
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.
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.
435 chars[nChars - 1] |= 0xf000;
436 uc = chars[nChars - 1];
438 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
440 if (special_ucs_table[k].ucs_value == uc)
442 p[j] = special_ucs_table[k].keyval;
448 /* Special-case shift-tab since GTK+ expects
449 * GDK_KEY_ISO_Left_Tab for that.
451 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
452 p[j] = GDK_KEY_ISO_Left_Tab;
455 p[j] = gdk_unicode_to_keyval (uc);
473 g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
474 " - not supported right now");
478 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
480 p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
482 if (p[0] == 0 && p[1] == 0 &&
483 p[2] == 0 && p[3] == 0)
484 p[0] = modifier_keys[i].keyval;
487 for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
489 p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
491 p[0] = function_keys[i].keyval;
492 p[1] = p[2] = p[3] = 0;
495 for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
497 p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
499 if (p[0] == known_numeric_keys[i].normal_keyval)
500 p[0] = known_numeric_keys[i].keypad_keyval;
504 g_signal_emit_by_name (default_keymap, "keys_changed");
506 current_layout = new_layout;
510 static PangoDirection
511 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
513 return PANGO_DIRECTION_NEUTRAL;
517 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
519 /* FIXME: Can we implement this? */
524 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
526 /* FIXME: Implement this. */
531 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
533 /* FIXME: Implement this. */
538 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap *keymap,
546 maybe_update_keymap ();
549 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
551 for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
555 if (keyval_array[i] != keyval)
560 key.keycode = i / KEYVALS_PER_KEYCODE;
561 key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
564 g_array_append_val (keys_array, key);
567 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
573 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap *keymap,
574 guint hardware_keycode,
579 GArray *keys_array, *keyvals_array;
583 maybe_update_keymap ();
587 if (hardware_keycode > NUM_KEYCODES)
591 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
596 keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
598 keyvals_array = NULL;
600 p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
602 for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
610 g_array_append_val (keyvals_array, p[i]);
616 key.keycode = hardware_keycode;
620 g_array_append_val (keys_array, key);
625 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
628 *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
630 return *n_entries > 0;
634 gdk_quartz_keymap_lookup_key (GdkKeymap *keymap,
635 const GdkKeymapKey *key)
637 /* FIXME: Implement */
642 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
645 translate_keysym (guint hardware_keycode,
647 GdkModifierType state,
648 gint *effective_group,
649 gint *effective_level)
654 level = (state & GDK_SHIFT_MASK) ? 1 : 0;
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)))
660 if (!GET_KEYVAL (hardware_keycode, group, level) &&
661 GET_KEYVAL (hardware_keycode, group, 0))
664 tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
666 if (state & GDK_LOCK_MASK)
668 guint upper = gdk_keyval_to_upper (tmp_keyval);
669 if (upper != tmp_keyval)
674 *effective_group = group;
676 *effective_level = level;
682 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap *keymap,
683 guint hardware_keycode,
684 GdkModifierType state,
687 gint *effective_group,
689 GdkModifierType *consumed_modifiers)
693 guint tmp_modifiers = 0;
695 maybe_update_keymap ();
700 *effective_group = 0;
703 if (consumed_modifiers)
704 *consumed_modifiers = 0;
706 if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
709 /* Check if modifiers modify the keyval */
710 for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1)
712 if (translate_keysym (hardware_keycode,
713 (bit == GDK_MOD1_MASK) ? 0 : group,
716 translate_keysym (hardware_keycode,
717 (bit == GDK_MOD1_MASK) ? 1 : group,
720 tmp_modifiers |= bit;
723 tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
725 if (consumed_modifiers)
726 *consumed_modifiers = tmp_modifiers;
729 *keyval = tmp_keyval;
735 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap *keymap,
736 GdkModifierType *state)
738 if (*state & GDK_MOD2_MASK)
739 *state |= GDK_META_MASK;
743 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap,
744 GdkModifierType *state)
746 if (*state & GDK_META_MASK)
747 *state |= GDK_MOD2_MASK;
752 static GdkModifierType
753 gdk_quartz_keymap_get_modifier_mask (GdkKeymap *keymap,
754 GdkModifierIntent intent)
758 case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR:
759 return GDK_MOD2_MASK;
761 case GDK_MODIFIER_INTENT_CONTEXT_MENU:
762 return GDK_CONTROL_MASK;
764 case GDK_MODIFIER_INTENT_EXTEND_SELECTION:
765 return GDK_SHIFT_MASK;
767 case GDK_MODIFIER_INTENT_MODIFY_SELECTION:
768 return GDK_MOD2_MASK;
770 case GDK_MODIFIER_INTENT_NO_TEXT_INPUT:
771 return GDK_MOD2_MASK | GDK_CONTROL_MASK;
773 case GDK_MODIFIER_INTENT_SHIFT_GROUP:
774 return GDK_MOD1_MASK;
777 g_return_val_if_reached (0);
781 /* What sort of key event is this? Returns one of
782 * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
785 _gdk_quartz_keys_event_type (NSEvent *event)
787 unsigned short keycode;
791 switch ([event type])
794 return GDK_KEY_PRESS;
796 return GDK_KEY_RELEASE;
800 g_assert_not_reached ();
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];
808 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
810 if (modifier_keys[i].keycode == keycode)
812 if (flags & modifier_keys[i].modmask)
813 return GDK_KEY_PRESS;
815 return GDK_KEY_RELEASE;
819 /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
820 * events for no good reason. Ignore them! */
825 _gdk_quartz_keys_is_modifier (guint keycode)
829 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
831 if (modifier_keys[i].modmask == 0)
834 if (modifier_keys[i].keycode == keycode)
842 gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
847 gdk_quartz_keymap_finalize (GObject *object)
849 G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
853 gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
855 GObjectClass *object_class = G_OBJECT_CLASS (klass);
856 GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
858 object_class->finalize = gdk_quartz_keymap_finalize;
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;