winemac: Rebuild key map when Mac keyboard layout changes.
[wine] / dlls / winemac.drv / keyboard.c
1 /*
2  * MACDRV keyboard driver
3  *
4  * Copyright 1993 Bob Amstadt
5  * Copyright 1996 Albrecht Kleine
6  * Copyright 1997 David Faure
7  * Copyright 1998 Morten Welinder
8  * Copyright 1998 Ulrich Weigand
9  * Copyright 1999 Ove Kåven
10  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26
27 #include "config.h"
28
29 #include "macdrv.h"
30 #include "winuser.h"
31 #include "wine/unicode.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
34
35
36 /* Carbon-style modifier mask definitions from <Carbon/HIToolbox/Events.h>. */
37 enum {
38     cmdKeyBit       = 8,
39     shiftKeyBit     = 9,
40     alphaLockBit    = 10,
41     optionKeyBit    = 11,
42     controlKeyBit   = 12,
43 };
44
45 enum {
46     cmdKey      = 1 << cmdKeyBit,
47     shiftKey    = 1 << shiftKeyBit,
48     alphaLock   = 1 << alphaLockBit,
49     optionKey   = 1 << optionKeyBit,
50     controlKey  = 1 << controlKeyBit,
51 };
52
53
54 /* Mac virtual key code definitions from <Carbon/HIToolbox/Events.h>. */
55 enum {
56     kVK_ANSI_A              = 0x00,
57     kVK_ANSI_S              = 0x01,
58     kVK_ANSI_D              = 0x02,
59     kVK_ANSI_F              = 0x03,
60     kVK_ANSI_H              = 0x04,
61     kVK_ANSI_G              = 0x05,
62     kVK_ANSI_Z              = 0x06,
63     kVK_ANSI_X              = 0x07,
64     kVK_ANSI_C              = 0x08,
65     kVK_ANSI_V              = 0x09,
66     kVK_ISO_Section         = 0x0A,
67     kVK_ANSI_B              = 0x0B,
68     kVK_ANSI_Q              = 0x0C,
69     kVK_ANSI_W              = 0x0D,
70     kVK_ANSI_E              = 0x0E,
71     kVK_ANSI_R              = 0x0F,
72     kVK_ANSI_Y              = 0x10,
73     kVK_ANSI_T              = 0x11,
74     kVK_ANSI_1              = 0x12,
75     kVK_ANSI_2              = 0x13,
76     kVK_ANSI_3              = 0x14,
77     kVK_ANSI_4              = 0x15,
78     kVK_ANSI_6              = 0x16,
79     kVK_ANSI_5              = 0x17,
80     kVK_ANSI_Equal          = 0x18,
81     kVK_ANSI_9              = 0x19,
82     kVK_ANSI_7              = 0x1A,
83     kVK_ANSI_Minus          = 0x1B,
84     kVK_ANSI_8              = 0x1C,
85     kVK_ANSI_0              = 0x1D,
86     kVK_ANSI_RightBracket   = 0x1E,
87     kVK_ANSI_O              = 0x1F,
88     kVK_ANSI_U              = 0x20,
89     kVK_ANSI_LeftBracket    = 0x21,
90     kVK_ANSI_I              = 0x22,
91     kVK_ANSI_P              = 0x23,
92     kVK_Return              = 0x24,
93     kVK_ANSI_L              = 0x25,
94     kVK_ANSI_J              = 0x26,
95     kVK_ANSI_Quote          = 0x27,
96     kVK_ANSI_K              = 0x28,
97     kVK_ANSI_Semicolon      = 0x29,
98     kVK_ANSI_Backslash      = 0x2A,
99     kVK_ANSI_Comma          = 0x2B,
100     kVK_ANSI_Slash          = 0x2C,
101     kVK_ANSI_N              = 0x2D,
102     kVK_ANSI_M              = 0x2E,
103     kVK_ANSI_Period         = 0x2F,
104     kVK_Tab                 = 0x30,
105     kVK_Space               = 0x31,
106     kVK_ANSI_Grave          = 0x32,
107     kVK_Delete              = 0x33,
108     kVK_Escape              = 0x35,
109     kVK_RightCommand        = 0x36, /* invented for Wine; co-opt unused key code */
110     kVK_Command             = 0x37,
111     kVK_Shift               = 0x38,
112     kVK_CapsLock            = 0x39,
113     kVK_Option              = 0x3A,
114     kVK_Control             = 0x3B,
115     kVK_RightShift          = 0x3C,
116     kVK_RightOption         = 0x3D,
117     kVK_RightControl        = 0x3E,
118     kVK_Function            = 0x3F,
119     kVK_F17                 = 0x40,
120     kVK_ANSI_KeypadDecimal  = 0x41,
121     kVK_ANSI_KeypadMultiply = 0x43,
122     kVK_ANSI_KeypadPlus     = 0x45,
123     kVK_ANSI_KeypadClear    = 0x47,
124     kVK_VolumeUp            = 0x48,
125     kVK_VolumeDown          = 0x49,
126     kVK_Mute                = 0x4A,
127     kVK_ANSI_KeypadDivide   = 0x4B,
128     kVK_ANSI_KeypadEnter    = 0x4C,
129     kVK_ANSI_KeypadMinus    = 0x4E,
130     kVK_F18                 = 0x4F,
131     kVK_F19                 = 0x50,
132     kVK_ANSI_KeypadEquals   = 0x51,
133     kVK_ANSI_Keypad0        = 0x52,
134     kVK_ANSI_Keypad1        = 0x53,
135     kVK_ANSI_Keypad2        = 0x54,
136     kVK_ANSI_Keypad3        = 0x55,
137     kVK_ANSI_Keypad4        = 0x56,
138     kVK_ANSI_Keypad5        = 0x57,
139     kVK_ANSI_Keypad6        = 0x58,
140     kVK_ANSI_Keypad7        = 0x59,
141     kVK_F20                 = 0x5A,
142     kVK_ANSI_Keypad8        = 0x5B,
143     kVK_ANSI_Keypad9        = 0x5C,
144     kVK_JIS_Yen             = 0x5D,
145     kVK_JIS_Underscore      = 0x5E,
146     kVK_JIS_KeypadComma     = 0x5F,
147     kVK_F5                  = 0x60,
148     kVK_F6                  = 0x61,
149     kVK_F7                  = 0x62,
150     kVK_F3                  = 0x63,
151     kVK_F8                  = 0x64,
152     kVK_F9                  = 0x65,
153     kVK_JIS_Eisu            = 0x66,
154     kVK_F11                 = 0x67,
155     kVK_JIS_Kana            = 0x68,
156     kVK_F13                 = 0x69,
157     kVK_F16                 = 0x6A,
158     kVK_F14                 = 0x6B,
159     kVK_F10                 = 0x6D,
160     kVK_F12                 = 0x6F,
161     kVK_F15                 = 0x71,
162     kVK_Help                = 0x72,
163     kVK_Home                = 0x73,
164     kVK_PageUp              = 0x74,
165     kVK_ForwardDelete       = 0x75,
166     kVK_F4                  = 0x76,
167     kVK_End                 = 0x77,
168     kVK_F2                  = 0x78,
169     kVK_PageDown            = 0x79,
170     kVK_F1                  = 0x7A,
171     kVK_LeftArrow           = 0x7B,
172     kVK_RightArrow          = 0x7C,
173     kVK_DownArrow           = 0x7D,
174     kVK_UpArrow             = 0x7E,
175 };
176
177
178 /* Indexed by Mac virtual keycode values defined above. */
179 static const struct {
180     WORD vkey;
181     WORD scan;
182     BOOL fixed;
183 } default_map[128] = {
184     { 'A',                      0x1E,           FALSE },    /* kVK_ANSI_A */
185     { 'S',                      0x1F,           FALSE },    /* kVK_ANSI_S */
186     { 'D',                      0x20,           FALSE },    /* kVK_ANSI_D */
187     { 'F',                      0x21,           FALSE },    /* kVK_ANSI_F */
188     { 'H',                      0x23,           FALSE },    /* kVK_ANSI_H */
189     { 'G',                      0x22,           FALSE },    /* kVK_ANSI_G */
190     { 'Z',                      0x2C,           FALSE },    /* kVK_ANSI_Z */
191     { 'X',                      0x2D,           FALSE },    /* kVK_ANSI_X */
192     { 'C',                      0x2E,           FALSE },    /* kVK_ANSI_C */
193     { 'V',                      0x2F,           FALSE },    /* kVK_ANSI_V */
194     { VK_OEM_102,               0x56,           TRUE },     /* kVK_ISO_Section */
195     { 'B',                      0x30,           FALSE },    /* kVK_ANSI_B */
196     { 'Q',                      0x10,           FALSE },    /* kVK_ANSI_Q */
197     { 'W',                      0x11,           FALSE },    /* kVK_ANSI_W */
198     { 'E',                      0x12,           FALSE },    /* kVK_ANSI_E */
199     { 'R',                      0x13,           FALSE },    /* kVK_ANSI_R */
200     { 'Y',                      0x15,           FALSE },    /* kVK_ANSI_Y */
201     { 'T',                      0x14,           FALSE },    /* kVK_ANSI_T */
202     { '1',                      0x02,           FALSE },    /* kVK_ANSI_1 */
203     { '2',                      0x03,           FALSE },    /* kVK_ANSI_2 */
204     { '3',                      0x04,           FALSE },    /* kVK_ANSI_3 */
205     { '4',                      0x05,           FALSE },    /* kVK_ANSI_4 */
206     { '6',                      0x07,           FALSE },    /* kVK_ANSI_6 */
207     { '5',                      0x06,           FALSE },    /* kVK_ANSI_5 */
208     { VK_OEM_PLUS,              0x0D,           FALSE },    /* kVK_ANSI_Equal */
209     { '9',                      0x0A,           FALSE },    /* kVK_ANSI_9 */
210     { '7',                      0x08,           FALSE },    /* kVK_ANSI_7 */
211     { VK_OEM_MINUS,             0x0C,           FALSE },    /* kVK_ANSI_Minus */
212     { '8',                      0x09,           FALSE },    /* kVK_ANSI_8 */
213     { '0',                      0x0B,           FALSE },    /* kVK_ANSI_0 */
214     { VK_OEM_6,                 0x1B,           FALSE },    /* kVK_ANSI_RightBracket */
215     { 'O',                      0x18,           FALSE },    /* kVK_ANSI_O */
216     { 'U',                      0x16,           FALSE },    /* kVK_ANSI_U */
217     { VK_OEM_4,                 0x1A,           FALSE },    /* kVK_ANSI_LeftBracket */
218     { 'I',                      0x17,           FALSE },    /* kVK_ANSI_I */
219     { 'P',                      0x19,           FALSE },    /* kVK_ANSI_P */
220     { VK_RETURN,                0x1C,           TRUE },     /* kVK_Return */
221     { 'L',                      0x26,           FALSE },    /* kVK_ANSI_L */
222     { 'J',                      0x24,           FALSE },    /* kVK_ANSI_J */
223     { VK_OEM_7,                 0x28,           FALSE },    /* kVK_ANSI_Quote */
224     { 'K',                      0x25,           FALSE },    /* kVK_ANSI_K */
225     { VK_OEM_1,                 0x27,           FALSE },    /* kVK_ANSI_Semicolon */
226     { VK_OEM_5,                 0x2B,           FALSE },    /* kVK_ANSI_Backslash */
227     { VK_OEM_COMMA,             0x33,           FALSE },    /* kVK_ANSI_Comma */
228     { VK_OEM_2,                 0x35,           FALSE },    /* kVK_ANSI_Slash */
229     { 'N',                      0x31,           FALSE },    /* kVK_ANSI_N */
230     { 'M',                      0x32,           FALSE },    /* kVK_ANSI_M */
231     { VK_OEM_PERIOD,            0x34,           FALSE },    /* kVK_ANSI_Period */
232     { VK_TAB,                   0x0F,           TRUE },     /* kVK_Tab */
233     { VK_SPACE,                 0x39,           TRUE },     /* kVK_Space */
234     { VK_OEM_3,                 0x29,           FALSE },    /* kVK_ANSI_Grave */
235     { VK_BACK,                  0x0E,           TRUE },     /* kVK_Delete */
236     { 0,                        0,              FALSE },    /* 0x34 unused */
237     { VK_ESCAPE,                0x01,           TRUE },     /* kVK_Escape */
238     { VK_RMENU,                 0x38 | 0x100,   TRUE },     /* kVK_RightCommand */
239     { VK_LMENU,                 0x38,           TRUE },     /* kVK_Command */
240     { VK_LSHIFT,                0x2A,           TRUE },     /* kVK_Shift */
241     { VK_CAPITAL,               0x3A,           TRUE },     /* kVK_CapsLock */
242     { 0,                        0,              FALSE },    /* kVK_Option */
243     { VK_LCONTROL,              0x1D,           TRUE },     /* kVK_Control */
244     { VK_RSHIFT,                0x36,           TRUE },     /* kVK_RightShift */
245     { 0,                        0,              FALSE },    /* kVK_RightOption */
246     { VK_RCONTROL,              0x1D | 0x100,   TRUE },     /* kVK_RightControl */
247     { 0,                        0,              FALSE },    /* kVK_Function */
248     { VK_F17,                   0x68,           TRUE },     /* kVK_F17 */
249     { VK_DECIMAL,               0x53,           TRUE },     /* kVK_ANSI_KeypadDecimal */
250     { 0,                        0,              FALSE },    /* 0x42 unused */
251     { VK_MULTIPLY,              0x37,           TRUE },     /* kVK_ANSI_KeypadMultiply */
252     { 0,                        0,              FALSE },    /* 0x44 unused */
253     { VK_ADD,                   0x4E,           TRUE },     /* kVK_ANSI_KeypadPlus */
254     { 0,                        0,              FALSE },    /* 0x46 unused */
255     { VK_OEM_CLEAR,             0x59,           TRUE },     /* kVK_ANSI_KeypadClear */
256     { VK_VOLUME_UP,             0 | 0x100,      TRUE },     /* kVK_VolumeUp */
257     { VK_VOLUME_DOWN,           0 | 0x100,      TRUE },     /* kVK_VolumeDown */
258     { VK_VOLUME_MUTE,           0 | 0x100,      TRUE },     /* kVK_Mute */
259     { VK_DIVIDE,                0x35 | 0x100,   TRUE },     /* kVK_ANSI_KeypadDivide */
260     { VK_RETURN,                0x1C | 0x100,   TRUE },     /* kVK_ANSI_KeypadEnter */
261     { 0,                        0,              FALSE },    /* 0x4D unused */
262     { VK_SUBTRACT,              0x4A,           TRUE },     /* kVK_ANSI_KeypadMinus */
263     { VK_F18,                   0x69,           TRUE },     /* kVK_F18 */
264     { VK_F19,                   0x6A,           TRUE },     /* kVK_F19 */
265     { VK_OEM_NEC_EQUAL,         0x0D | 0x100,   TRUE },     /* kVK_ANSI_KeypadEquals */
266     { VK_NUMPAD0,               0x52,           TRUE },     /* kVK_ANSI_Keypad0 */
267     { VK_NUMPAD1,               0x4F,           TRUE },     /* kVK_ANSI_Keypad1 */
268     { VK_NUMPAD2,               0x50,           TRUE },     /* kVK_ANSI_Keypad2 */
269     { VK_NUMPAD3,               0x51,           TRUE },     /* kVK_ANSI_Keypad3 */
270     { VK_NUMPAD4,               0x4B,           TRUE },     /* kVK_ANSI_Keypad4 */
271     { VK_NUMPAD5,               0x4C,           TRUE },     /* kVK_ANSI_Keypad5 */
272     { VK_NUMPAD6,               0x4D,           TRUE },     /* kVK_ANSI_Keypad6 */
273     { VK_NUMPAD7,               0x47,           TRUE },     /* kVK_ANSI_Keypad7 */
274     { VK_F20,                   0x6B,           TRUE },     /* kVK_F20 */
275     { VK_NUMPAD8,               0x48,           TRUE },     /* kVK_ANSI_Keypad8 */
276     { VK_NUMPAD9,               0x49,           TRUE },     /* kVK_ANSI_Keypad9 */
277     { 0xFF,                     0x7D,           TRUE },     /* kVK_JIS_Yen */
278     { 0xC1,                     0x73,           TRUE },     /* kVK_JIS_Underscore */
279     { VK_SEPARATOR,             0x7E,           TRUE },     /* kVK_JIS_KeypadComma */
280     { VK_F5,                    0x3F,           TRUE },     /* kVK_F5 */
281     { VK_F6,                    0x40,           TRUE },     /* kVK_F6 */
282     { VK_F7,                    0x41,           TRUE },     /* kVK_F7 */
283     { VK_F3,                    0x3D,           TRUE },     /* kVK_F3 */
284     { VK_F8,                    0x42,           TRUE },     /* kVK_F8 */
285     { VK_F9,                    0x43,           TRUE },     /* kVK_F9 */
286     { 0xFF,                     0x72,           TRUE },     /* kVK_JIS_Eisu */
287     { VK_F11,                   0x57,           TRUE },     /* kVK_F11 */
288     { VK_OEM_RESET,             0x71,           TRUE },     /* kVK_JIS_Kana */
289     { VK_F13,                   0x64,           TRUE },     /* kVK_F13 */
290     { VK_F16,                   0x67,           TRUE },     /* kVK_F16 */
291     { VK_F14,                   0x65,           TRUE },     /* kVK_F14 */
292     { 0,                        0,              FALSE },    /* 0x6C unused */
293     { VK_F10,                   0x44,           TRUE },     /* kVK_F10 */
294     { 0,                        0,              FALSE },    /* 0x6E unused */
295     { VK_F12,                   0x58,           TRUE },     /* kVK_F12 */
296     { 0,                        0,              FALSE },    /* 0x70 unused */
297     { VK_F15,                   0x66,           TRUE },     /* kVK_F15 */
298     { VK_INSERT,                0x52 | 0x100,   TRUE },     /* kVK_Help */ /* map to Insert */
299     { VK_HOME,                  0x47 | 0x100,   TRUE },     /* kVK_Home */
300     { VK_PRIOR,                 0x49 | 0x100,   TRUE },     /* kVK_PageUp */
301     { VK_DELETE,                0x53 | 0x100,   TRUE },     /* kVK_ForwardDelete */
302     { VK_F4,                    0x3E,           TRUE },     /* kVK_F4 */
303     { VK_END,                   0x4F | 0x100,   TRUE },     /* kVK_End */
304     { VK_F2,                    0x3C,           TRUE },     /* kVK_F2 */
305     { VK_NEXT,                  0x51 | 0x100,   TRUE },     /* kVK_PageDown */
306     { VK_F1,                    0x3B,           TRUE },     /* kVK_F1 */
307     { VK_LEFT,                  0x4B | 0x100,   TRUE },     /* kVK_LeftArrow */
308     { VK_RIGHT,                 0x4D | 0x100,   TRUE },     /* kVK_RightArrow */
309     { VK_DOWN,                  0x50 | 0x100,   TRUE },     /* kVK_DownArrow */
310     { VK_UP,                    0x48 | 0x100,   TRUE },     /* kVK_UpArrow */
311 };
312
313
314 static BOOL char_matches_string(WCHAR wchar, UniChar *string, BOOL ignore_diacritics)
315 {
316     BOOL ret;
317     CFStringRef s1 = CFStringCreateWithCharactersNoCopy(NULL, (UniChar*)&wchar, 1, kCFAllocatorNull);
318     CFStringRef s2 = CFStringCreateWithCharactersNoCopy(NULL, string, strlenW(string), kCFAllocatorNull);
319     CFStringCompareFlags flags = kCFCompareCaseInsensitive | kCFCompareNonliteral | kCFCompareWidthInsensitive;
320     if (ignore_diacritics)
321         flags |= kCFCompareDiacriticInsensitive;
322     ret = (CFStringCompare(s1, s2, flags) == kCFCompareEqualTo);
323     CFRelease(s1);
324     CFRelease(s2);
325     return ret;
326 }
327
328
329 /***********************************************************************
330  *              macdrv_compute_keyboard_layout
331  */
332 void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data)
333 {
334     int keyc;
335     WCHAR vkey;
336     const UCKeyboardLayout *uchr;
337     const UInt32 modifier_combos[] = {
338         0,
339         shiftKey >> 8,
340         cmdKey >> 8,
341         (shiftKey | cmdKey) >> 8,
342         optionKey >> 8,
343         (shiftKey | optionKey) >> 8,
344     };
345     UniChar map[128][sizeof(modifier_combos) / sizeof(modifier_combos[0])][4 + 1];
346     int combo;
347     BYTE vkey_used[256];
348     int ignore_diacritics;
349     static const struct {
350         WCHAR wchar;
351         DWORD vkey;
352     } symbol_vkeys[] = {
353         { '-', VK_OEM_MINUS },
354         { '+', VK_OEM_PLUS },
355         { '_', VK_OEM_MINUS },
356         { ',', VK_OEM_COMMA },
357         { '.', VK_OEM_PERIOD },
358         { '=', VK_OEM_PLUS },
359         { '>', VK_OEM_PERIOD },
360         { '<', VK_OEM_COMMA },
361         { '|', VK_OEM_5 },
362         { '\\', VK_OEM_5 },
363         { '`', VK_OEM_3 },
364         { '[', VK_OEM_4 },
365         { '~', VK_OEM_3 },
366         { '?', VK_OEM_2 },
367         { ']', VK_OEM_6 },
368         { '/', VK_OEM_2 },
369         { ':', VK_OEM_1 },
370         { '}', VK_OEM_6 },
371         { '{', VK_OEM_4 },
372         { ';', VK_OEM_1 },
373         { '\'', VK_OEM_7 },
374         { ':', VK_OEM_PERIOD },
375         { ';', VK_OEM_COMMA },
376         { '"', VK_OEM_7 },
377         { 0x00B4, VK_OEM_4 }, /* 0x00B4 is ACUTE ACCENT */
378         { '\'', VK_OEM_2 },
379         { 0x00A7, VK_OEM_5 }, /* 0x00A7 is SECTION SIGN */
380         { '*', VK_OEM_PLUS },
381         { 0x00B4, VK_OEM_7 },
382         { '`', VK_OEM_4 },
383         { '[', VK_OEM_6 },
384         { '/', VK_OEM_5 },
385         { '^', VK_OEM_6 },
386         { '*', VK_OEM_2 },
387         { '{', VK_OEM_6 },
388         { '~', VK_OEM_1 },
389         { '?', VK_OEM_PLUS },
390         { '?', VK_OEM_4 },
391         { 0x00B4, VK_OEM_3 },
392         { '?', VK_OEM_COMMA },
393         { '~', VK_OEM_PLUS },
394         { ']', VK_OEM_4 },
395         { '\'', VK_OEM_3 },
396         { 0x00A7, VK_OEM_7 },
397     };
398     int i;
399
400     /* Vkeys that are suitable for assigning to arbitrary keys, organized in
401        contiguous ranges. */
402     static const struct {
403         WORD first, last;
404     } vkey_ranges[] = {
405         { 'A', 'Z' },
406         { '0', '9' },
407         { VK_OEM_1, VK_OEM_3 },
408         { VK_OEM_4, VK_ICO_CLEAR },
409         { 0xe9, 0xf5 },
410         { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
411         { VK_F1, VK_F24 },
412         { 0, 0 }
413     };
414     int vkey_range;
415
416     if (!thread_data->keyboard_layout_uchr)
417     {
418         ERR("no keyboard layout UCHR data\n");
419         return;
420     }
421
422     memset(thread_data->keyc2vkey, 0, sizeof(thread_data->keyc2vkey));
423     memset(vkey_used, 0, sizeof(vkey_used));
424
425     for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
426     {
427         thread_data->keyc2scan[keyc] = default_map[keyc].scan;
428         if (default_map[keyc].fixed)
429         {
430             vkey = default_map[keyc].vkey;
431             thread_data->keyc2vkey[keyc] = vkey;
432             vkey_used[vkey] = 1;
433             TRACE("keyc 0x%04x -> vkey 0x%04x (fixed)\n", keyc, vkey);
434         }
435     }
436
437     if (thread_data->iso_keyboard)
438     {
439         /* In almost all cases, the Mac key codes indicate a physical key position
440            and this corresponds nicely to Win32 scan codes.  However, the Mac key
441            codes differ in one case between ANSI and ISO keyboards.  For ANSI
442            keyboards, the key to the left of the digits and above the Tab key
443            produces key code kVK_ANSI_Grave.  For ISO keyboards, the key in that
444            some position produces kVK_ISO_Section.  The additional key on ISO
445            keyboards, the one to the right of the left Shift key, produces
446            kVK_ANSI_Grave, which is just weird.
447
448            Since we want the key in that upper left corner to always produce the
449            same scan code (0x29), we need to swap the scan codes of those two
450            Mac key codes for ISO keyboards. */
451         DWORD temp = thread_data->keyc2scan[kVK_ANSI_Grave];
452         thread_data->keyc2scan[kVK_ANSI_Grave] = thread_data->keyc2scan[kVK_ISO_Section];
453         thread_data->keyc2scan[kVK_ISO_Section] = temp;
454     }
455
456     uchr = (const UCKeyboardLayout*)CFDataGetBytePtr(thread_data->keyboard_layout_uchr);
457
458     /* Using the keyboard layout, build a map of key code + modifiers -> characters. */
459     memset(map, 0, sizeof(map));
460     for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
461     {
462         if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
463         if (thread_data->keyc2vkey[keyc]) continue; /* assigned a fixed vkey */
464
465         TRACE("keyc 0x%04x: ", keyc);
466
467         for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
468         {
469             UInt32 deadKeyState;
470             UniCharCount len;
471             OSStatus status;
472
473             deadKeyState = 0;
474             status = UCKeyTranslate(uchr, keyc, kUCKeyActionDown, modifier_combos[combo],
475                 thread_data->keyboard_type, kUCKeyTranslateNoDeadKeysMask,
476                 &deadKeyState, sizeof(map[keyc][combo])/sizeof(map[keyc][combo][0]) - 1,
477                 &len, map[keyc][combo]);
478             if (status != noErr)
479                 map[keyc][combo][0] = 0;
480
481             TRACE("%s%s", (combo ? ", " : ""), debugstr_w(map[keyc][combo]));
482         }
483
484         TRACE("\n");
485     }
486
487     /* First try to match key codes to the vkeys for the letters A through Z.
488        Try unmodified first, then with various modifier combinations in succession.
489        On the first pass, try to get a match lacking diacritical marks.  On the
490        second pass, accept matches with diacritical marks. */
491     for (ignore_diacritics = 0; ignore_diacritics <= 1; ignore_diacritics++)
492     {
493         for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
494         {
495             for (vkey = 'A'; vkey <= 'Z'; vkey++)
496             {
497                 if (vkey_used[vkey])
498                     continue;
499
500                 for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
501                 {
502                     if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
503                         continue;
504
505                     if (char_matches_string(vkey, map[keyc][combo], ignore_diacritics))
506                     {
507                         thread_data->keyc2vkey[keyc] = vkey;
508                         vkey_used[vkey] = 1;
509                         TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
510                               debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
511                         break;
512                     }
513                 }
514             }
515         }
516     }
517
518     /* Next try to match key codes to the vkeys for the digits 0 through 9. */
519     for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
520     {
521         for (vkey = '0'; vkey <= '9'; vkey++)
522         {
523             if (vkey_used[vkey])
524                 continue;
525
526             for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
527             {
528                 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
529                     continue;
530
531                 if (char_matches_string(vkey, map[keyc][combo], FALSE))
532                 {
533                     thread_data->keyc2vkey[keyc] = vkey;
534                     vkey_used[vkey] = 1;
535                     TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
536                           debugstr_wn(&vkey, 1), debugstr_w(map[keyc][combo]));
537                     break;
538                 }
539             }
540         }
541     }
542
543     /* Now try to match key codes for certain common punctuation characters to
544        the most common OEM vkeys (e.g. '.' to VK_OEM_PERIOD). */
545     for (i = 0; i < sizeof(symbol_vkeys) / sizeof(symbol_vkeys[0]); i++)
546     {
547         vkey = symbol_vkeys[i].vkey;
548
549         if (vkey_used[vkey])
550             continue;
551
552         for (combo = 0; combo < sizeof(modifier_combos) / sizeof(modifier_combos[0]); combo++)
553         {
554             for (keyc = 0; keyc < sizeof(map) / sizeof(map[0]); keyc++)
555             {
556                 if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
557                 if (thread_data->keyc2vkey[keyc] || !map[keyc][combo][0])
558                     continue;
559
560                 if (char_matches_string(symbol_vkeys[i].wchar, map[keyc][combo], FALSE))
561                 {
562                     thread_data->keyc2vkey[keyc] = vkey;
563                     vkey_used[vkey] = 1;
564                     TRACE("keyc 0x%04x -> vkey 0x%04x (%s match %s)\n", keyc, vkey,
565                           debugstr_wn(&symbol_vkeys[i].wchar, 1), debugstr_w(map[keyc][combo]));
566                     break;
567                 }
568             }
569
570             if (vkey_used[vkey])
571                 break;
572         }
573     }
574
575     /* For those key codes still without a vkey, try to use the default vkey
576        from the default map, if it's still available. */
577     for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
578     {
579         DWORD vkey = default_map[keyc].vkey;
580
581         if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
582         if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
583
584         if (!vkey_used[vkey])
585         {
586             thread_data->keyc2vkey[keyc] = vkey;
587             vkey_used[vkey] = 1;
588             TRACE("keyc 0x%04x -> vkey 0x%04x (default map)\n", keyc, vkey);
589         }
590     }
591
592     /* For any unassigned key codes which would map to a letter in the default
593        map, but whose normal letter vkey wasn't available, try to find a
594        different letter. */
595     vkey = 'A';
596     for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
597     {
598         if (default_map[keyc].vkey < 'A' || 'Z' < default_map[keyc].vkey)
599             continue; /* not a letter in ANSI layout */
600         if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
601         if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
602
603         while (vkey <= 'Z' && vkey_used[vkey]) vkey++;
604         if (vkey <= 'Z')
605         {
606             thread_data->keyc2vkey[keyc] = vkey;
607             vkey_used[vkey] = 1;
608             TRACE("keyc 0x%04x -> vkey 0x%04x (spare letter)\n", keyc, vkey);
609         }
610         else
611             break; /* no more unused letter vkeys, so stop trying */
612     }
613
614     /* Same thing but with the digits. */
615     vkey = '0';
616     for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
617     {
618         if (default_map[keyc].vkey < '0' || '9' < default_map[keyc].vkey)
619             continue; /* not a digit in ANSI layout */
620         if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
621         if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
622
623         while (vkey <= '9' && vkey_used[vkey]) vkey++;
624         if (vkey <= '9')
625         {
626             thread_data->keyc2vkey[keyc] = vkey;
627             vkey_used[vkey] = 1;
628             TRACE("keyc 0x%04x -> vkey 0x%04x (spare digit)\n", keyc, vkey);
629         }
630         else
631             break; /* no more unused digit vkeys, so stop trying */
632     }
633
634     /* Last chance.  Assign any available vkey. */
635     vkey_range = 0;
636     vkey = vkey_ranges[vkey_range].first;
637     for (keyc = 0; keyc < sizeof(default_map) / sizeof(default_map[0]); keyc++)
638     {
639         if (!thread_data->keyc2scan[keyc]) continue; /* not a known Mac key code */
640         if (thread_data->keyc2vkey[keyc]) continue; /* already assigned */
641
642         while (vkey && vkey_used[vkey])
643         {
644             if (vkey == vkey_ranges[vkey_range].last)
645             {
646                 vkey_range++;
647                 vkey = vkey_ranges[vkey_range].first;
648             }
649             else
650                 vkey++;
651         }
652
653         if (!vkey)
654         {
655             WARN("No more vkeys available!\n");
656             break;
657         }
658
659         thread_data->keyc2vkey[keyc] = vkey;
660         vkey_used[vkey] = 1;
661         TRACE("keyc 0x%04x -> vkey 0x%04x (spare vkey)\n", keyc, vkey);
662     }
663 }
664
665
666 /***********************************************************************
667  *              macdrv_keyboard_changed
668  *
669  * Handler for KEYBOARD_CHANGED events.
670  */
671 void macdrv_keyboard_changed(const macdrv_event *event)
672 {
673     struct macdrv_thread_data *thread_data = macdrv_thread_data();
674
675     TRACE("new keyboard layout uchr data %p, type %u, iso %d\n", event->keyboard_changed.uchr,
676           event->keyboard_changed.keyboard_type, event->keyboard_changed.iso_keyboard);
677
678     if (thread_data->keyboard_layout_uchr)
679         CFRelease(thread_data->keyboard_layout_uchr);
680     thread_data->keyboard_layout_uchr = CFDataCreateCopy(NULL, event->keyboard_changed.uchr);
681     thread_data->keyboard_type = event->keyboard_changed.keyboard_type;
682     thread_data->iso_keyboard = event->keyboard_changed.iso_keyboard;
683
684     macdrv_compute_keyboard_layout(thread_data);
685 }