Add comment from darco about what the "Palette Browser" dock dialog was intended...
[synfig.git] / synfig-osx / trunk / launcher / darwin-new-keymap.c
1 /* darwin-new-keymap.c -- code to build a keymap from the system
2    $Id: darwin-new-keymap.c,v 1.7 2003/02/21 22:33:19 jharper Exp $
3
4    Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
5
6    Permission is hereby granted, free of charge, to any person
7    obtaining a copy of this software and associated documentation files
8    (the "Software"), to deal in the Software without restriction,
9    including without limitation the rights to use, copy, modify, merge,
10    publish, distribute, sublicense, and/or sell copies of the Software,
11    and to permit persons to whom the Software is furnished to do so,
12    subject to the following conditions:
13
14    The above copyright notice and this permission notice shall be
15    included in all copies or substantial portions of the Software.
16
17    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20    NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
21    HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24    DEALINGS IN THE SOFTWARE.
25
26    Except as contained in this notice, the name(s) of the above
27    copyright holders shall not be used in advertising or otherwise to
28    promote the sale, use or other dealings in this Software without
29    prior written authorization. */
30
31
32 #define Cursor X_Cursor
33 # include "darwin-keyboard.h"
34 # include "keysym.h"
35 #undef Cursor
36
37 #include <CoreServices/CoreServices.h>
38 #include <Carbon/Carbon.h>
39
40 #include "keysym2ucs.h"
41
42 #define HACK_MISSING 1
43 #define HACK_KEYPAD 1
44
45 enum {
46     MOD_COMMAND = 256,
47     MOD_SHIFT = 512,
48     MOD_OPTION = 2048,
49     MOD_CONTROL = 4096,
50 };
51
52 #define UKEYSYM(u) ((u) | 0x01000000)
53
54 /* Table of keycode->keysym mappings we use to fallback on for important
55    keys that are often not in the Unicode mapping. */
56
57 const static struct {
58     unsigned short keycode;
59     KeySym keysym;
60 } known_keys[] = {
61     {55,  XK_Meta_L},
62     {56,  XK_Shift_L},
63     {57,  XK_Caps_Lock},
64     {58,  XK_Alt_L},
65     {59,  XK_Control_L},
66     {60,  XK_Shift_R},
67     {61,  XK_Alt_R},
68     {62,  XK_Control_R},
69
70     {122, XK_F1},
71     {120, XK_F2},
72     {99,  XK_F3},
73     {118, XK_F4},
74     {96,  XK_F5},
75     {97,  XK_F6},
76     {98,  XK_F7},
77     {100, XK_F8},
78     {101, XK_F9},
79     {109, XK_F10},
80     {103, XK_F11},
81     {111, XK_F12},
82     {105, XK_F13},
83     {107, XK_F14},
84     {113, XK_F15},
85 };
86
87 /* Table of keycode->old,new-keysym mappings we use to fixup the numeric
88    keypad entries. */
89
90 const static struct {
91     unsigned short keycode;
92     KeySym normal, keypad;
93 } known_numeric_keys[] = {
94     {65, XK_period, XK_KP_Decimal},
95     {67, XK_asterisk, XK_KP_Multiply},
96     {69, XK_plus, XK_KP_Add},
97     {75, XK_slash, XK_KP_Divide},
98     {76, 0x01000003, XK_KP_Enter},
99     {78, XK_minus, XK_KP_Subtract},
100     {81, XK_equal, XK_KP_Equal},
101     {82, XK_0, XK_KP_0},
102     {83, XK_1, XK_KP_1},
103     {84, XK_2, XK_KP_2},
104     {85, XK_3, XK_KP_3},
105     {86, XK_4, XK_KP_4},
106     {87, XK_5, XK_KP_5},
107     {88, XK_6, XK_KP_6},
108     {89, XK_7, XK_KP_7},
109     {91, XK_8, XK_KP_8},
110     {92, XK_9, XK_KP_9},
111 };
112
113 /* Table mapping normal keysyms to their dead equivalents.
114    FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
115
116 const static struct {
117     KeySym normal, dead;
118 } dead_keys[] = {
119     {XK_grave, XK_dead_grave},
120     {XK_acute, XK_dead_acute},
121     {XK_asciicircum, XK_dead_circumflex},
122     {UKEYSYM (0x2c6), XK_dead_circumflex},      /* MODIFIER LETTER CIRCUMFLEX ACCENT */
123     {XK_asciitilde, XK_dead_tilde},
124     {UKEYSYM (0x2dc), XK_dead_tilde},           /* SMALL TILDE */
125     {XK_macron, XK_dead_macron},
126     {XK_breve, XK_dead_breve},
127     {XK_abovedot, XK_dead_abovedot},
128     {XK_diaeresis, XK_dead_diaeresis},
129     {UKEYSYM (0x2da), XK_dead_abovering},       /* DOT ABOVE */
130     {XK_doubleacute, XK_dead_doubleacute},
131     {XK_caron, XK_dead_caron},
132     {XK_cedilla, XK_dead_cedilla},
133     {XK_ogonek, XK_dead_ogonek},
134     {UKEYSYM (0x269), XK_dead_iota},            /* LATIN SMALL LETTER IOTA */
135     {UKEYSYM (0x2ec), XK_dead_voiced_sound},    /* MODIFIER LETTER VOICING */
136 /*  {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
137     {UKEYSYM (0x323), XK_dead_belowdot},        /* COMBINING DOT BELOW */
138     {UKEYSYM (0x309), XK_dead_hook},            /* COMBINING HOOK ABOVE */
139     {UKEYSYM (0x31b), XK_dead_horn},            /* COMBINING HORN */
140 };
141
142 unsigned int
143 DarwinSystemKeymapSeed (void)
144 {
145     static unsigned int seed;
146
147     static KeyboardLayoutRef last_key_layout;
148     KeyboardLayoutRef key_layout;
149
150     KLGetCurrentKeyboardLayout (&key_layout);
151
152     if (key_layout != last_key_layout)
153         seed++;
154
155     last_key_layout = key_layout;
156
157     return seed;
158 }
159
160 static inline UniChar
161 macroman2ucs (unsigned char c)
162 {
163     /* Precalculated table mapping MacRoman-128 to Unicode. Generated
164        by creating single element CFStringRefs then extracting the
165        first character. */
166
167     static const unsigned short table[128] = {
168         0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
169         0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
170         0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
171         0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
172         0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
173         0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
174         0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
175         0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
176         0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
177         0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
178         0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
179         0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
180         0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
181         0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
182         0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
183         0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
184     };
185
186     if (c < 128)
187         return c;
188     else
189         return table[c - 128];
190 }
191
192 static KeySym
193 make_dead_key (KeySym in)
194 {
195     int i;
196
197     for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++)
198     {
199         if (dead_keys[i].normal == in)
200             return dead_keys[i].dead;
201     }
202
203     return in;
204 }
205
206 int
207 DarwinReadSystemKeymap (darwin_keyboard_info *info)
208 {
209     KeyboardLayoutRef key_layout;
210     const void *chr_data;
211     int num_keycodes = NUM_KEYCODES;
212     UInt32 keyboard_type = 0;
213     int is_uchr, i, j;
214     OSStatus err;
215     KeySym *k;
216
217     KLGetCurrentKeyboardLayout (&key_layout);
218     KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data);
219
220     if (chr_data != NULL)
221     {
222         is_uchr = 1;
223         keyboard_type = LMGetKbdType ();
224     }
225     else
226     {
227         KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data);
228
229         if (chr_data == NULL)
230         {
231             fprintf (stderr, "couldn't get uchr or kchr resource\n");
232             return FALSE;
233         }
234
235         is_uchr = 0;
236         num_keycodes = 128;
237     }    
238
239
240     /* Scan the keycode range for the Unicode character that each
241        key produces in the four shift states. Then convert that to
242        an X11 keysym (which may just the bit that says "this is
243        Unicode" if it can't find the real symbol.) */
244
245     for (i = 0; i < num_keycodes; i++)
246     {
247         static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION,
248                                     MOD_OPTION | MOD_SHIFT};
249
250         k = info->key_map + i * GLYPHS_PER_KEY;
251
252         for (j = 0; j < 4; j++)
253         {
254             if (is_uchr)
255             {
256                 UniChar s[8];
257                 UniCharCount len;
258                 UInt32 dead_key_state, extra_dead;
259
260                 dead_key_state = 0;
261                 err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
262                                       mods[j] >> 8, keyboard_type, 0,
263                                       &dead_key_state, 8, &len, s);
264                 if (err != noErr)
265                     continue;
266
267                 if (len == 0 && dead_key_state != 0)
268                 {
269                     /* Found a dead key. Work out which one it is, but
270                        remembering that it's dead. */
271
272                     extra_dead = 0;
273                     err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
274                                           mods[j] >> 8, keyboard_type,
275                                           kUCKeyTranslateNoDeadKeysMask,
276                                           &extra_dead, 8, &len, s);
277                     if (err != noErr)
278                         continue;
279                 }
280
281                 if (len > 0 && s[0] != 0x0010)
282                 {
283                     k[j] = ucs2keysym (s[0]);
284
285                     if (dead_key_state != 0)
286                         k[j] = make_dead_key (k[j]);
287                 }
288             }
289             else
290             {
291                 UInt32 c, state = 0;
292                 UInt16 code;
293
294                 code = i | mods[j];
295                 c = KeyTranslate (chr_data, code, &state);
296
297                 /* Dead keys are only processed on key-down, so ask
298                    to translate those events. When we find a dead key,
299                    translating the matching key up event will give
300                    us the actual dead character. */
301
302                 if (state != 0)
303                 {
304                     UInt32 state2 = 0;
305                     c = KeyTranslate (chr_data, code | 128, &state2);
306                 }
307
308                 /* Characters seem to be in MacRoman encoding. */
309
310                 if (c != 0 && c != 0x0010)
311                 {
312                     k[j] = ucs2keysym (macroman2ucs (c & 255));
313
314                     if (state != 0)
315                         k[j] = make_dead_key (k[j]);
316                 }
317             }
318         }
319
320         if (k[3] == k[2])
321             k[3] = NoSymbol;
322         if (k[2] == k[1])
323             k[2] = NoSymbol;
324         if (k[1] == k[0])
325             k[1] = NoSymbol;
326         if (k[0] == k[2] && k[1] == k[3])
327             k[2] = k[3] = NoSymbol;
328     }
329
330     /* Fix up some things that are normally missing.. */
331
332     if (HACK_MISSING)
333     {
334         for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++)
335         {
336             k = info->key_map + known_keys[i].keycode * GLYPHS_PER_KEY;
337
338             if (k[0] == NoSymbol && k[1] == NoSymbol
339                 && k[2] == NoSymbol && k[3] == NoSymbol)
340             {
341                 k[0] = known_keys[i].keysym;
342             }
343         }
344     }
345
346     /* And some more things. We find the right symbols for the numeric
347        keypad, but not the KP_ keysyms. So try to convert known keycodes. */
348
349     if (HACK_KEYPAD)
350     {
351         for (i = 0; i < sizeof (known_numeric_keys)
352              / sizeof (known_numeric_keys[0]); i++)
353         {
354             k = info->key_map + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
355
356             if (k[0] == known_numeric_keys[i].normal)
357             {
358                 k[0] = known_numeric_keys[i].keypad;
359             }
360         }
361     }
362
363     return TRUE;
364 }