winex11: Unify German keyboard mapping.
[wine] / dlls / winex11.drv / keyboard.c
1 /*
2  * X11 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  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
35 #endif
36
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
40
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wingdi.h"
46 #include "winuser.h"
47 #include "winreg.h"
48 #include "winnls.h"
49 #include "x11drv.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
53
54 /* log format (add 0-padding as appropriate):
55     keycode  %u  as in output from xev
56     keysym   %lx as in X11/keysymdef.h
57     vkey     %X  as in winuser.h
58     scancode %x
59 */
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
62
63 /* key state table bits:
64   0x80 -> key is pressed
65   0x40 -> key got pressed since last time
66   0x01 -> key is toggled
67 */
68 BYTE key_state_table[256];
69
70 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
71                                 or a WM_KEYUP message */
72
73 static int min_keycode, max_keycode, keysyms_per_keycode;
74 static WORD keyc2vkey[256], keyc2scan[256];
75
76 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
77
78 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
79
80 /* Keyboard translation tables */
81 #define MAIN_LEN 49
82 static const WORD main_key_scan_qwerty[MAIN_LEN] =
83 {
84 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
85  /* `    1    2    3    4    5    6    7    8    9    0    -    = */
86    0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
87  /* q    w    e    r    t    y    u    i    o    p    [    ] */
88    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
89  /* a    s    d    f    g    h    j    k    l    ;    '    \ */
90    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
91  /* z    x    c    v    b    n    m    ,    .    / */
92    0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
93    0x56 /* the 102nd key (actually to the right of l-shift) */
94 };
95
96 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
97 {
98  /* `    1    2    3    4    5    6    7    8    9    0    -    = */
99    0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
100  /* q    w    e    r    t    y    u    i    o    p    [    ] */
101    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
102  /* a    s    d    f    g    h    j    k    l    ;    '    \ */
103    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
104  /* \      z    x    c    v    b    n    m    ,    .    / */
105    0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
106    0x56, /* the 102nd key (actually to the right of l-shift) */
107 };
108
109 static const WORD main_key_scan_dvorak[MAIN_LEN] =
110 {
111  /* `    1    2    3    4    5    6    7    8    9    0    [    ] */
112    0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
113  /* '    ,    .    p    y    f    g    c    r    l    /    = */
114    0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
115  /* a    o    e    u    i    d    h    t    n    s    -    \ */
116    0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
117  /* ;    q    j    k    x    b    m    w    v    z */
118    0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
119    0x56 /* the 102nd key (actually to the right of l-shift) */
120 };
121
122 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
123 {
124   /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
125  /* 1    2    3    4    5    6    7    8    9    0    -    ^    \ */
126    0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
127  /* q    w    e    r    t    y    u    i    o    p    @    [ */
128    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
129  /* a    s    d    f    g    h    j    k    l    ;    :    ] */
130    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
131  /* z    x    c    v    b    n    m    ,    .    / */
132    0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
133    0x56 /* the 102nd key (actually to the right of l-shift) */
134 };
135
136 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
137 {
138  /* 1    2    3    4    5    6    7    8    9    0    -    ^    \ */
139    0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
140  /* q    w    e    r    t    y    u    i    o    p    @    [ */
141    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
142  /* a    s    d    f    g    h    j    k    l    ;    :    ] */
143    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
144  /* z    x    c    v    b    n    m    ,    .    / */
145    0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
146    0x73 /* the 102nd key (actually to the right of l-shift) */
147 };
148
149
150 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
151 {
152 /* NOTE: this layout must concur with the scan codes layout above */
153    VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
154    'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
155    'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
156    'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
157    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
158 };
159
160 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
161 {
162 /* NOTE: this layout must concur with the scan codes layout above */
163    '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
164    'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
165    'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
166    'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
167    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
168 };
169
170 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
171 {
172 /* NOTE: this layout must concur with the scan codes layout above */
173    '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
174    'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
175    'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
176    'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
177    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
178 };
179
180 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
181 {
182 /* NOTE: this layout must concur with the scan codes layout above */
183    VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
184    'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
185    'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
186    'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
187    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
188 };
189
190 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
191 {
192 /* NOTE: this layout must concur with the scan codes layout above */
193    VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
194    'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
195    'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
196    'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
197    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
198 };
199
200 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
201 {
202 /* NOTE: this layout must concur with the scan codes layout above */
203    VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
204    'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
205    'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
206    VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
207    VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
208 };
209
210 static const WORD main_key_vkey_azerty[MAIN_LEN] =
211 {
212 /* NOTE: this layout must concur with the scan codes layout above */
213    VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
214    'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
215    'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
216    'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
217    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
218 };
219
220 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
221 {
222 /* NOTE: this layout must concur with the scan codes layout above */
223    VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
224    VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
225    'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
226    VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
227    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
228 };
229
230 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
231
232 /* the VK mappings for the main keyboard will be auto-assigned as before,
233    so what we have here is just the character tables */
234 /* order: Normal, Shift, AltGr, Shift-AltGr */
235 /* We recommend you write just what is guaranteed to be correct (i.e. what's
236    written on the keycaps), not the bunch of special characters behind AltGr
237    and Shift-AltGr if it can vary among different X servers */
238 /* These tables serve to guess the keyboard type and scancode mapping.
239    Complete modeling is not important, identification/discrimination is. */
240 /* Remember that your 102nd key (to the right of l-shift) should be on a
241    separate line, see existing tables */
242 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
243 /* Remember to also add your new table to the layout index table far below! */
244
245 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
246 static const char main_key_US[MAIN_LEN][4] =
247 {
248  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
249  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
250  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
251  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
252 };
253
254 /*** United States keyboard layout (phantom key version) */
255 /* (XFree86 reports the <> key even if it's not physically there) */
256 static const char main_key_US_phantom[MAIN_LEN][4] =
257 {
258  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
259  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
260  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
261  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
262  "<>" /* the phantom key */
263 };
264
265 /*** United States keyboard layout (dvorak version) */
266 static const char main_key_US_dvorak[MAIN_LEN][4] =
267 {
268  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
269  "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
270  "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
271  ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
272 };
273
274 /*** British keyboard layout */
275 static const char main_key_UK[MAIN_LEN][4] =
276 {
277  "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
278  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
279  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
280  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
281  "\\|"
282 };
283
284 /*** French keyboard layout (setxkbmap fr) */
285 static const char main_key_FR[MAIN_LEN][4] =
286 {
287  "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
288  "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
289  "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
290  "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
291  "<>"
292 };
293
294 /*** Icelandic keyboard layout (setxkbmap is) */
295 static const char main_key_IS[MAIN_LEN][4] =
296 {
297  "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
298  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
299  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
300  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
301  "<>"
302 };
303
304 /* All german keyb layout tables have the acute/apostrophe symbol next to
305  * the BACKSPACE key removed (replaced with NULL which is ignored by the
306  * detection code).
307  * This was done because the mapping of the acute (and apostrophe) is done
308  * differently in various xkb-data/xkeyboard-config versions. Some replace
309  * the acute with a normal apostrophe, so that the apostrophe is found twice
310  * on the keyboard (one next to BACKSPACE and one next to ENTER).
311  * Others put the acute and grave accents on the key left of BACKSPACE.
312  * More information on the fd.o bugtracker:
313  * https://bugs.freedesktop.org/show_bug.cgi?id=11514
314  * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
315  * among PC and Mac keyboards, so these are not listed.
316  */
317
318 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
319 static const char main_key_DE[MAIN_LEN][4] =
320 {
321  "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","",
322  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
323  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
324  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
325  "<>"
326 };
327
328 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
329 static const char main_key_SG[MAIN_LEN][4] =
330 {
331  "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
332  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
333  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
334  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
335  "<>"
336 };
337
338 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
339 static const char main_key_SF[MAIN_LEN][4] =
340 {
341  "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
342  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
343  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
344  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
345  "<>"
346 };
347
348 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
349 static const char main_key_NO[MAIN_LEN][4] =
350 {
351  "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
352  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
353  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
354  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
355  "<>"
356 };
357
358 /*** Danish keyboard layout (setxkbmap dk) */
359 static const char main_key_DA[MAIN_LEN][4] =
360 {
361  "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
362  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
363  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
364  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
365  "<>"
366 };
367
368 /*** Swedish keyboard layout (setxkbmap se) */
369 static const char main_key_SE[MAIN_LEN][4] =
370 {
371  "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
372  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
373  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
374  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
375  "<>"
376 };
377
378 /*** Estonian keyboard layout (setxkbmap ee) */
379 static const char main_key_ET[MAIN_LEN][4] =
380 {
381  "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
382  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
383  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
384  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
385  "<>"
386 };
387
388 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
389 static const char main_key_CF[MAIN_LEN][4] =
390 {
391  "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
392  "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
393  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
394  "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
395  "«»°"
396 };
397
398 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
399 static const char main_key_CA_fr[MAIN_LEN][4] =
400 {
401  "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
402  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
403  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
404  "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
405  "«»"
406 };
407
408 /*** Canadian keyboard layout (setxkbmap ca) */
409 static const char main_key_CA[MAIN_LEN][4] =
410 {
411  "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
412  "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
413  "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
414  "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
415  "ùÙ"
416 };
417
418 /*** Portuguese keyboard layout (setxkbmap pt) */
419 static const char main_key_PT[MAIN_LEN][4] =
420 {
421  "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
422  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
423  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
424  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
425  "<>"
426 };
427
428 /*** Italian keyboard layout (setxkbmap it) */
429 static const char main_key_IT[MAIN_LEN][4] =
430 {
431  "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
432  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
433  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
434  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
435  "<>"
436 };
437
438 /*** Finnish keyboard layout (setxkbmap fi) */
439 static const char main_key_FI[MAIN_LEN][4] =
440 {
441  "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
442  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
443  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
444  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
445  "<>"
446 };
447
448 /*** Bulgarian bds keyboard layout */
449 static const char main_key_BG_bds[MAIN_LEN][4] =
450 {
451  "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
452  "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
453  "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
454  "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
455  "<>" /* the phantom key */
456 };
457
458 /*** Bulgarian phonetic keyboard layout */
459 static const char main_key_BG_phonetic[MAIN_LEN][4] =
460 {
461  "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
462  "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
463  "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
464  "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
465  "<>" /* the phantom key */
466 };
467
468 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
469 /*** It matches belarusian layout for XKB from Alexander Mikhailian    */
470 static const char main_key_BY[MAIN_LEN][4] =
471 {
472  "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
473  "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
474  "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
475  "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
476 };
477
478
479 /*** Russian keyboard layout (contributed by Pavel Roskin) */
480 static const char main_key_RU[MAIN_LEN][4] =
481 {
482  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
483  "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
484  "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
485  "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
486 };
487
488 /*** Russian keyboard layout (phantom key version) */
489 static const char main_key_RU_phantom[MAIN_LEN][4] =
490 {
491  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
492  "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
493  "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
494  "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
495  "<>" /* the phantom key */
496 };
497
498 /*** Russian keyboard layout KOI8-R */
499 static const char main_key_RU_koi8r[MAIN_LEN][4] =
500 {
501  "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
502  "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
503  "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
504  "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
505  "<>" /* the phantom key */
506 };
507
508 /*** Russian keyboard layout cp1251 */
509 static const char main_key_RU_cp1251[MAIN_LEN][4] =
510 {
511  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
512  "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
513  "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
514  "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
515  "<>" /* the phantom key */
516 };
517
518 /*** Russian phonetic keyboard layout */
519 static const char main_key_RU_phonetic[MAIN_LEN][4] =
520 {
521  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
522  "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
523  "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
524  "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
525  "<>" /* the phantom key */
526 };
527
528 /*** Ukrainian keyboard layout KOI8-U */
529 static const char main_key_UA[MAIN_LEN][4] =
530 {
531  "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
532  "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
533  "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
534  "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
535  "<>" /* the phantom key */
536 };
537
538 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
539 /***  (as it appears on most of keyboards sold today)   */
540 static const char main_key_UA_std[MAIN_LEN][4] =
541 {
542  "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
543  "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
544  "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
545  "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
546  "<>" /* the phantom key */
547 };
548
549 /*** Russian keyboard layout KOI8-R (pair to the previous) */
550 static const char main_key_RU_std[MAIN_LEN][4] =
551 {
552  "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
553  "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
554  "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
555  "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
556  "<>" /* the phantom key */
557 };
558
559 /*** Spanish keyboard layout (setxkbmap es) */
560 static const char main_key_ES[MAIN_LEN][4] =
561 {
562  "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
563  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
564  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
565  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
566  "<>"
567 };
568
569 /*** Belgian keyboard layout ***/
570 static const char main_key_BE[MAIN_LEN][4] =
571 {
572  "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
573  "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
574  "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
575  "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
576  "<>\\"
577 };
578
579 /*** Hungarian keyboard layout (setxkbmap hu) */
580 static const char main_key_HU[MAIN_LEN][4] =
581 {
582  "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
583  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
584  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
585  "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
586  "íÍ"
587 };
588
589 /*** Polish (programmer's) keyboard layout ***/
590 static const char main_key_PL[MAIN_LEN][4] =
591 {
592  "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
593  "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
594  "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
595  "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
596  "<>|"
597 };
598
599 /*** Slovenian keyboard layout (setxkbmap si) ***/
600 static const char main_key_SI[MAIN_LEN][4] =
601 {
602  "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
603  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
604  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
605  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
606  "<>"
607 };
608
609 /*** Serbian keyboard layout (setxkbmap sr) ***/
610 static const char main_key_SR[MAIN_LEN][4] =
611 {
612  "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
613  "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
614  "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
615  "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
616  "<>" /* the phantom key */
617 };
618
619 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
620 static const char main_key_US_SR[MAIN_LEN][4] =
621 {
622  "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
623  "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
624  "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
625  "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
626  "<>" /* the phantom key */
627 };
628
629 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
630 static const char main_key_HR_jelly[MAIN_LEN][4] =
631 {
632  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
633  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
634  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
635  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
636  "<>|"
637 };
638
639 /*** Croatian keyboard layout (setxkbmap hr) ***/
640 static const char main_key_HR[MAIN_LEN][4] =
641 {
642  "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
643  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
644  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
645  "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
646  "<>"
647 };
648
649 /*** Japanese 106 keyboard layout ***/
650 static const char main_key_JA_jp106[MAIN_LEN][4] =
651 {
652  "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
653  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
654  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
655  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
656  "\\_",
657 };
658
659 static const char main_key_JA_macjp[MAIN_LEN][4] =
660 {
661  "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
662  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
663  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
664  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
665  "__",
666 };
667
668 /*** Japanese pc98x1 keyboard layout ***/
669 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
670 {
671  "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
672  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
673  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
674  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
675  "\\_",
676 };
677
678 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
679 static const char main_key_PT_br[MAIN_LEN][4] =
680 {
681  "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
682  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
683  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
684  "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
685 };
686
687 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
688 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
689 {
690  "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
691  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
692  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
693  "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
694 };
695
696 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
697 static const char main_key_US_intl[MAIN_LEN][4] =
698 {
699   "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
700   "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
701   "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
702   "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
703 };
704
705 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
706   - dead_abovering replaced with degree - no symbol in iso8859-2
707   - brokenbar replaced with bar                                 */
708 static const char main_key_SK[MAIN_LEN][4] =
709 {
710  ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
711  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
712  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
713  "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
714  "<>"
715 };
716
717 /*** Czech keyboard layout (setxkbmap cz) */
718 static const char main_key_CZ[MAIN_LEN][4] =
719 {
720  ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
721  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
722  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
723  "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
724  "\\"
725 };
726
727 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
728 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
729 {
730  ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
731  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
732  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
733  "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
734  "\\"
735 };
736
737 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
738 static const char main_key_SK_prog[MAIN_LEN][4] =
739 {
740  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
741  "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
742  "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
743  "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
744  "<>"
745 };
746
747 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
748 static const char main_key_CS[MAIN_LEN][4] =
749 {
750  ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
751  "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
752  "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
753  "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
754  "<>\\|"
755 };
756
757 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
758 static const char main_key_LA[MAIN_LEN][4] =
759 {
760  "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
761  "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
762  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
763  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
764  "<>"
765 };
766
767 /*** Lithuanian keyboard layout (setxkbmap lt) */
768 static const char main_key_LT_B[MAIN_LEN][4] =
769 {
770  "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
771  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
772  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
773  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
774  "ª¬"
775 };
776
777 /*** Turkish keyboard Layout */
778 static const char main_key_TK[MAIN_LEN][4] =
779 {
780 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
781 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
782 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
783 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
784 };
785
786 /*** Turkish keyboard layout (setxkbmap tr) */
787 static const char main_key_TR[MAIN_LEN][4] =
788 {
789 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
790 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
791 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
792 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
793 "<>"
794 };
795
796 /*** Turkish F keyboard layout (setxkbmap trf) */
797 static const char main_key_TR_F[MAIN_LEN][4] =
798 {
799 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
800 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
801 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
802 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
803 "<>"
804 };
805
806 /*** Israelian keyboard layout (setxkbmap us,il) */
807 static const char main_key_IL[MAIN_LEN][4] =
808 {
809  "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
810  "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
811  "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
812  "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
813  "<>"
814 };
815
816 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
817 static const char main_key_IL_phonetic[MAIN_LEN][4] =
818 {
819  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
820  "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
821  "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
822  "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
823  "<>"
824 };
825
826 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
827 static const char main_key_IL_saharon[MAIN_LEN][4] =
828 {
829  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
830  "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
831  "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
832  "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
833  "<>"
834 };
835
836 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
837   Greek characters for "wW" and "sS" are omitted to not produce a mismatch
838   message since they have different characters in gr and el XFree86 layouts. */
839 static const char main_key_EL[MAIN_LEN][4] =
840 {
841  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
842  "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
843  "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
844  "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
845  "<>"
846 };
847
848 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
849 static const char main_key_th[MAIN_LEN][4] =
850 {
851  "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
852  "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
853  "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
854  "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
855 }; 
856
857 /*** VNC keyboard layout */
858 static const WORD main_key_scan_vnc[MAIN_LEN] =
859 {
860    0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
861    0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C,
862    0x56
863 };
864
865 static const WORD main_key_vkey_vnc[MAIN_LEN] =
866 {
867    '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_4,VK_OEM_6,VK_OEM_1,VK_OEM_7,VK_OEM_3,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_5,
868    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
869    VK_OEM_102
870 };
871
872 static const char main_key_vnc[MAIN_LEN][4] =
873 {
874  "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
875  "aA","bB","cC","dD","eE","fF","gG","hH","iI","jJ","kK","lL","mM","nN","oO","pP","qQ","rR","sS","tT","uU","vV","wW","xX","yY","zZ"
876 };
877
878 /*** Dutch keyboard layout (setxkbmap nl) ***/
879 static const char main_key_NL[MAIN_LEN][4] =
880 {
881  "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
882  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
883  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
884  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
885  "[]"
886 };
887
888
889
890 /*** Layout table. Add your keyboard mappings to this list */
891 static const struct {
892     LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
893                  in the appropriate dlls/kernel/nls/.nls file */
894     const char *comment;
895     const char (*key)[MAIN_LEN][4];
896     const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
897     const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
898 } main_key_tab[]={
899  {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900  {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901  {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
902  {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903  {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904  {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
905  {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
906  {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
907  {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
908  {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
909  {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910  {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911  {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
912  {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
913  {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914  {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915  {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
916  {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917  {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
918  {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
919  {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920  {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921  {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922  {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923  {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924  {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925  {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926  {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927  {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928  {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929  {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930  {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931  {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932  {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933  {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934  {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
935  {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936  {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
937  {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
938  {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
939  {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
940  {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941  {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
942  {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
943  {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944  {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945  {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946  {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947  {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
948  {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949  {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950  {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951  {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952  {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
953  {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954  {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
955  {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
956  {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
957  {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
958  {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
959  {0x041e, "Thai (Kedmanee)  keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
960  {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
961
962  {0, NULL, NULL, NULL, NULL} /* sentinel */
963 };
964 static unsigned kbd_layout=0; /* index into above table of layouts */
965
966 /* maybe more of these scancodes should be extended? */
967                 /* extended must be set for ALT_R, CTRL_R,
968                    INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
969                    keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
970                 /* FIXME should we set extended bit for NumLock ? My
971                  * Windows does ... DF */
972                 /* Yes, to distinguish based on scan codes, also
973                    for PrtScn key ... GA */
974
975 static const WORD nonchar_key_vkey[256] =
976 {
977     /* unused */
978     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF00 */
979     /* special keys */
980     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
981     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
982     0, 0, 0, VK_ESCAPE, 0, 0, 0, 0,                             /* FF18 */
983     /* unused */
984     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF20 */
985     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF28 */
986     0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0,                      /* FF30 */
987     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF38 */
988     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF40 */
989     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF48 */
990     /* cursor keys */
991     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT,                          /* FF50 */
992     VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
993     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF58 */
994     /* misc keys */
995     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
996     0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0,               /* FF68 */
997     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF70 */
998     /* keypad keys */
999     0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK,                            /* FF78 */
1000     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
1001     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
1002     0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,                     /* FF90 */
1003     VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT,                       /* FF98 */
1004     VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1005     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
1006     0, 0, VK_MULTIPLY, VK_ADD,                                  /* FFA8 */
1007     VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1008     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,             /* FFB0 */
1009     VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1010     VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL,          /* FFB8 */
1011     /* function keys */
1012     VK_F1, VK_F2,
1013     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
1014     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1015     VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,       /* FFD0 */
1016     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFD8 */
1017     /* modifier keys */
1018     0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL,                       /* FFE0 */
1019     VK_RCONTROL, VK_CAPITAL, 0, VK_MENU,
1020     VK_MENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0,     /* FFE8 */
1021     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFF0 */
1022     0, 0, 0, 0, 0, 0, 0, VK_DELETE                              /* FFF8 */
1023 };
1024
1025 static const WORD nonchar_key_scan[256] =
1026 {
1027     /* unused */
1028     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF00 */
1029     /* special keys */
1030     0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00,           /* FF08 */
1031     0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00,              /* FF10 */
1032     0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,              /* FF18 */
1033     /* unused */
1034     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF20 */
1035     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF28 */
1036     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF30 */
1037     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF38 */
1038     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF40 */
1039     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF48 */
1040     /* cursor keys */
1041     0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F,      /* FF50 */
1042     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF58 */
1043     /* misc keys */
1044     /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D,     /* FF60 */
1045     /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00,       /* FF68 */
1046     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF70 */
1047     /* keypad keys */
1048     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145,             /* FF78 */
1049     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF80 */
1050     0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00,             /* FF88 */
1051     0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48,              /* FF90 */
1052     0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53,              /* FF98 */
1053     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFA0 */
1054     0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135,             /* FFA8 */
1055     0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47,              /* FFB0 */
1056     0x48, 0x49, 0x00, 0x00, 0x00, 0x00,                          /* FFB8 */
1057     /* function keys */
1058     0x3B, 0x3C,
1059     0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,              /* FFC0 */
1060     0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00,              /* FFC8 */
1061     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFD0 */
1062     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFD8 */
1063     /* modifier keys */
1064     0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38,            /* FFE0 */
1065     0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00,          /* FFE8 */
1066     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFF0 */
1067     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153              /* FFF8 */
1068 };
1069
1070 static const WORD xfree86_vendor_key_vkey[256] =
1071 {
1072     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF00 */
1073     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF08 */
1074     0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP,            /* 1008FF10 */
1075     VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1076     VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1077     0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH,                    /* 1008FF18 */
1078     0, 0, 0, VK_BROWSER_HOME,
1079     0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD,      /* 1008FF20 */
1080     VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0,      /* 1008FF28 */
1081     VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0,         /* 1008FF30 */
1082     0, 0, 0, 0,
1083     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF38 */
1084     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF40 */
1085     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF48 */
1086     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF50 */
1087     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF58 */
1088     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF60 */
1089     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF68 */
1090     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF70 */
1091     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF78 */
1092     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF80 */
1093     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF88 */
1094     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF90 */
1095     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF98 */
1096     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFA0 */
1097     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFA8 */
1098     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFB0 */
1099     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFB8 */
1100     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFC0 */
1101     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFC8 */
1102     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFD0 */
1103     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFD8 */
1104     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFE0 */
1105     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFE8 */
1106     0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFF0 */
1107     0, 0, 0, 0, 0, 0, 0, 0                                      /* 1008FFF8 */
1108 };
1109
1110 /* Returns the Windows virtual key code associated with the X event <e> */
1111 /* x11 lock must be held */
1112 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1113 {
1114     KeySym keysym = 0;
1115     Status status;
1116     char buf[24];
1117
1118     /* Clients should pass only KeyPress events to XmbLookupString */
1119     if (xic && e->type == KeyPress)
1120         XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1121     else
1122         XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1123
1124     if ((e->state & NumLockMask) &&
1125         (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1126          (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1127         /* Only the Keypad keys 0-9 and . send different keysyms
1128          * depending on the NumLock state */
1129         return nonchar_key_vkey[keysym & 0xFF];
1130
1131     /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1132      * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1133     if ((e->state & ControlMask) && (keysym == XK_Break))
1134         return VK_CANCEL;
1135
1136     TRACE_(key)("e->keycode = %u\n", e->keycode);
1137
1138     return keyc2vkey[e->keycode];
1139 }
1140
1141
1142 /***********************************************************************
1143  *           X11DRV_send_keyboard_input
1144  */
1145 void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD event_flags, DWORD time,
1146                                  DWORD dwExtraInfo, UINT injected_flags )
1147 {
1148     UINT message;
1149     KBDLLHOOKSTRUCT hook;
1150     WORD flags, wVkStripped, wVkL, wVkR, vk_hook = wVk;
1151     LPARAM lParam = 0;
1152
1153     wVk = LOBYTE(wVk);
1154     flags = LOBYTE(wScan);
1155
1156     if (event_flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1157     /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1158
1159     /* strip left/right for menu, control, shift */
1160     switch (wVk)
1161     {
1162     case VK_MENU:
1163     case VK_LMENU:
1164     case VK_RMENU:
1165         wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1166         wVkStripped = VK_MENU;
1167         wVkL = VK_LMENU;
1168         wVkR = VK_RMENU;
1169         break;
1170     case VK_CONTROL:
1171     case VK_LCONTROL:
1172     case VK_RCONTROL:
1173         wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1174         wVkStripped = VK_CONTROL;
1175         wVkL = VK_LCONTROL;
1176         wVkR = VK_RCONTROL;
1177         break;
1178     case VK_SHIFT:
1179     case VK_LSHIFT:
1180     case VK_RSHIFT:
1181         wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1182         wVkStripped = VK_SHIFT;
1183         wVkL = VK_LSHIFT;
1184         wVkR = VK_RSHIFT;
1185         break;
1186     default:
1187         wVkStripped = wVkL = wVkR = wVk;
1188     }
1189
1190     if (event_flags & KEYEVENTF_KEYUP)
1191     {
1192         message = WM_KEYUP;
1193         if (((key_state_table[VK_MENU] & 0x80) &&
1194              ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1195               || !(key_state_table[VK_CONTROL] & 0x80)))
1196             || (wVkStripped == VK_F10))
1197         {
1198             if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1199                 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1200                 message = WM_SYSKEYUP;
1201             TrackSysKey = 0;
1202         }
1203         flags |= KF_REPEAT | KF_UP;
1204     }
1205     else
1206     {
1207         message = WM_KEYDOWN;
1208         if (((key_state_table[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1209              !(key_state_table[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL)) ||
1210             (wVkStripped == VK_F10))
1211         {
1212             message = WM_SYSKEYDOWN;
1213             TrackSysKey = wVkStripped;
1214         }
1215         if (!(event_flags & KEYEVENTF_UNICODE) && key_state_table[wVk] & 0x80) flags |= KF_REPEAT;
1216     }
1217
1218     if (event_flags & KEYEVENTF_UNICODE)
1219     {
1220         vk_hook = wVk = VK_PACKET;
1221         lParam = MAKELPARAM(1 /* repeat count */, wScan);
1222         TRACE_(key)("message=0x%04x wParam=0x%04X lParam=0x%08lx\n",
1223                     message, wVk, lParam);
1224     }
1225
1226     /* Hook gets whatever key was sent. */
1227     hook.vkCode      = vk_hook;
1228     hook.scanCode    = wScan;
1229     hook.flags       = (flags >> 8) | injected_flags;
1230     hook.time        = time;
1231     hook.dwExtraInfo = dwExtraInfo;
1232     if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1233
1234     if (!(event_flags & KEYEVENTF_UNICODE))
1235     {
1236         if (event_flags & KEYEVENTF_KEYUP)
1237         {
1238             key_state_table[wVk] &= ~0x80;
1239             key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1240         }
1241         else
1242         {
1243             if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1244             key_state_table[wVk] |= 0xc0;
1245             key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1246         }
1247
1248         if (key_state_table[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1249
1250         if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1251
1252         lParam = MAKELPARAM(1 /* repeat count */, flags);
1253
1254         TRACE_(key)(" message=0x%04x wParam=0x%04X, lParam=0x%08lx, InputKeyState=0x%x\n",
1255                     message, wVk, lParam, key_state_table[wVk]);
1256     }
1257
1258     SERVER_START_REQ( send_hardware_message )
1259     {
1260         req->id       = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1261         req->win      = 0;
1262         req->msg      = message;
1263         req->wparam   = wVk;
1264         req->lparam   = lParam;
1265         req->x        = cursor_pos.x;
1266         req->y        = cursor_pos.y;
1267         req->time     = time;
1268         req->info     = dwExtraInfo;
1269         wine_server_call( req );
1270     }
1271     SERVER_END_REQ;
1272 }
1273
1274
1275 /***********************************************************************
1276  *           KEYBOARD_UpdateOneState
1277  *
1278  * Updates internal state for <vkey>, depending on key <state> under X
1279  *
1280  */
1281 static inline void KEYBOARD_UpdateOneState ( WORD vkey, WORD scan, int state, DWORD time )
1282 {
1283     /* Do something if internal table state != X state for keycode */
1284     if (((key_state_table[vkey & 0xff] & 0x80)!=0) != state)
1285     {
1286         DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1287
1288         if (!state) flags |= KEYEVENTF_KEYUP;
1289
1290         TRACE("Adjusting state for vkey %#.2X. State before %#.2x\n",
1291               vkey, key_state_table[vkey & 0xff]);
1292
1293         /* Fake key being pressed inside wine */
1294         X11DRV_send_keyboard_input( vkey & 0xff, scan & 0xff, flags, time, 0, 0 );
1295
1296         TRACE("State after %#.2x\n", key_state_table[vkey & 0xff]);
1297     }
1298 }
1299
1300 /***********************************************************************
1301  *           X11DRV_KeymapNotify
1302  *
1303  * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1304  *
1305  * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1306  * from wine to another application and back.
1307  * Toggle keys are handled in HandleEvent.
1308  */
1309 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1310 {
1311     int i, j;
1312     DWORD time = GetCurrentTime();
1313
1314     /* the minimum keycode is always greater or equal to 8, so we can
1315      * skip the first 8 values, hence start at 1
1316      */
1317     for (i = 1; i < 32; i++)
1318     {
1319         for (j = 0; j < 8; j++)
1320         {
1321             WORD vkey = keyc2vkey[(i * 8) + j];
1322             WORD scan = keyc2scan[(i * 8) + j];
1323             int state = (event->xkeymap.key_vector[i] & (1<<j)) != 0;
1324
1325             switch(vkey & 0xff)
1326             {
1327             case VK_LMENU:
1328             case VK_RMENU:
1329             case VK_LCONTROL:
1330             case VK_RCONTROL:
1331             case VK_LSHIFT:
1332             case VK_RSHIFT:
1333                 KEYBOARD_UpdateOneState( vkey, scan, state, time );
1334                 break;
1335             }
1336         }
1337     }
1338 }
1339
1340 static void update_lock_state(BYTE vkey, WORD scan, DWORD time)
1341 {
1342     DWORD flags = vkey == VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0;
1343
1344     if (key_state_table[vkey] & 0x80) flags ^= KEYEVENTF_KEYUP;
1345
1346     X11DRV_send_keyboard_input( vkey, scan, flags, time, 0, 0 );
1347     X11DRV_send_keyboard_input( vkey, scan, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
1348 }
1349
1350 /***********************************************************************
1351  *           X11DRV_KeyEvent
1352  *
1353  * Handle a X key event
1354  */
1355 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1356 {
1357     XKeyEvent *event = &xev->xkey;
1358     char buf[24];
1359     char *Str = buf;
1360     KeySym keysym = 0;
1361     WORD vkey = 0, bScan;
1362     DWORD dwFlags;
1363     int ascii_chars;
1364     XIC xic = X11DRV_get_ic( hwnd );
1365     DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1366     Status status = 0;
1367
1368     TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1369                 event->type, event->window, event->state, event->keycode);
1370
1371     wine_tsx11_lock();
1372     /* Clients should pass only KeyPress events to XmbLookupString */
1373     if (xic && event->type == KeyPress)
1374     {
1375         ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1376         TRACE("XmbLookupString needs %i byte(s)\n", ascii_chars);
1377         if (status == XBufferOverflow)
1378         {
1379             Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1380             if (Str == NULL)
1381             {
1382                 ERR("Failed to allocate memory!\n");
1383                 wine_tsx11_unlock();
1384                 return;
1385             }
1386             ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1387         }
1388     }
1389     else
1390         ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1391     wine_tsx11_unlock();
1392
1393     TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1394
1395     if (status == XLookupChars)
1396     {
1397         X11DRV_XIMLookupChars( Str, ascii_chars );
1398         if (buf != Str)
1399             HeapFree(GetProcessHeap(), 0, Str);
1400         return;
1401     }
1402
1403     /* If XKB extensions are used, the state mask for AltGr will use the group
1404        index instead of the modifier mask. The group index is set in bits
1405        13-14 of the state field in the XKeyEvent structure. So if AltGr is
1406        pressed, look if the group index is different than 0. From XKB
1407        extension documentation, the group index for AltGr should be 2
1408        (event->state = 0x2000). It's probably better to not assume a
1409        predefined group index and find it dynamically
1410
1411        Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1412     /* Save also all possible modifier states. */
1413     AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1414
1415     if (TRACE_ON(key)){
1416         const char *ksname;
1417
1418         wine_tsx11_lock();
1419         ksname = XKeysymToString(keysym);
1420         wine_tsx11_unlock();
1421         if (!ksname)
1422           ksname = "No Name";
1423         TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1424                     (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1425                     keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1426     }
1427     if (buf != Str)
1428         HeapFree(GetProcessHeap(), 0, Str);
1429
1430     wine_tsx11_lock();
1431     vkey = EVENT_event_to_vkey(xic,event);
1432     /* X returns keycode 0 for composed characters */
1433     if (!vkey && ascii_chars) vkey = VK_NONAME;
1434     wine_tsx11_unlock();
1435
1436     TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1437                 event->keycode, vkey);
1438
1439     if (!vkey) return;
1440
1441     dwFlags = 0;
1442     if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1443     if ( vkey & 0x100 )              dwFlags |= KEYEVENTF_EXTENDEDKEY;
1444
1445
1446     /* Note: X sets the below states on key down and clears them on key up.
1447        Windows triggers them on key down. */
1448
1449     /* Adjust the CAPSLOCK state if it has been changed outside wine */
1450     if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask) &&
1451         vkey != VK_CAPITAL)
1452     {
1453         TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table[VK_CAPITAL]);
1454         update_lock_state(VK_CAPITAL, 0x3A, event_time);
1455     }
1456
1457     /* Adjust the NUMLOCK state if it has been changed outside wine */
1458     if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask) &&
1459         (vkey & 0xff) != VK_NUMLOCK)
1460     {
1461         TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table[VK_NUMLOCK]);
1462         update_lock_state(VK_NUMLOCK, 0x45, event_time);
1463     }
1464
1465     /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1466     if (!(key_state_table[VK_SCROLL] & 0x01) != !(event->state & ScrollLockMask) &&
1467         vkey != VK_SCROLL)
1468     {
1469         TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table[VK_SCROLL]);
1470         update_lock_state(VK_SCROLL, 0x46, event_time);
1471     }
1472
1473     bScan = keyc2scan[event->keycode] & 0xFF;
1474     TRACE_(key)("bScan = 0x%02x.\n", bScan);
1475
1476     X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1477 }
1478
1479 /**********************************************************************
1480  *              X11DRV_KEYBOARD_DetectLayout
1481  *
1482  * Called from X11DRV_InitKeyboard
1483  *  This routine walks through the defined keyboard layouts and selects
1484  *  whichever matches most closely.
1485  * X11 lock must be held.
1486  */
1487 static void
1488 X11DRV_KEYBOARD_DetectLayout( Display *display )
1489 {
1490   unsigned current, match, mismatch, seq, i, syms;
1491   int score, keyc, key, pkey, ok;
1492   KeySym keysym = 0;
1493   const char (*lkey)[MAIN_LEN][4];
1494   unsigned max_seq = 0;
1495   int max_score = 0, ismatch = 0;
1496   char ckey[256][4];
1497
1498   syms = keysyms_per_keycode;
1499   if (syms > 4) {
1500     WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1501     syms = 4;
1502   }
1503
1504   memset( ckey, 0, sizeof(ckey) );
1505   for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1506       /* get data for keycode from X server */
1507       for (i = 0; i < syms; i++) {
1508         if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1509         /* Allow both one-byte and two-byte national keysyms */
1510         if ((keysym < 0x8000) && (keysym != ' '))
1511         {
1512 #ifdef HAVE_XKB
1513             if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1514 #endif
1515             {
1516                 TRACE("XKB could not translate keysym %04lx\n", keysym);
1517                 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1518                  * with appropriate ShiftMask and Mode_switch, use XLookupString
1519                  * to get character in the local encoding.
1520                  */
1521                 ckey[keyc][i] = keysym & 0xFF;
1522             }
1523         }
1524         else {
1525           ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1526         }
1527       }
1528   }
1529
1530   for (current = 0; main_key_tab[current].comment; current++) {
1531     TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1532     match = 0;
1533     mismatch = 0;
1534     score = 0;
1535     seq = 0;
1536     lkey = main_key_tab[current].key;
1537     pkey = -1;
1538     for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1539       if (ckey[keyc][0]) {
1540         /* search for a match in layout table */
1541         /* right now, we just find an absolute match for defined positions */
1542         /* (undefined positions are ignored, so if it's defined as "3#" in */
1543         /* the table, it's okay that the X server has "3#£", for example) */
1544         /* however, the score will be higher for longer matches */
1545         for (key = 0; key < MAIN_LEN; key++) {
1546           for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1547             if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1548               ok++;
1549             if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1550               ok = -1;
1551           }
1552           if (ok > 0) {
1553             score += ok;
1554             break;
1555           }
1556         }
1557         /* count the matches and mismatches */
1558         if (ok > 0) {
1559           match++;
1560           /* and how much the keycode order matches */
1561           if (key > pkey) seq++;
1562           pkey = key;
1563         } else {
1564           /* print spaces instead of \0's */
1565           char str[5];
1566           for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1567           str[4] = 0;
1568           TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1569           mismatch++;
1570           score -= syms;
1571         }
1572       }
1573     }
1574     TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1575            match, mismatch, seq, score);
1576     if ((score > max_score) ||
1577         ((score == max_score) && (seq > max_seq))) {
1578       /* best match so far */
1579       kbd_layout = current;
1580       max_score = score;
1581       max_seq = seq;
1582       ismatch = !mismatch;
1583     }
1584   }
1585   /* we're done, report results if necessary */
1586   if (!ismatch)
1587     WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1588         main_key_tab[kbd_layout].comment);
1589
1590   TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1591 }
1592
1593 static HKL get_locale_kbd_layout(void)
1594 {
1595     ULONG_PTR layout;
1596     LANGID langid;
1597
1598     /* FIXME:
1599      *
1600      * layout = main_key_tab[kbd_layout].lcid;
1601      *
1602      * Winword uses return value of GetKeyboardLayout as a codepage
1603      * to translate ANSI keyboard messages to unicode. But we have
1604      * a problem with it: for instance Polish keyboard layout is
1605      * identical to the US one, and therefore instead of the Polish
1606      * locale id we return the US one.
1607      */
1608
1609     layout = GetUserDefaultLCID();
1610
1611     /*
1612      * Microsoft Office expects this value to be something specific
1613      * for Japanese and Korean Windows with an IME the value is 0xe001
1614      * We should probably check to see if an IME exists and if so then
1615      * set this word properly.
1616      */
1617     langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1618     if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1619         layout |= 0xe001 << 16; /* IME */
1620     else
1621         layout |= layout << 16;
1622
1623     return (HKL)layout;
1624 }
1625
1626 /***********************************************************************
1627  *     GetKeyboardLayoutName (X11DRV.@)
1628  */
1629 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1630 {
1631     static const WCHAR formatW[] = {'%','0','8','x',0};
1632     DWORD layout;
1633
1634     layout = HandleToUlong( get_locale_kbd_layout() );
1635     if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1636     sprintfW(name, formatW, layout);
1637     TRACE("returning %s\n", debugstr_w(name));
1638     return TRUE;
1639 }
1640
1641 static void set_kbd_layout_preload_key(void)
1642 {
1643     static const WCHAR preload[] =
1644         {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1645     static const WCHAR one[] = {'1',0};
1646
1647     HKEY hkey;
1648     WCHAR layout[KL_NAMELENGTH];
1649
1650     if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1651         return;
1652
1653     if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1654     {
1655         RegCloseKey(hkey);
1656         return;
1657     }
1658     if (X11DRV_GetKeyboardLayoutName(layout))
1659         RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1660
1661     RegCloseKey(hkey);
1662 }
1663
1664 /**********************************************************************
1665  *              X11DRV_InitKeyboard
1666  */
1667 void X11DRV_InitKeyboard( Display *display )
1668 {
1669     KeySym *ksp;
1670     XModifierKeymap *mmp;
1671     KeySym keysym;
1672     KeyCode *kcp;
1673     XKeyEvent e2;
1674     WORD scan, vkey;
1675     int keyc, i, keyn, syms;
1676     char ckey[4]={0,0,0,0};
1677     const char (*lkey)[MAIN_LEN][4];
1678     char vkey_used[256] = { 0 };
1679
1680     /* Ranges of OEM, function key, and character virtual key codes.
1681      * Don't include those handled specially in X11DRV_ToUnicodeEx and
1682      * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1683     static const struct {
1684         WORD first, last;
1685     } vkey_ranges[] = {
1686         { VK_OEM_1, VK_OEM_3 },
1687         { VK_OEM_4, VK_ICO_00 },
1688         { 0xe6, 0xe6 },
1689         { 0xe9, 0xf5 },
1690         { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1691         { VK_F1, VK_F24 },
1692         { 0x30, 0x39 }, /* VK_0 - VK_9 */
1693         { 0x41, 0x5a }, /* VK_A - VK_Z */
1694         { 0, 0 }
1695     };
1696     int vkey_range;
1697
1698     set_kbd_layout_preload_key();
1699
1700     wine_tsx11_lock();
1701     XDisplayKeycodes(display, &min_keycode, &max_keycode);
1702     ksp = XGetKeyboardMapping(display, min_keycode,
1703                               max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1704     /* We are only interested in keysyms_per_keycode.
1705        There is no need to hold a local copy of the keysyms table */
1706     XFree(ksp);
1707
1708     mmp = XGetModifierMapping(display);
1709     kcp = mmp->modifiermap;
1710     for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1711     {
1712         int j;
1713
1714         for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1715             if (*kcp)
1716             {
1717                 int k;
1718
1719                 for (k = 0; k < keysyms_per_keycode; k += 1)
1720                     if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1721                     {
1722                         NumLockMask = 1 << i;
1723                         TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1724                     }
1725                     else if (XKeycodeToKeysym(display, *kcp, k) == XK_Scroll_Lock)
1726                     {
1727                         ScrollLockMask = 1 << i;
1728                         TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1729                     }
1730             }
1731     }
1732     XFreeModifiermap(mmp);
1733
1734     /* Detect the keyboard layout */
1735     X11DRV_KEYBOARD_DetectLayout( display );
1736     lkey = main_key_tab[kbd_layout].key;
1737     syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1738
1739     /* Now build two conversion arrays :
1740      * keycode -> vkey + scancode + extended
1741      * vkey + extended -> keycode */
1742
1743     e2.display = display;
1744     e2.state = 0;
1745     e2.type = KeyPress;
1746
1747     memset(keyc2vkey, 0, sizeof(keyc2vkey));
1748     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1749     {
1750         char buf[30];
1751         int have_chars;
1752
1753         keysym = 0;
1754         e2.keycode = (KeyCode)keyc;
1755         have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1756         vkey = 0; scan = 0;
1757         if (keysym)  /* otherwise, keycode not used */
1758         {
1759             if ((keysym >> 8) == 0xFF)         /* non-character key */
1760             {
1761                 vkey = nonchar_key_vkey[keysym & 0xff];
1762                 scan = nonchar_key_scan[keysym & 0xff];
1763                 /* set extended bit when necessary */
1764                 if (scan & 0x100) vkey |= 0x100;
1765             } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1766                 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1767                 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1768                 scan = 0x100;
1769                 vkey |= 0x100;
1770             } else if (keysym == 0x20) {                 /* Spacebar */
1771                 vkey = VK_SPACE;
1772                 scan = 0x39;
1773             } else if (have_chars) {
1774               /* we seem to need to search the layout-dependent scancodes */
1775               int maxlen=0,maxval=-1,ok;
1776               for (i=0; i<syms; i++) {
1777                 keysym = XKeycodeToKeysym(display, keyc, i);
1778                 if ((keysym<0x8000) && (keysym!=' '))
1779                 {
1780 #ifdef HAVE_XKB
1781                     if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1782 #endif
1783                     {
1784                         /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1785                          * with appropriate ShiftMask and Mode_switch, use XLookupString
1786                          * to get character in the local encoding.
1787                          */
1788                         ckey[i] = keysym & 0xFF;
1789                     }
1790                 } else {
1791                   ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1792                 }
1793               }
1794               /* find key with longest match streak */
1795               for (keyn=0; keyn<MAIN_LEN; keyn++) {
1796                 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1797                   if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1798                 if (!ok) i--; /* we overshot */
1799                 if (ok||(i>maxlen)) {
1800                   maxlen=i; maxval=keyn;
1801                 }
1802                 if (ok) break;
1803               }
1804               if (maxval>=0) {
1805                 /* got it */
1806                 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1807                 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1808                 scan = (*lscan)[maxval];
1809                 vkey = (*lvkey)[maxval];
1810               }
1811             }
1812         }
1813         TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1814         keyc2vkey[e2.keycode] = vkey;
1815         keyc2scan[e2.keycode] = scan;
1816         if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1817             WARN("vkey %04X is being used by more than one keycode\n", vkey);
1818         vkey_used[(vkey & 0xff)] = 1;
1819     } /* for */
1820
1821 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1822     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1823     {
1824         vkey = keyc2vkey[keyc] & 0xff;
1825         if (vkey)
1826             continue;
1827
1828         e2.keycode = (KeyCode)keyc;
1829         keysym = XLookupKeysym(&e2, 0);
1830         if (!keysym)
1831            continue;
1832
1833         /* find a suitable layout-dependent VK code */
1834         /* (most Winelib apps ought to be able to work without layout tables!) */
1835         for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1836         {
1837             keysym = XLookupKeysym(&e2, i);
1838             if ((keysym >= XK_0 && keysym <= XK_9)
1839                 || (keysym >= XK_A && keysym <= XK_Z)) {
1840                 vkey = VKEY_IF_NOT_USED(keysym);
1841             }
1842         }
1843
1844         for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1845         {
1846             keysym = XLookupKeysym(&e2, i);
1847             switch (keysym)
1848             {
1849             case ';':             vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1850             case '/':             vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1851             case '`':             vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1852             case '[':             vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1853             case '\\':            vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1854             case ']':             vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1855             case '\'':            vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1856             case ',':             vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1857             case '.':             vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1858             case '-':             vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1859             case '+':             vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1860             }
1861         }
1862
1863         if (vkey)
1864         {
1865             TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1866             keyc2vkey[e2.keycode] = vkey;
1867         }
1868     } /* for */
1869
1870     /* For any keycodes which still don't have a vkey, assign any spare
1871      * character, function key, or OEM virtual key code. */
1872     vkey_range = 0;
1873     vkey = vkey_ranges[vkey_range].first;
1874     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1875     {
1876         if (keyc2vkey[keyc] & 0xff)
1877             continue;
1878
1879         e2.keycode = (KeyCode)keyc;
1880         keysym = XLookupKeysym(&e2, 0);
1881         if (!keysym)
1882            continue;
1883
1884         while (vkey && vkey_used[vkey])
1885         {
1886             if (vkey == vkey_ranges[vkey_range].last)
1887             {
1888                 vkey_range++;
1889                 vkey = vkey_ranges[vkey_range].first;
1890             }
1891             else
1892                 vkey++;
1893         }
1894
1895         if (!vkey)
1896         {
1897             WARN("No more vkeys available!\n");
1898             break;
1899         }
1900
1901         if (TRACE_ON(keyboard))
1902         {
1903             TRACE("spare virtual key %04X assigned to keycode %u:\n",
1904                              vkey, e2.keycode);
1905             TRACE("(");
1906             for (i = 0; i < keysyms_per_keycode; i += 1)
1907             {
1908                 const char *ksname;
1909
1910                 keysym = XLookupKeysym(&e2, i);
1911                 ksname = XKeysymToString(keysym);
1912                 if (!ksname)
1913                     ksname = "NoSymbol";
1914                 TRACE( "%lx (%s) ", keysym, ksname);
1915             }
1916             TRACE(")\n");
1917         }
1918
1919         TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1920         keyc2vkey[e2.keycode] = vkey;
1921         vkey_used[vkey] = 1;
1922     } /* for */
1923 #undef VKEY_IF_NOT_USED
1924
1925     /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1926     for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1927       if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1928         const char *ksname;
1929         keysym = XKeycodeToKeysym(display, keyc, 0);
1930         ksname = XKeysymToString(keysym);
1931         if (!ksname) ksname = "NoSymbol";
1932
1933         /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1934
1935         TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1936         keyc2scan[keyc]=scan++;
1937       }
1938
1939     wine_tsx11_unlock();
1940 }
1941
1942 static BOOL match_x11_keyboard_layout(HKL hkl)
1943 {
1944     const DWORD isIME = 0xE0000000;
1945     HKL xHkl = get_locale_kbd_layout();
1946
1947     /* if the layout is an IME, only match the low word (LCID) */
1948     if (((ULONG_PTR)hkl & isIME) == isIME)
1949         return (LOWORD(hkl) == LOWORD(xHkl));
1950     else
1951         return (hkl == xHkl);
1952 }
1953
1954 /**********************************************************************
1955  *              GetAsyncKeyState (X11DRV.@)
1956  */
1957 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1958 {
1959     SHORT retval;
1960
1961     /* Photoshop livelocks unless mouse events are included here */
1962     X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1963
1964     retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1965              ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1966     key_state_table[key] &= ~0x40;
1967     TRACE_(key)("(%X) -> %x\n", key, retval);
1968     return retval;
1969 }
1970
1971
1972 /***********************************************************************
1973  *              GetKeyboardLayout (X11DRV.@)
1974  */
1975 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1976 {
1977     if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1978     {
1979         struct x11drv_thread_data *thread_data = x11drv_thread_data();
1980         if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1981     }
1982     else
1983         FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1984
1985     return get_locale_kbd_layout();
1986 }
1987
1988
1989 /***********************************************************************
1990  *              LoadKeyboardLayout (X11DRV.@)
1991  */
1992 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1993 {
1994     FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1995     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1996     return 0;
1997 }
1998
1999
2000 /***********************************************************************
2001  *              UnloadKeyboardLayout (X11DRV.@)
2002  */
2003 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
2004 {
2005     FIXME("%p: stub!\n", hkl);
2006     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2007     return FALSE;
2008 }
2009
2010
2011 /***********************************************************************
2012  *              ActivateKeyboardLayout (X11DRV.@)
2013  */
2014 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
2015 {
2016     HKL oldHkl = 0;
2017     struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
2018
2019     FIXME("%p, %04x: semi-stub!\n", hkl, flags);
2020     if (flags & KLF_SETFORPROCESS)
2021     {
2022         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2023         FIXME("KLF_SETFORPROCESS not supported\n");
2024         return 0;
2025     }
2026
2027     if (flags)
2028         FIXME("flags %x not supported\n",flags);
2029
2030     if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
2031     {
2032         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2033         FIXME("HKL_NEXT and HKL_PREV not supported\n");
2034         return 0;
2035     }
2036
2037     if (!match_x11_keyboard_layout(hkl))
2038     {
2039         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2040         FIXME("setting keyboard of different locales not supported\n");
2041         return 0;
2042     }
2043
2044     oldHkl = thread_data->kbd_layout;
2045     if (!oldHkl) oldHkl = get_locale_kbd_layout();
2046
2047     thread_data->kbd_layout = hkl;
2048
2049     return oldHkl;
2050 }
2051
2052
2053 /***********************************************************************
2054  *           X11DRV_MappingNotify
2055  */
2056 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
2057 {
2058     HWND hwnd;
2059
2060     wine_tsx11_lock();
2061     XRefreshKeyboardMapping(&event->xmapping);
2062     wine_tsx11_unlock();
2063     X11DRV_InitKeyboard( event->xmapping.display );
2064
2065     hwnd = GetFocus();
2066     if (!hwnd) hwnd = GetActiveWindow();
2067     PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2068                  0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2069 }
2070
2071
2072 /***********************************************************************
2073  *              VkKeyScanEx (X11DRV.@)
2074  *
2075  * Note: Windows ignores HKL parameter and uses current active layout instead
2076  */
2077 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2078 {
2079     Display *display = thread_init_display();
2080     KeyCode keycode;
2081     KeySym keysym;
2082     int i, index;
2083     CHAR cChar;
2084     SHORT ret;
2085
2086     /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2087      * is UTF-8 (multibyte encoding)?
2088      */
2089     if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2090     {
2091         WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2092         return -1;
2093     }
2094
2095     TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2096
2097     /* char->keysym (same for ANSI chars) */
2098     keysym = (unsigned char)cChar; /* (!) cChar is signed */
2099     if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2100
2101     wine_tsx11_lock();
2102     keycode = XKeysymToKeycode(display, keysym);  /* keysym -> keycode */
2103     if (!keycode)
2104     {
2105         if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2106         {
2107             ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2108             TRACE(" ... returning ctrl char %#.2x\n", ret);
2109             wine_tsx11_unlock();
2110             return ret;
2111         }
2112         /* It didn't work ... let's try with deadchar code. */
2113         TRACE("retrying with | 0xFE00\n");
2114         keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2115     }
2116     wine_tsx11_unlock();
2117
2118     TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2119
2120     /* keycode -> (keyc2vkey) vkey */
2121     ret = keyc2vkey[keycode];
2122
2123     if (!keycode || !ret)
2124     {
2125         TRACE("keycode for '%c' not found, returning -1\n", cChar);
2126         return -1;
2127     }
2128
2129     index = -1;
2130     wine_tsx11_lock();
2131     for (i = 0; i < 4; i++) /* find shift state */
2132     {
2133         if (XKeycodeToKeysym(display, keycode, i) == keysym)
2134         {
2135             index = i;
2136             break;
2137         }
2138     }
2139     wine_tsx11_unlock();
2140
2141     switch (index)
2142     {
2143         default:
2144         case -1:
2145             WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2146             return -1;
2147
2148         case 0: break;
2149         case 1: ret += 0x0100; break;
2150         case 2: ret += 0x0600; break;
2151         case 3: ret += 0x0700; break;
2152     }
2153     /*
2154       index : 0     adds 0x0000
2155       index : 1     adds 0x0100 (shift)
2156       index : ?     adds 0x0200 (ctrl)
2157       index : 2     adds 0x0600 (ctrl+alt)
2158       index : 3     adds 0x0700 (ctrl+alt+shift)
2159      */
2160
2161     TRACE(" ... returning %#.2x\n", ret);
2162     return ret;
2163 }
2164
2165 /***********************************************************************
2166  *              MapVirtualKeyEx (X11DRV.@)
2167  */
2168 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2169 {
2170     Display *display = thread_init_display();
2171
2172 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2173
2174     TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2175     if (!match_x11_keyboard_layout(hkl))
2176         FIXME("keyboard layout %p is not supported\n", hkl);
2177
2178     switch(wMapType)
2179     {
2180         case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2181         case MAPVK_VK_TO_VSC_EX:
2182         {
2183             int keyc;
2184
2185             switch (wCode)
2186             {
2187                 case VK_SHIFT: wCode = VK_LSHIFT; break;
2188                 case VK_CONTROL: wCode = VK_LCONTROL; break;
2189                 case VK_MENU: wCode = VK_LMENU; break;
2190             }
2191
2192             /* let's do vkey -> keycode -> scan */
2193             for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2194                 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2195
2196             if (keyc > max_keycode)
2197             {
2198                 TRACE("returning no scan-code.\n");
2199                 return 0;
2200             }
2201             returnMVK (keyc2scan[keyc] & 0xFF);
2202         }
2203         case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2204         case MAPVK_VSC_TO_VK_EX:
2205         {
2206             int keyc;
2207             UINT vkey = 0;
2208
2209             /* let's do scan -> keycode -> vkey */
2210             for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2211                 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2212                 {
2213                     vkey = keyc2vkey[keyc] & 0xFF;
2214                     /* Only stop if it's not a numpad vkey; otherwise keep
2215                        looking for a potential better vkey. */
2216                     if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2217                         break;
2218                 }
2219
2220             if (vkey == 0)
2221             {
2222                 TRACE("returning no vkey-code.\n");
2223                 return 0;
2224             }
2225
2226             if (wMapType == MAPVK_VSC_TO_VK)
2227                 switch (vkey)
2228                 {
2229                     case VK_LSHIFT:
2230                     case VK_RSHIFT:
2231                         vkey = VK_SHIFT; break;
2232                     case VK_LCONTROL:
2233                     case VK_RCONTROL:
2234                         vkey = VK_CONTROL; break;
2235                     case VK_LMENU:
2236                     case VK_RMENU:
2237                         vkey = VK_MENU; break;
2238                 }
2239
2240             returnMVK (vkey);
2241         }
2242                 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2243                 {
2244                         /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2245                          * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2246                          * key.. Looks like something is wrong with the MS docs?
2247                          * This is only true for letters, for example VK_0 returns '0' not ')'.
2248                          * - hence we use the lock mask to ensure this happens.
2249                          */
2250                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
2251                         XKeyEvent e;
2252                         KeySym keysym;
2253                         int keyc, len;
2254                         char s[10];
2255
2256                         e.display = display;
2257                         e.state = 0;
2258                         e.keycode = 0;
2259                         e.type = KeyPress;
2260
2261                         wine_tsx11_lock();
2262
2263                         /* We exit on the first keycode found, to speed up the thing. */
2264                         for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2265                         { /* Find a keycode that could have generated this virtual key */
2266                             if  ((keyc2vkey[keyc] & 0xFF) == wCode)
2267                             { /* We filter the extended bit, we don't know it */
2268                                 e.keycode = keyc; /* Store it temporarily */
2269                                 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2270                                     e.keycode = 0; /* Wrong one (ex: because of the NumLock
2271                                          state), so set it to 0, we'll find another one */
2272                                 }
2273                             }
2274                         }
2275
2276                         if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2277                           e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2278
2279                         if (wCode==VK_DECIMAL)
2280                           e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2281
2282                         if (!e.keycode)
2283                         {
2284                           WARN("Unknown virtual key %X !!!\n", wCode);
2285                           wine_tsx11_unlock();
2286                           return 0; /* whatever */
2287                         }
2288                         TRACE("Found keycode %u\n",e.keycode);
2289
2290                         len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2291                         wine_tsx11_unlock();
2292
2293                         if (len)
2294                         {
2295                             WCHAR wch;
2296                             if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2297                                 returnMVK(toupperW(wch));
2298                         }
2299                         TRACE("returning no ANSI.\n");
2300                         return 0;
2301                 }
2302                 default: /* reserved */
2303                         FIXME("Unknown wMapType %d !\n", wMapType);
2304                         return 0;
2305         }
2306         return 0;
2307 }
2308
2309 /***********************************************************************
2310  *              GetKeyNameText (X11DRV.@)
2311  */
2312 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2313 {
2314   Display *display = thread_init_display();
2315   int vkey, ansi, scanCode;
2316   KeyCode keyc;
2317   int keyi;
2318   KeySym keys;
2319   char *name;
2320
2321   scanCode = lParam >> 16;
2322   scanCode &= 0x1ff;  /* keep "extended-key" flag with code */
2323
2324   vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2325
2326   /*  handle "don't care" bit (0x02000000) */
2327   if (!(lParam & 0x02000000)) {
2328     switch (vkey) {
2329          case VK_RSHIFT:
2330                           /* R-Shift is "special" - it is an extended key with separate scan code */
2331                           scanCode |= 0x100;
2332          case VK_LSHIFT:
2333                           vkey = VK_SHIFT;
2334                           break;
2335        case VK_LCONTROL:
2336        case VK_RCONTROL:
2337                           vkey = VK_CONTROL;
2338                           break;
2339           case VK_LMENU:
2340           case VK_RMENU:
2341                           vkey = VK_MENU;
2342                           break;
2343     }
2344   }
2345
2346   ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2347   TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2348
2349   /* first get the name of the "regular" keys which is the Upper case
2350      value of the keycap imprint.                                     */
2351   if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2352        (scanCode != 0x137) &&   /* PrtScn   */
2353        (scanCode != 0x135) &&   /* numpad / */
2354        (scanCode != 0x37 ) &&   /* numpad * */
2355        (scanCode != 0x4a ) &&   /* numpad - */
2356        (scanCode != 0x4e ) )    /* numpad + */
2357       {
2358         if ((nSize >= 2) && lpBuffer)
2359         {
2360           *lpBuffer = toupperW((WCHAR)ansi);
2361           *(lpBuffer+1) = 0;
2362           return 1;
2363         }
2364      else
2365         return 0;
2366   }
2367
2368   /* FIXME: horrible hack to fix function keys. Windows reports scancode
2369             without "extended-key" flag. However Wine generates scancode
2370             *with* "extended-key" flag. Seems to occur *only* for the
2371             function keys. Soooo.. We will leave the table alone and
2372             fudge the lookup here till the other part is found and fixed!!! */
2373
2374   if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2375        (scanCode == 0x157) || (scanCode == 0x158))
2376     scanCode &= 0xff;   /* remove "extended-key" flag for Fx keys */
2377
2378   /* let's do scancode -> keycode -> keysym -> String */
2379
2380   for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2381       if ((keyc2scan[keyi]) == scanCode)
2382          break;
2383   if (keyi <= max_keycode)
2384   {
2385       wine_tsx11_lock();
2386       keyc = (KeyCode) keyi;
2387       keys = XKeycodeToKeysym(display, keyc, 0);
2388       name = XKeysymToString(keys);
2389       wine_tsx11_unlock();
2390       TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2391             scanCode, keyc, (int)keys, name);
2392       if (lpBuffer && nSize && name)
2393           return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2394   }
2395
2396   /* Finally issue WARN for unknown keys   */
2397
2398   WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2399   if (lpBuffer && nSize)
2400     *lpBuffer = 0;
2401   return 0;
2402 }
2403
2404 /***********************************************************************
2405  *              X11DRV_KEYBOARD_MapDeadKeysym
2406  */
2407 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2408 {
2409         switch (keysym)
2410             {
2411         /* symbolic ASCII is the same as defined in rfc1345 */
2412 #ifdef XK_dead_tilde
2413             case XK_dead_tilde :
2414 #endif
2415             case 0x1000FE7E : /* Xfree's XK_Dtilde */
2416                 return '~';     /* '? */
2417 #ifdef XK_dead_acute
2418             case XK_dead_acute :
2419 #endif
2420             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2421                 return 0xb4;    /* '' */
2422 #ifdef XK_dead_circumflex
2423             case XK_dead_circumflex:
2424 #endif
2425             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2426                 return '^';     /* '> */
2427 #ifdef XK_dead_grave
2428             case XK_dead_grave :
2429 #endif
2430             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2431                 return '`';     /* '! */
2432 #ifdef XK_dead_diaeresis
2433             case XK_dead_diaeresis :
2434 #endif
2435             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2436                 return 0xa8;    /* ': */
2437 #ifdef XK_dead_cedilla
2438             case XK_dead_cedilla :
2439                 return 0xb8;    /* ', */
2440 #endif
2441 #ifdef XK_dead_macron
2442             case XK_dead_macron :
2443                 return '-';     /* 'm isn't defined on iso-8859-x */
2444 #endif
2445 #ifdef XK_dead_breve
2446             case XK_dead_breve :
2447                 return 0xa2;    /* '( */
2448 #endif
2449 #ifdef XK_dead_abovedot
2450             case XK_dead_abovedot :
2451                 return 0xff;    /* '. */
2452 #endif
2453 #ifdef XK_dead_abovering
2454             case XK_dead_abovering :
2455                 return '0';     /* '0 isn't defined on iso-8859-x */
2456 #endif
2457 #ifdef XK_dead_doubleacute
2458             case XK_dead_doubleacute :
2459                 return 0xbd;    /* '" */
2460 #endif
2461 #ifdef XK_dead_caron
2462             case XK_dead_caron :
2463                 return 0xb7;    /* '< */
2464 #endif
2465 #ifdef XK_dead_ogonek
2466             case XK_dead_ogonek :
2467                 return 0xb2;    /* '; */
2468 #endif
2469 /* FIXME: I don't know this three.
2470             case XK_dead_iota :
2471                 return 'i';
2472             case XK_dead_voiced_sound :
2473                 return 'v';
2474             case XK_dead_semivoiced_sound :
2475                 return 's';
2476 */
2477             }
2478         TRACE("no character for dead keysym 0x%08lx\n",keysym);
2479         return 0;
2480 }
2481
2482 /***********************************************************************
2483  *              ToUnicodeEx (X11DRV.@)
2484  *
2485  * The ToUnicode function translates the specified virtual-key code and keyboard
2486  * state to the corresponding Windows character or characters.
2487  *
2488  * If the specified key is a dead key, the return value is negative. Otherwise,
2489  * it is one of the following values:
2490  * Value        Meaning
2491  * 0    The specified virtual key has no translation for the current state of the keyboard.
2492  * 1    One Windows character was copied to the buffer.
2493  * 2    Two characters were copied to the buffer. This usually happens when a
2494  *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
2495  *      be composed with the specified virtual key to form a single character.
2496  *
2497  * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2498  *
2499  */
2500 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2501                              LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2502 {
2503     Display *display = thread_init_display();
2504     XKeyEvent e;
2505     KeySym keysym = 0;
2506     INT ret;
2507     int keyc;
2508     char buf[10];
2509     char *lpChar = buf;
2510     HWND focus;
2511     XIC xic;
2512     Status status = 0;
2513
2514     if (scanCode & 0x8000)
2515     {
2516         TRACE("Key UP, doing nothing\n" );
2517         return 0;
2518     }
2519
2520     if (!match_x11_keyboard_layout(hkl))
2521         FIXME("keyboard layout %p is not supported\n", hkl);
2522
2523     if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2524     {
2525         TRACE("Ctrl+Alt+[key] won't generate a character\n");
2526         return 0;
2527     }
2528
2529     e.display = display;
2530     e.keycode = 0;
2531     e.state = 0;
2532     e.type = KeyPress;
2533
2534     focus = GetFocus();
2535     if (focus) focus = GetAncestor( focus, GA_ROOT );
2536     if (!focus) focus = GetActiveWindow();
2537     e.window = X11DRV_get_whole_window( focus );
2538     xic = X11DRV_get_ic( focus );
2539
2540     if (lpKeyState[VK_SHIFT] & 0x80)
2541     {
2542         TRACE("ShiftMask = %04x\n", ShiftMask);
2543         e.state |= ShiftMask;
2544     }
2545     if (lpKeyState[VK_CAPITAL] & 0x01)
2546     {
2547         TRACE("LockMask = %04x\n", LockMask);
2548         e.state |= LockMask;
2549     }
2550     if (lpKeyState[VK_CONTROL] & 0x80)
2551     {
2552         TRACE("ControlMask = %04x\n", ControlMask);
2553         e.state |= ControlMask;
2554     }
2555     if (lpKeyState[VK_NUMLOCK] & 0x01)
2556     {
2557         TRACE("NumLockMask = %04x\n", NumLockMask);
2558         e.state |= NumLockMask;
2559     }
2560
2561     /* Restore saved AltGr state */
2562     TRACE("AltGrMask = %04x\n", AltGrMask);
2563     e.state |= AltGrMask;
2564
2565     TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2566                 virtKey, scanCode, e.state);
2567     wine_tsx11_lock();
2568     /* We exit on the first keycode found, to speed up the thing. */
2569     for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2570       { /* Find a keycode that could have generated this virtual key */
2571           if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
2572           { /* We filter the extended bit, we don't know it */
2573               e.keycode = keyc; /* Store it temporarily */
2574               if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2575                   e.keycode = 0; /* Wrong one (ex: because of the NumLock
2576                          state), so set it to 0, we'll find another one */
2577               }
2578           }
2579       }
2580
2581     if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2582         e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2583
2584     if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2585         e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2586
2587     if (virtKey==VK_DECIMAL)
2588         e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2589
2590     if (virtKey==VK_SEPARATOR)
2591         e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2592
2593     if (!e.keycode && virtKey != VK_NONAME)
2594       {
2595         WARN("Unknown virtual key %X !!!\n", virtKey);
2596         wine_tsx11_unlock();
2597         return 0;
2598       }
2599     else TRACE("Found keycode %u\n",e.keycode);
2600
2601     TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2602                 e.type, e.window, e.state, e.keycode);
2603
2604     /* Clients should pass only KeyPress events to XmbLookupString,
2605      * e.type was set to KeyPress above.
2606      */
2607     if (xic)
2608     {
2609         ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2610         TRACE("XmbLookupString needs %d byte(s)\n", ret);
2611         if (status == XBufferOverflow)
2612         {
2613             lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2614             if (lpChar == NULL)
2615             {
2616                 ERR("Failed to allocate memory!\n");
2617                 wine_tsx11_unlock();
2618                 return 0;
2619             }
2620             ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2621         }
2622     }
2623     else
2624         ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2625     wine_tsx11_unlock();
2626
2627     TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2628
2629     if (TRACE_ON(key))
2630     {
2631         const char *ksname;
2632
2633         wine_tsx11_lock();
2634         ksname = XKeysymToString(keysym);
2635         wine_tsx11_unlock();
2636         if (!ksname) ksname = "No Name";
2637         TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2638                     (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2639                     keysym, ksname, ret, debugstr_an(lpChar, ret));
2640     }
2641
2642     if (ret == 0)
2643     {
2644         char dead_char;
2645
2646 #ifdef XK_EuroSign
2647         /* An ugly hack for EuroSign: X can't translate it to a character
2648            for some locales. */
2649         if (keysym == XK_EuroSign)
2650         {
2651             bufW[0] = 0x20AC;
2652             ret = 1;
2653             goto found;
2654         }
2655 #endif
2656         /* Special case: X turns shift-tab into ISO_Left_Tab. */
2657         /* Here we change it back. */
2658         if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2659         {
2660             bufW[0] = 0x09;
2661             ret = 1;
2662             goto found;
2663         }
2664
2665         dead_char = KEYBOARD_MapDeadKeysym(keysym);
2666         if (dead_char)
2667         {
2668             MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2669             ret = -1;
2670             goto found;
2671         }
2672
2673         if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2674         {
2675             /* Unicode direct mapping */
2676             bufW[0] = keysym & 0xffff;
2677             ret = 1;
2678             goto found;
2679         }
2680         else if ((keysym >> 8) == 0x1008FF) {
2681             bufW[0] = 0;
2682             ret = 0;
2683             goto found;
2684         }
2685         else
2686             {
2687             const char *ksname;
2688
2689             wine_tsx11_lock();
2690             ksname = XKeysymToString(keysym);
2691             wine_tsx11_unlock();
2692             if (!ksname)
2693                 ksname = "No Name";
2694             if ((keysym >> 8) != 0xff)
2695                 {
2696                 WARN("no char for keysym %04lx (%s) :\n",
2697                     keysym, ksname);
2698                 WARN("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2699                     virtKey, scanCode, e.keycode, e.state);
2700                 }
2701             }
2702         }
2703     else {  /* ret != 0 */
2704         /* We have a special case to handle : Shift + arrow, shift + home, ...
2705            X returns a char for it, but Windows doesn't. Let's eat it. */
2706         if (!(e.state & NumLockMask)  /* NumLock is off */
2707             && (e.state & ShiftMask) /* Shift is pressed */
2708             && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2709         {
2710             lpChar[0] = 0;
2711             ret = 0;
2712         }
2713
2714         /* more areas where X returns characters but Windows does not
2715            CTRL + number or CTRL + symbol */
2716         if (e.state & ControlMask)
2717         {
2718             if (((keysym>=33) && (keysym < 'A')) ||
2719                 ((keysym > 'Z') && (keysym < 'a')) ||
2720                 (keysym == XK_Tab))
2721             {
2722                 lpChar[0] = 0;
2723                 ret = 0;
2724             }
2725         }
2726
2727         /* We have another special case for delete key (XK_Delete) on an
2728          extended keyboard. X returns a char for it, but Windows doesn't */
2729         if (keysym == XK_Delete)
2730         {
2731             lpChar[0] = 0;
2732             ret = 0;
2733         }
2734         else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2735                 && (keysym == XK_KP_Decimal))
2736         {
2737             lpChar[0] = 0;
2738             ret = 0;
2739         }
2740         else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2741                 && (keysym == XK_Return || keysym == XK_KP_Enter))
2742         {
2743             lpChar[0] = '\n';
2744             ret = 1;
2745         }
2746
2747         /* Hack to detect an XLookupString hard-coded to Latin1 */
2748         if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2749         {
2750             bufW[0] = (BYTE)lpChar[0];
2751             goto found;
2752         }
2753
2754         /* perform translation to unicode */
2755         if(ret)
2756         {
2757             TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2758             ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2759         }
2760     }
2761
2762 found:
2763     if (buf != lpChar)
2764         HeapFree(GetProcessHeap(), 0, lpChar);
2765     TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2766     return ret;
2767 }
2768
2769 /***********************************************************************
2770  *              Beep (X11DRV.@)
2771  */
2772 void CDECL X11DRV_Beep(void)
2773 {
2774     wine_tsx11_lock();
2775     XBell(gdi_display, 0);
2776     wine_tsx11_unlock();
2777 }