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