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 "gdkkeysprivate.h"
58 #include "gdkkeysyms.h"
60 #define NUM_KEYCODES 128
61 #define KEYVALS_PER_KEYCODE 4
63 static GdkKeymap *default_keymap = NULL;
66 #define GDK_TYPE_QUARTZ_KEYMAP (gdk_quartz_keymap_get_type ())
67 #define GDK_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymap))
68 #define GDK_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
69 #define GDK_IS_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_KEYMAP))
70 #define GDK_IS_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_KEYMAP))
71 #define GDK_QUARTZ_KEYMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
73 typedef struct _GdkQuartzKeymap GdkQuartzKeymap;
74 typedef struct _GdkQuartzKeymapClass GdkQuartzKeymapClass;
76 struct _GdkQuartzKeymap
81 struct _GdkQuartzKeymapClass
83 GdkKeymapClass keymap_class;
86 G_DEFINE_TYPE (GdkQuartzKeymap, _gdk_quartz_keymap, GDK_TYPE_KEYMAP)
89 _gdk_quartz_display_get_keymap (GdkDisplay *display)
91 if (default_keymap == NULL)
92 default_keymap = g_object_new (_gdk_quartz_keymap_get_type (), NULL);
94 return default_keymap;
97 /* Note: we could check only if building against the 10.5 SDK instead, but
98 * that would make non-xml layouts not work in 32-bit which would be a quite
99 * bad regression. This way, old unsupported layouts will just not work in
103 static TISInputSourceRef current_layout = NULL;
105 static KeyboardLayoutRef current_layout = NULL;
108 /* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
109 * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
111 static guint *keyval_array = NULL;
113 static inline UniChar
114 macroman2ucs (unsigned char c)
116 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
117 by creating single element CFStringRefs then extracting the
120 static const unsigned short table[128] = {
121 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
122 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
123 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
124 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
125 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
126 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
127 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
128 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
129 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
130 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
131 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
132 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
133 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
134 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
135 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
136 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
142 return table[c - 128];
145 const static struct {
148 unsigned int modmask; /* So we can tell when a mod key is pressed/released */
150 { 54, GDK_KEY_Meta_R, NSCommandKeyMask },
151 { 55, GDK_KEY_Meta_L, NSCommandKeyMask },
152 { 56, GDK_KEY_Shift_L, NSShiftKeyMask },
153 { 57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
154 { 58, GDK_KEY_Alt_L, NSAlternateKeyMask },
155 { 59, GDK_KEY_Control_L, NSControlKeyMask },
156 { 60, GDK_KEY_Shift_R, NSShiftKeyMask },
157 { 61, GDK_KEY_Alt_R, NSAlternateKeyMask },
158 { 62, GDK_KEY_Control_R, NSControlKeyMask },
159 { 122, GDK_KEY_F1, 0 },
160 { 120, GDK_KEY_F2, 0 },
161 { 99, GDK_KEY_F3, 0 },
162 { 118, GDK_KEY_F4, 0 },
163 { 96, GDK_KEY_F5, 0 },
164 { 97, GDK_KEY_F6, 0 },
165 { 98, GDK_KEY_F7, 0 },
166 { 100, GDK_KEY_F8, 0 },
167 { 101, GDK_KEY_F9, 0 },
168 { 109, GDK_KEY_F10, 0 },
169 { 103, GDK_KEY_F11, 0 },
170 { 111, GDK_KEY_F12, 0 },
171 { 105, GDK_KEY_F13, 0 },
172 { 107, GDK_KEY_F14, 0 },
173 { 113, GDK_KEY_F15, 0 },
174 { 106, GDK_KEY_F16, 0 }
177 const static struct {
179 guint normal_keyval, keypad_keyval;
180 } known_numeric_keys[] = {
181 { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
182 { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
183 { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
184 { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
185 { 76, 0x01000003, GDK_KEY_KP_Enter },
186 { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
187 { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
188 { 82, GDK_KEY_0, GDK_KEY_KP_0 },
189 { 83, GDK_KEY_1, GDK_KEY_KP_1 },
190 { 84, GDK_KEY_2, GDK_KEY_KP_2 },
191 { 85, GDK_KEY_3, GDK_KEY_KP_3 },
192 { 86, GDK_KEY_4, GDK_KEY_KP_4 },
193 { 87, GDK_KEY_5, GDK_KEY_KP_5 },
194 { 88, GDK_KEY_6, GDK_KEY_KP_6 },
195 { 89, GDK_KEY_7, GDK_KEY_KP_7 },
196 { 91, GDK_KEY_8, GDK_KEY_KP_8 },
197 { 92, GDK_KEY_9, GDK_KEY_KP_9 }
200 /* These values aren't covered by gdk_unicode_to_keyval */
201 const static struct {
204 } special_ucs_table [] = {
205 { 0x0001, GDK_KEY_Home },
206 { 0x0003, GDK_KEY_Return },
207 { 0x0004, GDK_KEY_End },
208 { 0x0008, GDK_KEY_BackSpace },
209 { 0x0009, GDK_KEY_Tab },
210 { 0x000b, GDK_KEY_Page_Up },
211 { 0x000c, GDK_KEY_Page_Down },
212 { 0x000d, GDK_KEY_Return },
213 { 0x001b, GDK_KEY_Escape },
214 { 0x001c, GDK_KEY_Left },
215 { 0x001d, GDK_KEY_Right },
216 { 0x001e, GDK_KEY_Up },
217 { 0x001f, GDK_KEY_Down },
218 { 0x007f, GDK_KEY_Delete }
222 maybe_update_keymap (void)
224 const void *chr_data = NULL;
227 TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
228 CFDataRef layout_data_ref;
231 KeyboardLayoutRef new_layout;
232 KeyboardLayoutKind layout_kind;
234 KLGetCurrentKeyboardLayout (&new_layout);
237 if (new_layout != current_layout)
242 g_free (keyval_array);
243 keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
246 layout_data_ref = (CFDataRef) TISGetInputSourceProperty
247 (new_layout, kTISPropertyUnicodeKeyLayoutData);
250 chr_data = CFDataGetBytePtr (layout_data_ref);
252 if (chr_data == NULL)
254 g_error ("cannot get keyboard layout data");
258 /* Get the layout kind */
259 KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
261 /* 8-bit-only keyabord layout */
262 if (layout_kind == kKLKCHRKind)
265 KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
267 for (i = 0; i < NUM_KEYCODES; i++)
270 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
272 p = keyval_array + i * KEYVALS_PER_KEYCODE;
274 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
280 key_code = modifiers[j] | i;
281 c = KeyTranslate (chr_data, key_code, &state);
286 c = KeyTranslate (chr_data, key_code | 128, &state2);
289 if (c != 0 && c != 0x10)
292 gboolean found = FALSE;
294 /* FIXME: some keyboard layouts (e.g. Russian) use
295 * a different 8-bit character set. We should
296 * check for this. Not a serious problem, because
297 * most (all?) of these layouts also have a
300 uc = macroman2ucs (c);
302 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
304 if (special_ucs_table[k].ucs_value == uc)
306 p[j] = special_ucs_table[k].keyval;
312 /* Special-case shift-tab since GTK+ expects
313 * GDK_KEY_ISO_Left_Tab for that.
315 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
316 p[j] = GDK_KEY_ISO_Left_Tab;
322 tmp = gdk_unicode_to_keyval (uc);
323 if (tmp != (uc | 0x01000000))
342 /* unicode keyboard layout */
343 else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
346 KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
349 for (i = 0; i < NUM_KEYCODES; i++)
352 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
356 p = keyval_array + i * KEYVALS_PER_KEYCODE;
358 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
365 key_code = modifiers[j] | i;
366 err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
367 (modifiers[j] >> 8) & 0xFF,
369 kUCKeyTranslateNoDeadKeysMask,
370 &state, 4, &nChars, chars);
373 /* FIXME: Theoretically, we can get multiple UTF-16 values;
374 * we should convert them to proper unicode and figure
375 * out whether there are really keyboard layouts that
376 * give us more than one character for one keypress. */
377 if (err == noErr && nChars == 1)
380 gboolean found = FALSE;
384 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
386 if (special_ucs_table[k].ucs_value == uc)
388 p[j] = special_ucs_table[k].keyval;
394 /* Special-case shift-tab since GTK+ expects
395 * GDK_KEY_ISO_Left_Tab for that.
397 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
398 p[j] = GDK_KEY_ISO_Left_Tab;
404 tmp = gdk_unicode_to_keyval (uc);
405 if (tmp != (uc | 0x01000000))
427 g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
428 " - not supported right now");
432 for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
434 p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
436 if (p[0] == 0 && p[1] == 0 &&
437 p[2] == 0 && p[3] == 0)
438 p[0] = known_keys[i].keyval;
441 for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
443 p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
445 if (p[0] == known_numeric_keys[i].normal_keyval)
446 p[0] = known_numeric_keys[i].keypad_keyval;
450 g_signal_emit_by_name (default_keymap, "keys_changed");
452 current_layout = new_layout;
457 gdk_keymap_get_for_display (GdkDisplay *display)
459 g_return_val_if_fail (display == gdk_display_get_default (), NULL);
461 if (default_keymap == NULL)
462 default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
464 return default_keymap;
467 static PangoDirection
468 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
470 return PANGO_DIRECTION_NEUTRAL;
474 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
476 /* FIXME: Can we implement this? */
481 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
483 /* FIXME: Implement this. */
488 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
490 /* FIXME: Implement this. */
495 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap *keymap,
503 maybe_update_keymap ();
506 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
508 for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
512 if (keyval_array[i] != keyval)
517 key.keycode = i / KEYVALS_PER_KEYCODE;
519 key.level = i % KEYVALS_PER_KEYCODE;
521 g_array_append_val (keys_array, key);
524 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
530 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap *keymap,
531 guint hardware_keycode,
536 GArray *keys_array, *keyvals_array;
540 maybe_update_keymap ();
544 if (hardware_keycode > NUM_KEYCODES)
548 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
553 keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
555 keyvals_array = NULL;
557 p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
559 for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
567 g_array_append_val (keyvals_array, p[i]);
573 key.keycode = hardware_keycode;
577 g_array_append_val (keys_array, key);
582 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
585 *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
587 return *n_entries > 0;
591 gdk_quartz_keymap_lookup_key (GdkKeymap *keymap,
592 const GdkKeymapKey *key)
594 /* FIXME: Implement */
599 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
602 translate_keysym (guint hardware_keycode,
604 GdkModifierType state,
605 gint *effective_group,
606 gint *effective_level)
611 level = (state & GDK_SHIFT_MASK) ? 1 : 0;
613 if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
614 (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
617 if (!GET_KEYVAL (hardware_keycode, group, level) &&
618 GET_KEYVAL (hardware_keycode, group, 0))
621 tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
623 if (state & GDK_LOCK_MASK)
625 guint upper = gdk_keyval_to_upper (tmp_keyval);
626 if (upper != tmp_keyval)
634 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap *keymap,
635 guint hardware_keycode,
636 GdkModifierType state,
639 gint *effective_group,
641 GdkModifierType *consumed_modifiers)
645 guint tmp_modifiers = 0;
647 maybe_update_keymap ();
652 *effective_group = 0;
655 if (consumed_modifiers)
656 *consumed_modifiers = 0;
658 if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
661 /* Check if shift or capslock modify the keyval */
662 for (bit = GDK_SHIFT_MASK; bit < GDK_CONTROL_MASK; bit <<= 1)
664 if (translate_keysym (hardware_keycode, group, state & ~bit, NULL, NULL) !=
665 translate_keysym (hardware_keycode, group, state | bit, NULL, NULL))
666 tmp_modifiers |= bit;
669 tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
671 if (consumed_modifiers)
672 *consumed_modifiers = tmp_modifiers;
675 *keyval = tmp_keyval;
681 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap *keymap,
682 GdkModifierType *state)
684 /* FIXME: For now, we've mimiced the Windows backend. */
688 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap,
689 GdkModifierType *state)
691 /* FIXME: For now, we've mimiced the Windows backend. */
695 /* What sort of key event is this? Returns one of
696 * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
699 _gdk_quartz_keys_event_type (NSEvent *event)
701 unsigned short keycode;
705 switch ([event type])
708 return GDK_KEY_PRESS;
710 return GDK_KEY_RELEASE;
714 g_assert_not_reached ();
717 /* For flags-changed events, we have to find the special key that caused the
718 * event, and see if it's in the modifier mask. */
719 keycode = [event keyCode];
720 flags = [event modifierFlags];
722 for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
724 if (known_keys[i].keycode == keycode)
726 if (flags & known_keys[i].modmask)
727 return GDK_KEY_PRESS;
729 return GDK_KEY_RELEASE;
733 /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
734 * events for no good reason. Ignore them! */
739 _gdk_quartz_keys_is_modifier (guint keycode)
743 for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
745 if (known_keys[i].modmask == 0)
748 if (known_keys[i].keycode == keycode)
756 _gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
761 _gdk_quartz_keymap_finalize (GObject *object)
763 G_OBJECT_CLASS (_gdk_quartz_keymap_parent_class)->finalize (object);
767 _gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
769 GObjectClass *object_class = G_OBJECT_CLASS (klass);
770 GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
772 object_class->finalize = _gdk_quartz_keymap_finalize;
774 keymap_class->get_direction = gdk_quartz_keymap_get_direction;
775 keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
776 keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
777 keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
778 keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
779 keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
780 keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
781 keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
782 keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
783 keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;