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