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, see <http://www.gnu.org/licenses/>.
18 */
19 /* Some parts of this code come from quartzKeyboard.c,
20 * from the Apple X11 Server.
21 *
22 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
23 *
24 * Permission is hereby granted, free of charge, to any person
25 * obtaining a copy of this software and associated documentation files
26 * (the "Software"), to deal in the Software without restriction,
27 * including without limitation the rights to use, copy, modify, merge,
28 * publish, distribute, sublicense, and/or sell copies of the Software,
29 * and to permit persons to whom the Software is furnished to do so,
30 * subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be
33 * included in all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
36 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
38 * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
39 * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
40 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42 * DEALINGS IN THE SOFTWARE.
43 *
44 * Except as contained in this notice, the name(s) of the above
45 * copyright holders shall not be used in advertising or otherwise to
46 * promote the sale, use or other dealings in this Software without
47 * prior written authorization.
48 */
49
50 #include "config.h"
51
52 #include <Carbon/Carbon.h>
53 #include <AppKit/NSEvent.h>
54 #include "gdk.h"
55 #include "gdkquartzkeys.h"
56 #include "gdkkeysprivate.h"
57 #include "gdkkeysyms.h"
58 #include "gdkkeys-quartz.h"
59 #include "gdkinternal-quartz.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
G_DEFINE_TYPE(GdkQuartzKeymap,gdk_quartz_keymap,GDK_TYPE_KEYMAP)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 /* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
88 * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
89 */
90 static guint *keyval_array = NULL;
91
92 const static struct {
93 guint keycode;
94 guint keyval;
95 unsigned int modmask; /* So we can tell when a mod key is pressed/released */
96 } modifier_keys[] = {
97 { 54, GDK_KEY_Meta_R, GDK_QUARTZ_COMMAND_KEY_MASK },
98 { 55, GDK_KEY_Meta_L, GDK_QUARTZ_COMMAND_KEY_MASK },
99 { 56, GDK_KEY_Shift_L, GDK_QUARTZ_SHIFT_KEY_MASK },
100 { 57, GDK_KEY_Caps_Lock, GDK_QUARTZ_ALPHA_SHIFT_KEY_MASK },
101 { 58, GDK_KEY_Alt_L, GDK_QUARTZ_ALTERNATE_KEY_MASK },
102 { 59, GDK_KEY_Control_L, GDK_QUARTZ_CONTROL_KEY_MASK },
103 { 60, GDK_KEY_Shift_R, GDK_QUARTZ_SHIFT_KEY_MASK },
104 { 61, GDK_KEY_Alt_R, GDK_QUARTZ_ALTERNATE_KEY_MASK },
105 { 62, GDK_KEY_Control_R, GDK_QUARTZ_CONTROL_KEY_MASK }
106 };
107
108 const static struct {
109 guint keycode;
110 guint keyval;
111 } function_keys[] = {
112 { 122, GDK_KEY_F1 },
113 { 120, GDK_KEY_F2 },
114 { 99, GDK_KEY_F3 },
115 { 118, GDK_KEY_F4 },
116 { 96, GDK_KEY_F5 },
117 { 97, GDK_KEY_F6 },
118 { 98, GDK_KEY_F7 },
119 { 100, GDK_KEY_F8 },
120 { 101, GDK_KEY_F9 },
121 { 109, GDK_KEY_F10 },
122 { 103, GDK_KEY_F11 },
123 { 111, GDK_KEY_F12 },
124 { 105, GDK_KEY_F13 },
125 { 107, GDK_KEY_F14 },
126 { 113, GDK_KEY_F15 },
127 { 106, GDK_KEY_F16 }
128 };
129
130 const static struct {
131 guint keycode;
132 guint normal_keyval, keypad_keyval;
133 } known_numeric_keys[] = {
134 { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
135 { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
136 { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
137 { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
138 { 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
139 { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
140 { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
141 { 82, GDK_KEY_0, GDK_KEY_KP_0 },
142 { 83, GDK_KEY_1, GDK_KEY_KP_1 },
143 { 84, GDK_KEY_2, GDK_KEY_KP_2 },
144 { 85, GDK_KEY_3, GDK_KEY_KP_3 },
145 { 86, GDK_KEY_4, GDK_KEY_KP_4 },
146 { 87, GDK_KEY_5, GDK_KEY_KP_5 },
147 { 88, GDK_KEY_6, GDK_KEY_KP_6 },
148 { 89, GDK_KEY_7, GDK_KEY_KP_7 },
149 { 91, GDK_KEY_8, GDK_KEY_KP_8 },
150 { 92, GDK_KEY_9, GDK_KEY_KP_9 }
151 };
152
153 /* These values aren't covered by gdk_unicode_to_keyval */
154 const static struct {
155 gunichar ucs_value;
156 guint keyval;
157 } special_ucs_table [] = {
158 { 0x0001, GDK_KEY_Home },
159 { 0x0003, GDK_KEY_Return },
160 { 0x0004, GDK_KEY_End },
161 { 0x0008, GDK_KEY_BackSpace },
162 { 0x0009, GDK_KEY_Tab },
163 { 0x000b, GDK_KEY_Page_Up },
164 { 0x000c, GDK_KEY_Page_Down },
165 { 0x000d, GDK_KEY_Return },
166 { 0x001b, GDK_KEY_Escape },
167 { 0x001c, GDK_KEY_Left },
168 { 0x001d, GDK_KEY_Right },
169 { 0x001e, GDK_KEY_Up },
170 { 0x001f, GDK_KEY_Down },
171 { 0x007f, GDK_KEY_Delete },
172 { 0xf027, GDK_KEY_dead_acute },
173 { 0xf060, GDK_KEY_dead_grave },
174 { 0xf300, GDK_KEY_dead_grave },
175 { 0xf0b4, GDK_KEY_dead_acute },
176 { 0xf301, GDK_KEY_dead_acute },
177 { 0xf385, GDK_KEY_dead_acute },
178 { 0xf05e, GDK_KEY_dead_circumflex },
179 { 0xf2c6, GDK_KEY_dead_circumflex },
180 { 0xf302, GDK_KEY_dead_circumflex },
181 { 0xf07e, GDK_KEY_dead_tilde },
182 { 0xf2dc, GDK_KEY_dead_tilde },
183 { 0xf303, GDK_KEY_dead_tilde },
184 { 0xf342, GDK_KEY_dead_perispomeni },
185 { 0xf0af, GDK_KEY_dead_macron },
186 { 0xf304, GDK_KEY_dead_macron },
187 { 0xf2d8, GDK_KEY_dead_breve },
188 { 0xf306, GDK_KEY_dead_breve },
189 { 0xf2d9, GDK_KEY_dead_abovedot },
190 { 0xf307, GDK_KEY_dead_abovedot },
191 { 0xf0a8, GDK_KEY_dead_diaeresis },
192 { 0xf308, GDK_KEY_dead_diaeresis },
193 { 0xf2da, GDK_KEY_dead_abovering },
194 { 0xf30A, GDK_KEY_dead_abovering },
195 { 0xf022, GDK_KEY_dead_doubleacute },
196 { 0xf2dd, GDK_KEY_dead_doubleacute },
197 { 0xf30B, GDK_KEY_dead_doubleacute },
198 { 0xf2c7, GDK_KEY_dead_caron },
199 { 0xf30C, GDK_KEY_dead_caron },
200 { 0xf0be, GDK_KEY_dead_cedilla },
201 { 0xf327, GDK_KEY_dead_cedilla },
202 { 0xf2db, GDK_KEY_dead_ogonek },
203 { 0xf328, GDK_KEY_dead_ogonek },
204 { 0xfe5d, GDK_KEY_dead_iota },
205 { 0xf323, GDK_KEY_dead_belowdot },
206 { 0xf309, GDK_KEY_dead_hook },
207 { 0xf31B, GDK_KEY_dead_horn },
208 { 0xf02d, GDK_KEY_dead_stroke },
209 { 0xf335, GDK_KEY_dead_stroke },
210 { 0xf336, GDK_KEY_dead_stroke },
211 { 0xf313, GDK_KEY_dead_abovecomma },
212 /* { 0xf313, GDK_KEY_dead_psili }, */
213 { 0xf314, GDK_KEY_dead_abovereversedcomma },
214 /* { 0xf314, GDK_KEY_dead_dasia }, */
215 { 0xf30F, GDK_KEY_dead_doublegrave },
216 { 0xf325, GDK_KEY_dead_belowring },
217 { 0xf2cd, GDK_KEY_dead_belowmacron },
218 { 0xf331, GDK_KEY_dead_belowmacron },
219 { 0xf32D, GDK_KEY_dead_belowcircumflex },
220 { 0xf330, GDK_KEY_dead_belowtilde },
221 { 0xf32E, GDK_KEY_dead_belowbreve },
222 { 0xf324, GDK_KEY_dead_belowdiaeresis },
223 { 0xf311, GDK_KEY_dead_invertedbreve },
224 { 0xf02c, GDK_KEY_dead_belowcomma },
225 { 0xf326, GDK_KEY_dead_belowcomma }
226 };
227
228 static void
update_keymap(void)229 update_keymap (void)
230 {
231 const void *chr_data = NULL;
232 guint *p;
233 int i;
234
235 /* Note: we could check only if building against the 10.5 SDK instead, but
236 * that would make non-xml layouts not work in 32-bit which would be a quite
237 * bad regression. This way, old unsupported layouts will just not work in
238 * 64-bit.
239 */
240 #ifdef __LP64__
241 TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
242 CFDataRef layout_data_ref;
243
244 #else
245 KeyboardLayoutRef new_layout;
246 KeyboardLayoutKind layout_kind;
247
248 KLGetCurrentKeyboardLayout (&new_layout);
249 #endif
250
251 g_free (keyval_array);
252 keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
253
254 #ifdef __LP64__
255 layout_data_ref = (CFDataRef) TISGetInputSourceProperty
256 (new_layout, kTISPropertyUnicodeKeyLayoutData);
257
258 if (layout_data_ref)
259 chr_data = CFDataGetBytePtr (layout_data_ref);
260
261 if (chr_data == NULL)
262 {
263 g_error ("cannot get keyboard layout data");
264 return;
265 }
266 #else
267
268 /* Get the layout kind */
269 KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
270
271 /* 8-bit-only keyabord layout */
272 if (layout_kind == kKLKCHRKind)
273 {
274 /* Get chr data */
275 KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
276
277 for (i = 0; i < NUM_KEYCODES; i++)
278 {
279 int j;
280 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
281
282 p = keyval_array + i * KEYVALS_PER_KEYCODE;
283
284 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
285 {
286 UInt32 c, state = 0;
287 UInt16 key_code;
288 UniChar uc;
289
290 key_code = modifiers[j] | i;
291 c = KeyTranslate (chr_data, key_code, &state);
292
293 if (state != 0)
294 {
295 UInt32 state2 = 0;
296 c = KeyTranslate (chr_data, key_code | 128, &state2);
297 }
298
299 if (c != 0 && c != 0x10)
300 {
301 int k;
302 gboolean found = FALSE;
303
304 /* FIXME: some keyboard layouts (e.g. Russian) use a
305 * different 8-bit character set. We should check
306 * for this. Not a serious problem, because most
307 * (all?) of these layouts also have a uchr version.
308 */
309 uc = macroman2ucs (c);
310
311 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
312 {
313 if (special_ucs_table[k].ucs_value == uc)
314 {
315 p[j] = special_ucs_table[k].keyval;
316 found = TRUE;
317 break;
318 }
319 }
320
321 /* Special-case shift-tab since GTK+ expects
322 * GDK_KEY_ISO_Left_Tab for that.
323 */
324 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
325 p[j] = GDK_KEY_ISO_Left_Tab;
326
327 if (!found)
328 p[j] = gdk_unicode_to_keyval (uc);
329 }
330 }
331
332 if (p[3] == p[2])
333 p[3] = 0;
334 if (p[2] == p[1])
335 p[2] = 0;
336 if (p[1] == p[0])
337 p[1] = 0;
338 if (p[0] == p[2] &&
339 p[1] == p[3])
340 p[2] = p[3] = 0;
341 }
342 }
343 /* unicode keyboard layout */
344 else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
345 {
346 /* Get chr data */
347 KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
348 #endif
349
350 for (i = 0; i < NUM_KEYCODES; i++)
351 {
352 int j;
353 UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
354 UniChar chars[4];
355 UniCharCount nChars;
356
357 p = keyval_array + i * KEYVALS_PER_KEYCODE;
358
359 for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
360 {
361 UInt32 state = 0;
362 OSStatus err;
363 UInt16 key_code;
364 UniChar uc;
365
366 key_code = modifiers[j] | i;
367 err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
368 (modifiers[j] >> 8) & 0xFF,
369 LMGetKbdType(),
370 0,
371 &state, 4, &nChars, chars);
372
373 /* FIXME: Theoretically, we can get multiple UTF-16
374 * values; we should convert them to proper unicode and
375 * figure out whether there are really keyboard layouts
376 * that give us more than one character for one
377 * keypress.
378 */
379 if (err == noErr && nChars == 1)
380 {
381 int k;
382 gboolean found = FALSE;
383
384 /* A few <Shift><Option>keys return two characters,
385 * the first of which is U+00a0, which isn't
386 * interesting; so we return the second. More
387 * sophisticated handling is the job of a
388 * GtkIMContext.
389 *
390 * If state isn't zero, it means that it's a dead
391 * key of some sort. Some of those are enumerated in
392 * the special_ucs_table with the high nibble set to
393 * f to push it into the private use range. Here we
394 * do the same.
395 */
396 if (state != 0)
397 chars[nChars - 1] |= 0xf000;
398 uc = chars[nChars - 1];
399
400 for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
401 {
402 if (special_ucs_table[k].ucs_value == uc)
403 {
404 p[j] = special_ucs_table[k].keyval;
405 found = TRUE;
406 break;
407 }
408 }
409
410 /* Special-case shift-tab since GTK+ expects
411 * GDK_KEY_ISO_Left_Tab for that.
412 */
413 if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
414 p[j] = GDK_KEY_ISO_Left_Tab;
415
416 if (!found)
417 p[j] = gdk_unicode_to_keyval (uc);
418 }
419 }
420
421 if (p[3] == p[2])
422 p[3] = 0;
423 if (p[2] == p[1])
424 p[2] = 0;
425 if (p[1] == p[0])
426 p[1] = 0;
427 if (p[0] == p[2] &&
428 p[1] == p[3])
429 p[2] = p[3] = 0;
430 }
431 #ifndef __LP64__
432 }
433 else
434 {
435 g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
436 " - not supported right now");
437 }
438 #endif
439
440 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
441 {
442 p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
443
444 if (p[0] == 0 && p[1] == 0 &&
445 p[2] == 0 && p[3] == 0)
446 p[0] = modifier_keys[i].keyval;
447 }
448
449 for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
450 {
451 p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
452
453 p[0] = function_keys[i].keyval;
454 p[1] = p[2] = p[3] = 0;
455 }
456
457 for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
458 {
459 p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
460
461 if (p[0] == known_numeric_keys[i].normal_keyval)
462 p[0] = known_numeric_keys[i].keypad_keyval;
463 }
464
465 if (default_keymap != NULL)
466 g_signal_emit_by_name (default_keymap, "keys-changed");
467 }
468
469 static PangoDirection
gdk_quartz_keymap_get_direction(GdkKeymap * keymap)470 gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
471 {
472 return PANGO_DIRECTION_NEUTRAL;
473 }
474
475 static gboolean
gdk_quartz_keymap_have_bidi_layouts(GdkKeymap * keymap)476 gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
477 {
478 /* FIXME: Can we implement this? */
479 return FALSE;
480 }
481
482 static gboolean
gdk_quartz_keymap_get_caps_lock_state(GdkKeymap * keymap)483 gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
484 {
485 /* FIXME: Implement this. */
486 return FALSE;
487 }
488
489 static gboolean
gdk_quartz_keymap_get_num_lock_state(GdkKeymap * keymap)490 gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
491 {
492 /* FIXME: Implement this. */
493 return FALSE;
494 }
495
496 static gboolean
gdk_quartz_keymap_get_scroll_lock_state(GdkKeymap * keymap)497 gdk_quartz_keymap_get_scroll_lock_state (GdkKeymap *keymap)
498 {
499 /* FIXME: Implement this. */
500 return FALSE;
501 }
502
503 static gboolean
gdk_quartz_keymap_get_entries_for_keyval(GdkKeymap * keymap,guint keyval,GdkKeymapKey ** keys,gint * n_keys)504 gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap *keymap,
505 guint keyval,
506 GdkKeymapKey **keys,
507 gint *n_keys)
508 {
509 GArray *keys_array;
510 int i;
511
512 *n_keys = 0;
513 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
514
515 for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
516 {
517 GdkKeymapKey key;
518
519 if (keyval_array[i] != keyval)
520 continue;
521
522 (*n_keys)++;
523
524 key.keycode = i / KEYVALS_PER_KEYCODE;
525 key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
526 key.level = i % 2;
527
528 g_array_append_val (keys_array, key);
529 }
530
531 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
532
533 return *n_keys > 0;;
534 }
535
536 static gboolean
gdk_quartz_keymap_get_entries_for_keycode(GdkKeymap * keymap,guint hardware_keycode,GdkKeymapKey ** keys,guint ** keyvals,gint * n_entries)537 gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap *keymap,
538 guint hardware_keycode,
539 GdkKeymapKey **keys,
540 guint **keyvals,
541 gint *n_entries)
542 {
543 GArray *keys_array, *keyvals_array;
544 int i;
545 guint *p;
546
547 *n_entries = 0;
548
549 if (hardware_keycode > NUM_KEYCODES)
550 return FALSE;
551
552 if (keys)
553 keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
554 else
555 keys_array = NULL;
556
557 if (keyvals)
558 keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
559 else
560 keyvals_array = NULL;
561
562 p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
563
564 for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
565 {
566 if (!p[i])
567 continue;
568
569 (*n_entries)++;
570
571 if (keyvals_array)
572 g_array_append_val (keyvals_array, p[i]);
573
574 if (keys_array)
575 {
576 GdkKeymapKey key;
577
578 key.keycode = hardware_keycode;
579 key.group = i >= 2;
580 key.level = i % 2;
581
582 g_array_append_val (keys_array, key);
583 }
584 }
585
586 if (keys)
587 *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
588
589 if (keyvals)
590 *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
591
592 return *n_entries > 0;
593 }
594
595 #define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
596
597 static guint
gdk_quartz_keymap_lookup_key(GdkKeymap * keymap,const GdkKeymapKey * key)598 gdk_quartz_keymap_lookup_key (GdkKeymap *keymap,
599 const GdkKeymapKey *key)
600 {
601 return GET_KEYVAL (key->keycode, key->group, key->level);
602 }
603
604 static guint
translate_keysym(guint hardware_keycode,gint group,GdkModifierType state,gint * effective_group,gint * effective_level)605 translate_keysym (guint hardware_keycode,
606 gint group,
607 GdkModifierType state,
608 gint *effective_group,
609 gint *effective_level)
610 {
611 gint level;
612 guint tmp_keyval;
613
614 level = (state & GDK_SHIFT_MASK) ? 1 : 0;
615
616 if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
617 (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
618 group = 0;
619
620 if (!GET_KEYVAL (hardware_keycode, group, level) &&
621 GET_KEYVAL (hardware_keycode, group, 0))
622 level = 0;
623
624 tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
625
626 if (state & GDK_LOCK_MASK)
627 {
628 guint upper = gdk_keyval_to_upper (tmp_keyval);
629 if (upper != tmp_keyval)
630 tmp_keyval = upper;
631 }
632
633 if (effective_group)
634 *effective_group = group;
635 if (effective_level)
636 *effective_level = level;
637
638 return tmp_keyval;
639 }
640
641 static gboolean
gdk_quartz_keymap_translate_keyboard_state(GdkKeymap * keymap,guint hardware_keycode,GdkModifierType state,gint group,guint * keyval,gint * effective_group,gint * level,GdkModifierType * consumed_modifiers)642 gdk_quartz_keymap_translate_keyboard_state (GdkKeymap *keymap,
643 guint hardware_keycode,
644 GdkModifierType state,
645 gint group,
646 guint *keyval,
647 gint *effective_group,
648 gint *level,
649 GdkModifierType *consumed_modifiers)
650 {
651 guint tmp_keyval;
652 GdkModifierType bit;
653
654 if (keyval)
655 *keyval = 0;
656 if (effective_group)
657 *effective_group = 0;
658 if (level)
659 *level = 0;
660 if (consumed_modifiers)
661 *consumed_modifiers = 0;
662
663 if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
664 return FALSE;
665
666 tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
667
668 /* Check if modifiers modify the keyval */
669 if (consumed_modifiers)
670 {
671 guint tmp_modifiers = (state & GDK_MODIFIER_MASK);
672
673 for (bit = 1; bit <= tmp_modifiers; bit <<= 1)
674 {
675 if ((bit & tmp_modifiers) &&
676 translate_keysym (hardware_keycode, group, state & ~bit,
677 NULL, NULL) == tmp_keyval)
678 tmp_modifiers &= ~bit;
679 }
680
681 *consumed_modifiers = tmp_modifiers;
682 }
683
684 if (keyval)
685 *keyval = tmp_keyval;
686
687 return TRUE;
688 }
689
690 static void
gdk_quartz_keymap_add_virtual_modifiers(GdkKeymap * keymap,GdkModifierType * state)691 gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap *keymap,
692 GdkModifierType *state)
693 {
694 if (*state & GDK_MOD2_MASK)
695 *state |= GDK_META_MASK;
696 }
697
698 static gboolean
gdk_quartz_keymap_map_virtual_modifiers(GdkKeymap * keymap,GdkModifierType * state)699 gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap,
700 GdkModifierType *state)
701 {
702 if (*state & GDK_META_MASK)
703 *state |= GDK_MOD2_MASK;
704
705 return TRUE;
706 }
707
708 static GdkModifierType
gdk_quartz_keymap_get_modifier_mask(GdkKeymap * keymap,GdkModifierIntent intent)709 gdk_quartz_keymap_get_modifier_mask (GdkKeymap *keymap,
710 GdkModifierIntent intent)
711 {
712 switch (intent)
713 {
714 case GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR:
715 return GDK_MOD2_MASK;
716
717 case GDK_MODIFIER_INTENT_CONTEXT_MENU:
718 return GDK_CONTROL_MASK;
719
720 case GDK_MODIFIER_INTENT_EXTEND_SELECTION:
721 return GDK_SHIFT_MASK;
722
723 case GDK_MODIFIER_INTENT_MODIFY_SELECTION:
724 return GDK_MOD2_MASK;
725
726 case GDK_MODIFIER_INTENT_NO_TEXT_INPUT:
727 return GDK_MOD2_MASK | GDK_CONTROL_MASK;
728
729 case GDK_MODIFIER_INTENT_SHIFT_GROUP:
730 return GDK_MOD1_MASK;
731
732 case GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK:
733 return (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK |
734 GDK_MOD2_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK |
735 GDK_META_MASK);
736
737 default:
738 g_return_val_if_reached (0);
739 }
740 }
741
742 /* What sort of key event is this? Returns one of
743 * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
744 */
745 GdkEventType
_gdk_quartz_keys_event_type(NSEvent * event)746 _gdk_quartz_keys_event_type (NSEvent *event)
747 {
748 unsigned short keycode;
749 unsigned int flags;
750 int i;
751
752 switch ([event type])
753 {
754 case GDK_QUARTZ_KEY_DOWN:
755 return GDK_KEY_PRESS;
756 case GDK_QUARTZ_KEY_UP:
757 return GDK_KEY_RELEASE;
758 case GDK_QUARTZ_FLAGS_CHANGED:
759 break;
760 default:
761 g_assert_not_reached ();
762 }
763
764 /* For flags-changed events, we have to find the special key that caused the
765 * event, and see if it's in the modifier mask. */
766 keycode = [event keyCode];
767 flags = [event modifierFlags];
768
769 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
770 {
771 if (modifier_keys[i].keycode == keycode)
772 {
773 if (flags & modifier_keys[i].modmask)
774 return GDK_KEY_PRESS;
775 else
776 return GDK_KEY_RELEASE;
777 }
778 }
779
780 /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
781 * events for no good reason. Ignore them! */
782 return GDK_NOTHING;
783 }
784
785 gboolean
_gdk_quartz_keys_is_modifier(guint keycode)786 _gdk_quartz_keys_is_modifier (guint keycode)
787 {
788 gint i;
789
790 for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
791 {
792 if (modifier_keys[i].modmask == 0)
793 break;
794
795 if (modifier_keys[i].keycode == keycode)
796 return TRUE;
797 }
798
799 return FALSE;
800 }
801
802 static void
input_sources_changed_notification(CFNotificationCenterRef center,void * observer,CFStringRef name,const void * object,CFDictionaryRef userInfo)803 input_sources_changed_notification (CFNotificationCenterRef center,
804 void *observer,
805 CFStringRef name,
806 const void *object,
807 CFDictionaryRef userInfo)
808 {
809 update_keymap ();
810 }
811
812 static void
gdk_quartz_keymap_init(GdkQuartzKeymap * keymap)813 gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
814 {
815 CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
816 keymap,
817 input_sources_changed_notification,
818 CFSTR ("AppleSelectedInputSourcesChangedNotification"),
819 NULL,
820 CFNotificationSuspensionBehaviorDeliverImmediately);
821 update_keymap ();
822 }
823
824 static void
gdk_quartz_keymap_finalize(GObject * object)825 gdk_quartz_keymap_finalize (GObject *object)
826 {
827 CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
828 object,
829 CFSTR ("AppleSelectedInputSourcesChangedNotification"),
830 NULL);
831
832 G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
833 }
834
835 static void
gdk_quartz_keymap_class_init(GdkQuartzKeymapClass * klass)836 gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
837 {
838 GObjectClass *object_class = G_OBJECT_CLASS (klass);
839 GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
840
841 object_class->finalize = gdk_quartz_keymap_finalize;
842
843 keymap_class->get_direction = gdk_quartz_keymap_get_direction;
844 keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
845 keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
846 keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
847 keymap_class->get_scroll_lock_state = gdk_quartz_keymap_get_scroll_lock_state;
848 keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
849 keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
850 keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
851 keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
852 keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
853 keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
854 keymap_class->get_modifier_mask = gdk_quartz_keymap_get_modifier_mask;
855 }
856