winex11: Avoid calling RtlInitUnicodeString on a static constant.
[wine.git] / dlls / winex11.drv / keyboard.c
blobf1ad4b01669b42252c09f161481106cc89c98250
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 #if 0
27 #pragma makedep unix
28 #endif
30 #include "config.h"
32 #include <X11/Xatom.h>
33 #include <X11/keysym.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xresource.h>
36 #include <X11/Xutil.h>
37 #ifdef HAVE_X11_XKBLIB_H
38 #include <X11/XKBlib.h>
39 #endif
41 #include <ctype.h>
42 #include <stdarg.h>
43 #include <string.h>
45 #define NONAMELESSUNION
47 #include "x11drv.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "winreg.h"
52 #include "winnls.h"
53 #include "ime.h"
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 /* log format (add 0-padding as appropriate):
58 keycode %u as in output from xev
59 keysym %lx as in X11/keysymdef.h
60 vkey %X as in winuser.h
61 scancode %x
63 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
64 WINE_DECLARE_DEBUG_CHANNEL(key);
66 static const unsigned int ControlMask = 1 << 2;
68 static int min_keycode, max_keycode, keysyms_per_keycode;
69 static KeySym *key_mapping;
70 static WORD keyc2vkey[256], keyc2scan[256];
72 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
74 static pthread_mutex_t kbd_mutex = PTHREAD_MUTEX_INITIALIZER;
76 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
78 /* Keyboard translation tables */
79 #define MAIN_LEN 49
80 static const WORD main_key_scan_qwerty[MAIN_LEN] =
82 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
83 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
84 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
85 /* q w e r t y u i o p [ ] */
86 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
87 /* a s d f g h j k l ; ' \ */
88 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
89 /* z x c v b n m , . / */
90 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
91 0x56 /* the 102nd key (actually to the right of l-shift) */
94 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
96 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
97 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
98 /* q w e r t y u i o p [ ] */
99 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
100 /* a s d f g h j k l ; ' \ */
101 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
102 /* \ z x c v b n m , . / */
103 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
104 0x56, /* the 102nd key (actually to the right of l-shift) */
107 static const WORD main_key_scan_dvorak[MAIN_LEN] =
109 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
110 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
111 /* ' , . p y f g c r l / = */
112 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
113 /* a o e u i d h t n s - \ */
114 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
115 /* ; q j k x b m w v z */
116 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
117 0x56 /* the 102nd key (actually to the right of l-shift) */
120 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
122 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ (Yen) */
123 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7D,
124 /* q w e r t y u i o p @ [ */
125 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
126 /* a s d f g h j k l ; : ] */
127 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
128 /* z x c v b n m , . / \ (Underscore) */
129 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x73
133 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
135 /* NOTE: this layout must concur with the scan codes layout above */
136 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
137 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
138 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
139 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
140 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
143 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
145 /* NOTE: this layout must concur with the scan codes layout above */
146 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
147 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
148 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
149 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
150 VK_OEM_102 /* the 102nd key (actually to the left of r-shift) */
153 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
155 /* NOTE: this layout must concur with the scan codes layout above */
156 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
157 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
158 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
159 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
160 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
163 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
165 /* NOTE: this layout must concur with the scan codes layout above */
166 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
167 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
168 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
169 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
170 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
173 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
175 /* NOTE: this layout must concur with the scan codes layout above */
176 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
177 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
178 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
179 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
180 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
183 static const WORD main_key_vkey_azerty[MAIN_LEN] =
185 /* NOTE: this layout must concur with the scan codes layout above */
186 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
187 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
188 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
189 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
190 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
193 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
195 /* NOTE: this layout must concur with the scan codes layout above */
196 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
197 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
198 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
199 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
200 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
203 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
205 /* the VK mappings for the main keyboard will be auto-assigned as before,
206 so what we have here is just the character tables */
207 /* order: Normal, Shift, AltGr, Shift-AltGr */
208 /* We recommend you write just what is guaranteed to be correct (i.e. what's
209 written on the keycaps), not the bunch of special characters behind AltGr
210 and Shift-AltGr if it can vary among different X servers */
211 /* These tables serve to guess the keyboard type and scancode mapping.
212 Complete modeling is not important, identification/discrimination is. */
213 /* Remember that your 102nd key (to the right of l-shift) should be on a
214 separate line, see existing tables */
215 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
216 /* Remember to also add your new table to the layout index table far below! */
218 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
219 static const char main_key_US[MAIN_LEN][4] =
221 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
222 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
223 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
224 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
227 /*** United States keyboard layout (phantom key version) */
228 /* (XFree86 reports the <> key even if it's not physically there) */
229 static const char main_key_US_phantom[MAIN_LEN][4] =
231 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
232 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
233 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
234 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
235 "<>" /* the phantom key */
238 /*** United States keyboard layout (dvorak version) */
239 static const char main_key_US_dvorak[MAIN_LEN][4] =
241 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
242 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
243 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
244 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
247 /*** British keyboard layout */
248 static const char main_key_UK[MAIN_LEN][4] =
250 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
251 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
252 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
253 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
254 "\\|"
257 /*** French keyboard layout (setxkbmap fr) */
258 static const char main_key_FR[MAIN_LEN][4] =
260 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
261 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
262 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
263 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
264 "<>"
267 /*** Icelandic keyboard layout (setxkbmap is) */
268 static const char main_key_IS[MAIN_LEN][4] =
270 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
271 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
272 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
273 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
274 "<>"
277 /* All german keyb layout tables have the acute/apostrophe symbol next to
278 * the BACKSPACE key removed (replaced with NULL which is ignored by the
279 * detection code).
280 * This was done because the mapping of the acute (and apostrophe) is done
281 * differently in various xkb-data/xkeyboard-config versions. Some replace
282 * the acute with a normal apostrophe, so that the apostrophe is found twice
283 * on the keyboard (one next to BACKSPACE and one next to ENTER).
284 * Others put the acute and grave accents on the key left of BACKSPACE.
285 * More information on the fd.o bugtracker:
286 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
287 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
288 * among PC and Mac keyboards, so these are not listed.
291 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
292 static const char main_key_DE[MAIN_LEN][4] =
294 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
295 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
296 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
297 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
298 "<>"
301 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
302 static const char main_key_SG[MAIN_LEN][4] =
304 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
305 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
306 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
307 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
308 "<>"
311 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
312 static const char main_key_SF[MAIN_LEN][4] =
314 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
315 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
316 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
317 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
318 "<>"
321 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
322 static const char main_key_NO[MAIN_LEN][4] =
324 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
325 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
326 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
327 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
328 "<>"
331 /*** Danish keyboard layout (setxkbmap dk) */
332 static const char main_key_DA[MAIN_LEN][4] =
334 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
335 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
336 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
337 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
338 "<>"
341 /*** Swedish keyboard layout (setxkbmap se) */
342 static const char main_key_SE[MAIN_LEN][4] =
344 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
345 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
346 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
347 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
348 "<>"
351 /*** Estonian keyboard layout (setxkbmap ee) */
352 static const char main_key_ET[MAIN_LEN][4] =
354 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
355 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
356 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
357 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
358 "<>"
361 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
362 static const char main_key_CF[MAIN_LEN][4] =
364 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
365 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
366 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
367 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
368 "\xab\xbb\xb0"
371 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
372 static const char main_key_CA_fr[MAIN_LEN][4] =
374 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
375 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
376 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
377 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
378 "\xab\xbb"
381 /*** Canadian keyboard layout (setxkbmap ca) */
382 static const char main_key_CA[MAIN_LEN][4] =
384 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
385 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
386 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
387 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
388 "\xf9\xd9"
391 /*** Portuguese keyboard layout (setxkbmap pt) */
392 static const char main_key_PT[MAIN_LEN][4] =
394 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
395 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
396 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
397 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
398 "<>"
401 /*** Italian keyboard layout (setxkbmap it) */
402 static const char main_key_IT[MAIN_LEN][4] =
404 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
405 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
406 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
407 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
408 "<>"
411 /*** Finnish keyboard layout (setxkbmap fi) */
412 static const char main_key_FI[MAIN_LEN][4] =
414 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
415 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
416 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
417 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
418 "<>"
421 /*** Bulgarian bds keyboard layout */
422 static const char main_key_BG_bds[MAIN_LEN][4] =
424 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
425 "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","]};",
426 "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",
427 "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",
428 "<>" /* the phantom key */
431 /*** Bulgarian phonetic keyboard layout */
432 static const char main_key_BG_phonetic[MAIN_LEN][4] =
434 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
435 "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",
436 "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",
437 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
438 "<>" /* the phantom key */
441 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
442 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
443 static const char main_key_BY[MAIN_LEN][4] =
445 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
446 "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","]}''",
447 "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","\\|/|",
448 "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",
452 /*** Russian keyboard layout (contributed by Pavel Roskin) */
453 static const char main_key_RU[MAIN_LEN][4] =
455 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
456 "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",
457 "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","\\|",
458 "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","/?"
461 /*** Russian keyboard layout (phantom key version) */
462 static const char main_key_RU_phantom[MAIN_LEN][4] =
464 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
465 "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",
466 "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","\\|",
467 "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","/?",
468 "<>" /* the phantom key */
471 /*** Russian keyboard layout KOI8-R */
472 static const char main_key_RU_koi8r[MAIN_LEN][4] =
474 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
475 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
476 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
477 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
478 "<>" /* the phantom key */
481 /*** Russian keyboard layout cp1251 */
482 static const char main_key_RU_cp1251[MAIN_LEN][4] =
484 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
485 "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",
486 "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","\\|",
487 "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","/?",
488 "<>" /* the phantom key */
491 /*** Russian phonetic keyboard layout */
492 static const char main_key_RU_phonetic[MAIN_LEN][4] =
494 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
495 "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",
496 "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",";:","'\"","\\|",
497 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
498 "<>" /* the phantom key */
501 /*** Ukrainian keyboard layout KOI8-U */
502 static const char main_key_UA[MAIN_LEN][4] =
504 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
505 "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",
506 "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","\\|\\|",
507 "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","/?/?",
508 "<>" /* the phantom key */
511 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
512 /*** (as it appears on most of keyboards sold today) */
513 static const char main_key_UA_std[MAIN_LEN][4] =
515 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
516 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
517 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
518 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
519 "<>" /* the phantom key */
522 /*** Russian keyboard layout KOI8-R (pair to the previous) */
523 static const char main_key_RU_std[MAIN_LEN][4] =
525 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
526 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
527 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
528 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
529 "<>" /* the phantom key */
532 /*** Spanish keyboard layout (setxkbmap es) */
533 static const char main_key_ES[MAIN_LEN][4] =
535 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
536 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
537 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
538 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
539 "<>"
542 /*** Belgian keyboard layout ***/
543 static const char main_key_BE[MAIN_LEN][4] =
545 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
546 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
547 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
548 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
549 "<>\\"
552 /*** Hungarian keyboard layout (setxkbmap hu) */
553 static const char main_key_HU[MAIN_LEN][4] =
555 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
556 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
557 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
558 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
559 "\xed\xcd"
562 /*** Polish (programmer's) keyboard layout ***/
563 static const char main_key_PL[MAIN_LEN][4] =
565 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
566 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
567 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
568 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
569 "<>|"
572 /*** Slovenian keyboard layout (setxkbmap si) ***/
573 static const char main_key_SI[MAIN_LEN][4] =
575 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
576 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
577 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
578 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
579 "<>"
582 /*** Serbian keyboard layout (setxkbmap sr) ***/
583 static const char main_key_SR[MAIN_LEN][4] =
585 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
586 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
587 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
588 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
589 "<>" /* the phantom key */
592 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
593 static const char main_key_US_SR[MAIN_LEN][4] =
595 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
596 "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","]}[]",
597 "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","\\|-_",
598 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
599 "<>" /* the phantom key */
602 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
603 static const char main_key_HR_jelly[MAIN_LEN][4] =
605 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
606 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
607 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
608 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
609 "<>|"
612 /*** Croatian keyboard layout (setxkbmap hr) ***/
613 static const char main_key_HR[MAIN_LEN][4] =
615 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
616 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
617 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
618 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
619 "<>"
622 /*** Japanese 106 keyboard layout ***/
623 static const char main_key_JA_jp106[MAIN_LEN][4] =
625 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
626 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
627 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
628 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
629 "\\_",
632 static const char main_key_JA_macjp[MAIN_LEN][4] =
634 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
635 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
636 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
637 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
638 "__",
641 /*** Japanese pc98x1 keyboard layout ***/
642 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
644 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
645 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
646 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
647 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
648 "\\_",
651 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
652 static const char main_key_PT_br[MAIN_LEN][4] =
654 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
655 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
656 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
657 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
660 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
661 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
663 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
664 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
665 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
666 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
669 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
670 static const char main_key_US_intl[MAIN_LEN][4] =
672 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
673 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
674 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
675 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
678 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
679 - dead_abovering replaced with degree - no symbol in iso8859-2
680 - brokenbar replaced with bar */
681 static const char main_key_SK[MAIN_LEN][4] =
683 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
684 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
685 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
686 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
687 "<>"
690 /*** Czech keyboard layout (setxkbmap cz) */
691 static const char main_key_CZ[MAIN_LEN][4] =
693 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
694 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
695 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
696 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
697 "\\"
700 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
701 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
703 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
704 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
705 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
706 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
707 "\\"
710 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
711 static const char main_key_SK_prog[MAIN_LEN][4] =
713 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
714 "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","[{","]}",
715 "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",";:","'\"","\\|",
716 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
717 "<>"
720 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
721 static const char main_key_CS[MAIN_LEN][4] =
723 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
724 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
725 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
726 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
727 "<>\\|"
730 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
731 static const char main_key_LA[MAIN_LEN][4] =
733 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
734 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
735 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
736 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
737 "<>"
740 /*** Lithuanian keyboard layout (setxkbmap lt) */
741 static const char main_key_LT_B[MAIN_LEN][4] =
743 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
744 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
745 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
746 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
747 "\xaa\xac"
750 /*** Turkish keyboard Layout */
751 static const char main_key_TK[MAIN_LEN][4] =
753 "\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
754 "qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
755 "aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
756 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
759 /*** Turkish keyboard layout (setxkbmap tr) */
760 static const char main_key_TR[MAIN_LEN][4] =
762 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
763 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
764 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
765 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
766 "<>"
769 /*** Turkish F keyboard layout (setxkbmap trf) */
770 static const char main_key_TR_F[MAIN_LEN][4] =
772 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
773 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
774 "uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
775 "jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
776 "<>"
779 /*** Israelian keyboard layout (setxkbmap us,il) */
780 static const char main_key_IL[MAIN_LEN][4] =
782 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
783 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
784 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
785 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
786 "<>"
789 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
790 static const char main_key_IL_phonetic[MAIN_LEN][4] =
792 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
793 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
794 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
795 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
796 "<>"
799 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
800 static const char main_key_IL_saharon[MAIN_LEN][4] =
802 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
803 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
804 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
805 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
806 "<>"
809 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
810 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
811 message since they have different characters in gr and el XFree86 layouts. */
812 static const char main_key_EL[MAIN_LEN][4] =
814 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
815 "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","[{","]}",
816 "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","'\"","\\|",
817 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
818 "<>"
821 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
822 static const char main_key_th[MAIN_LEN][4] =
824 "`~_%","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",
825 "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,",
826 "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",
827 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
830 /*** VNC keyboard layout */
831 static const WORD main_key_scan_vnc[MAIN_LEN] =
833 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
834 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,
835 0x56
838 static const WORD main_key_vkey_vnc[MAIN_LEN] =
840 '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,
841 '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',
842 VK_OEM_102
845 static const char main_key_vnc[MAIN_LEN][4] =
847 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
848 "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"
851 /*** Dutch keyboard layout (setxkbmap nl) ***/
852 static const char main_key_NL[MAIN_LEN][4] =
854 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
855 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
856 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
857 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
858 "[]"
863 /*** Layout table. Add your keyboard mappings to this list */
864 static const struct {
865 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
866 in the appropriate dlls/kernel/nls/.nls file */
867 const char *comment;
868 const char (*key)[MAIN_LEN][4];
869 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
870 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
871 } main_key_tab[]={
872 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
873 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
874 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
875 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
876 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
877 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
878 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
879 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
880 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
881 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
882 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
883 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
884 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
885 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
886 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
887 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
888 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
889 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
891 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
892 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
895 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
896 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
897 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
898 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
902 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
906 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
908 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
909 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
910 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
911 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
912 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
913 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
915 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
916 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
921 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
931 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0, NULL, NULL, NULL, NULL} /* sentinel */
937 static unsigned kbd_layout=0; /* index into above table of layouts */
939 /* maybe more of these scancodes should be extended? */
940 /* extended must be set for ALT_R, CTRL_R,
941 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
942 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
943 /* FIXME should we set extended bit for NumLock ? My
944 * Windows does ... DF */
945 /* Yes, to distinguish based on scan codes, also
946 for PrtScn key ... GA */
948 static const WORD nonchar_key_vkey[256] =
950 /* unused */
951 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
952 /* special keys */
953 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
954 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
955 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
956 /* Japanese special keys */
957 0, VK_KANJI, VK_NONCONVERT, VK_CONVERT, /* FF20 */
958 VK_DBE_ROMAN, 0, 0, VK_DBE_HIRAGANA,
959 0, 0, VK_DBE_SBCSCHAR, 0, 0, 0, 0, 0, /* FF28 */
960 /* Korean special keys (FF31-) */
961 VK_DBE_ALPHANUMERIC, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
962 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
963 /* unused */
964 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
965 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
966 /* cursor keys */
967 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
968 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
969 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
970 /* misc keys */
971 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
972 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
973 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
974 /* keypad keys */
975 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
976 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
977 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
978 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
979 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
980 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
981 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
982 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
983 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
984 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
985 * in order to produce a locale dependent numeric separator.
987 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
988 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
989 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
990 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
991 /* function keys */
992 VK_F1, VK_F2,
993 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
994 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
995 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
996 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
997 /* modifier keys */
998 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
999 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1000 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1001 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1002 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1005 static const WORD nonchar_key_scan[256] =
1007 /* unused */
1008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1009 /* special keys */
1010 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1011 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1012 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1013 /* Japanese special keys */
1014 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */
1015 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1016 /* Korean special keys (FF31-) */
1017 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1019 /* unused */
1020 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1022 /* cursor keys */
1023 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1025 /* misc keys */
1026 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1027 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1029 /* keypad keys */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1034 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1036 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1037 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1038 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1039 /* function keys */
1040 0x3B, 0x3C,
1041 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1042 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1045 /* modifier keys */
1046 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1047 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1048 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1049 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1052 static const WORD xfree86_vendor_key_vkey[256] =
1054 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1055 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1056 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1057 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1058 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1059 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1060 0, 0, 0, VK_BROWSER_HOME,
1061 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1062 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1063 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1064 0, 0, 0, 0,
1065 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1066 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1067 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1068 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1069 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1070 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1071 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1072 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1089 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1092 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1094 #ifdef HAVE_XKB
1095 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1096 #endif
1097 return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index];
1100 /* Returns the Windows virtual key code associated with the X event <e> */
1101 /* kbd_section must be held */
1102 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1104 KeySym keysym = 0;
1105 Status status;
1106 char buf[24];
1108 /* Clients should pass only KeyPress events to XmbLookupString */
1109 if (xic && e->type == KeyPress)
1110 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1111 else
1112 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1114 if ((e->state & NumLockMask) &&
1115 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1116 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1117 /* Only the Keypad keys 0-9 and . send different keysyms
1118 * depending on the NumLock state */
1119 return nonchar_key_vkey[keysym & 0xFF];
1121 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1122 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1123 if ((e->state & ControlMask) && (keysym == XK_Break))
1124 return VK_CANCEL;
1126 TRACE_(key)("e->keycode = %u\n", e->keycode);
1128 return keyc2vkey[e->keycode];
1132 /***********************************************************************
1133 * X11DRV_send_keyboard_input
1135 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT flags, UINT time )
1137 INPUT input;
1139 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1141 input.type = INPUT_KEYBOARD;
1142 input.u.ki.wVk = vkey;
1143 input.u.ki.wScan = scan;
1144 input.u.ki.dwFlags = flags;
1145 input.u.ki.time = time;
1146 input.u.ki.dwExtraInfo = 0;
1148 __wine_send_input( hwnd, &input, NULL );
1152 /***********************************************************************
1153 * get_async_key_state
1155 static BOOL get_async_key_state( BYTE state[256] )
1157 BOOL ret;
1159 SERVER_START_REQ( get_key_state )
1161 req->async = 1;
1162 req->key = -1;
1163 wine_server_set_reply( req, state, 256 );
1164 ret = !wine_server_call( req );
1166 SERVER_END_REQ;
1167 return ret;
1170 /***********************************************************************
1171 * set_async_key_state
1173 static void set_async_key_state( const BYTE state[256] )
1175 SERVER_START_REQ( set_key_state )
1177 req->async = 1;
1178 wine_server_add_data( req, state, 256 );
1179 wine_server_call( req );
1181 SERVER_END_REQ;
1184 static void update_key_state( BYTE *keystate, BYTE key, int down )
1186 if (down)
1188 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1189 keystate[key] |= 0x80;
1191 else keystate[key] &= ~0x80;
1194 /***********************************************************************
1195 * X11DRV_KeymapNotify
1197 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1199 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1200 * from wine to another application and back.
1201 * Toggle keys are handled in HandleEvent.
1203 BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1205 int i, j;
1206 BYTE keystate[256];
1207 WORD vkey;
1208 BOOL changed = FALSE;
1209 struct {
1210 WORD vkey;
1211 WORD pressed;
1212 } keys[256];
1214 if (!get_async_key_state( keystate )) return FALSE;
1216 memset(keys, 0, sizeof(keys));
1218 pthread_mutex_lock( &kbd_mutex );
1220 /* the minimum keycode is always greater or equal to 8, so we can
1221 * skip the first 8 values, hence start at 1
1223 for (i = 1; i < 32; i++)
1225 for (j = 0; j < 8; j++)
1227 vkey = keyc2vkey[(i * 8) + j];
1229 /* If multiple keys map to the same vkey, we want to report it as
1230 * pressed iff any of them are pressed. */
1231 if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey;
1232 if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE;
1236 for (vkey = 1; vkey <= 0xff; vkey++)
1238 if (keys[vkey].vkey && !(keystate[vkey] & 0x80) != !keys[vkey].pressed)
1240 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1241 keys[vkey].vkey, keystate[vkey]);
1243 update_key_state( keystate, vkey, keys[vkey].pressed );
1244 changed = TRUE;
1248 pthread_mutex_unlock( &kbd_mutex );
1249 if (!changed) return FALSE;
1251 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1252 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1253 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1254 set_async_key_state( keystate );
1255 return TRUE;
1258 static void adjust_lock_state( BYTE *keystate, HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1260 BYTE prev_state = keystate[vkey] & 0x01;
1262 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags, time );
1263 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags ^ KEYEVENTF_KEYUP, time );
1265 /* Keyboard hooks may have blocked processing lock keys causing our state
1266 * to be different than state on X server side. Although Windows allows hooks
1267 * to block changing state, we can't prevent it on X server side. Having
1268 * different states would cause us to try to adjust it again on the next
1269 * key event. We prevent that by overriding hooks and setting key states here. */
1270 if (get_async_key_state( keystate ) && (keystate[vkey] & 0x01) == prev_state)
1272 WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey, keystate[vkey]);
1273 keystate[vkey] ^= 0x01;
1274 set_async_key_state( keystate );
1278 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, UINT time )
1280 BYTE keystate[256];
1282 /* Note: X sets the below states on key down and clears them on key up.
1283 Windows triggers them on key down. */
1285 if (!get_async_key_state( keystate )) return;
1287 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1288 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1290 DWORD flags = 0;
1291 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1292 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1293 adjust_lock_state( keystate, hwnd, VK_CAPITAL, 0x3a, flags, time );
1296 /* Adjust the NUMLOCK state if it has been changed outside wine */
1297 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1299 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1300 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1301 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1302 adjust_lock_state( keystate, hwnd, VK_NUMLOCK, 0x45, flags, time );
1305 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1306 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1308 DWORD flags = 0;
1309 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1310 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1311 adjust_lock_state( keystate, hwnd, VK_SCROLL, 0x46, flags, time );
1315 /***********************************************************************
1316 * X11DRV_KeyEvent
1318 * Handle a X key event
1320 BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1322 XKeyEvent *event = &xev->xkey;
1323 char buf[24];
1324 char *Str = buf;
1325 KeySym keysym = 0;
1326 WORD vkey = 0, bScan;
1327 DWORD dwFlags;
1328 int ascii_chars;
1329 XIC xic = X11DRV_get_ic( hwnd );
1330 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1331 Status status = 0;
1333 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1334 event->type, event->window, event->state, event->keycode);
1336 if (event->type == KeyPress) update_user_time( event->time );
1338 /* Clients should pass only KeyPress events to XmbLookupString */
1339 if (xic && event->type == KeyPress)
1341 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1342 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1343 if (status == XBufferOverflow)
1345 Str = malloc( ascii_chars );
1346 if (Str == NULL)
1348 ERR_(key)("Failed to allocate memory!\n");
1349 return FALSE;
1351 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1354 else
1355 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1357 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1359 if (status == XLookupChars)
1361 X11DRV_XIMLookupChars( Str, ascii_chars );
1362 if (buf != Str)
1363 free( Str );
1364 return TRUE;
1367 pthread_mutex_lock( &kbd_mutex );
1369 /* If XKB extensions are used, the state mask for AltGr will use the group
1370 index instead of the modifier mask. The group index is set in bits
1371 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1372 pressed, look if the group index is different than 0. From XKB
1373 extension documentation, the group index for AltGr should be 2
1374 (event->state = 0x2000). It's probably better to not assume a
1375 predefined group index and find it dynamically
1377 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1378 /* Save also all possible modifier states. */
1379 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1381 if (TRACE_ON(key)){
1382 const char *ksname;
1384 ksname = XKeysymToString(keysym);
1385 if (!ksname)
1386 ksname = "No Name";
1387 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1388 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1389 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1391 if (buf != Str)
1392 free( Str );
1394 vkey = EVENT_event_to_vkey(xic,event);
1395 /* X returns keycode 0 for composed characters */
1396 if (!vkey && ascii_chars) vkey = VK_NONAME;
1397 bScan = keyc2scan[event->keycode] & 0xFF;
1399 TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
1400 event->keycode, vkey, bScan);
1402 pthread_mutex_unlock( &kbd_mutex );
1404 if (!vkey) return FALSE;
1406 dwFlags = 0;
1407 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1408 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1410 update_lock_state( hwnd, vkey, event->state, event_time );
1412 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1413 return TRUE;
1416 /**********************************************************************
1417 * X11DRV_KEYBOARD_DetectLayout
1419 * Called from X11DRV_InitKeyboard
1420 * This routine walks through the defined keyboard layouts and selects
1421 * whichever matches most closely.
1422 * kbd_section must be held.
1424 static void
1425 X11DRV_KEYBOARD_DetectLayout( Display *display )
1427 unsigned current, match, mismatch, seq, i, syms;
1428 int score, keyc, key, pkey, ok;
1429 KeySym keysym = 0;
1430 const char (*lkey)[MAIN_LEN][4];
1431 unsigned max_seq = 0;
1432 int max_score = INT_MIN, ismatch = 0;
1433 char ckey[256][4];
1435 syms = keysyms_per_keycode;
1436 if (syms > 4) {
1437 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1438 syms = 4;
1441 memset( ckey, 0, sizeof(ckey) );
1442 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1443 /* get data for keycode from X server */
1444 for (i = 0; i < syms; i++) {
1445 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1446 /* Allow both one-byte and two-byte national keysyms */
1447 if ((keysym < 0x8000) && (keysym != ' '))
1449 #ifdef HAVE_XKB
1450 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1451 #endif
1453 TRACE("XKB could not translate keysym %04lx\n", keysym);
1454 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1455 * with appropriate ShiftMask and Mode_switch, use XLookupString
1456 * to get character in the local encoding.
1458 ckey[keyc][i] = keysym & 0xFF;
1461 else {
1462 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1467 for (current = 0; main_key_tab[current].comment; current++) {
1468 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1469 match = 0;
1470 mismatch = 0;
1471 score = 0;
1472 seq = 0;
1473 lkey = main_key_tab[current].key;
1474 pkey = -1;
1475 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1476 if (ckey[keyc][0]) {
1477 /* search for a match in layout table */
1478 /* right now, we just find an absolute match for defined positions */
1479 /* (undefined positions are ignored, so if it's defined as "3#" in */
1480 /* the table, it's okay that the X server has "3#£", for example) */
1481 /* however, the score will be higher for longer matches */
1482 for (key = 0; key < MAIN_LEN; key++) {
1483 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1484 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1485 ok++;
1486 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1487 ok = -1;
1489 if (ok > 0) {
1490 score += ok;
1491 break;
1494 /* count the matches and mismatches */
1495 if (ok > 0) {
1496 match++;
1497 /* and how much the keycode order matches */
1498 if (key > pkey) seq++;
1499 pkey = key;
1500 } else {
1501 /* print spaces instead of \0's */
1502 char str[5];
1503 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1504 str[4] = 0;
1505 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, debugstr_a(str));
1506 mismatch++;
1507 score -= syms;
1511 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1512 match, mismatch, seq, score);
1513 if ((score > max_score) ||
1514 ((score == max_score) && (seq > max_seq))) {
1515 /* best match so far */
1516 kbd_layout = current;
1517 max_score = score;
1518 max_seq = seq;
1519 ismatch = !mismatch;
1522 /* we're done, report results if necessary */
1523 if (!ismatch)
1524 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1525 main_key_tab[kbd_layout].comment);
1527 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1530 static HKL get_locale_kbd_layout(void)
1532 LCID layout;
1533 LANGID langid;
1535 /* FIXME:
1537 * layout = main_key_tab[kbd_layout].lcid;
1539 * Winword uses return value of GetKeyboardLayout as a codepage
1540 * to translate ANSI keyboard messages to unicode. But we have
1541 * a problem with it: for instance Polish keyboard layout is
1542 * identical to the US one, and therefore instead of the Polish
1543 * locale id we return the US one.
1546 NtQueryDefaultLocale( TRUE, &layout );
1549 * Microsoft Office expects this value to be something specific
1550 * for Japanese and Korean Windows with an IME the value is 0xe001
1551 * We should probably check to see if an IME exists and if so then
1552 * set this word properly.
1554 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1555 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1556 layout = MAKELONG( layout, 0xe001 ); /* IME */
1557 else
1558 layout |= layout << 16;
1560 return (HKL)(UINT_PTR)layout;
1564 /**********************************************************************
1565 * X11DRV_InitKeyboard
1567 void X11DRV_InitKeyboard( Display *display )
1569 XModifierKeymap *mmp;
1570 KeySym keysym;
1571 KeyCode *kcp;
1572 XKeyEvent e2;
1573 WORD scan, vkey;
1574 int keyc, i, keyn, syms;
1575 char ckey[4]={0,0,0,0};
1576 const char (*lkey)[MAIN_LEN][4];
1577 char vkey_used[256] = { 0 };
1579 /* Ranges of OEM, function key, and character virtual key codes.
1580 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1581 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1582 static const struct {
1583 WORD first, last;
1584 } vkey_ranges[] = {
1585 { VK_OEM_1, VK_OEM_3 },
1586 { VK_OEM_4, VK_OEM_8 },
1587 { VK_OEM_AX, VK_ICO_00 },
1588 { 0xe6, 0xe6 },
1589 { 0xe9, 0xf5 },
1590 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1591 { VK_F1, VK_F24 },
1592 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1593 { 0x41, 0x5a }, /* VK_A - VK_Z */
1594 { 0, 0 }
1596 int vkey_range;
1598 pthread_mutex_lock( &kbd_mutex );
1599 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1600 if (key_mapping) XFree( key_mapping );
1601 key_mapping = XGetKeyboardMapping(display, min_keycode,
1602 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1604 mmp = XGetModifierMapping(display);
1605 kcp = mmp->modifiermap;
1606 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1608 int j;
1610 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1611 if (*kcp)
1613 int k;
1615 for (k = 0; k < keysyms_per_keycode; k += 1)
1616 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1618 NumLockMask = 1 << i;
1619 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1621 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1623 ScrollLockMask = 1 << i;
1624 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1628 XFreeModifiermap(mmp);
1630 /* Detect the keyboard layout */
1631 X11DRV_KEYBOARD_DetectLayout( display );
1632 lkey = main_key_tab[kbd_layout].key;
1633 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1635 /* Now build two conversion arrays :
1636 * keycode -> vkey + scancode + extended
1637 * vkey + extended -> keycode */
1639 e2.display = display;
1640 e2.state = 0;
1641 e2.type = KeyPress;
1643 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1644 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1646 char buf[30];
1647 int have_chars;
1649 keysym = 0;
1650 e2.keycode = (KeyCode)keyc;
1651 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1652 vkey = 0; scan = 0;
1653 if (keysym) /* otherwise, keycode not used */
1655 if ((keysym >> 8) == 0xFF) /* non-character key */
1657 vkey = nonchar_key_vkey[keysym & 0xff];
1658 scan = nonchar_key_scan[keysym & 0xff];
1659 /* set extended bit when necessary */
1660 if (scan & 0x100) vkey |= 0x100;
1661 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1662 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1663 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1664 scan = 0x100;
1665 vkey |= 0x100;
1666 } else if (keysym == 0x20) { /* Spacebar */
1667 vkey = VK_SPACE;
1668 scan = 0x39;
1669 } else if (have_chars) {
1670 /* we seem to need to search the layout-dependent scancodes */
1671 int maxlen=0,maxval=-1,ok;
1672 for (i=0; i<syms; i++) {
1673 keysym = keycode_to_keysym(display, keyc, i);
1674 if ((keysym<0x8000) && (keysym!=' '))
1676 #ifdef HAVE_XKB
1677 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1678 #endif
1680 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1681 * with appropriate ShiftMask and Mode_switch, use XLookupString
1682 * to get character in the local encoding.
1684 ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1686 } else {
1687 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1690 /* find key with longest match streak */
1691 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1692 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1693 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1694 if (!ok) i--; /* we overshot */
1695 if (ok||(i>maxlen)) {
1696 maxlen=i; maxval=keyn;
1698 if (ok) break;
1700 if (maxval>=0) {
1701 /* got it */
1702 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1703 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1704 scan = (*lscan)[maxval];
1705 vkey = (*lvkey)[maxval];
1709 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1710 keyc2vkey[e2.keycode] = vkey;
1711 keyc2scan[e2.keycode] = scan;
1712 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1713 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1714 vkey_used[(vkey & 0xff)] = 1;
1715 } /* for */
1717 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1718 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1720 vkey = keyc2vkey[keyc] & 0xff;
1721 if (vkey)
1722 continue;
1724 e2.keycode = (KeyCode)keyc;
1725 keysym = XLookupKeysym(&e2, 0);
1726 if (!keysym)
1727 continue;
1729 /* find a suitable layout-dependent VK code */
1730 /* (most Winelib apps ought to be able to work without layout tables!) */
1731 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1733 keysym = XLookupKeysym(&e2, i);
1734 if ((keysym >= XK_0 && keysym <= XK_9)
1735 || (keysym >= XK_A && keysym <= XK_Z)) {
1736 vkey = VKEY_IF_NOT_USED(keysym);
1740 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1742 keysym = XLookupKeysym(&e2, i);
1743 switch (keysym)
1745 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1746 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1747 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1748 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1749 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1750 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1751 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1752 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1753 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1754 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1755 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1759 if (vkey)
1761 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1762 keyc2vkey[e2.keycode] = vkey;
1764 } /* for */
1766 /* For any keycodes which still don't have a vkey, assign any spare
1767 * character, function key, or OEM virtual key code. */
1768 vkey_range = 0;
1769 vkey = vkey_ranges[vkey_range].first;
1770 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1772 if (keyc2vkey[keyc] & 0xff)
1773 continue;
1775 e2.keycode = (KeyCode)keyc;
1776 keysym = XLookupKeysym(&e2, 0);
1777 if (!keysym)
1778 continue;
1780 while (vkey && vkey_used[vkey])
1782 if (vkey == vkey_ranges[vkey_range].last)
1784 vkey_range++;
1785 vkey = vkey_ranges[vkey_range].first;
1787 else
1788 vkey++;
1791 if (!vkey)
1793 WARN("No more vkeys available!\n");
1794 break;
1797 if (TRACE_ON(keyboard))
1799 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1800 vkey, e2.keycode);
1801 TRACE("(");
1802 for (i = 0; i < keysyms_per_keycode; i += 1)
1804 const char *ksname;
1806 keysym = XLookupKeysym(&e2, i);
1807 ksname = XKeysymToString(keysym);
1808 if (!ksname)
1809 ksname = "NoSymbol";
1810 TRACE( "%lx (%s) ", keysym, ksname);
1812 TRACE(")\n");
1815 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1816 keyc2vkey[e2.keycode] = vkey;
1817 vkey_used[vkey] = 1;
1818 } /* for */
1819 #undef VKEY_IF_NOT_USED
1821 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1822 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1823 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1824 const char *ksname;
1825 keysym = keycode_to_keysym(display, keyc, 0);
1826 ksname = XKeysymToString(keysym);
1827 if (!ksname) ksname = "NoSymbol";
1829 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1831 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1832 keyc2scan[keyc]=scan++;
1835 pthread_mutex_unlock( &kbd_mutex );
1838 static BOOL match_x11_keyboard_layout(HKL hkl)
1840 const DWORD isIME = 0xE0000000;
1841 HKL xHkl = get_locale_kbd_layout();
1843 /* if the layout is an IME, only match the low word (LCID) */
1844 if (((ULONG_PTR)hkl & isIME) == isIME)
1845 return (LOWORD(hkl) == LOWORD(xHkl));
1846 else
1847 return (hkl == xHkl);
1851 /***********************************************************************
1852 * ActivateKeyboardLayout (X11DRV.@)
1854 BOOL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1856 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1858 if (flags & KLF_SETFORPROCESS)
1860 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1861 FIXME("KLF_SETFORPROCESS not supported\n");
1862 return FALSE;
1865 if (!match_x11_keyboard_layout(hkl))
1867 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1868 FIXME("setting keyboard of different locales not supported\n");
1869 return FALSE;
1872 return TRUE;
1876 /***********************************************************************
1877 * X11DRV_MappingNotify
1879 BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
1881 HWND hwnd;
1883 XRefreshKeyboardMapping(&event->xmapping);
1884 X11DRV_InitKeyboard( event->xmapping.display );
1886 hwnd = get_focus();
1887 if (!hwnd) hwnd = get_active_window();
1888 NtUserPostMessage( hwnd, WM_INPUTLANGCHANGEREQUEST,
1889 0 /*FIXME*/, (LPARAM)NtUserGetKeyboardLayout(0) );
1890 return TRUE;
1894 /***********************************************************************
1895 * VkKeyScanEx (X11DRV.@)
1897 * Note: Windows ignores HKL parameter and uses current active layout instead
1899 SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl )
1901 Display *display = thread_init_display();
1902 KeyCode keycode;
1903 KeySym keysym;
1904 int index;
1905 CHAR cChar;
1906 SHORT ret;
1908 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
1909 * is UTF-8 (multibyte encoding)?
1911 if (!ntdll_wcstoumbs( &wChar, 1, &cChar, 1, FALSE ))
1913 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1914 return -1;
1917 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1919 /* char->keysym (same for ANSI chars) */
1920 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1921 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1923 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1924 if (!keycode)
1926 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
1928 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
1929 TRACE(" ... returning ctrl char %#.2x\n", ret);
1930 return ret;
1932 /* It didn't work ... let's try with deadchar code. */
1933 TRACE("retrying with | 0xFE00\n");
1934 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
1937 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
1938 if (!keycode) return -1;
1940 pthread_mutex_lock( &kbd_mutex );
1942 /* keycode -> (keyc2vkey) vkey */
1943 ret = keyc2vkey[keycode];
1944 if (!ret)
1946 pthread_mutex_unlock( &kbd_mutex );
1947 TRACE("keycode for '%c' not found, returning -1\n", cChar);
1948 return -1;
1951 for (index = 0; index < 4; index++) /* find shift state */
1952 if (keycode_to_keysym(display, keycode, index) == keysym) break;
1954 pthread_mutex_unlock( &kbd_mutex );
1956 switch (index)
1958 case 0: break;
1959 case 1: ret += 0x0100; break;
1960 case 2: ret += 0x0600; break;
1961 case 3: ret += 0x0700; break;
1962 default:
1963 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
1964 return -1;
1967 index : 0 adds 0x0000
1968 index : 1 adds 0x0100 (shift)
1969 index : ? adds 0x0200 (ctrl)
1970 index : 2 adds 0x0600 (ctrl+alt)
1971 index : 3 adds 0x0700 (ctrl+alt+shift)
1974 TRACE(" ... returning %#.2x\n", ret);
1975 return ret;
1978 /***********************************************************************
1979 * MapVirtualKeyEx (X11DRV.@)
1981 UINT X11DRV_MapVirtualKeyEx( UINT wCode, UINT wMapType, HKL hkl )
1983 UINT ret = 0;
1984 int keyc;
1985 Display *display = thread_init_display();
1987 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1988 if (!match_x11_keyboard_layout(hkl))
1989 FIXME("keyboard layout %p is not supported\n", hkl);
1991 pthread_mutex_lock( &kbd_mutex );
1993 switch(wMapType)
1995 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
1996 case MAPVK_VK_TO_VSC_EX:
1997 switch (wCode)
1999 case VK_SHIFT: wCode = VK_LSHIFT; break;
2000 case VK_CONTROL: wCode = VK_LCONTROL; break;
2001 case VK_MENU: wCode = VK_LMENU; break;
2004 /* let's do vkey -> keycode -> scan */
2005 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2007 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2009 ret = keyc2scan[keyc] & 0xFF;
2010 break;
2014 /* set scan code prefix */
2015 if (wMapType == MAPVK_VK_TO_VSC_EX &&
2016 (wCode == VK_RCONTROL || wCode == VK_RMENU))
2017 ret |= 0xe000;
2018 break;
2020 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2021 case MAPVK_VSC_TO_VK_EX:
2023 /* let's do scan -> keycode -> vkey */
2024 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2025 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2027 ret = keyc2vkey[keyc] & 0xFF;
2028 /* Only stop if it's not a numpad vkey; otherwise keep
2029 looking for a potential better vkey. */
2030 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
2031 break;
2034 if (wMapType == MAPVK_VSC_TO_VK)
2035 switch (ret)
2037 case VK_LSHIFT:
2038 case VK_RSHIFT:
2039 ret = VK_SHIFT; break;
2040 case VK_LCONTROL:
2041 case VK_RCONTROL:
2042 ret = VK_CONTROL; break;
2043 case VK_LMENU:
2044 case VK_RMENU:
2045 ret = VK_MENU; break;
2048 break;
2050 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2052 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2053 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2054 * key.. Looks like something is wrong with the MS docs?
2055 * This is only true for letters, for example VK_0 returns '0' not ')'.
2056 * - hence we use the lock mask to ensure this happens.
2058 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2059 XKeyEvent e;
2060 KeySym keysym;
2061 int len;
2062 char s[10];
2064 e.display = display;
2065 e.state = 0;
2066 e.keycode = 0;
2067 e.type = KeyPress;
2069 /* We exit on the first keycode found, to speed up the thing. */
2070 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2071 { /* Find a keycode that could have generated this virtual key */
2072 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2073 { /* We filter the extended bit, we don't know it */
2074 e.keycode = keyc; /* Store it temporarily */
2075 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2076 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2077 state), so set it to 0, we'll find another one */
2082 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2083 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2085 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2086 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2087 * in order to produce a locale dependent numeric separator.
2089 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2091 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2092 if (!e.keycode)
2093 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2096 if (!e.keycode)
2098 WARN("Unknown virtual key %X !!!\n", wCode);
2099 break;
2101 TRACE("Found keycode %u\n",e.keycode);
2103 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2104 if (len)
2106 WCHAR wch;
2107 if (ntdll_umbstowcs( s, len, &wch, 1 )) ret = RtlUpcaseUnicodeChar( wch );
2109 break;
2112 default: /* reserved */
2113 FIXME("Unknown wMapType %d !\n", wMapType);
2114 break;
2117 pthread_mutex_unlock( &kbd_mutex );
2118 TRACE( "returning 0x%x.\n", ret );
2119 return ret;
2122 /***********************************************************************
2123 * GetKeyNameText (X11DRV.@)
2125 INT X11DRV_GetKeyNameText( LONG lParam, LPWSTR lpBuffer, INT nSize )
2127 Display *display = thread_init_display();
2128 int vkey, ansi, scanCode;
2129 KeyCode keyc;
2130 int keyi;
2131 KeySym keys;
2132 char *name;
2134 scanCode = lParam >> 16;
2135 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2137 vkey = X11DRV_MapVirtualKeyEx( scanCode, MAPVK_VSC_TO_VK_EX, NtUserGetKeyboardLayout(0) );
2139 /* handle "don't care" bit (0x02000000) */
2140 if (!(lParam & 0x02000000)) {
2141 switch (vkey) {
2142 case VK_RSHIFT:
2143 /* R-Shift is "special" - it is an extended key with separate scan code */
2144 scanCode |= 0x100;
2145 /* fall through */
2146 case VK_LSHIFT:
2147 vkey = VK_SHIFT;
2148 break;
2149 case VK_LCONTROL:
2150 case VK_RCONTROL:
2151 vkey = VK_CONTROL;
2152 break;
2153 case VK_LMENU:
2154 case VK_RMENU:
2155 vkey = VK_MENU;
2156 break;
2160 ansi = X11DRV_MapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, NtUserGetKeyboardLayout(0) );
2161 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2163 /* first get the name of the "regular" keys which is the Upper case
2164 value of the keycap imprint. */
2165 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2166 (scanCode != 0x137) && /* PrtScn */
2167 (scanCode != 0x135) && /* numpad / */
2168 (scanCode != 0x37 ) && /* numpad * */
2169 (scanCode != 0x4a ) && /* numpad - */
2170 (scanCode != 0x4e ) ) /* numpad + */
2172 if (nSize >= 2)
2174 *lpBuffer = RtlUpcaseUnicodeChar( ansi );
2175 *(lpBuffer+1) = 0;
2176 return 1;
2178 else
2179 return 0;
2182 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2183 without "extended-key" flag. However Wine generates scancode
2184 *with* "extended-key" flag. Seems to occur *only* for the
2185 function keys. Soooo.. We will leave the table alone and
2186 fudge the lookup here till the other part is found and fixed!!! */
2188 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2189 (scanCode == 0x157) || (scanCode == 0x158))
2190 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2192 /* let's do scancode -> keycode -> keysym -> String */
2194 pthread_mutex_lock( &kbd_mutex );
2196 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2197 if ((keyc2scan[keyi]) == scanCode)
2198 break;
2199 if (keyi <= max_keycode)
2201 INT rc;
2203 keyc = (KeyCode) keyi;
2204 keys = keycode_to_keysym(display, keyc, 0);
2205 name = XKeysymToString(keys);
2207 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2209 char* idx = strrchr(name, '_');
2210 if (idx && (idx[1] == 'r' || idx[1] == 'R' || idx[1] == 'l' || idx[1] == 'L') && !idx[2])
2212 pthread_mutex_unlock( &kbd_mutex );
2213 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2214 scanCode, keyc, keys, debugstr_an(name,idx-name));
2215 rc = ntdll_umbstowcs( name, idx - name + 1, lpBuffer, nSize );
2216 if (!rc) rc = nSize;
2217 lpBuffer[--rc] = 0;
2218 return rc;
2222 if (name)
2224 pthread_mutex_unlock( &kbd_mutex );
2225 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2226 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2227 rc = ntdll_umbstowcs( name, strlen(name) + 1, lpBuffer, nSize );
2228 if (!rc) rc = nSize;
2229 lpBuffer[--rc] = 0;
2230 return rc;
2234 /* Finally issue WARN for unknown keys */
2236 pthread_mutex_unlock( &kbd_mutex );
2237 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",(int)lParam,lpBuffer,nSize,vkey,ansi);
2238 *lpBuffer = 0;
2239 return 0;
2242 /***********************************************************************
2243 * X11DRV_KEYBOARD_MapDeadKeysym
2245 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2247 switch (keysym)
2249 /* symbolic ASCII is the same as defined in rfc1345 */
2250 #ifdef XK_dead_tilde
2251 case XK_dead_tilde :
2252 #endif
2253 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2254 return '~'; /* '? */
2255 #ifdef XK_dead_acute
2256 case XK_dead_acute :
2257 #endif
2258 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2259 return 0xb4; /* '' */
2260 #ifdef XK_dead_circumflex
2261 case XK_dead_circumflex:
2262 #endif
2263 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2264 return '^'; /* '> */
2265 #ifdef XK_dead_grave
2266 case XK_dead_grave :
2267 #endif
2268 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2269 return '`'; /* '! */
2270 #ifdef XK_dead_diaeresis
2271 case XK_dead_diaeresis :
2272 #endif
2273 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2274 return 0xa8; /* ': */
2275 #ifdef XK_dead_cedilla
2276 case XK_dead_cedilla :
2277 return 0xb8; /* ', */
2278 #endif
2279 #ifdef XK_dead_macron
2280 case XK_dead_macron :
2281 return '-'; /* 'm isn't defined on iso-8859-x */
2282 #endif
2283 #ifdef XK_dead_breve
2284 case XK_dead_breve :
2285 return 0xa2; /* '( */
2286 #endif
2287 #ifdef XK_dead_abovedot
2288 case XK_dead_abovedot :
2289 return 0xff; /* '. */
2290 #endif
2291 #ifdef XK_dead_abovering
2292 case XK_dead_abovering :
2293 return '0'; /* '0 isn't defined on iso-8859-x */
2294 #endif
2295 #ifdef XK_dead_doubleacute
2296 case XK_dead_doubleacute :
2297 return 0xbd; /* '" */
2298 #endif
2299 #ifdef XK_dead_caron
2300 case XK_dead_caron :
2301 return 0xb7; /* '< */
2302 #endif
2303 #ifdef XK_dead_ogonek
2304 case XK_dead_ogonek :
2305 return 0xb2; /* '; */
2306 #endif
2307 /* FIXME: I don't know this three.
2308 case XK_dead_iota :
2309 return 'i';
2310 case XK_dead_voiced_sound :
2311 return 'v';
2312 case XK_dead_semivoiced_sound :
2313 return 's';
2316 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2317 return 0;
2320 /***********************************************************************
2321 * ToUnicodeEx (X11DRV.@)
2323 * The ToUnicode function translates the specified virtual-key code and keyboard
2324 * state to the corresponding Windows character or characters.
2326 * If the specified key is a dead key, the return value is negative. Otherwise,
2327 * it is one of the following values:
2328 * Value Meaning
2329 * 0 The specified virtual key has no translation for the current state of the keyboard.
2330 * 1 One Windows character was copied to the buffer.
2331 * 2 Two characters were copied to the buffer. This usually happens when a
2332 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2333 * be composed with the specified virtual key to form a single character.
2335 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2338 INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2339 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl )
2341 Display *display = thread_init_display();
2342 XKeyEvent e;
2343 KeySym keysym = 0;
2344 INT ret;
2345 int keyc;
2346 char buf[10];
2347 char *lpChar = buf;
2348 HWND focus;
2349 XIC xic;
2350 Status status = 0;
2352 if (scanCode & 0x8000)
2354 TRACE_(key)("Key UP, doing nothing\n" );
2355 return 0;
2358 if (!match_x11_keyboard_layout(hkl))
2359 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2361 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2363 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2364 return 0;
2367 e.display = display;
2368 e.keycode = 0;
2369 e.state = 0;
2370 e.type = KeyPress;
2372 focus = x11drv_thread_data()->last_xic_hwnd;
2373 if (!focus)
2375 focus = get_focus();
2376 if (focus) focus = NtUserGetAncestor( focus, GA_ROOT );
2377 if (!focus) focus = get_active_window();
2379 e.window = X11DRV_get_whole_window( focus );
2380 xic = X11DRV_get_ic( focus );
2382 pthread_mutex_lock( &kbd_mutex );
2384 if (lpKeyState[VK_SHIFT] & 0x80)
2386 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2387 e.state |= ShiftMask;
2389 if (lpKeyState[VK_CAPITAL] & 0x01)
2391 TRACE_(key)("LockMask = %04x\n", LockMask);
2392 e.state |= LockMask;
2394 if (lpKeyState[VK_CONTROL] & 0x80)
2396 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2397 e.state |= ControlMask;
2399 if (lpKeyState[VK_NUMLOCK] & 0x01)
2401 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2402 e.state |= NumLockMask;
2405 /* Restore saved AltGr state */
2406 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2407 e.state |= AltGrMask;
2409 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2410 virtKey, scanCode, e.state);
2412 /* We exit on the first keycode found, to speed up the thing. */
2413 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2414 { /* Find a keycode that could have generated this virtual key */
2415 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2416 { /* We filter the extended bit, we don't know it */
2417 e.keycode = keyc; /* Store it temporarily */
2418 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2419 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2420 state), so set it to 0, we'll find another one */
2425 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2426 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2428 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2429 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2431 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2432 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2433 * in order to produce a locale dependent numeric separator.
2435 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2437 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2438 if (!e.keycode)
2439 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2442 /* Ctrl-Space generates space on Windows */
2443 if (e.state == ControlMask && virtKey == VK_SPACE)
2445 bufW[0] = ' ';
2446 ret = 1;
2447 goto found;
2450 if (!e.keycode && virtKey != VK_NONAME)
2452 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2453 pthread_mutex_unlock( &kbd_mutex );
2454 return 0;
2456 else TRACE_(key)("Found keycode %u\n",e.keycode);
2458 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2459 e.type, e.window, e.state, e.keycode);
2461 /* Clients should pass only KeyPress events to XmbLookupString,
2462 * e.type was set to KeyPress above.
2464 if (xic)
2466 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2467 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2468 if (status == XBufferOverflow)
2470 lpChar = malloc( ret );
2471 if (lpChar == NULL)
2473 ERR_(key)("Failed to allocate memory!\n");
2474 pthread_mutex_unlock( &kbd_mutex );
2475 return 0;
2477 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2480 else
2481 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2483 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2485 if (TRACE_ON(key))
2487 const char *ksname;
2489 ksname = XKeysymToString(keysym);
2490 if (!ksname) ksname = "No Name";
2491 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2492 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2493 keysym, ksname, ret, debugstr_an(lpChar, ret));
2496 if (ret == 0)
2498 char dead_char;
2500 #ifdef XK_EuroSign
2501 /* An ugly hack for EuroSign: X can't translate it to a character
2502 for some locales. */
2503 if (keysym == XK_EuroSign)
2505 bufW[0] = 0x20AC;
2506 ret = 1;
2507 goto found;
2509 #endif
2510 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2511 /* Here we change it back. */
2512 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2514 bufW[0] = 0x09;
2515 ret = 1;
2516 goto found;
2519 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2520 if (dead_char)
2522 ntdll_umbstowcs( &dead_char, 1, bufW, bufW_size );
2523 ret = -1;
2524 goto found;
2527 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2529 /* Unicode direct mapping */
2530 bufW[0] = keysym & 0xffff;
2531 ret = 1;
2532 goto found;
2534 else if ((keysym >> 8) == 0x1008FF) {
2535 bufW[0] = 0;
2536 ret = 0;
2537 goto found;
2539 else
2541 const char *ksname;
2543 ksname = XKeysymToString(keysym);
2544 if (!ksname)
2545 ksname = "No Name";
2546 if ((keysym >> 8) != 0xff)
2548 WARN_(key)("no char for keysym %04lx (%s) :\n",
2549 keysym, ksname);
2550 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2551 virtKey, scanCode, e.keycode, e.state);
2555 else { /* ret != 0 */
2556 /* We have a special case to handle : Shift + arrow, shift + home, ...
2557 X returns a char for it, but Windows doesn't. Let's eat it. */
2558 if (!(e.state & NumLockMask) /* NumLock is off */
2559 && (e.state & ShiftMask) /* Shift is pressed */
2560 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2562 lpChar[0] = 0;
2563 ret = 0;
2566 /* more areas where X returns characters but Windows does not
2567 CTRL + number or CTRL + symbol */
2568 if (e.state & ControlMask)
2570 if (((keysym>=33) && (keysym < '@')) ||
2571 (keysym == '`') ||
2572 (keysym == XK_Tab))
2574 lpChar[0] = 0;
2575 ret = 0;
2579 /* We have another special case for delete key (XK_Delete) on an
2580 extended keyboard. X returns a char for it, but Windows doesn't */
2581 if (keysym == XK_Delete)
2583 lpChar[0] = 0;
2584 ret = 0;
2586 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2587 && (keysym == XK_KP_Decimal))
2589 lpChar[0] = 0;
2590 ret = 0;
2592 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2593 && (keysym == XK_Return || keysym == XK_KP_Enter))
2595 if (lpKeyState[VK_SHIFT] & 0x80)
2597 lpChar[0] = 0;
2598 ret = 0;
2600 else
2602 lpChar[0] = '\n';
2603 ret = 1;
2607 /* Hack to detect an XLookupString hard-coded to Latin1 */
2608 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2610 bufW[0] = (BYTE)lpChar[0];
2611 goto found;
2614 /* perform translation to unicode */
2615 if(ret)
2617 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2618 ret = ntdll_umbstowcs( lpChar, ret, bufW, bufW_size );
2622 found:
2623 if (buf != lpChar)
2624 free( lpChar );
2626 pthread_mutex_unlock( &kbd_mutex );
2628 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2629 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2630 if (1 <= ret && ret < bufW_size)
2631 bufW[ret] = 0;
2633 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2634 return ret;
2637 /***********************************************************************
2638 * Beep (X11DRV.@)
2640 void X11DRV_Beep(void)
2642 XBell(gdi_display, 0);