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>
56 #include "gdkkeysyms.h"
58 #define NUM_KEYCODES 128
59 #define KEYVALS_PER_KEYCODE 4
61 static GdkKeymap *default_keymap = NULL;
63 static KeyboardLayoutRef current_layout = NULL;
65 /* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
66 * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
68 static guint *keyval_array = NULL;
71 macroman2ucs (unsigned char c)
73 /* Precalculated table mapping MacRoman-128 to Unicode. Generated
74 by creating single element CFStringRefs then extracting the
77 static const unsigned short table[128] = {
78 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
79 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
80 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
81 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
82 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
83 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
84 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
85 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
86 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
87 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
88 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
89 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
90 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
91 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
92 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
93 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
99 return table[c - 128];
102 const static struct {
108 { 57, GDK_Caps_Lock },
110 { 59, GDK_Control_L },
113 { 62, GDK_Control_R },
131 const static struct {
133 guint normal_keyval, keypad_keyval;
134 } known_numeric_keys[] = {
135 { 65, GDK_period, GDK_KP_Decimal },
136 { 67, GDK_asterisk, GDK_KP_Multiply },
137 { 69, GDK_plus, GDK_KP_Add },
138 { 75, GDK_slash, GDK_KP_Divide },
139 { 76, 0x01000003, GDK_KP_Enter },
140 { 78, GDK_minus, GDK_KP_Subtract },
141 { 81, GDK_equal, GDK_KP_Equal },
142 { 82, GDK_0, GDK_KP_0 },
143 { 83, GDK_1, GDK_KP_1 },
144 { 84, GDK_2, GDK_KP_2 },
145 { 85, GDK_3, GDK_KP_3 },
146 { 86, GDK_4, GDK_KP_4 },
147 { 87, GDK_5, GDK_KP_5 },
148 { 88, GDK_6, GDK_KP_6 },
149 { 89, GDK_7, GDK_KP_7 },
150 { 91, GDK_8, GDK_KP_8 },
151 { 92, GDK_9, GDK_KP_9 },
154 /* These values aren't covered by gdk_unicode_to_keyval */
155 const static struct {
158 } special_ucs_table [] = {
159 { 0x0001, GDK_Home },
160 { 0x0008, GDK_BackSpace },
162 { 0x000b, GDK_Page_Up },
163 { 0x000c, GDK_Page_Down },
164 { 0x000d, GDK_Return },
165 { 0x001c, GDK_Left },
166 { 0x001d, GDK_Right },
168 { 0x001f, GDK_Down },
172 maybe_update_keymap (void)
174 KeyboardLayoutRef new_layout;
176 KLGetCurrentKeyboardLayout (&new_layout);
178 if (new_layout != current_layout)
183 KeyboardLayoutKind layout_kind;
185 g_free (keyval_array);
186 keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
188 /* Get the layout kind */
189 KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
191 /* 8-bit-only keyabord layout */
192 if (layout_kind == kKLKCHRKind)
194 const void *chr_data;
197 KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
199 for (i = 0; i < NUM_KEYCODES; i++)
202 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey|optionKey};
204 p = keyval_array + i * KEYVALS_PER_KEYCODE;
206 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
212 key_code = modifiers[j]|i;
213 c = KeyTranslate (chr_data, key_code, &state);
218 c = KeyTranslate (chr_data, key_code | 128, &state2);
221 if (c != 0 && c != 0x10)
224 gboolean found = FALSE;
226 /* FIXME: some keyboard layouts (e.g. Russian) use
227 * a different 8-bit character set. We should
228 * check for this. Not a serious problem, because
229 * most (all?) of these layouts also have a
232 uc = macroman2ucs (c);
234 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
236 if (special_ucs_table[k].ucs_value == uc)
238 p[j] = special_ucs_table[k].keyval;
245 p[j] = gdk_unicode_to_keyval (uc);
260 /* unicode keyboard layout */
261 else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
263 const void *chr_data;
266 KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
268 for (i = 0; i < NUM_KEYCODES; i++)
271 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey|optionKey};
275 p = keyval_array + i * KEYVALS_PER_KEYCODE;
277 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
284 key_code = modifiers[j]|i;
285 err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
286 (modifiers[j] >> 8) & 0xFF,
288 kUCKeyTranslateNoDeadKeysMask,
289 &state, 4, &nChars, chars);
292 /* FIXME: Theoretically, we can get multiple UTF-16 values;
293 * we should convert them to proper unicode and figure
294 * out whether there are really keyboard layouts that
295 * give us more than one character for one keypress. */
296 if (err == noErr && nChars == 1)
299 gboolean found = FALSE;
303 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
305 if (special_ucs_table[k].ucs_value == uc)
307 p[j] = special_ucs_table[k].keyval;
314 p[j] = gdk_unicode_to_keyval (uc);
331 g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
332 " - not supported right now");
335 for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
337 p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
339 if (p[0] == 0 && p[1] == 0 &&
340 p[2] == 0 && p[3] == 0)
341 p[0] = known_keys[i].keyval;
344 for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
346 p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
348 if (p[0] == known_numeric_keys[i].normal_keyval);
349 p[0] = known_numeric_keys[i].keypad_keyval;
353 g_signal_emit_by_name (default_keymap, "keys_changed");
355 current_layout = new_layout;
360 gdk_keymap_get_for_display (GdkDisplay *display)
362 g_return_val_if_fail (display == gdk_display_get_default (), NULL);
364 if (default_keymap == NULL)
365 default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
367 return default_keymap;
371 gdk_keymap_get_direction (GdkKeymap *keymap)
373 return PANGO_DIRECTION_NEUTRAL;
377 gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap,
385 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
386 g_return_val_if_fail (keys != NULL, FALSE);
387 g_return_val_if_fail (n_keys != NULL, FALSE);
388 g_return_val_if_fail (keyval != 0, FALSE);
390 maybe_update_keymap ();
393 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
395 for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
399 if (keyval_array[i] != keyval)
404 key.keycode = i / KEYVALS_PER_KEYCODE;
406 key.level = i % KEYVALS_PER_KEYCODE;
408 g_array_append_val (keys_array, key);
411 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
417 gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap,
418 guint hardware_keycode,
423 GArray *keys_array, *keyvals_array;
427 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
428 g_return_val_if_fail (n_entries != NULL, FALSE);
430 maybe_update_keymap ();
434 if (hardware_keycode > NUM_KEYCODES)
438 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
443 keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
445 keyvals_array = NULL;
447 p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
449 for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
457 g_array_append_val (keyvals_array, p[i]);
463 key.keycode = hardware_keycode;
467 g_array_append_val (keys_array, key);
472 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
475 *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
477 return *n_entries > 0;
481 gdk_keymap_lookup_key (GdkKeymap *keymap,
482 const GdkKeymapKey *key)
484 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
485 g_return_val_if_fail (key != NULL, 0);
486 g_return_val_if_fail (key->group < 4, 0);
488 /* FIXME: Implement */
494 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
497 translate_keysym (guint hardware_keycode,
499 GdkModifierType state,
500 guint *effective_group,
501 guint *effective_level)
506 level = (state & GDK_SHIFT_MASK) ? 1 : 0;
508 if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
509 (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
512 if (!GET_KEYVAL (hardware_keycode, group, level) &&
513 GET_KEYVAL (hardware_keycode, group, 0))
516 tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
518 if (state & GDK_LOCK_MASK)
520 guint upper = gdk_keyval_to_upper (tmp_keyval);
521 if (upper != tmp_keyval)
529 gdk_keymap_translate_keyboard_state (GdkKeymap *keymap,
530 guint hardware_keycode,
531 GdkModifierType state,
534 gint *effective_group,
536 GdkModifierType *consumed_modifiers)
540 guint tmp_modifiers = 0;
542 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
543 g_return_val_if_fail (group >= 0 && group <= 1, FALSE);
545 maybe_update_keymap ();
550 *effective_group = 0;
553 if (consumed_modifiers)
554 *consumed_modifiers = 0;
556 if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
559 /* Check if shift or capslock modify the keyval */
560 for (bit = GDK_SHIFT_MASK; bit < GDK_CONTROL_MASK; bit <<= 1)
562 if (translate_keysym (hardware_keycode, group, state & ~bit, NULL, NULL) !=
563 translate_keysym (hardware_keycode, group, state | bit, NULL, NULL))
564 tmp_modifiers |= bit;
567 tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
569 if (consumed_modifiers)
570 *consumed_modifiers = tmp_modifiers;
573 *keyval = tmp_keyval;