dmime/tests: Add more GetTrack() tests.
[wine.git] / dlls / winex11.drv / keyboard.c
blob48da12c0292cb8cab0d85af0c72bf1a4ca49cb29
1 /*
2 * X11 keyboard driver
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
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.
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.
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
26 #include "config.h"
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
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
41 #define NONAMELESSUNION
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 "ime.h"
50 #include "x11drv.h"
51 #include "wine/server.h"
52 #include "wine/unicode.h"
53 #include "wine/debug.h"
55 /* log format (add 0-padding as appropriate):
56 keycode %u as in output from xev
57 keysym %lx as in X11/keysymdef.h
58 vkey %X as in winuser.h
59 scancode %x
61 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
62 WINE_DECLARE_DEBUG_CHANNEL(key);
64 static int min_keycode, max_keycode, keysyms_per_keycode;
65 static KeySym *key_mapping;
66 static WORD keyc2vkey[256], keyc2scan[256];
68 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
70 static CRITICAL_SECTION kbd_section;
71 static CRITICAL_SECTION_DEBUG critsect_debug =
73 0, 0, &kbd_section,
74 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": kbd_section") }
77 static CRITICAL_SECTION kbd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
79 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
81 /* Keyboard translation tables */
82 #define MAIN_LEN 49
83 static const WORD main_key_scan_qwerty[MAIN_LEN] =
85 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
86 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
87 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
88 /* q w e r t y u i o p [ ] */
89 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
90 /* a s d f g h j k l ; ' \ */
91 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
92 /* z x c v b n m , . / */
93 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
94 0x56 /* the 102nd key (actually to the right of l-shift) */
97 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
99 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
100 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
101 /* q w e r t y u i o p [ ] */
102 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
103 /* a s d f g h j k l ; ' \ */
104 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
105 /* \ z x c v b n m , . / */
106 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
107 0x56, /* the 102nd key (actually to the right of l-shift) */
110 static const WORD main_key_scan_dvorak[MAIN_LEN] =
112 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
113 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
114 /* ' , . p y f g c r l / = */
115 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
116 /* a o e u i d h t n s - \ */
117 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
118 /* ; q j k x b m w v z */
119 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
120 0x56 /* the 102nd key (actually to the right of l-shift) */
123 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
125 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ (Yen) */
126 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7D,
127 /* q w e r t y u i o p @ [ */
128 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
129 /* a s d f g h j k l ; : ] */
130 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
131 /* z x c v b n m , . / \ (Underscore) */
132 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x73
136 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
138 /* NOTE: this layout must concur with the scan codes layout above */
139 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
140 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
141 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
142 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
143 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
146 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
148 /* NOTE: this layout must concur with the scan codes layout above */
149 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
150 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
151 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
152 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
153 VK_OEM_102 /* the 102nd key (actually to the left of r-shift) */
156 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
158 /* NOTE: this layout must concur with the scan codes layout above */
159 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
160 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
161 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
162 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
163 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
166 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
168 /* NOTE: this layout must concur with the scan codes layout above */
169 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
170 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
171 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
172 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
173 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
176 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
178 /* NOTE: this layout must concur with the scan codes layout above */
179 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
180 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
181 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
182 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
183 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
186 static const WORD main_key_vkey_azerty[MAIN_LEN] =
188 /* NOTE: this layout must concur with the scan codes layout above */
189 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
190 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
191 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
192 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
193 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
196 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
198 /* NOTE: this layout must concur with the scan codes layout above */
199 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
200 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
201 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
202 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
203 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
206 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
208 /* the VK mappings for the main keyboard will be auto-assigned as before,
209 so what we have here is just the character tables */
210 /* order: Normal, Shift, AltGr, Shift-AltGr */
211 /* We recommend you write just what is guaranteed to be correct (i.e. what's
212 written on the keycaps), not the bunch of special characters behind AltGr
213 and Shift-AltGr if it can vary among different X servers */
214 /* These tables serve to guess the keyboard type and scancode mapping.
215 Complete modeling is not important, identification/discrimination is. */
216 /* Remember that your 102nd key (to the right of l-shift) should be on a
217 separate line, see existing tables */
218 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
219 /* Remember to also add your new table to the layout index table far below! */
221 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
222 static const char main_key_US[MAIN_LEN][4] =
224 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
225 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
226 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
227 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
230 /*** United States keyboard layout (phantom key version) */
231 /* (XFree86 reports the <> key even if it's not physically there) */
232 static const char main_key_US_phantom[MAIN_LEN][4] =
234 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
235 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
236 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
237 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
238 "<>" /* the phantom key */
241 /*** United States keyboard layout (dvorak version) */
242 static const char main_key_US_dvorak[MAIN_LEN][4] =
244 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
245 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
246 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
247 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
250 /*** British keyboard layout */
251 static const char main_key_UK[MAIN_LEN][4] =
253 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
254 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
255 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
256 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
257 "\\|"
260 /*** French keyboard layout (setxkbmap fr) */
261 static const char main_key_FR[MAIN_LEN][4] =
263 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
264 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
265 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
266 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
267 "<>"
270 /*** Icelandic keyboard layout (setxkbmap is) */
271 static const char main_key_IS[MAIN_LEN][4] =
273 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
274 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
275 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
276 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
277 "<>"
280 /* All german keyb layout tables have the acute/apostrophe symbol next to
281 * the BACKSPACE key removed (replaced with NULL which is ignored by the
282 * detection code).
283 * This was done because the mapping of the acute (and apostrophe) is done
284 * differently in various xkb-data/xkeyboard-config versions. Some replace
285 * the acute with a normal apostrophe, so that the apostrophe is found twice
286 * on the keyboard (one next to BACKSPACE and one next to ENTER).
287 * Others put the acute and grave accents on the key left of BACKSPACE.
288 * More information on the fd.o bugtracker:
289 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
290 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
291 * among PC and Mac keyboards, so these are not listed.
294 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
295 static const char main_key_DE[MAIN_LEN][4] =
297 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
298 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
299 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
300 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
301 "<>"
304 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
305 static const char main_key_SG[MAIN_LEN][4] =
307 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
308 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
309 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
310 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
311 "<>"
314 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
315 static const char main_key_SF[MAIN_LEN][4] =
317 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
318 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
319 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
320 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
321 "<>"
324 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
325 static const char main_key_NO[MAIN_LEN][4] =
327 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
328 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
330 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
331 "<>"
334 /*** Danish keyboard layout (setxkbmap dk) */
335 static const char main_key_DA[MAIN_LEN][4] =
337 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
338 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
339 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
340 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
341 "<>"
344 /*** Swedish keyboard layout (setxkbmap se) */
345 static const char main_key_SE[MAIN_LEN][4] =
347 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
348 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
349 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
350 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
351 "<>"
354 /*** Estonian keyboard layout (setxkbmap ee) */
355 static const char main_key_ET[MAIN_LEN][4] =
357 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
358 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
359 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
360 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
361 "<>"
364 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
365 static const char main_key_CF[MAIN_LEN][4] =
367 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
368 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
369 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
370 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
371 "\xab\xbb\xb0"
374 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
375 static const char main_key_CA_fr[MAIN_LEN][4] =
377 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
378 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
379 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
380 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
381 "\xab\xbb"
384 /*** Canadian keyboard layout (setxkbmap ca) */
385 static const char main_key_CA[MAIN_LEN][4] =
387 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
388 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
389 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
390 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
391 "\xf9\xd9"
394 /*** Portuguese keyboard layout (setxkbmap pt) */
395 static const char main_key_PT[MAIN_LEN][4] =
397 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
398 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
399 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
400 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
401 "<>"
404 /*** Italian keyboard layout (setxkbmap it) */
405 static const char main_key_IT[MAIN_LEN][4] =
407 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
408 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
409 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
410 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
411 "<>"
414 /*** Finnish keyboard layout (setxkbmap fi) */
415 static const char main_key_FI[MAIN_LEN][4] =
417 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
418 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
419 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
420 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
421 "<>"
424 /*** Bulgarian bds keyboard layout */
425 static const char main_key_BG_bds[MAIN_LEN][4] =
427 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
428 "qQ,\xfb","wW\xf3\xd3","eE\xe5\xc5","rR\xe8\xc8","tT\xf8\xd8","yY\xf9\xd9","uU\xea\xca","iI\xf1\xd1","oO\xe4\xc4","pP\xe7\xc7","[{\xf6\xd6","]};",
429 "aA\xfc\xdc","sS\xff\xdf","dD\xe0\xc0","fF\xee\xce","gG\xe6\xc6","hH\xe3\xc3","jJ\xf2\xd2","kK\xed\xcd","lL\xe2\xc2",";:\xec\xcc","'\"\xf7\xd7","\\|'\xdb",
430 "zZ\xfe\xde","xX\xe9\xc9","cC\xfa\xda","vV\xfd\xdd","bB\xf4\xd4","nN\xf5\xd5","mM\xef\xcf",",<\xf0\xd0",".>\xeb\xcb","/?\xe1\xc1",
431 "<>" /* the phantom key */
434 /*** Bulgarian phonetic keyboard layout */
435 static const char main_key_BG_phonetic[MAIN_LEN][4] =
437 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
438 "qQ\xff\xdf","wW\xe2\xc2","eE\xe5\xc5","rR\xf0\xd0","tT\xf2\xd2","yY\xfa\xda","uU\xf3\xd3","iI\xe8\xc8","oO\xee\xce","pP\xef\xcf","[{\xf8\xd8","]}\xf9\xd9",
439 "aA\xe0\xc0","sS\xf1\xd1","dD\xe4\xc4","fF\xf4\xd4","gG\xe3\xc3","hH\xf5\xd5","jJ\xe9\xc9","kK\xea\xca","lL\xeb\xcb",";:","'\"","\\|\xfe\xde",
440 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
441 "<>" /* the phantom key */
444 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
445 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
446 static const char main_key_BY[MAIN_LEN][4] =
448 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
449 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xae\xbe","pP\xda\xfa","[{\xc8\xe8","]}''",
450 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|/|",
451 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xa6\xb6","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?.,", "<>|\xa6",
455 /*** Russian keyboard layout (contributed by Pavel Roskin) */
456 static const char main_key_RU[MAIN_LEN][4] =
458 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
459 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
460 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
461 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?"
464 /*** Russian keyboard layout (phantom key version) */
465 static const char main_key_RU_phantom[MAIN_LEN][4] =
467 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
468 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
469 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
470 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?",
471 "<>" /* the phantom key */
474 /*** Russian keyboard layout KOI8-R */
475 static const char main_key_RU_koi8r[MAIN_LEN][4] =
477 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
478 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
479 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
480 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
481 "<>" /* the phantom key */
484 /*** Russian keyboard layout cp1251 */
485 static const char main_key_RU_cp1251[MAIN_LEN][4] =
487 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
488 "qQ\xe9\xc9","wW\xf6\xd6","eE\xf3\xd3","rR\xea\xca","tT\xe5\xc5","yY\xed\xcd","uU\xe3\xc3","iI\xf8\xd8","oO\xf9\xd9","pP\xe7\xc7","[{\xf5\xd5","]}\xfa\xda",
489 "aA\xf4\xd4","sS\xfb\xdb","dD\xe2\xc2","fF\xe0\xc0","gG\xef\xcf","hH\xf0\xd0","jJ\xee\xce","kK\xeb\xcb","lL\xe4\xc4",";:\xe6\xc6","'\"\xfd\xdd","\\|",
490 "zZ\xff\xdf","xX\xf7\xd7","cC\xf1\xd1","vV\xec\xcc","bB\xe8\xc8","nN\xf2\xd2","mM\xfc\xdc",",<\xe1\xc1",".>\xfe\xde","/?",
491 "<>" /* the phantom key */
494 /*** Russian phonetic keyboard layout */
495 static const char main_key_RU_phonetic[MAIN_LEN][4] =
497 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
498 "qQ\xd1\xf1","wW\xd7\xf7","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xd9\xf9","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}\xdd\xfd",
499 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xca\xea","kK\xcb\xeb","lL\xcc\xec",";:","'\"","\\|",
500 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
501 "<>" /* the phantom key */
504 /*** Ukrainian keyboard layout KOI8-U */
505 static const char main_key_UA[MAIN_LEN][4] =
507 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
508 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xa7\xb7",
509 "aA\xc6\xe6","sS\xa6\xb6","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xa4\xb4","\\|\\|",
510 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?/?",
511 "<>" /* the phantom key */
514 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
515 /*** (as it appears on most of keyboards sold today) */
516 static const char main_key_UA_std[MAIN_LEN][4] =
518 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
519 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
520 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
521 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
522 "<>" /* the phantom key */
525 /*** Russian keyboard layout KOI8-R (pair to the previous) */
526 static const char main_key_RU_std[MAIN_LEN][4] =
528 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
529 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
530 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
531 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
532 "<>" /* the phantom key */
535 /*** Spanish keyboard layout (setxkbmap es) */
536 static const char main_key_ES[MAIN_LEN][4] =
538 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
539 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
540 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
541 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
542 "<>"
545 /*** Belgian keyboard layout ***/
546 static const char main_key_BE[MAIN_LEN][4] =
548 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
549 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
550 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
551 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
552 "<>\\"
555 /*** Hungarian keyboard layout (setxkbmap hu) */
556 static const char main_key_HU[MAIN_LEN][4] =
558 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
559 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
560 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
561 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
562 "\xed\xcd"
565 /*** Polish (programmer's) keyboard layout ***/
566 static const char main_key_PL[MAIN_LEN][4] =
568 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
569 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
570 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
571 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
572 "<>|"
575 /*** Slovenian keyboard layout (setxkbmap si) ***/
576 static const char main_key_SI[MAIN_LEN][4] =
578 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
579 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
580 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
581 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
582 "<>"
585 /*** Serbian keyboard layout (setxkbmap sr) ***/
586 static const char main_key_SR[MAIN_LEN][4] =
588 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
589 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
590 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
591 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
592 "<>" /* the phantom key */
595 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
596 static const char main_key_US_SR[MAIN_LEN][4] =
598 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
599 "qQ\xa9\xb9","wW\xaa\xba","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xda\xfa","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}[]",
600 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xa8\xb8","kK\xcb\xeb","lL\xcc\xec",";:\xde\xfe","'\"\xab\xbb","\\|-_",
601 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
602 "<>" /* the phantom key */
605 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
606 static const char main_key_HR_jelly[MAIN_LEN][4] =
608 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
609 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
610 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
611 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
612 "<>|"
615 /*** Croatian keyboard layout (setxkbmap hr) ***/
616 static const char main_key_HR[MAIN_LEN][4] =
618 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
619 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
620 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
621 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
622 "<>"
625 /*** Japanese 106 keyboard layout ***/
626 static const char main_key_JA_jp106[MAIN_LEN][4] =
628 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
629 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
630 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
631 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
632 "\\_",
635 static const char main_key_JA_macjp[MAIN_LEN][4] =
637 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
638 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
639 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
640 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
641 "__",
644 /*** Japanese pc98x1 keyboard layout ***/
645 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
647 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
648 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
649 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
650 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
651 "\\_",
654 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
655 static const char main_key_PT_br[MAIN_LEN][4] =
657 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
658 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
659 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
660 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
663 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
664 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
666 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
667 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
668 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
669 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
672 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
673 static const char main_key_US_intl[MAIN_LEN][4] =
675 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
676 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
677 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
678 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
681 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
682 - dead_abovering replaced with degree - no symbol in iso8859-2
683 - brokenbar replaced with bar */
684 static const char main_key_SK[MAIN_LEN][4] =
686 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
687 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
688 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
689 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
690 "<>"
693 /*** Czech keyboard layout (setxkbmap cz) */
694 static const char main_key_CZ[MAIN_LEN][4] =
696 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
697 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
698 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
699 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
700 "\\"
703 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
704 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
706 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
707 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
708 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
709 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
710 "\\"
713 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
714 static const char main_key_SK_prog[MAIN_LEN][4] =
716 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
717 "qQ\xe4\xc4","wW\xec\xcc","eE\xe9\xc9","rR\xf8\xd8","tT\xbb\xab","yY\xfd\xdd","uU\xf9\xd9","iI\xed\xcd","oO\xf3\xd3","pP\xf6\xd6","[{","]}",
718 "aA\xe1\xc1","sS\xb9\xa9","dD\xef\xcf","fF\xeb\xcb","gG\xe0\xc0","hH\xfa\xda","jJ\xfc\xdc","kK\xf4\xd4","lL\xb5\xa5",";:","'\"","\\|",
719 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
720 "<>"
723 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
724 static const char main_key_CS[MAIN_LEN][4] =
726 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
727 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
728 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
729 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
730 "<>\\|"
733 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
734 static const char main_key_LA[MAIN_LEN][4] =
736 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
737 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
738 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
739 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
740 "<>"
743 /*** Lithuanian keyboard layout (setxkbmap lt) */
744 static const char main_key_LT_B[MAIN_LEN][4] =
746 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
747 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
748 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
749 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
750 "\xaa\xac"
753 /*** Turkish keyboard Layout */
754 static const char main_key_TK[MAIN_LEN][4] =
756 "\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
757 "qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
758 "aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
759 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
762 /*** Turkish keyboard layout (setxkbmap tr) */
763 static const char main_key_TR[MAIN_LEN][4] =
765 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
766 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
767 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
768 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
769 "<>"
772 /*** Turkish F keyboard layout (setxkbmap trf) */
773 static const char main_key_TR_F[MAIN_LEN][4] =
775 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
776 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
777 "uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
778 "jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
779 "<>"
782 /*** Israelian keyboard layout (setxkbmap us,il) */
783 static const char main_key_IL[MAIN_LEN][4] =
785 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
786 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
787 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
788 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
789 "<>"
792 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
793 static const char main_key_IL_phonetic[MAIN_LEN][4] =
795 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
796 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
797 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
798 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
799 "<>"
802 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
803 static const char main_key_IL_saharon[MAIN_LEN][4] =
805 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
806 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
807 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
808 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
809 "<>"
812 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
813 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
814 message since they have different characters in gr and el XFree86 layouts. */
815 static const char main_key_EL[MAIN_LEN][4] =
817 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
818 "qQ;:","wW","eE\xe5\xc5","rR\xf1\xd1","tT\xf4\xd4","yY\xf5\xd5","uU\xe8\xc8","iI\xe9\xc9","oO\xef\xcf","pP\xf0\xd0","[{","]}",
819 "aA\xe1\xc1","sS","dD\xe4\xc4","fF\xf6\xd6","gG\xe3\xc3","hH\xe7\xc7","jJ\xee\xce","kK\xea\xca","lL\xeb\xcb",";:\xb4\xa8","'\"","\\|",
820 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
821 "<>"
824 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
825 static const char main_key_th[MAIN_LEN][4] =
827 "`~_%","1!\xe5+","2@/\xf1","3#-\xf2","4$\xc0\xf3","5%\xb6\xf4","6^\xd8\xd9","7&\xd6\xdf","8*\xa4\xf5","9(\xb5\xf6","0)\xa8\xf7","-_\xa2\xf8","=+\xaa\xf9",
828 "qQ\xe6\xf0","wW\xe4\"","eE\xd3\xae","rR\xbe\xb1","tT\xd0\xb8","yY\xd1\xed","uU\xd5\xea","iI\xc3\xb3","oO\xb9\xcf","pP\xc2\xad","[{\xba\xb0","]}\xc5,",
829 "aA\xbf\xc4","sS\xcb\xa6","dD\xa1\xaf","fF\xb4\xe2","gG\xe0\xac","hH\xe9\xe7","jJ\xe8\xeb","kK\xd2\xc9","lL\xca\xc8",";:\xc7\xab","\'\"\xa7.","\\|\xa3\xa5",
830 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
833 /*** VNC keyboard layout */
834 static const WORD main_key_scan_vnc[MAIN_LEN] =
836 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
837 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,
838 0x56
841 static const WORD main_key_vkey_vnc[MAIN_LEN] =
843 '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,
844 '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',
845 VK_OEM_102
848 static const char main_key_vnc[MAIN_LEN][4] =
850 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
851 "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"
854 /*** Dutch keyboard layout (setxkbmap nl) ***/
855 static const char main_key_NL[MAIN_LEN][4] =
857 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
858 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
859 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
860 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
861 "[]"
866 /*** Layout table. Add your keyboard mappings to this list */
867 static const struct {
868 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
869 in the appropriate dlls/kernel/nls/.nls file */
870 const char *comment;
871 const char (*key)[MAIN_LEN][4];
872 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
873 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
874 } main_key_tab[]={
875 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
876 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
877 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
878 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
879 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
880 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
881 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
882 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
883 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
884 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
885 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
886 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
887 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
888 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
889 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
892 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
894 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
895 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
896 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
897 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
898 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
902 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
906 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
908 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
909 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
911 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
913 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
914 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
915 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
916 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
918 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
919 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
924 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
934 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
938 {0, NULL, NULL, NULL, NULL} /* sentinel */
940 static unsigned kbd_layout=0; /* index into above table of layouts */
942 /* maybe more of these scancodes should be extended? */
943 /* extended must be set for ALT_R, CTRL_R,
944 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
945 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
946 /* FIXME should we set extended bit for NumLock ? My
947 * Windows does ... DF */
948 /* Yes, to distinguish based on scan codes, also
949 for PrtScn key ... GA */
951 static const WORD nonchar_key_vkey[256] =
953 /* unused */
954 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
955 /* special keys */
956 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
957 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
958 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
959 /* Japanese special keys */
960 0, VK_KANJI, VK_NONCONVERT, VK_CONVERT, /* FF20 */
961 VK_DBE_ROMAN, 0, 0, VK_DBE_HIRAGANA,
962 0, 0, VK_DBE_SBCSCHAR, 0, 0, 0, 0, 0, /* FF28 */
963 /* Korean special keys (FF31-) */
964 VK_DBE_ALPHANUMERIC, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
965 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
966 /* unused */
967 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
968 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
969 /* cursor keys */
970 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
971 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
972 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
973 /* misc keys */
974 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
975 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
976 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
977 /* keypad keys */
978 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
980 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
981 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
982 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
983 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
984 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
985 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
986 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
987 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
988 * in order to produce a locale dependent numeric separator.
990 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
991 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
992 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
993 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
994 /* function keys */
995 VK_F1, VK_F2,
996 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
997 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
998 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
999 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1000 /* modifier keys */
1001 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1002 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1003 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1004 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1005 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1008 static const WORD nonchar_key_scan[256] =
1010 /* unused */
1011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1012 /* special keys */
1013 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1014 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1015 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1016 /* Japanese special keys */
1017 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */
1018 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1019 /* Korean special keys (FF31-) */
1020 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1022 /* unused */
1023 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1025 /* cursor keys */
1026 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1028 /* misc keys */
1029 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1030 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1032 /* keypad keys */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1035 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1037 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1039 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1040 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1041 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1042 /* function keys */
1043 0x3B, 0x3C,
1044 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1045 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1047 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1048 /* modifier keys */
1049 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1050 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1055 static const WORD xfree86_vendor_key_vkey[256] =
1057 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1058 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1059 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1060 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1061 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1062 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1063 0, 0, 0, VK_BROWSER_HOME,
1064 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1065 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1066 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1067 0, 0, 0, 0,
1068 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1069 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1070 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1071 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1072 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1092 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1095 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1097 #ifdef HAVE_XKB
1098 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1099 #endif
1100 return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index];
1103 /* Returns the Windows virtual key code associated with the X event <e> */
1104 /* kbd_section must be held */
1105 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1107 KeySym keysym = 0;
1108 Status status;
1109 char buf[24];
1111 /* Clients should pass only KeyPress events to XmbLookupString */
1112 if (xic && e->type == KeyPress)
1113 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1114 else
1115 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1117 if ((e->state & NumLockMask) &&
1118 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1119 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1120 /* Only the Keypad keys 0-9 and . send different keysyms
1121 * depending on the NumLock state */
1122 return nonchar_key_vkey[keysym & 0xFF];
1124 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1125 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1126 if ((e->state & ControlMask) && (keysym == XK_Break))
1127 return VK_CANCEL;
1129 TRACE_(key)("e->keycode = %u\n", e->keycode);
1131 return keyc2vkey[e->keycode];
1135 /***********************************************************************
1136 * X11DRV_send_keyboard_input
1138 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1140 INPUT input;
1142 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1144 input.type = INPUT_KEYBOARD;
1145 input.u.ki.wVk = vkey;
1146 input.u.ki.wScan = scan;
1147 input.u.ki.dwFlags = flags;
1148 input.u.ki.time = time;
1149 input.u.ki.dwExtraInfo = 0;
1151 __wine_send_input( hwnd, &input );
1155 /***********************************************************************
1156 * get_async_key_state
1158 static BOOL get_async_key_state( BYTE state[256] )
1160 BOOL ret;
1162 SERVER_START_REQ( get_key_state )
1164 req->tid = 0;
1165 req->key = -1;
1166 wine_server_set_reply( req, state, 256 );
1167 ret = !wine_server_call( req );
1169 SERVER_END_REQ;
1170 return ret;
1173 /***********************************************************************
1174 * set_async_key_state
1176 static void set_async_key_state( const BYTE state[256] )
1178 SERVER_START_REQ( set_key_state )
1180 req->tid = GetCurrentThreadId();
1181 req->async = 1;
1182 wine_server_add_data( req, state, 256 );
1183 wine_server_call( req );
1185 SERVER_END_REQ;
1188 static void update_key_state( BYTE *keystate, BYTE key, int down )
1190 if (down)
1192 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1193 keystate[key] |= 0x80;
1195 else keystate[key] &= ~0x80;
1198 /***********************************************************************
1199 * X11DRV_KeymapNotify
1201 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1203 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1204 * from wine to another application and back.
1205 * Toggle keys are handled in HandleEvent.
1207 BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1209 int i, j;
1210 BYTE keystate[256];
1211 WORD vkey;
1212 BOOL changed = FALSE;
1213 struct {
1214 WORD vkey;
1215 WORD pressed;
1216 } keys[256];
1218 if (!get_async_key_state( keystate )) return FALSE;
1220 memset(keys, 0, sizeof(keys));
1222 EnterCriticalSection( &kbd_section );
1224 /* the minimum keycode is always greater or equal to 8, so we can
1225 * skip the first 8 values, hence start at 1
1227 for (i = 1; i < 32; i++)
1229 for (j = 0; j < 8; j++)
1231 vkey = keyc2vkey[(i * 8) + j];
1233 /* If multiple keys map to the same vkey, we want to report it as
1234 * pressed iff any of them are pressed. */
1235 if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey;
1236 if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE;
1240 for (vkey = 1; vkey <= 0xff; vkey++)
1242 if (keys[vkey].vkey && !(keystate[vkey] & 0x80) != !keys[vkey].pressed)
1244 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1245 keys[vkey].vkey, keystate[vkey]);
1247 update_key_state( keystate, vkey, keys[vkey].pressed );
1248 changed = TRUE;
1252 LeaveCriticalSection( &kbd_section );
1253 if (!changed) return FALSE;
1255 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1256 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1257 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1258 set_async_key_state( keystate );
1259 return TRUE;
1262 static void adjust_lock_state( BYTE *keystate, HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1264 BYTE prev_state = keystate[vkey] & 0x01;
1266 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags, time );
1267 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags ^ KEYEVENTF_KEYUP, time );
1269 /* Keyboard hooks may have blocked processing lock keys causing our state
1270 * to be different than state on X server side. Although Windows allows hooks
1271 * to block changing state, we can't prevent it on X server side. Having
1272 * different states would cause us to try to adjust it again on the next
1273 * key event. We prevent that by overriding hooks and setting key states here. */
1274 if (get_async_key_state( keystate ) && (keystate[vkey] & 0x01) == prev_state)
1276 WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey, keystate[vkey]);
1277 keystate[vkey] ^= 0x01;
1278 set_async_key_state( keystate );
1282 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1284 BYTE keystate[256];
1286 /* Note: X sets the below states on key down and clears them on key up.
1287 Windows triggers them on key down. */
1289 if (!get_async_key_state( keystate )) return;
1291 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1292 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1294 DWORD flags = 0;
1295 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1296 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1297 adjust_lock_state( keystate, hwnd, VK_CAPITAL, 0x3a, flags, time );
1300 /* Adjust the NUMLOCK state if it has been changed outside wine */
1301 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1303 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1304 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1305 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1306 adjust_lock_state( keystate, hwnd, VK_NUMLOCK, 0x45, flags, time );
1309 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1310 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1312 DWORD flags = 0;
1313 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1314 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1315 adjust_lock_state( keystate, hwnd, VK_SCROLL, 0x46, flags, time );
1319 /***********************************************************************
1320 * X11DRV_KeyEvent
1322 * Handle a X key event
1324 BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1326 XKeyEvent *event = &xev->xkey;
1327 char buf[24];
1328 char *Str = buf;
1329 KeySym keysym = 0;
1330 WORD vkey = 0, bScan;
1331 DWORD dwFlags;
1332 int ascii_chars;
1333 XIC xic = X11DRV_get_ic( hwnd );
1334 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1335 Status status = 0;
1337 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1338 event->type, event->window, event->state, event->keycode);
1340 if (event->type == KeyPress) update_user_time( event->time );
1342 /* Clients should pass only KeyPress events to XmbLookupString */
1343 if (xic && event->type == KeyPress)
1345 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1346 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1347 if (status == XBufferOverflow)
1349 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1350 if (Str == NULL)
1352 ERR_(key)("Failed to allocate memory!\n");
1353 return FALSE;
1355 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1358 else
1359 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1361 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1363 if (status == XLookupChars)
1365 X11DRV_XIMLookupChars( Str, ascii_chars );
1366 if (buf != Str)
1367 HeapFree(GetProcessHeap(), 0, Str);
1368 return TRUE;
1371 EnterCriticalSection( &kbd_section );
1373 /* If XKB extensions are used, the state mask for AltGr will use the group
1374 index instead of the modifier mask. The group index is set in bits
1375 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1376 pressed, look if the group index is different than 0. From XKB
1377 extension documentation, the group index for AltGr should be 2
1378 (event->state = 0x2000). It's probably better to not assume a
1379 predefined group index and find it dynamically
1381 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1382 /* Save also all possible modifier states. */
1383 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1385 if (TRACE_ON(key)){
1386 const char *ksname;
1388 ksname = XKeysymToString(keysym);
1389 if (!ksname)
1390 ksname = "No Name";
1391 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1392 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1393 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1395 if (buf != Str)
1396 HeapFree(GetProcessHeap(), 0, Str);
1398 vkey = EVENT_event_to_vkey(xic,event);
1399 /* X returns keycode 0 for composed characters */
1400 if (!vkey && ascii_chars) vkey = VK_NONAME;
1401 bScan = keyc2scan[event->keycode] & 0xFF;
1403 TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
1404 event->keycode, vkey, bScan);
1406 LeaveCriticalSection( &kbd_section );
1408 if (!vkey) return FALSE;
1410 dwFlags = 0;
1411 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1412 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1414 update_lock_state( hwnd, vkey, event->state, event_time );
1416 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1417 return TRUE;
1420 /**********************************************************************
1421 * X11DRV_KEYBOARD_DetectLayout
1423 * Called from X11DRV_InitKeyboard
1424 * This routine walks through the defined keyboard layouts and selects
1425 * whichever matches most closely.
1426 * kbd_section must be held.
1428 static void
1429 X11DRV_KEYBOARD_DetectLayout( Display *display )
1431 unsigned current, match, mismatch, seq, i, syms;
1432 int score, keyc, key, pkey, ok;
1433 KeySym keysym = 0;
1434 const char (*lkey)[MAIN_LEN][4];
1435 unsigned max_seq = 0;
1436 int max_score = 0, ismatch = 0;
1437 char ckey[256][4];
1439 syms = keysyms_per_keycode;
1440 if (syms > 4) {
1441 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1442 syms = 4;
1445 memset( ckey, 0, sizeof(ckey) );
1446 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1447 /* get data for keycode from X server */
1448 for (i = 0; i < syms; i++) {
1449 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1450 /* Allow both one-byte and two-byte national keysyms */
1451 if ((keysym < 0x8000) && (keysym != ' '))
1453 #ifdef HAVE_XKB
1454 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1455 #endif
1457 TRACE("XKB could not translate keysym %04lx\n", keysym);
1458 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1459 * with appropriate ShiftMask and Mode_switch, use XLookupString
1460 * to get character in the local encoding.
1462 ckey[keyc][i] = keysym & 0xFF;
1465 else {
1466 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1471 for (current = 0; main_key_tab[current].comment; current++) {
1472 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1473 match = 0;
1474 mismatch = 0;
1475 score = 0;
1476 seq = 0;
1477 lkey = main_key_tab[current].key;
1478 pkey = -1;
1479 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1480 if (ckey[keyc][0]) {
1481 /* search for a match in layout table */
1482 /* right now, we just find an absolute match for defined positions */
1483 /* (undefined positions are ignored, so if it's defined as "3#" in */
1484 /* the table, it's okay that the X server has "3#£", for example) */
1485 /* however, the score will be higher for longer matches */
1486 for (key = 0; key < MAIN_LEN; key++) {
1487 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1488 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1489 ok++;
1490 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1491 ok = -1;
1493 if (ok > 0) {
1494 score += ok;
1495 break;
1498 /* count the matches and mismatches */
1499 if (ok > 0) {
1500 match++;
1501 /* and how much the keycode order matches */
1502 if (key > pkey) seq++;
1503 pkey = key;
1504 } else {
1505 /* print spaces instead of \0's */
1506 char str[5];
1507 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1508 str[4] = 0;
1509 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1510 mismatch++;
1511 score -= syms;
1515 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1516 match, mismatch, seq, score);
1517 if ((score > max_score) ||
1518 ((score == max_score) && (seq > max_seq))) {
1519 /* best match so far */
1520 kbd_layout = current;
1521 max_score = score;
1522 max_seq = seq;
1523 ismatch = !mismatch;
1526 /* we're done, report results if necessary */
1527 if (!ismatch)
1528 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1529 main_key_tab[kbd_layout].comment);
1531 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1534 static HKL get_locale_kbd_layout(void)
1536 ULONG_PTR layout;
1537 LANGID langid;
1539 /* FIXME:
1541 * layout = main_key_tab[kbd_layout].lcid;
1543 * Winword uses return value of GetKeyboardLayout as a codepage
1544 * to translate ANSI keyboard messages to unicode. But we have
1545 * a problem with it: for instance Polish keyboard layout is
1546 * identical to the US one, and therefore instead of the Polish
1547 * locale id we return the US one.
1550 layout = GetUserDefaultLCID();
1553 * Microsoft Office expects this value to be something specific
1554 * for Japanese and Korean Windows with an IME the value is 0xe001
1555 * We should probably check to see if an IME exists and if so then
1556 * set this word properly.
1558 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1559 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1560 layout = MAKELONG( layout, 0xe001 ); /* IME */
1561 else
1562 layout |= layout << 16;
1564 return (HKL)layout;
1567 /***********************************************************************
1568 * GetKeyboardLayoutName (X11DRV.@)
1570 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1572 static const WCHAR formatW[] = {'%','0','8','x',0};
1573 DWORD layout;
1575 layout = HandleToUlong( get_locale_kbd_layout() );
1576 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1577 sprintfW(name, formatW, layout);
1578 TRACE("returning %s\n", debugstr_w(name));
1579 return TRUE;
1582 static void set_kbd_layout_preload_key(void)
1584 static const WCHAR preload[] =
1585 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1586 static const WCHAR one[] = {'1',0};
1588 HKEY hkey;
1589 WCHAR layout[KL_NAMELENGTH];
1591 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1592 return;
1594 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1596 RegCloseKey(hkey);
1597 return;
1599 if (X11DRV_GetKeyboardLayoutName(layout))
1600 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1602 RegCloseKey(hkey);
1605 /**********************************************************************
1606 * X11DRV_InitKeyboard
1608 void X11DRV_InitKeyboard( Display *display )
1610 XModifierKeymap *mmp;
1611 KeySym keysym;
1612 KeyCode *kcp;
1613 XKeyEvent e2;
1614 WORD scan, vkey;
1615 int keyc, i, keyn, syms;
1616 char ckey[4]={0,0,0,0};
1617 const char (*lkey)[MAIN_LEN][4];
1618 char vkey_used[256] = { 0 };
1620 /* Ranges of OEM, function key, and character virtual key codes.
1621 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1622 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1623 static const struct {
1624 WORD first, last;
1625 } vkey_ranges[] = {
1626 { VK_OEM_1, VK_OEM_3 },
1627 { VK_OEM_4, VK_ICO_00 },
1628 { 0xe6, 0xe6 },
1629 { 0xe9, 0xf5 },
1630 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1631 { VK_F1, VK_F24 },
1632 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1633 { 0x41, 0x5a }, /* VK_A - VK_Z */
1634 { 0, 0 }
1636 int vkey_range;
1638 set_kbd_layout_preload_key();
1640 EnterCriticalSection( &kbd_section );
1641 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1642 if (key_mapping) XFree( key_mapping );
1643 key_mapping = XGetKeyboardMapping(display, min_keycode,
1644 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1646 mmp = XGetModifierMapping(display);
1647 kcp = mmp->modifiermap;
1648 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1650 int j;
1652 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1653 if (*kcp)
1655 int k;
1657 for (k = 0; k < keysyms_per_keycode; k += 1)
1658 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1660 NumLockMask = 1 << i;
1661 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1663 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1665 ScrollLockMask = 1 << i;
1666 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1670 XFreeModifiermap(mmp);
1672 /* Detect the keyboard layout */
1673 X11DRV_KEYBOARD_DetectLayout( display );
1674 lkey = main_key_tab[kbd_layout].key;
1675 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1677 /* Now build two conversion arrays :
1678 * keycode -> vkey + scancode + extended
1679 * vkey + extended -> keycode */
1681 e2.display = display;
1682 e2.state = 0;
1683 e2.type = KeyPress;
1685 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1686 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1688 char buf[30];
1689 int have_chars;
1691 keysym = 0;
1692 e2.keycode = (KeyCode)keyc;
1693 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1694 vkey = 0; scan = 0;
1695 if (keysym) /* otherwise, keycode not used */
1697 if ((keysym >> 8) == 0xFF) /* non-character key */
1699 vkey = nonchar_key_vkey[keysym & 0xff];
1700 scan = nonchar_key_scan[keysym & 0xff];
1701 /* set extended bit when necessary */
1702 if (scan & 0x100) vkey |= 0x100;
1703 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1704 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1705 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1706 scan = 0x100;
1707 vkey |= 0x100;
1708 } else if (keysym == 0x20) { /* Spacebar */
1709 vkey = VK_SPACE;
1710 scan = 0x39;
1711 } else if (have_chars) {
1712 /* we seem to need to search the layout-dependent scancodes */
1713 int maxlen=0,maxval=-1,ok;
1714 for (i=0; i<syms; i++) {
1715 keysym = keycode_to_keysym(display, keyc, i);
1716 if ((keysym<0x8000) && (keysym!=' '))
1718 #ifdef HAVE_XKB
1719 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1720 #endif
1722 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1723 * with appropriate ShiftMask and Mode_switch, use XLookupString
1724 * to get character in the local encoding.
1726 ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1728 } else {
1729 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1732 /* find key with longest match streak */
1733 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1734 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1735 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1736 if (!ok) i--; /* we overshot */
1737 if (ok||(i>maxlen)) {
1738 maxlen=i; maxval=keyn;
1740 if (ok) break;
1742 if (maxval>=0) {
1743 /* got it */
1744 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1745 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1746 scan = (*lscan)[maxval];
1747 vkey = (*lvkey)[maxval];
1751 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1752 keyc2vkey[e2.keycode] = vkey;
1753 keyc2scan[e2.keycode] = scan;
1754 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1755 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1756 vkey_used[(vkey & 0xff)] = 1;
1757 } /* for */
1759 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1760 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1762 vkey = keyc2vkey[keyc] & 0xff;
1763 if (vkey)
1764 continue;
1766 e2.keycode = (KeyCode)keyc;
1767 keysym = XLookupKeysym(&e2, 0);
1768 if (!keysym)
1769 continue;
1771 /* find a suitable layout-dependent VK code */
1772 /* (most Winelib apps ought to be able to work without layout tables!) */
1773 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1775 keysym = XLookupKeysym(&e2, i);
1776 if ((keysym >= XK_0 && keysym <= XK_9)
1777 || (keysym >= XK_A && keysym <= XK_Z)) {
1778 vkey = VKEY_IF_NOT_USED(keysym);
1782 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1784 keysym = XLookupKeysym(&e2, i);
1785 switch (keysym)
1787 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1788 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1789 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1790 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1791 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1792 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1793 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1794 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1795 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1796 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1797 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1801 if (vkey)
1803 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1804 keyc2vkey[e2.keycode] = vkey;
1806 } /* for */
1808 /* For any keycodes which still don't have a vkey, assign any spare
1809 * character, function key, or OEM virtual key code. */
1810 vkey_range = 0;
1811 vkey = vkey_ranges[vkey_range].first;
1812 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1814 if (keyc2vkey[keyc] & 0xff)
1815 continue;
1817 e2.keycode = (KeyCode)keyc;
1818 keysym = XLookupKeysym(&e2, 0);
1819 if (!keysym)
1820 continue;
1822 while (vkey && vkey_used[vkey])
1824 if (vkey == vkey_ranges[vkey_range].last)
1826 vkey_range++;
1827 vkey = vkey_ranges[vkey_range].first;
1829 else
1830 vkey++;
1833 if (!vkey)
1835 WARN("No more vkeys available!\n");
1836 break;
1839 if (TRACE_ON(keyboard))
1841 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1842 vkey, e2.keycode);
1843 TRACE("(");
1844 for (i = 0; i < keysyms_per_keycode; i += 1)
1846 const char *ksname;
1848 keysym = XLookupKeysym(&e2, i);
1849 ksname = XKeysymToString(keysym);
1850 if (!ksname)
1851 ksname = "NoSymbol";
1852 TRACE( "%lx (%s) ", keysym, ksname);
1854 TRACE(")\n");
1857 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1858 keyc2vkey[e2.keycode] = vkey;
1859 vkey_used[vkey] = 1;
1860 } /* for */
1861 #undef VKEY_IF_NOT_USED
1863 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1864 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1865 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1866 const char *ksname;
1867 keysym = keycode_to_keysym(display, keyc, 0);
1868 ksname = XKeysymToString(keysym);
1869 if (!ksname) ksname = "NoSymbol";
1871 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1873 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1874 keyc2scan[keyc]=scan++;
1877 LeaveCriticalSection( &kbd_section );
1880 static BOOL match_x11_keyboard_layout(HKL hkl)
1882 const DWORD isIME = 0xE0000000;
1883 HKL xHkl = get_locale_kbd_layout();
1885 /* if the layout is an IME, only match the low word (LCID) */
1886 if (((ULONG_PTR)hkl & isIME) == isIME)
1887 return (LOWORD(hkl) == LOWORD(xHkl));
1888 else
1889 return (hkl == xHkl);
1893 /***********************************************************************
1894 * GetKeyboardLayout (X11DRV.@)
1896 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1898 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1900 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1901 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1903 else
1904 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1906 return get_locale_kbd_layout();
1910 /***********************************************************************
1911 * LoadKeyboardLayout (X11DRV.@)
1913 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1915 FIXME("%s, %04x: semi-stub! Returning default layout.\n", debugstr_w(name), flags);
1916 return get_locale_kbd_layout();
1920 /***********************************************************************
1921 * UnloadKeyboardLayout (X11DRV.@)
1923 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1925 FIXME("%p: stub!\n", hkl);
1926 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1927 return FALSE;
1931 /***********************************************************************
1932 * ActivateKeyboardLayout (X11DRV.@)
1934 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1936 HKL oldHkl = 0;
1937 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1939 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1940 if (flags & KLF_SETFORPROCESS)
1942 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1943 FIXME("KLF_SETFORPROCESS not supported\n");
1944 return 0;
1947 if (flags)
1948 FIXME("flags %x not supported\n",flags);
1950 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1953 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1954 return 0;
1957 if (!match_x11_keyboard_layout(hkl))
1959 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1960 FIXME("setting keyboard of different locales not supported\n");
1961 return 0;
1964 oldHkl = thread_data->kbd_layout;
1965 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1967 thread_data->kbd_layout = hkl;
1969 return oldHkl;
1973 /***********************************************************************
1974 * X11DRV_MappingNotify
1976 BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
1978 HWND hwnd;
1980 XRefreshKeyboardMapping(&event->xmapping);
1981 X11DRV_InitKeyboard( event->xmapping.display );
1983 hwnd = GetFocus();
1984 if (!hwnd) hwnd = GetActiveWindow();
1985 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1986 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1987 return TRUE;
1991 /***********************************************************************
1992 * VkKeyScanEx (X11DRV.@)
1994 * Note: Windows ignores HKL parameter and uses current active layout instead
1996 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1998 Display *display = thread_init_display();
1999 KeyCode keycode;
2000 KeySym keysym;
2001 int index;
2002 CHAR cChar;
2003 SHORT ret;
2005 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2006 * is UTF-8 (multibyte encoding)?
2008 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2010 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2011 return -1;
2014 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2016 /* char->keysym (same for ANSI chars) */
2017 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2018 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2020 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2021 if (!keycode)
2023 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2025 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2026 TRACE(" ... returning ctrl char %#.2x\n", ret);
2027 return ret;
2029 /* It didn't work ... let's try with deadchar code. */
2030 TRACE("retrying with | 0xFE00\n");
2031 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2034 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2035 if (!keycode) return -1;
2037 EnterCriticalSection( &kbd_section );
2039 /* keycode -> (keyc2vkey) vkey */
2040 ret = keyc2vkey[keycode];
2041 if (!ret)
2043 LeaveCriticalSection( &kbd_section );
2044 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2045 return -1;
2048 for (index = 0; index < 4; index++) /* find shift state */
2049 if (keycode_to_keysym(display, keycode, index) == keysym) break;
2051 LeaveCriticalSection( &kbd_section );
2053 switch (index)
2055 case 0: break;
2056 case 1: ret += 0x0100; break;
2057 case 2: ret += 0x0600; break;
2058 case 3: ret += 0x0700; break;
2059 default:
2060 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2061 return -1;
2064 index : 0 adds 0x0000
2065 index : 1 adds 0x0100 (shift)
2066 index : ? adds 0x0200 (ctrl)
2067 index : 2 adds 0x0600 (ctrl+alt)
2068 index : 3 adds 0x0700 (ctrl+alt+shift)
2071 TRACE(" ... returning %#.2x\n", ret);
2072 return ret;
2075 /***********************************************************************
2076 * MapVirtualKeyEx (X11DRV.@)
2078 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2080 UINT ret = 0;
2081 int keyc;
2082 Display *display = thread_init_display();
2084 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2085 if (!match_x11_keyboard_layout(hkl))
2086 FIXME("keyboard layout %p is not supported\n", hkl);
2088 EnterCriticalSection( &kbd_section );
2090 switch(wMapType)
2092 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2093 case MAPVK_VK_TO_VSC_EX:
2094 switch (wCode)
2096 case VK_SHIFT: wCode = VK_LSHIFT; break;
2097 case VK_CONTROL: wCode = VK_LCONTROL; break;
2098 case VK_MENU: wCode = VK_LMENU; break;
2101 /* let's do vkey -> keycode -> scan */
2102 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2104 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2106 ret = keyc2scan[keyc] & 0xFF;
2107 break;
2111 /* set scan code prefix */
2112 if (wMapType == MAPVK_VK_TO_VSC_EX &&
2113 (wCode == VK_RCONTROL || wCode == VK_RMENU))
2114 ret |= 0xe000;
2115 break;
2117 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2118 case MAPVK_VSC_TO_VK_EX:
2120 /* let's do scan -> keycode -> vkey */
2121 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2122 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2124 ret = keyc2vkey[keyc] & 0xFF;
2125 /* Only stop if it's not a numpad vkey; otherwise keep
2126 looking for a potential better vkey. */
2127 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
2128 break;
2131 if (wMapType == MAPVK_VSC_TO_VK)
2132 switch (ret)
2134 case VK_LSHIFT:
2135 case VK_RSHIFT:
2136 ret = VK_SHIFT; break;
2137 case VK_LCONTROL:
2138 case VK_RCONTROL:
2139 ret = VK_CONTROL; break;
2140 case VK_LMENU:
2141 case VK_RMENU:
2142 ret = VK_MENU; break;
2145 break;
2147 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2149 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2150 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2151 * key.. Looks like something is wrong with the MS docs?
2152 * This is only true for letters, for example VK_0 returns '0' not ')'.
2153 * - hence we use the lock mask to ensure this happens.
2155 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2156 XKeyEvent e;
2157 KeySym keysym;
2158 int len;
2159 char s[10];
2161 e.display = display;
2162 e.state = 0;
2163 e.keycode = 0;
2164 e.type = KeyPress;
2166 /* We exit on the first keycode found, to speed up the thing. */
2167 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2168 { /* Find a keycode that could have generated this virtual key */
2169 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2170 { /* We filter the extended bit, we don't know it */
2171 e.keycode = keyc; /* Store it temporarily */
2172 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2173 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2174 state), so set it to 0, we'll find another one */
2179 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2180 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2182 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2183 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2184 * in order to produce a locale dependent numeric separator.
2186 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2188 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2189 if (!e.keycode)
2190 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2193 if (!e.keycode)
2195 WARN("Unknown virtual key %X !!!\n", wCode);
2196 break;
2198 TRACE("Found keycode %u\n",e.keycode);
2200 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2201 if (len)
2203 WCHAR wch;
2204 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) ret = toupperW(wch);
2206 break;
2209 default: /* reserved */
2210 FIXME("Unknown wMapType %d !\n", wMapType);
2211 break;
2214 LeaveCriticalSection( &kbd_section );
2215 TRACE( "returning 0x%x.\n", ret );
2216 return ret;
2219 /***********************************************************************
2220 * GetKeyNameText (X11DRV.@)
2222 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2224 Display *display = thread_init_display();
2225 int vkey, ansi, scanCode;
2226 KeyCode keyc;
2227 int keyi;
2228 KeySym keys;
2229 char *name;
2231 scanCode = lParam >> 16;
2232 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2234 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2236 /* handle "don't care" bit (0x02000000) */
2237 if (!(lParam & 0x02000000)) {
2238 switch (vkey) {
2239 case VK_RSHIFT:
2240 /* R-Shift is "special" - it is an extended key with separate scan code */
2241 scanCode |= 0x100;
2242 /* fall through */
2243 case VK_LSHIFT:
2244 vkey = VK_SHIFT;
2245 break;
2246 case VK_LCONTROL:
2247 case VK_RCONTROL:
2248 vkey = VK_CONTROL;
2249 break;
2250 case VK_LMENU:
2251 case VK_RMENU:
2252 vkey = VK_MENU;
2253 break;
2257 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2258 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2260 /* first get the name of the "regular" keys which is the Upper case
2261 value of the keycap imprint. */
2262 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2263 (scanCode != 0x137) && /* PrtScn */
2264 (scanCode != 0x135) && /* numpad / */
2265 (scanCode != 0x37 ) && /* numpad * */
2266 (scanCode != 0x4a ) && /* numpad - */
2267 (scanCode != 0x4e ) ) /* numpad + */
2269 if (nSize >= 2)
2271 *lpBuffer = toupperW((WCHAR)ansi);
2272 *(lpBuffer+1) = 0;
2273 return 1;
2275 else
2276 return 0;
2279 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2280 without "extended-key" flag. However Wine generates scancode
2281 *with* "extended-key" flag. Seems to occur *only* for the
2282 function keys. Soooo.. We will leave the table alone and
2283 fudge the lookup here till the other part is found and fixed!!! */
2285 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2286 (scanCode == 0x157) || (scanCode == 0x158))
2287 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2289 /* let's do scancode -> keycode -> keysym -> String */
2291 EnterCriticalSection( &kbd_section );
2293 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2294 if ((keyc2scan[keyi]) == scanCode)
2295 break;
2296 if (keyi <= max_keycode)
2298 INT rc;
2300 keyc = (KeyCode) keyi;
2301 keys = keycode_to_keysym(display, keyc, 0);
2302 name = XKeysymToString(keys);
2304 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2306 char* idx = strrchr(name, '_');
2307 if (idx && (_strnicmp(idx, "_r", -1) == 0 || _strnicmp(idx, "_l", -1) == 0))
2309 LeaveCriticalSection( &kbd_section );
2310 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2311 scanCode, keyc, keys, debugstr_an(name,idx-name));
2312 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2313 if (!rc) rc = nSize;
2314 lpBuffer[--rc] = 0;
2315 return rc;
2319 if (name)
2321 LeaveCriticalSection( &kbd_section );
2322 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2323 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2324 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2325 if (!rc) rc = nSize;
2326 lpBuffer[--rc] = 0;
2327 return rc;
2331 /* Finally issue WARN for unknown keys */
2333 LeaveCriticalSection( &kbd_section );
2334 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2335 *lpBuffer = 0;
2336 return 0;
2339 /***********************************************************************
2340 * X11DRV_KEYBOARD_MapDeadKeysym
2342 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2344 switch (keysym)
2346 /* symbolic ASCII is the same as defined in rfc1345 */
2347 #ifdef XK_dead_tilde
2348 case XK_dead_tilde :
2349 #endif
2350 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2351 return '~'; /* '? */
2352 #ifdef XK_dead_acute
2353 case XK_dead_acute :
2354 #endif
2355 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2356 return 0xb4; /* '' */
2357 #ifdef XK_dead_circumflex
2358 case XK_dead_circumflex:
2359 #endif
2360 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2361 return '^'; /* '> */
2362 #ifdef XK_dead_grave
2363 case XK_dead_grave :
2364 #endif
2365 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2366 return '`'; /* '! */
2367 #ifdef XK_dead_diaeresis
2368 case XK_dead_diaeresis :
2369 #endif
2370 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2371 return 0xa8; /* ': */
2372 #ifdef XK_dead_cedilla
2373 case XK_dead_cedilla :
2374 return 0xb8; /* ', */
2375 #endif
2376 #ifdef XK_dead_macron
2377 case XK_dead_macron :
2378 return '-'; /* 'm isn't defined on iso-8859-x */
2379 #endif
2380 #ifdef XK_dead_breve
2381 case XK_dead_breve :
2382 return 0xa2; /* '( */
2383 #endif
2384 #ifdef XK_dead_abovedot
2385 case XK_dead_abovedot :
2386 return 0xff; /* '. */
2387 #endif
2388 #ifdef XK_dead_abovering
2389 case XK_dead_abovering :
2390 return '0'; /* '0 isn't defined on iso-8859-x */
2391 #endif
2392 #ifdef XK_dead_doubleacute
2393 case XK_dead_doubleacute :
2394 return 0xbd; /* '" */
2395 #endif
2396 #ifdef XK_dead_caron
2397 case XK_dead_caron :
2398 return 0xb7; /* '< */
2399 #endif
2400 #ifdef XK_dead_ogonek
2401 case XK_dead_ogonek :
2402 return 0xb2; /* '; */
2403 #endif
2404 /* FIXME: I don't know this three.
2405 case XK_dead_iota :
2406 return 'i';
2407 case XK_dead_voiced_sound :
2408 return 'v';
2409 case XK_dead_semivoiced_sound :
2410 return 's';
2413 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2414 return 0;
2417 /***********************************************************************
2418 * ToUnicodeEx (X11DRV.@)
2420 * The ToUnicode function translates the specified virtual-key code and keyboard
2421 * state to the corresponding Windows character or characters.
2423 * If the specified key is a dead key, the return value is negative. Otherwise,
2424 * it is one of the following values:
2425 * Value Meaning
2426 * 0 The specified virtual key has no translation for the current state of the keyboard.
2427 * 1 One Windows character was copied to the buffer.
2428 * 2 Two characters were copied to the buffer. This usually happens when a
2429 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2430 * be composed with the specified virtual key to form a single character.
2432 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2435 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2436 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2438 Display *display = thread_init_display();
2439 XKeyEvent e;
2440 KeySym keysym = 0;
2441 INT ret;
2442 int keyc;
2443 char buf[10];
2444 char *lpChar = buf;
2445 HWND focus;
2446 XIC xic;
2447 Status status = 0;
2449 if (scanCode & 0x8000)
2451 TRACE_(key)("Key UP, doing nothing\n" );
2452 return 0;
2455 if (!match_x11_keyboard_layout(hkl))
2456 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2458 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2460 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2461 return 0;
2464 e.display = display;
2465 e.keycode = 0;
2466 e.state = 0;
2467 e.type = KeyPress;
2469 focus = x11drv_thread_data()->last_xic_hwnd;
2470 if (!focus)
2472 focus = GetFocus();
2473 if (focus) focus = GetAncestor( focus, GA_ROOT );
2474 if (!focus) focus = GetActiveWindow();
2476 e.window = X11DRV_get_whole_window( focus );
2477 xic = X11DRV_get_ic( focus );
2479 EnterCriticalSection( &kbd_section );
2481 if (lpKeyState[VK_SHIFT] & 0x80)
2483 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2484 e.state |= ShiftMask;
2486 if (lpKeyState[VK_CAPITAL] & 0x01)
2488 TRACE_(key)("LockMask = %04x\n", LockMask);
2489 e.state |= LockMask;
2491 if (lpKeyState[VK_CONTROL] & 0x80)
2493 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2494 e.state |= ControlMask;
2496 if (lpKeyState[VK_NUMLOCK] & 0x01)
2498 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2499 e.state |= NumLockMask;
2502 /* Restore saved AltGr state */
2503 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2504 e.state |= AltGrMask;
2506 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2507 virtKey, scanCode, e.state);
2509 /* We exit on the first keycode found, to speed up the thing. */
2510 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2511 { /* Find a keycode that could have generated this virtual key */
2512 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2513 { /* We filter the extended bit, we don't know it */
2514 e.keycode = keyc; /* Store it temporarily */
2515 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2516 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2517 state), so set it to 0, we'll find another one */
2522 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2523 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2525 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2526 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2528 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2529 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2530 * in order to produce a locale dependent numeric separator.
2532 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2534 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2535 if (!e.keycode)
2536 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2539 /* Ctrl-Space generates space on Windows */
2540 if (e.state == ControlMask && virtKey == VK_SPACE)
2542 bufW[0] = ' ';
2543 ret = 1;
2544 goto found;
2547 if (!e.keycode && virtKey != VK_NONAME)
2549 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2550 LeaveCriticalSection( &kbd_section );
2551 return 0;
2553 else TRACE_(key)("Found keycode %u\n",e.keycode);
2555 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2556 e.type, e.window, e.state, e.keycode);
2558 /* Clients should pass only KeyPress events to XmbLookupString,
2559 * e.type was set to KeyPress above.
2561 if (xic)
2563 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2564 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2565 if (status == XBufferOverflow)
2567 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2568 if (lpChar == NULL)
2570 ERR_(key)("Failed to allocate memory!\n");
2571 LeaveCriticalSection( &kbd_section );
2572 return 0;
2574 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2577 else
2578 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2580 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2582 if (TRACE_ON(key))
2584 const char *ksname;
2586 ksname = XKeysymToString(keysym);
2587 if (!ksname) ksname = "No Name";
2588 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2589 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2590 keysym, ksname, ret, debugstr_an(lpChar, ret));
2593 if (ret == 0)
2595 char dead_char;
2597 #ifdef XK_EuroSign
2598 /* An ugly hack for EuroSign: X can't translate it to a character
2599 for some locales. */
2600 if (keysym == XK_EuroSign)
2602 bufW[0] = 0x20AC;
2603 ret = 1;
2604 goto found;
2606 #endif
2607 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2608 /* Here we change it back. */
2609 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2611 bufW[0] = 0x09;
2612 ret = 1;
2613 goto found;
2616 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2617 if (dead_char)
2619 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2620 ret = -1;
2621 goto found;
2624 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2626 /* Unicode direct mapping */
2627 bufW[0] = keysym & 0xffff;
2628 ret = 1;
2629 goto found;
2631 else if ((keysym >> 8) == 0x1008FF) {
2632 bufW[0] = 0;
2633 ret = 0;
2634 goto found;
2636 else
2638 const char *ksname;
2640 ksname = XKeysymToString(keysym);
2641 if (!ksname)
2642 ksname = "No Name";
2643 if ((keysym >> 8) != 0xff)
2645 WARN_(key)("no char for keysym %04lx (%s) :\n",
2646 keysym, ksname);
2647 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2648 virtKey, scanCode, e.keycode, e.state);
2652 else { /* ret != 0 */
2653 /* We have a special case to handle : Shift + arrow, shift + home, ...
2654 X returns a char for it, but Windows doesn't. Let's eat it. */
2655 if (!(e.state & NumLockMask) /* NumLock is off */
2656 && (e.state & ShiftMask) /* Shift is pressed */
2657 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2659 lpChar[0] = 0;
2660 ret = 0;
2663 /* more areas where X returns characters but Windows does not
2664 CTRL + number or CTRL + symbol */
2665 if (e.state & ControlMask)
2667 if (((keysym>=33) && (keysym < '@')) ||
2668 (keysym == '`') ||
2669 (keysym == XK_Tab))
2671 lpChar[0] = 0;
2672 ret = 0;
2676 /* We have another special case for delete key (XK_Delete) on an
2677 extended keyboard. X returns a char for it, but Windows doesn't */
2678 if (keysym == XK_Delete)
2680 lpChar[0] = 0;
2681 ret = 0;
2683 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2684 && (keysym == XK_KP_Decimal))
2686 lpChar[0] = 0;
2687 ret = 0;
2689 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2690 && (keysym == XK_Return || keysym == XK_KP_Enter))
2692 if (lpKeyState[VK_SHIFT] & 0x80)
2694 lpChar[0] = 0;
2695 ret = 0;
2697 else
2699 lpChar[0] = '\n';
2700 ret = 1;
2704 /* Hack to detect an XLookupString hard-coded to Latin1 */
2705 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2707 bufW[0] = (BYTE)lpChar[0];
2708 goto found;
2711 /* perform translation to unicode */
2712 if(ret)
2714 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2715 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2719 found:
2720 if (buf != lpChar)
2721 HeapFree(GetProcessHeap(), 0, lpChar);
2723 LeaveCriticalSection( &kbd_section );
2725 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2726 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2727 if (1 <= ret && ret < bufW_size)
2728 bufW[ret] = 0;
2730 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2731 return ret;
2734 /***********************************************************************
2735 * Beep (X11DRV.@)
2737 void CDECL X11DRV_Beep(void)
2739 XBell(gdi_display, 0);