wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / winex11.drv / keyboard.c
blob35a801fc8950c599496565f39dc2dd02255ad982
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->async = 1;
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->async = 1;
1181 wine_server_add_data( req, state, 256 );
1182 wine_server_call( req );
1184 SERVER_END_REQ;
1187 static void update_key_state( BYTE *keystate, BYTE key, int down )
1189 if (down)
1191 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1192 keystate[key] |= 0x80;
1194 else keystate[key] &= ~0x80;
1197 /***********************************************************************
1198 * X11DRV_KeymapNotify
1200 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1202 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1203 * from wine to another application and back.
1204 * Toggle keys are handled in HandleEvent.
1206 BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1208 int i, j;
1209 BYTE keystate[256];
1210 WORD vkey;
1211 BOOL changed = FALSE;
1212 struct {
1213 WORD vkey;
1214 WORD pressed;
1215 } keys[256];
1217 if (!get_async_key_state( keystate )) return FALSE;
1219 memset(keys, 0, sizeof(keys));
1221 EnterCriticalSection( &kbd_section );
1223 /* the minimum keycode is always greater or equal to 8, so we can
1224 * skip the first 8 values, hence start at 1
1226 for (i = 1; i < 32; i++)
1228 for (j = 0; j < 8; j++)
1230 vkey = keyc2vkey[(i * 8) + j];
1232 /* If multiple keys map to the same vkey, we want to report it as
1233 * pressed iff any of them are pressed. */
1234 if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey;
1235 if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE;
1239 for (vkey = 1; vkey <= 0xff; vkey++)
1241 if (keys[vkey].vkey && !(keystate[vkey] & 0x80) != !keys[vkey].pressed)
1243 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1244 keys[vkey].vkey, keystate[vkey]);
1246 update_key_state( keystate, vkey, keys[vkey].pressed );
1247 changed = TRUE;
1251 LeaveCriticalSection( &kbd_section );
1252 if (!changed) return FALSE;
1254 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1255 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1256 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1257 set_async_key_state( keystate );
1258 return TRUE;
1261 static void adjust_lock_state( BYTE *keystate, HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1263 BYTE prev_state = keystate[vkey] & 0x01;
1265 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags, time );
1266 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags ^ KEYEVENTF_KEYUP, time );
1268 /* Keyboard hooks may have blocked processing lock keys causing our state
1269 * to be different than state on X server side. Although Windows allows hooks
1270 * to block changing state, we can't prevent it on X server side. Having
1271 * different states would cause us to try to adjust it again on the next
1272 * key event. We prevent that by overriding hooks and setting key states here. */
1273 if (get_async_key_state( keystate ) && (keystate[vkey] & 0x01) == prev_state)
1275 WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey, keystate[vkey]);
1276 keystate[vkey] ^= 0x01;
1277 set_async_key_state( keystate );
1281 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1283 BYTE keystate[256];
1285 /* Note: X sets the below states on key down and clears them on key up.
1286 Windows triggers them on key down. */
1288 if (!get_async_key_state( keystate )) return;
1290 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1291 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1293 DWORD flags = 0;
1294 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1295 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1296 adjust_lock_state( keystate, hwnd, VK_CAPITAL, 0x3a, flags, time );
1299 /* Adjust the NUMLOCK state if it has been changed outside wine */
1300 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1302 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1303 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1304 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1305 adjust_lock_state( keystate, hwnd, VK_NUMLOCK, 0x45, flags, time );
1308 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1309 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1311 DWORD flags = 0;
1312 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1313 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1314 adjust_lock_state( keystate, hwnd, VK_SCROLL, 0x46, flags, time );
1318 /***********************************************************************
1319 * X11DRV_KeyEvent
1321 * Handle a X key event
1323 BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1325 XKeyEvent *event = &xev->xkey;
1326 char buf[24];
1327 char *Str = buf;
1328 KeySym keysym = 0;
1329 WORD vkey = 0, bScan;
1330 DWORD dwFlags;
1331 int ascii_chars;
1332 XIC xic = X11DRV_get_ic( hwnd );
1333 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1334 Status status = 0;
1336 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1337 event->type, event->window, event->state, event->keycode);
1339 if (event->type == KeyPress) update_user_time( event->time );
1341 /* Clients should pass only KeyPress events to XmbLookupString */
1342 if (xic && event->type == KeyPress)
1344 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1345 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1346 if (status == XBufferOverflow)
1348 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1349 if (Str == NULL)
1351 ERR_(key)("Failed to allocate memory!\n");
1352 return FALSE;
1354 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1357 else
1358 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1360 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1362 if (status == XLookupChars)
1364 X11DRV_XIMLookupChars( Str, ascii_chars );
1365 if (buf != Str)
1366 HeapFree(GetProcessHeap(), 0, Str);
1367 return TRUE;
1370 EnterCriticalSection( &kbd_section );
1372 /* If XKB extensions are used, the state mask for AltGr will use the group
1373 index instead of the modifier mask. The group index is set in bits
1374 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1375 pressed, look if the group index is different than 0. From XKB
1376 extension documentation, the group index for AltGr should be 2
1377 (event->state = 0x2000). It's probably better to not assume a
1378 predefined group index and find it dynamically
1380 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1381 /* Save also all possible modifier states. */
1382 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1384 if (TRACE_ON(key)){
1385 const char *ksname;
1387 ksname = XKeysymToString(keysym);
1388 if (!ksname)
1389 ksname = "No Name";
1390 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1391 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1392 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1394 if (buf != Str)
1395 HeapFree(GetProcessHeap(), 0, Str);
1397 vkey = EVENT_event_to_vkey(xic,event);
1398 /* X returns keycode 0 for composed characters */
1399 if (!vkey && ascii_chars) vkey = VK_NONAME;
1400 bScan = keyc2scan[event->keycode] & 0xFF;
1402 TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
1403 event->keycode, vkey, bScan);
1405 LeaveCriticalSection( &kbd_section );
1407 if (!vkey) return FALSE;
1409 dwFlags = 0;
1410 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1411 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1413 update_lock_state( hwnd, vkey, event->state, event_time );
1415 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1416 return TRUE;
1419 /**********************************************************************
1420 * X11DRV_KEYBOARD_DetectLayout
1422 * Called from X11DRV_InitKeyboard
1423 * This routine walks through the defined keyboard layouts and selects
1424 * whichever matches most closely.
1425 * kbd_section must be held.
1427 static void
1428 X11DRV_KEYBOARD_DetectLayout( Display *display )
1430 unsigned current, match, mismatch, seq, i, syms;
1431 int score, keyc, key, pkey, ok;
1432 KeySym keysym = 0;
1433 const char (*lkey)[MAIN_LEN][4];
1434 unsigned max_seq = 0;
1435 int max_score = 0, ismatch = 0;
1436 char ckey[256][4];
1438 syms = keysyms_per_keycode;
1439 if (syms > 4) {
1440 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1441 syms = 4;
1444 memset( ckey, 0, sizeof(ckey) );
1445 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1446 /* get data for keycode from X server */
1447 for (i = 0; i < syms; i++) {
1448 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1449 /* Allow both one-byte and two-byte national keysyms */
1450 if ((keysym < 0x8000) && (keysym != ' '))
1452 #ifdef HAVE_XKB
1453 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1454 #endif
1456 TRACE("XKB could not translate keysym %04lx\n", keysym);
1457 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1458 * with appropriate ShiftMask and Mode_switch, use XLookupString
1459 * to get character in the local encoding.
1461 ckey[keyc][i] = keysym & 0xFF;
1464 else {
1465 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1470 for (current = 0; main_key_tab[current].comment; current++) {
1471 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1472 match = 0;
1473 mismatch = 0;
1474 score = 0;
1475 seq = 0;
1476 lkey = main_key_tab[current].key;
1477 pkey = -1;
1478 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1479 if (ckey[keyc][0]) {
1480 /* search for a match in layout table */
1481 /* right now, we just find an absolute match for defined positions */
1482 /* (undefined positions are ignored, so if it's defined as "3#" in */
1483 /* the table, it's okay that the X server has "3#£", for example) */
1484 /* however, the score will be higher for longer matches */
1485 for (key = 0; key < MAIN_LEN; key++) {
1486 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1487 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1488 ok++;
1489 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1490 ok = -1;
1492 if (ok > 0) {
1493 score += ok;
1494 break;
1497 /* count the matches and mismatches */
1498 if (ok > 0) {
1499 match++;
1500 /* and how much the keycode order matches */
1501 if (key > pkey) seq++;
1502 pkey = key;
1503 } else {
1504 /* print spaces instead of \0's */
1505 char str[5];
1506 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1507 str[4] = 0;
1508 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1509 mismatch++;
1510 score -= syms;
1514 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1515 match, mismatch, seq, score);
1516 if ((score > max_score) ||
1517 ((score == max_score) && (seq > max_seq))) {
1518 /* best match so far */
1519 kbd_layout = current;
1520 max_score = score;
1521 max_seq = seq;
1522 ismatch = !mismatch;
1525 /* we're done, report results if necessary */
1526 if (!ismatch)
1527 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1528 main_key_tab[kbd_layout].comment);
1530 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1533 static HKL get_locale_kbd_layout(void)
1535 ULONG_PTR layout;
1536 LANGID langid;
1538 /* FIXME:
1540 * layout = main_key_tab[kbd_layout].lcid;
1542 * Winword uses return value of GetKeyboardLayout as a codepage
1543 * to translate ANSI keyboard messages to unicode. But we have
1544 * a problem with it: for instance Polish keyboard layout is
1545 * identical to the US one, and therefore instead of the Polish
1546 * locale id we return the US one.
1549 layout = GetUserDefaultLCID();
1552 * Microsoft Office expects this value to be something specific
1553 * for Japanese and Korean Windows with an IME the value is 0xe001
1554 * We should probably check to see if an IME exists and if so then
1555 * set this word properly.
1557 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1558 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1559 layout = MAKELONG( layout, 0xe001 ); /* IME */
1560 else
1561 layout |= layout << 16;
1563 return (HKL)layout;
1566 /***********************************************************************
1567 * GetKeyboardLayoutName (X11DRV.@)
1569 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1571 static const WCHAR formatW[] = {'%','0','8','x',0};
1572 DWORD layout;
1574 layout = HandleToUlong( get_locale_kbd_layout() );
1575 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1576 sprintfW(name, formatW, layout);
1577 TRACE("returning %s\n", debugstr_w(name));
1578 return TRUE;
1581 static void set_kbd_layout_preload_key(void)
1583 static const WCHAR preload[] =
1584 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1585 static const WCHAR one[] = {'1',0};
1587 HKEY hkey;
1588 WCHAR layout[KL_NAMELENGTH];
1590 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1591 return;
1593 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1595 RegCloseKey(hkey);
1596 return;
1598 if (X11DRV_GetKeyboardLayoutName(layout))
1599 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1601 RegCloseKey(hkey);
1604 /**********************************************************************
1605 * X11DRV_InitKeyboard
1607 void X11DRV_InitKeyboard( Display *display )
1609 XModifierKeymap *mmp;
1610 KeySym keysym;
1611 KeyCode *kcp;
1612 XKeyEvent e2;
1613 WORD scan, vkey;
1614 int keyc, i, keyn, syms;
1615 char ckey[4]={0,0,0,0};
1616 const char (*lkey)[MAIN_LEN][4];
1617 char vkey_used[256] = { 0 };
1619 /* Ranges of OEM, function key, and character virtual key codes.
1620 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1621 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1622 static const struct {
1623 WORD first, last;
1624 } vkey_ranges[] = {
1625 { VK_OEM_1, VK_OEM_3 },
1626 { VK_OEM_4, VK_ICO_00 },
1627 { 0xe6, 0xe6 },
1628 { 0xe9, 0xf5 },
1629 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1630 { VK_F1, VK_F24 },
1631 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1632 { 0x41, 0x5a }, /* VK_A - VK_Z */
1633 { 0, 0 }
1635 int vkey_range;
1637 set_kbd_layout_preload_key();
1639 EnterCriticalSection( &kbd_section );
1640 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1641 if (key_mapping) XFree( key_mapping );
1642 key_mapping = XGetKeyboardMapping(display, min_keycode,
1643 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1645 mmp = XGetModifierMapping(display);
1646 kcp = mmp->modifiermap;
1647 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1649 int j;
1651 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1652 if (*kcp)
1654 int k;
1656 for (k = 0; k < keysyms_per_keycode; k += 1)
1657 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1659 NumLockMask = 1 << i;
1660 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1662 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1664 ScrollLockMask = 1 << i;
1665 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1669 XFreeModifiermap(mmp);
1671 /* Detect the keyboard layout */
1672 X11DRV_KEYBOARD_DetectLayout( display );
1673 lkey = main_key_tab[kbd_layout].key;
1674 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1676 /* Now build two conversion arrays :
1677 * keycode -> vkey + scancode + extended
1678 * vkey + extended -> keycode */
1680 e2.display = display;
1681 e2.state = 0;
1682 e2.type = KeyPress;
1684 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1685 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1687 char buf[30];
1688 int have_chars;
1690 keysym = 0;
1691 e2.keycode = (KeyCode)keyc;
1692 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1693 vkey = 0; scan = 0;
1694 if (keysym) /* otherwise, keycode not used */
1696 if ((keysym >> 8) == 0xFF) /* non-character key */
1698 vkey = nonchar_key_vkey[keysym & 0xff];
1699 scan = nonchar_key_scan[keysym & 0xff];
1700 /* set extended bit when necessary */
1701 if (scan & 0x100) vkey |= 0x100;
1702 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1703 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1704 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1705 scan = 0x100;
1706 vkey |= 0x100;
1707 } else if (keysym == 0x20) { /* Spacebar */
1708 vkey = VK_SPACE;
1709 scan = 0x39;
1710 } else if (have_chars) {
1711 /* we seem to need to search the layout-dependent scancodes */
1712 int maxlen=0,maxval=-1,ok;
1713 for (i=0; i<syms; i++) {
1714 keysym = keycode_to_keysym(display, keyc, i);
1715 if ((keysym<0x8000) && (keysym!=' '))
1717 #ifdef HAVE_XKB
1718 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1719 #endif
1721 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1722 * with appropriate ShiftMask and Mode_switch, use XLookupString
1723 * to get character in the local encoding.
1725 ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1727 } else {
1728 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1731 /* find key with longest match streak */
1732 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1733 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1734 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1735 if (!ok) i--; /* we overshot */
1736 if (ok||(i>maxlen)) {
1737 maxlen=i; maxval=keyn;
1739 if (ok) break;
1741 if (maxval>=0) {
1742 /* got it */
1743 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1744 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1745 scan = (*lscan)[maxval];
1746 vkey = (*lvkey)[maxval];
1750 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1751 keyc2vkey[e2.keycode] = vkey;
1752 keyc2scan[e2.keycode] = scan;
1753 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1754 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1755 vkey_used[(vkey & 0xff)] = 1;
1756 } /* for */
1758 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1759 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1761 vkey = keyc2vkey[keyc] & 0xff;
1762 if (vkey)
1763 continue;
1765 e2.keycode = (KeyCode)keyc;
1766 keysym = XLookupKeysym(&e2, 0);
1767 if (!keysym)
1768 continue;
1770 /* find a suitable layout-dependent VK code */
1771 /* (most Winelib apps ought to be able to work without layout tables!) */
1772 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1774 keysym = XLookupKeysym(&e2, i);
1775 if ((keysym >= XK_0 && keysym <= XK_9)
1776 || (keysym >= XK_A && keysym <= XK_Z)) {
1777 vkey = VKEY_IF_NOT_USED(keysym);
1781 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1783 keysym = XLookupKeysym(&e2, i);
1784 switch (keysym)
1786 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1787 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1788 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1789 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1790 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1791 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1792 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1793 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1794 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1795 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1796 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1800 if (vkey)
1802 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1803 keyc2vkey[e2.keycode] = vkey;
1805 } /* for */
1807 /* For any keycodes which still don't have a vkey, assign any spare
1808 * character, function key, or OEM virtual key code. */
1809 vkey_range = 0;
1810 vkey = vkey_ranges[vkey_range].first;
1811 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1813 if (keyc2vkey[keyc] & 0xff)
1814 continue;
1816 e2.keycode = (KeyCode)keyc;
1817 keysym = XLookupKeysym(&e2, 0);
1818 if (!keysym)
1819 continue;
1821 while (vkey && vkey_used[vkey])
1823 if (vkey == vkey_ranges[vkey_range].last)
1825 vkey_range++;
1826 vkey = vkey_ranges[vkey_range].first;
1828 else
1829 vkey++;
1832 if (!vkey)
1834 WARN("No more vkeys available!\n");
1835 break;
1838 if (TRACE_ON(keyboard))
1840 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1841 vkey, e2.keycode);
1842 TRACE("(");
1843 for (i = 0; i < keysyms_per_keycode; i += 1)
1845 const char *ksname;
1847 keysym = XLookupKeysym(&e2, i);
1848 ksname = XKeysymToString(keysym);
1849 if (!ksname)
1850 ksname = "NoSymbol";
1851 TRACE( "%lx (%s) ", keysym, ksname);
1853 TRACE(")\n");
1856 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1857 keyc2vkey[e2.keycode] = vkey;
1858 vkey_used[vkey] = 1;
1859 } /* for */
1860 #undef VKEY_IF_NOT_USED
1862 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1863 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1864 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1865 const char *ksname;
1866 keysym = keycode_to_keysym(display, keyc, 0);
1867 ksname = XKeysymToString(keysym);
1868 if (!ksname) ksname = "NoSymbol";
1870 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1872 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1873 keyc2scan[keyc]=scan++;
1876 LeaveCriticalSection( &kbd_section );
1879 static BOOL match_x11_keyboard_layout(HKL hkl)
1881 const DWORD isIME = 0xE0000000;
1882 HKL xHkl = get_locale_kbd_layout();
1884 /* if the layout is an IME, only match the low word (LCID) */
1885 if (((ULONG_PTR)hkl & isIME) == isIME)
1886 return (LOWORD(hkl) == LOWORD(xHkl));
1887 else
1888 return (hkl == xHkl);
1892 /***********************************************************************
1893 * GetKeyboardLayout (X11DRV.@)
1895 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1897 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1899 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1900 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1902 else
1903 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1905 return get_locale_kbd_layout();
1909 /***********************************************************************
1910 * LoadKeyboardLayout (X11DRV.@)
1912 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1914 FIXME("%s, %04x: semi-stub! Returning default layout.\n", debugstr_w(name), flags);
1915 return get_locale_kbd_layout();
1919 /***********************************************************************
1920 * UnloadKeyboardLayout (X11DRV.@)
1922 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1924 FIXME("%p: stub!\n", hkl);
1925 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1926 return FALSE;
1930 /***********************************************************************
1931 * ActivateKeyboardLayout (X11DRV.@)
1933 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1935 HKL oldHkl = 0;
1936 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1938 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1939 if (flags & KLF_SETFORPROCESS)
1941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1942 FIXME("KLF_SETFORPROCESS not supported\n");
1943 return 0;
1946 if (flags)
1947 FIXME("flags %x not supported\n",flags);
1949 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1951 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1952 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1953 return 0;
1956 if (!match_x11_keyboard_layout(hkl))
1958 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1959 FIXME("setting keyboard of different locales not supported\n");
1960 return 0;
1963 oldHkl = thread_data->kbd_layout;
1964 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1966 thread_data->kbd_layout = hkl;
1968 return oldHkl;
1972 /***********************************************************************
1973 * X11DRV_MappingNotify
1975 BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
1977 HWND hwnd;
1979 XRefreshKeyboardMapping(&event->xmapping);
1980 X11DRV_InitKeyboard( event->xmapping.display );
1982 hwnd = GetFocus();
1983 if (!hwnd) hwnd = GetActiveWindow();
1984 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1985 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1986 return TRUE;
1990 /***********************************************************************
1991 * VkKeyScanEx (X11DRV.@)
1993 * Note: Windows ignores HKL parameter and uses current active layout instead
1995 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1997 Display *display = thread_init_display();
1998 KeyCode keycode;
1999 KeySym keysym;
2000 int index;
2001 CHAR cChar;
2002 SHORT ret;
2004 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2005 * is UTF-8 (multibyte encoding)?
2007 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2009 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2010 return -1;
2013 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2015 /* char->keysym (same for ANSI chars) */
2016 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2017 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2019 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2020 if (!keycode)
2022 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2024 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2025 TRACE(" ... returning ctrl char %#.2x\n", ret);
2026 return ret;
2028 /* It didn't work ... let's try with deadchar code. */
2029 TRACE("retrying with | 0xFE00\n");
2030 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2033 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2034 if (!keycode) return -1;
2036 EnterCriticalSection( &kbd_section );
2038 /* keycode -> (keyc2vkey) vkey */
2039 ret = keyc2vkey[keycode];
2040 if (!ret)
2042 LeaveCriticalSection( &kbd_section );
2043 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2044 return -1;
2047 for (index = 0; index < 4; index++) /* find shift state */
2048 if (keycode_to_keysym(display, keycode, index) == keysym) break;
2050 LeaveCriticalSection( &kbd_section );
2052 switch (index)
2054 case 0: break;
2055 case 1: ret += 0x0100; break;
2056 case 2: ret += 0x0600; break;
2057 case 3: ret += 0x0700; break;
2058 default:
2059 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2060 return -1;
2063 index : 0 adds 0x0000
2064 index : 1 adds 0x0100 (shift)
2065 index : ? adds 0x0200 (ctrl)
2066 index : 2 adds 0x0600 (ctrl+alt)
2067 index : 3 adds 0x0700 (ctrl+alt+shift)
2070 TRACE(" ... returning %#.2x\n", ret);
2071 return ret;
2074 /***********************************************************************
2075 * MapVirtualKeyEx (X11DRV.@)
2077 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2079 UINT ret = 0;
2080 int keyc;
2081 Display *display = thread_init_display();
2083 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2084 if (!match_x11_keyboard_layout(hkl))
2085 FIXME("keyboard layout %p is not supported\n", hkl);
2087 EnterCriticalSection( &kbd_section );
2089 switch(wMapType)
2091 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2092 case MAPVK_VK_TO_VSC_EX:
2093 switch (wCode)
2095 case VK_SHIFT: wCode = VK_LSHIFT; break;
2096 case VK_CONTROL: wCode = VK_LCONTROL; break;
2097 case VK_MENU: wCode = VK_LMENU; break;
2100 /* let's do vkey -> keycode -> scan */
2101 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2103 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2105 ret = keyc2scan[keyc] & 0xFF;
2106 break;
2110 /* set scan code prefix */
2111 if (wMapType == MAPVK_VK_TO_VSC_EX &&
2112 (wCode == VK_RCONTROL || wCode == VK_RMENU))
2113 ret |= 0xe000;
2114 break;
2116 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2117 case MAPVK_VSC_TO_VK_EX:
2119 /* let's do scan -> keycode -> vkey */
2120 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2121 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2123 ret = keyc2vkey[keyc] & 0xFF;
2124 /* Only stop if it's not a numpad vkey; otherwise keep
2125 looking for a potential better vkey. */
2126 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
2127 break;
2130 if (wMapType == MAPVK_VSC_TO_VK)
2131 switch (ret)
2133 case VK_LSHIFT:
2134 case VK_RSHIFT:
2135 ret = VK_SHIFT; break;
2136 case VK_LCONTROL:
2137 case VK_RCONTROL:
2138 ret = VK_CONTROL; break;
2139 case VK_LMENU:
2140 case VK_RMENU:
2141 ret = VK_MENU; break;
2144 break;
2146 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2148 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2149 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2150 * key.. Looks like something is wrong with the MS docs?
2151 * This is only true for letters, for example VK_0 returns '0' not ')'.
2152 * - hence we use the lock mask to ensure this happens.
2154 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2155 XKeyEvent e;
2156 KeySym keysym;
2157 int len;
2158 char s[10];
2160 e.display = display;
2161 e.state = 0;
2162 e.keycode = 0;
2163 e.type = KeyPress;
2165 /* We exit on the first keycode found, to speed up the thing. */
2166 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2167 { /* Find a keycode that could have generated this virtual key */
2168 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2169 { /* We filter the extended bit, we don't know it */
2170 e.keycode = keyc; /* Store it temporarily */
2171 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2172 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2173 state), so set it to 0, we'll find another one */
2178 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2179 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2181 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2182 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2183 * in order to produce a locale dependent numeric separator.
2185 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2187 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2188 if (!e.keycode)
2189 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2192 if (!e.keycode)
2194 WARN("Unknown virtual key %X !!!\n", wCode);
2195 break;
2197 TRACE("Found keycode %u\n",e.keycode);
2199 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2200 if (len)
2202 WCHAR wch;
2203 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) ret = toupperW(wch);
2205 break;
2208 default: /* reserved */
2209 FIXME("Unknown wMapType %d !\n", wMapType);
2210 break;
2213 LeaveCriticalSection( &kbd_section );
2214 TRACE( "returning 0x%x.\n", ret );
2215 return ret;
2218 /***********************************************************************
2219 * GetKeyNameText (X11DRV.@)
2221 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2223 Display *display = thread_init_display();
2224 int vkey, ansi, scanCode;
2225 KeyCode keyc;
2226 int keyi;
2227 KeySym keys;
2228 char *name;
2230 scanCode = lParam >> 16;
2231 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2233 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2235 /* handle "don't care" bit (0x02000000) */
2236 if (!(lParam & 0x02000000)) {
2237 switch (vkey) {
2238 case VK_RSHIFT:
2239 /* R-Shift is "special" - it is an extended key with separate scan code */
2240 scanCode |= 0x100;
2241 /* fall through */
2242 case VK_LSHIFT:
2243 vkey = VK_SHIFT;
2244 break;
2245 case VK_LCONTROL:
2246 case VK_RCONTROL:
2247 vkey = VK_CONTROL;
2248 break;
2249 case VK_LMENU:
2250 case VK_RMENU:
2251 vkey = VK_MENU;
2252 break;
2256 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2257 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2259 /* first get the name of the "regular" keys which is the Upper case
2260 value of the keycap imprint. */
2261 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2262 (scanCode != 0x137) && /* PrtScn */
2263 (scanCode != 0x135) && /* numpad / */
2264 (scanCode != 0x37 ) && /* numpad * */
2265 (scanCode != 0x4a ) && /* numpad - */
2266 (scanCode != 0x4e ) ) /* numpad + */
2268 if (nSize >= 2)
2270 *lpBuffer = toupperW((WCHAR)ansi);
2271 *(lpBuffer+1) = 0;
2272 return 1;
2274 else
2275 return 0;
2278 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2279 without "extended-key" flag. However Wine generates scancode
2280 *with* "extended-key" flag. Seems to occur *only* for the
2281 function keys. Soooo.. We will leave the table alone and
2282 fudge the lookup here till the other part is found and fixed!!! */
2284 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2285 (scanCode == 0x157) || (scanCode == 0x158))
2286 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2288 /* let's do scancode -> keycode -> keysym -> String */
2290 EnterCriticalSection( &kbd_section );
2292 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2293 if ((keyc2scan[keyi]) == scanCode)
2294 break;
2295 if (keyi <= max_keycode)
2297 INT rc;
2299 keyc = (KeyCode) keyi;
2300 keys = keycode_to_keysym(display, keyc, 0);
2301 name = XKeysymToString(keys);
2303 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2305 char* idx = strrchr(name, '_');
2306 if (idx && (_strnicmp(idx, "_r", -1) == 0 || _strnicmp(idx, "_l", -1) == 0))
2308 LeaveCriticalSection( &kbd_section );
2309 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2310 scanCode, keyc, keys, debugstr_an(name,idx-name));
2311 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2312 if (!rc) rc = nSize;
2313 lpBuffer[--rc] = 0;
2314 return rc;
2318 if (name)
2320 LeaveCriticalSection( &kbd_section );
2321 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2322 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2323 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2324 if (!rc) rc = nSize;
2325 lpBuffer[--rc] = 0;
2326 return rc;
2330 /* Finally issue WARN for unknown keys */
2332 LeaveCriticalSection( &kbd_section );
2333 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2334 *lpBuffer = 0;
2335 return 0;
2338 /***********************************************************************
2339 * X11DRV_KEYBOARD_MapDeadKeysym
2341 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2343 switch (keysym)
2345 /* symbolic ASCII is the same as defined in rfc1345 */
2346 #ifdef XK_dead_tilde
2347 case XK_dead_tilde :
2348 #endif
2349 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2350 return '~'; /* '? */
2351 #ifdef XK_dead_acute
2352 case XK_dead_acute :
2353 #endif
2354 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2355 return 0xb4; /* '' */
2356 #ifdef XK_dead_circumflex
2357 case XK_dead_circumflex:
2358 #endif
2359 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2360 return '^'; /* '> */
2361 #ifdef XK_dead_grave
2362 case XK_dead_grave :
2363 #endif
2364 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2365 return '`'; /* '! */
2366 #ifdef XK_dead_diaeresis
2367 case XK_dead_diaeresis :
2368 #endif
2369 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2370 return 0xa8; /* ': */
2371 #ifdef XK_dead_cedilla
2372 case XK_dead_cedilla :
2373 return 0xb8; /* ', */
2374 #endif
2375 #ifdef XK_dead_macron
2376 case XK_dead_macron :
2377 return '-'; /* 'm isn't defined on iso-8859-x */
2378 #endif
2379 #ifdef XK_dead_breve
2380 case XK_dead_breve :
2381 return 0xa2; /* '( */
2382 #endif
2383 #ifdef XK_dead_abovedot
2384 case XK_dead_abovedot :
2385 return 0xff; /* '. */
2386 #endif
2387 #ifdef XK_dead_abovering
2388 case XK_dead_abovering :
2389 return '0'; /* '0 isn't defined on iso-8859-x */
2390 #endif
2391 #ifdef XK_dead_doubleacute
2392 case XK_dead_doubleacute :
2393 return 0xbd; /* '" */
2394 #endif
2395 #ifdef XK_dead_caron
2396 case XK_dead_caron :
2397 return 0xb7; /* '< */
2398 #endif
2399 #ifdef XK_dead_ogonek
2400 case XK_dead_ogonek :
2401 return 0xb2; /* '; */
2402 #endif
2403 /* FIXME: I don't know this three.
2404 case XK_dead_iota :
2405 return 'i';
2406 case XK_dead_voiced_sound :
2407 return 'v';
2408 case XK_dead_semivoiced_sound :
2409 return 's';
2412 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2413 return 0;
2416 /***********************************************************************
2417 * ToUnicodeEx (X11DRV.@)
2419 * The ToUnicode function translates the specified virtual-key code and keyboard
2420 * state to the corresponding Windows character or characters.
2422 * If the specified key is a dead key, the return value is negative. Otherwise,
2423 * it is one of the following values:
2424 * Value Meaning
2425 * 0 The specified virtual key has no translation for the current state of the keyboard.
2426 * 1 One Windows character was copied to the buffer.
2427 * 2 Two characters were copied to the buffer. This usually happens when a
2428 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2429 * be composed with the specified virtual key to form a single character.
2431 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2434 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2435 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2437 Display *display = thread_init_display();
2438 XKeyEvent e;
2439 KeySym keysym = 0;
2440 INT ret;
2441 int keyc;
2442 char buf[10];
2443 char *lpChar = buf;
2444 HWND focus;
2445 XIC xic;
2446 Status status = 0;
2448 if (scanCode & 0x8000)
2450 TRACE_(key)("Key UP, doing nothing\n" );
2451 return 0;
2454 if (!match_x11_keyboard_layout(hkl))
2455 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2457 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2459 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2460 return 0;
2463 e.display = display;
2464 e.keycode = 0;
2465 e.state = 0;
2466 e.type = KeyPress;
2468 focus = x11drv_thread_data()->last_xic_hwnd;
2469 if (!focus)
2471 focus = GetFocus();
2472 if (focus) focus = GetAncestor( focus, GA_ROOT );
2473 if (!focus) focus = GetActiveWindow();
2475 e.window = X11DRV_get_whole_window( focus );
2476 xic = X11DRV_get_ic( focus );
2478 EnterCriticalSection( &kbd_section );
2480 if (lpKeyState[VK_SHIFT] & 0x80)
2482 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2483 e.state |= ShiftMask;
2485 if (lpKeyState[VK_CAPITAL] & 0x01)
2487 TRACE_(key)("LockMask = %04x\n", LockMask);
2488 e.state |= LockMask;
2490 if (lpKeyState[VK_CONTROL] & 0x80)
2492 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2493 e.state |= ControlMask;
2495 if (lpKeyState[VK_NUMLOCK] & 0x01)
2497 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2498 e.state |= NumLockMask;
2501 /* Restore saved AltGr state */
2502 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2503 e.state |= AltGrMask;
2505 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2506 virtKey, scanCode, e.state);
2508 /* We exit on the first keycode found, to speed up the thing. */
2509 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2510 { /* Find a keycode that could have generated this virtual key */
2511 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2512 { /* We filter the extended bit, we don't know it */
2513 e.keycode = keyc; /* Store it temporarily */
2514 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2515 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2516 state), so set it to 0, we'll find another one */
2521 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2522 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2524 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2525 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2527 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2528 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2529 * in order to produce a locale dependent numeric separator.
2531 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2533 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2534 if (!e.keycode)
2535 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2538 /* Ctrl-Space generates space on Windows */
2539 if (e.state == ControlMask && virtKey == VK_SPACE)
2541 bufW[0] = ' ';
2542 ret = 1;
2543 goto found;
2546 if (!e.keycode && virtKey != VK_NONAME)
2548 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2549 LeaveCriticalSection( &kbd_section );
2550 return 0;
2552 else TRACE_(key)("Found keycode %u\n",e.keycode);
2554 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2555 e.type, e.window, e.state, e.keycode);
2557 /* Clients should pass only KeyPress events to XmbLookupString,
2558 * e.type was set to KeyPress above.
2560 if (xic)
2562 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2563 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2564 if (status == XBufferOverflow)
2566 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2567 if (lpChar == NULL)
2569 ERR_(key)("Failed to allocate memory!\n");
2570 LeaveCriticalSection( &kbd_section );
2571 return 0;
2573 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2576 else
2577 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2579 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2581 if (TRACE_ON(key))
2583 const char *ksname;
2585 ksname = XKeysymToString(keysym);
2586 if (!ksname) ksname = "No Name";
2587 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2588 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2589 keysym, ksname, ret, debugstr_an(lpChar, ret));
2592 if (ret == 0)
2594 char dead_char;
2596 #ifdef XK_EuroSign
2597 /* An ugly hack for EuroSign: X can't translate it to a character
2598 for some locales. */
2599 if (keysym == XK_EuroSign)
2601 bufW[0] = 0x20AC;
2602 ret = 1;
2603 goto found;
2605 #endif
2606 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2607 /* Here we change it back. */
2608 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2610 bufW[0] = 0x09;
2611 ret = 1;
2612 goto found;
2615 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2616 if (dead_char)
2618 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2619 ret = -1;
2620 goto found;
2623 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2625 /* Unicode direct mapping */
2626 bufW[0] = keysym & 0xffff;
2627 ret = 1;
2628 goto found;
2630 else if ((keysym >> 8) == 0x1008FF) {
2631 bufW[0] = 0;
2632 ret = 0;
2633 goto found;
2635 else
2637 const char *ksname;
2639 ksname = XKeysymToString(keysym);
2640 if (!ksname)
2641 ksname = "No Name";
2642 if ((keysym >> 8) != 0xff)
2644 WARN_(key)("no char for keysym %04lx (%s) :\n",
2645 keysym, ksname);
2646 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2647 virtKey, scanCode, e.keycode, e.state);
2651 else { /* ret != 0 */
2652 /* We have a special case to handle : Shift + arrow, shift + home, ...
2653 X returns a char for it, but Windows doesn't. Let's eat it. */
2654 if (!(e.state & NumLockMask) /* NumLock is off */
2655 && (e.state & ShiftMask) /* Shift is pressed */
2656 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2658 lpChar[0] = 0;
2659 ret = 0;
2662 /* more areas where X returns characters but Windows does not
2663 CTRL + number or CTRL + symbol */
2664 if (e.state & ControlMask)
2666 if (((keysym>=33) && (keysym < '@')) ||
2667 (keysym == '`') ||
2668 (keysym == XK_Tab))
2670 lpChar[0] = 0;
2671 ret = 0;
2675 /* We have another special case for delete key (XK_Delete) on an
2676 extended keyboard. X returns a char for it, but Windows doesn't */
2677 if (keysym == XK_Delete)
2679 lpChar[0] = 0;
2680 ret = 0;
2682 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2683 && (keysym == XK_KP_Decimal))
2685 lpChar[0] = 0;
2686 ret = 0;
2688 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2689 && (keysym == XK_Return || keysym == XK_KP_Enter))
2691 if (lpKeyState[VK_SHIFT] & 0x80)
2693 lpChar[0] = 0;
2694 ret = 0;
2696 else
2698 lpChar[0] = '\n';
2699 ret = 1;
2703 /* Hack to detect an XLookupString hard-coded to Latin1 */
2704 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2706 bufW[0] = (BYTE)lpChar[0];
2707 goto found;
2710 /* perform translation to unicode */
2711 if(ret)
2713 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2714 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2718 found:
2719 if (buf != lpChar)
2720 HeapFree(GetProcessHeap(), 0, lpChar);
2722 LeaveCriticalSection( &kbd_section );
2724 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2725 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2726 if (1 <= ret && ret < bufW_size)
2727 bufW[ret] = 0;
2729 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2730 return ret;
2733 /***********************************************************************
2734 * Beep (X11DRV.@)
2736 void CDECL X11DRV_Beep(void)
2738 XBell(gdi_display, 0);