include: Update the PEB and TEB structures.
[wine.git] / dlls / winex11.drv / keyboard.c
blobb1c47d5258e231c8f26f246e98436adc5efc76b0
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 #include <X11/XKBlib.h>
39 #include <ctype.h>
40 #include <stdarg.h>
41 #include <string.h>
43 #define NONAMELESSUNION
45 #include "x11drv.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "winreg.h"
50 #include "winnls.h"
51 #include "ime.h"
52 #include "wine/server.h"
53 #include "wine/debug.h"
55 /* log format (add 0-padding as appropriate):
56 keycode %u as in output from xev
57 keysym %lx as in X11/keysymdef.h
58 vkey %X as in winuser.h
59 scancode %x
61 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
62 WINE_DECLARE_DEBUG_CHANNEL(key);
64 static const unsigned int ControlMask = 1 << 2;
66 static int min_keycode, max_keycode, keysyms_per_keycode;
67 static WORD keyc2vkey[256], keyc2scan[256];
69 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
71 static pthread_mutex_t kbd_mutex = PTHREAD_MUTEX_INITIALIZER;
73 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
75 /* Keyboard translation tables */
76 #define MAIN_LEN 49
77 static const WORD main_key_scan_qwerty[MAIN_LEN] =
79 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
80 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
81 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
82 /* q w e r t y u i o p [ ] */
83 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
84 /* a s d f g h j k l ; ' \ */
85 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
86 /* z x c v b n m , . / */
87 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
88 0x56 /* the 102nd key (actually to the right of l-shift) */
91 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
93 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
94 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
95 /* q w e r t y u i o p [ ] */
96 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
97 /* a s d f g h j k l ; ' \ */
98 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
99 /* \ z x c v b n m , . / */
100 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
101 0x56, /* the 102nd key (actually to the right of l-shift) */
104 static const WORD main_key_scan_dvorak[MAIN_LEN] =
106 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
107 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
108 /* ' , . p y f g c r l / = */
109 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
110 /* a o e u i d h t n s - \ */
111 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
112 /* ; q j k x b m w v z */
113 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
114 0x56 /* the 102nd key (actually to the right of l-shift) */
117 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
119 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ (Yen) */
120 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7D,
121 /* q w e r t y u i o p @ [ */
122 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
123 /* a s d f g h j k l ; : ] */
124 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
125 /* z x c v b n m , . / \ (Underscore) */
126 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x73
130 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
132 /* NOTE: this layout must concur with the scan codes layout above */
133 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
134 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
135 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
136 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
137 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
140 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
142 /* NOTE: this layout must concur with the scan codes layout above */
143 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
144 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
145 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
146 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
147 VK_OEM_102 /* the 102nd key (actually to the left of r-shift) */
150 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
154 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
155 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
156 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
157 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
160 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
162 /* NOTE: this layout must concur with the scan codes layout above */
163 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
164 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
166 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
167 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
170 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
176 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
177 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_azerty[MAIN_LEN] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
184 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
185 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
186 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
187 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
192 /* NOTE: this layout must concur with the scan codes layout above */
193 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
194 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
195 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
196 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
197 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
200 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
202 /* the VK mappings for the main keyboard will be auto-assigned as before,
203 so what we have here is just the character tables */
204 /* order: Normal, Shift, AltGr, Shift-AltGr */
205 /* We recommend you write just what is guaranteed to be correct (i.e. what's
206 written on the keycaps), not the bunch of special characters behind AltGr
207 and Shift-AltGr if it can vary among different X servers */
208 /* These tables serve to guess the keyboard type and scancode mapping.
209 Complete modeling is not important, identification/discrimination is. */
210 /* Remember that your 102nd key (to the right of l-shift) should be on a
211 separate line, see existing tables */
212 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
213 /* Remember to also add your new table to the layout index table far below! */
215 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
216 static const char main_key_US[MAIN_LEN][4] =
218 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
219 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
220 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
221 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
224 /*** United States keyboard layout (phantom key version) */
225 /* (XFree86 reports the <> key even if it's not physically there) */
226 static const char main_key_US_phantom[MAIN_LEN][4] =
228 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
229 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
230 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
231 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
232 "<>" /* the phantom key */
235 /*** United States keyboard layout (dvorak version) */
236 static const char main_key_US_dvorak[MAIN_LEN][4] =
238 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
239 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
240 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
241 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
244 /*** British keyboard layout */
245 static const char main_key_UK[MAIN_LEN][4] =
247 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
248 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
249 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
250 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
251 "\\|"
254 /*** French keyboard layout (setxkbmap fr) */
255 static const char main_key_FR[MAIN_LEN][4] =
257 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
258 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
259 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
260 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
261 "<>"
264 /*** Icelandic keyboard layout (setxkbmap is) */
265 static const char main_key_IS[MAIN_LEN][4] =
267 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
268 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
269 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
270 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
271 "<>"
274 /* All german keyb layout tables have the acute/apostrophe symbol next to
275 * the BACKSPACE key removed (replaced with NULL which is ignored by the
276 * detection code).
277 * This was done because the mapping of the acute (and apostrophe) is done
278 * differently in various xkb-data/xkeyboard-config versions. Some replace
279 * the acute with a normal apostrophe, so that the apostrophe is found twice
280 * on the keyboard (one next to BACKSPACE and one next to ENTER).
281 * Others put the acute and grave accents on the key left of BACKSPACE.
282 * More information on the fd.o bugtracker:
283 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
284 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
285 * among PC and Mac keyboards, so these are not listed.
288 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
289 static const char main_key_DE[MAIN_LEN][4] =
291 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
292 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
293 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
294 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
295 "<>"
298 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
299 static const char main_key_SG[MAIN_LEN][4] =
301 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
302 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
303 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
304 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
305 "<>"
308 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
309 static const char main_key_SF[MAIN_LEN][4] =
311 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
312 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
313 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
314 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
315 "<>"
318 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
319 static const char main_key_NO[MAIN_LEN][4] =
321 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
322 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
323 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
324 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
325 "<>"
328 /*** Danish keyboard layout (setxkbmap dk) */
329 static const char main_key_DA[MAIN_LEN][4] =
331 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
332 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
333 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
334 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
335 "<>"
338 /*** Swedish keyboard layout (setxkbmap se) */
339 static const char main_key_SE[MAIN_LEN][4] =
341 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
342 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
343 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
344 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
345 "<>"
348 /*** Estonian keyboard layout (setxkbmap ee) */
349 static const char main_key_ET[MAIN_LEN][4] =
351 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
352 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
353 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
354 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
355 "<>"
358 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
359 static const char main_key_CF[MAIN_LEN][4] =
361 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
362 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
363 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
364 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
365 "\xab\xbb\xb0"
368 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
369 static const char main_key_CA_fr[MAIN_LEN][4] =
371 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
372 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
373 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
374 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
375 "\xab\xbb"
378 /*** Canadian keyboard layout (setxkbmap ca) */
379 static const char main_key_CA[MAIN_LEN][4] =
381 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
382 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
383 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
384 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
385 "\xf9\xd9"
388 /*** Portuguese keyboard layout (setxkbmap pt) */
389 static const char main_key_PT[MAIN_LEN][4] =
391 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
392 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
393 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
394 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
395 "<>"
398 /*** Italian keyboard layout (setxkbmap it) */
399 static const char main_key_IT[MAIN_LEN][4] =
401 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
402 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
403 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
404 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
405 "<>"
408 /*** Finnish keyboard layout (setxkbmap fi) */
409 static const char main_key_FI[MAIN_LEN][4] =
411 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
412 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
413 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
414 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
415 "<>"
418 /*** Bulgarian bds keyboard layout */
419 static const char main_key_BG_bds[MAIN_LEN][4] =
421 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
422 "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","]};",
423 "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",
424 "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",
425 "<>" /* the phantom key */
428 /*** Bulgarian phonetic keyboard layout */
429 static const char main_key_BG_phonetic[MAIN_LEN][4] =
431 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
432 "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",
433 "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",
434 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
435 "<>" /* the phantom key */
438 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
439 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
440 static const char main_key_BY[MAIN_LEN][4] =
442 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
443 "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","]}''",
444 "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","\\|/|",
445 "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",
449 /*** Russian keyboard layout (contributed by Pavel Roskin) */
450 static const char main_key_RU[MAIN_LEN][4] =
452 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
453 "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",
454 "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","\\|",
455 "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","/?"
458 /*** Russian keyboard layout (phantom key version) */
459 static const char main_key_RU_phantom[MAIN_LEN][4] =
461 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
462 "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",
463 "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","\\|",
464 "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","/?",
465 "<>" /* the phantom key */
468 /*** Russian keyboard layout KOI8-R */
469 static const char main_key_RU_koi8r[MAIN_LEN][4] =
471 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
472 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
473 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
474 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
475 "<>" /* the phantom key */
478 /*** Russian keyboard layout cp1251 */
479 static const char main_key_RU_cp1251[MAIN_LEN][4] =
481 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
482 "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",
483 "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","\\|",
484 "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","/?",
485 "<>" /* the phantom key */
488 /*** Russian phonetic keyboard layout */
489 static const char main_key_RU_phonetic[MAIN_LEN][4] =
491 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
492 "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",
493 "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",";:","'\"","\\|",
494 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
495 "<>" /* the phantom key */
498 /*** Ukrainian keyboard layout KOI8-U */
499 static const char main_key_UA[MAIN_LEN][4] =
501 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
502 "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",
503 "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","\\|\\|",
504 "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","/?/?",
505 "<>" /* the phantom key */
508 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
509 /*** (as it appears on most of keyboards sold today) */
510 static const char main_key_UA_std[MAIN_LEN][4] =
512 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
513 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
514 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
515 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
516 "<>" /* the phantom key */
519 /*** Russian keyboard layout KOI8-R (pair to the previous) */
520 static const char main_key_RU_std[MAIN_LEN][4] =
522 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
523 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
524 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
525 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
526 "<>" /* the phantom key */
529 /*** Spanish keyboard layout (setxkbmap es) */
530 static const char main_key_ES[MAIN_LEN][4] =
532 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
533 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
534 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
535 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
536 "<>"
539 /*** Belgian keyboard layout ***/
540 static const char main_key_BE[MAIN_LEN][4] =
542 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
543 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
544 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
545 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
546 "<>\\"
549 /*** Hungarian keyboard layout (setxkbmap hu) */
550 static const char main_key_HU[MAIN_LEN][4] =
552 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
553 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
554 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
555 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
556 "\xed\xcd"
559 /*** Polish (programmer's) keyboard layout ***/
560 static const char main_key_PL[MAIN_LEN][4] =
562 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
563 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
564 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
565 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
566 "<>|"
569 /*** Slovenian keyboard layout (setxkbmap si) ***/
570 static const char main_key_SI[MAIN_LEN][4] =
572 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
573 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
574 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
575 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
576 "<>"
579 /*** Serbian keyboard layout (setxkbmap sr) ***/
580 static const char main_key_SR[MAIN_LEN][4] =
582 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
583 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
584 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
585 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
586 "<>" /* the phantom key */
589 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
590 static const char main_key_US_SR[MAIN_LEN][4] =
592 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
593 "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","]}[]",
594 "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","\\|-_",
595 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
596 "<>" /* the phantom key */
599 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
600 static const char main_key_HR_jelly[MAIN_LEN][4] =
602 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
603 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
604 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
605 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
606 "<>|"
609 /*** Croatian keyboard layout (setxkbmap hr) ***/
610 static const char main_key_HR[MAIN_LEN][4] =
612 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
613 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
614 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
615 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
616 "<>"
619 /*** Japanese 106 keyboard layout ***/
620 static const char main_key_JA_jp106[MAIN_LEN][4] =
622 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
623 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
624 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
625 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
626 "\\_",
629 static const char main_key_JA_macjp[MAIN_LEN][4] =
631 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
632 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
633 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
634 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
635 "__",
638 /*** Japanese pc98x1 keyboard layout ***/
639 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
641 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
642 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
643 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
644 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
645 "\\_",
648 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
649 static const char main_key_PT_br[MAIN_LEN][4] =
651 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
652 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
653 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
654 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
657 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
658 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
660 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
661 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
662 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
663 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
666 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
667 static const char main_key_US_intl[MAIN_LEN][4] =
669 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
670 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
671 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
672 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
675 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
676 - dead_abovering replaced with degree - no symbol in iso8859-2
677 - brokenbar replaced with bar */
678 static const char main_key_SK[MAIN_LEN][4] =
680 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
681 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
682 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
683 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
684 "<>"
687 /*** Czech keyboard layout (setxkbmap cz) */
688 static const char main_key_CZ[MAIN_LEN][4] =
690 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
691 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
692 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
693 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
694 "\\"
697 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
698 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
700 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
701 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
702 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
703 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
704 "\\"
707 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
708 static const char main_key_SK_prog[MAIN_LEN][4] =
710 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
711 "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","[{","]}",
712 "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",";:","'\"","\\|",
713 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
714 "<>"
717 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
718 static const char main_key_CS[MAIN_LEN][4] =
720 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
721 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
722 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
723 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
724 "<>\\|"
727 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
728 static const char main_key_LA[MAIN_LEN][4] =
730 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
731 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
732 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
733 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
734 "<>"
737 /*** Lithuanian keyboard layout (setxkbmap lt) */
738 static const char main_key_LT_B[MAIN_LEN][4] =
740 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
741 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
742 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
743 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
744 "\xaa\xac"
747 /*** Turkish keyboard Layout */
748 static const char main_key_TK[MAIN_LEN][4] =
750 "\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
751 "qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
752 "aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
753 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
756 /*** Turkish keyboard layout (setxkbmap tr) */
757 static const char main_key_TR[MAIN_LEN][4] =
759 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
760 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
761 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
762 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
763 "<>"
766 /*** Turkish F keyboard layout (setxkbmap trf) */
767 static const char main_key_TR_F[MAIN_LEN][4] =
769 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
770 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
771 "uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
772 "jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
773 "<>"
776 /*** Israelian keyboard layout (setxkbmap us,il) */
777 static const char main_key_IL[MAIN_LEN][4] =
779 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
780 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
781 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
782 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
783 "<>"
786 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
787 static const char main_key_IL_phonetic[MAIN_LEN][4] =
789 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
790 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
791 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
792 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
793 "<>"
796 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
797 static const char main_key_IL_saharon[MAIN_LEN][4] =
799 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
800 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
801 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
802 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
803 "<>"
806 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
807 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
808 message since they have different characters in gr and el XFree86 layouts. */
809 static const char main_key_EL[MAIN_LEN][4] =
811 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
812 "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","[{","]}",
813 "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","'\"","\\|",
814 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
815 "<>"
818 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
819 static const char main_key_th[MAIN_LEN][4] =
821 "`~_%","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",
822 "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,",
823 "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",
824 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
827 /*** VNC keyboard layout */
828 static const WORD main_key_scan_vnc[MAIN_LEN] =
830 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
831 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,
832 0x56
835 static const WORD main_key_vkey_vnc[MAIN_LEN] =
837 '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,
838 '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',
839 VK_OEM_102
842 static const char main_key_vnc[MAIN_LEN][4] =
844 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
845 "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"
848 /*** Dutch keyboard layout (setxkbmap nl) ***/
849 static const char main_key_NL[MAIN_LEN][4] =
851 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
852 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
853 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
854 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
855 "[]"
860 /*** Layout table. Add your keyboard mappings to this list */
861 static const struct {
862 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
863 in the appropriate dlls/kernel/nls/.nls file */
864 const char *comment;
865 const char (*key)[MAIN_LEN][4];
866 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
867 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
868 } main_key_tab[]={
869 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
870 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
871 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
872 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
873 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
874 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
875 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
876 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
877 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
878 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
879 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
880 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
881 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
882 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
883 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
884 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
885 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
886 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
887 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
888 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
889 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
892 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
895 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
896 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
897 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
898 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
902 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
905 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
906 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
907 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
908 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
909 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
910 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
912 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
913 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
918 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
928 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0, NULL, NULL, NULL, NULL} /* sentinel */
934 static unsigned kbd_layout=0; /* index into above table of layouts */
936 /* maybe more of these scancodes should be extended? */
937 /* extended must be set for ALT_R, CTRL_R,
938 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
939 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
940 /* FIXME should we set extended bit for NumLock ? My
941 * Windows does ... DF */
942 /* Yes, to distinguish based on scan codes, also
943 for PrtScn key ... GA */
945 static const WORD nonchar_key_vkey[256] =
947 /* unused */
948 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
949 /* special keys */
950 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
951 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
952 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
953 /* Japanese special keys */
954 0, VK_KANJI, VK_NONCONVERT, VK_CONVERT, /* FF20 */
955 VK_DBE_ROMAN, 0, 0, VK_DBE_HIRAGANA,
956 0, 0, VK_DBE_SBCSCHAR, 0, 0, 0, 0, 0, /* FF28 */
957 /* Korean special keys (FF31-) */
958 VK_DBE_ALPHANUMERIC, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
959 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
960 /* unused */
961 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
962 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
963 /* cursor keys */
964 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
965 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
966 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
967 /* misc keys */
968 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
969 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
970 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
971 /* keypad keys */
972 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
973 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
974 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
975 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
976 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
977 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
978 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
979 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
980 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
981 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
982 * in order to produce a locale dependent numeric separator.
984 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
985 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
986 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
987 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
988 /* function keys */
989 VK_F1, VK_F2,
990 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
991 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
992 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
993 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
994 /* modifier keys */
995 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
996 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
997 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
998 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
999 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1002 static const WORD nonchar_key_scan[256] =
1004 /* unused */
1005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1006 /* special keys */
1007 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1008 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1009 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1010 /* Japanese special keys */
1011 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */
1012 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1013 /* Korean special keys (FF31-) */
1014 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1015 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1016 /* unused */
1017 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1019 /* cursor keys */
1020 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1022 /* misc keys */
1023 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1024 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1026 /* keypad keys */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1031 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1033 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1034 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1035 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1036 /* function keys */
1037 0x3B, 0x3C,
1038 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1039 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1042 /* modifier keys */
1043 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1044 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1049 static const WORD xfree86_vendor_key_vkey[256] =
1051 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1052 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1053 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1054 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1055 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1056 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1057 0, 0, 0, VK_BROWSER_HOME,
1058 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1059 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1060 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1061 0, 0, 0, 0,
1062 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1063 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1064 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1065 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1066 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1067 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1068 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1069 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1070 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1071 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1072 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1086 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1089 /* Returns the Windows virtual key code associated with the X event <e> */
1090 /* kbd_section must be held */
1091 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1093 KeySym keysym = 0;
1094 Status status;
1095 char buf[24];
1097 /* Clients should pass only KeyPress events to XmbLookupString */
1098 if (xic && e->type == KeyPress)
1099 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1100 else
1101 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1103 if ((e->state & NumLockMask) &&
1104 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1105 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1106 /* Only the Keypad keys 0-9 and . send different keysyms
1107 * depending on the NumLock state */
1108 return nonchar_key_vkey[keysym & 0xFF];
1110 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1111 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1112 if ((e->state & ControlMask) && (keysym == XK_Break))
1113 return VK_CANCEL;
1115 TRACE_(key)("e->keycode = %u\n", e->keycode);
1117 return keyc2vkey[e->keycode];
1121 /***********************************************************************
1122 * X11DRV_send_keyboard_input
1124 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT flags, UINT time )
1126 INPUT input;
1128 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1130 input.type = INPUT_KEYBOARD;
1131 input.u.ki.wVk = vkey;
1132 input.u.ki.wScan = scan;
1133 input.u.ki.dwFlags = flags;
1134 input.u.ki.time = time;
1135 input.u.ki.dwExtraInfo = 0;
1137 __wine_send_input( hwnd, &input, NULL );
1141 /***********************************************************************
1142 * get_async_key_state
1144 static BOOL get_async_key_state( BYTE state[256] )
1146 BOOL ret;
1148 SERVER_START_REQ( get_key_state )
1150 req->async = 1;
1151 req->key = -1;
1152 wine_server_set_reply( req, state, 256 );
1153 ret = !wine_server_call( req );
1155 SERVER_END_REQ;
1156 return ret;
1159 /***********************************************************************
1160 * set_async_key_state
1162 static void set_async_key_state( const BYTE state[256] )
1164 SERVER_START_REQ( set_key_state )
1166 req->async = 1;
1167 wine_server_add_data( req, state, 256 );
1168 wine_server_call( req );
1170 SERVER_END_REQ;
1173 static void update_key_state( BYTE *keystate, BYTE key, int down )
1175 if (down)
1177 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1178 keystate[key] |= 0x80;
1180 else keystate[key] &= ~0x80;
1183 /***********************************************************************
1184 * X11DRV_KeymapNotify
1186 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1188 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1189 * from wine to another application and back.
1190 * Toggle keys are handled in HandleEvent.
1192 BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1194 int i, j;
1195 BYTE keystate[256];
1196 WORD vkey;
1197 BOOL changed = FALSE;
1198 struct {
1199 WORD vkey;
1200 WORD pressed;
1201 } keys[256];
1203 if (!get_async_key_state( keystate )) return FALSE;
1205 memset(keys, 0, sizeof(keys));
1207 pthread_mutex_lock( &kbd_mutex );
1209 /* the minimum keycode is always greater or equal to 8, so we can
1210 * skip the first 8 values, hence start at 1
1212 for (i = 1; i < 32; i++)
1214 for (j = 0; j < 8; j++)
1216 vkey = keyc2vkey[(i * 8) + j];
1218 /* If multiple keys map to the same vkey, we want to report it as
1219 * pressed iff any of them are pressed. */
1220 if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey;
1221 if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE;
1225 for (vkey = 1; vkey <= 0xff; vkey++)
1227 if (keys[vkey].vkey && !(keystate[vkey] & 0x80) != !keys[vkey].pressed)
1229 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1230 keys[vkey].vkey, keystate[vkey]);
1232 update_key_state( keystate, vkey, keys[vkey].pressed );
1233 changed = TRUE;
1237 pthread_mutex_unlock( &kbd_mutex );
1238 if (!changed) return FALSE;
1240 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1241 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1242 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1243 set_async_key_state( keystate );
1244 return TRUE;
1247 static void adjust_lock_state( BYTE *keystate, HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1249 BYTE prev_state = keystate[vkey] & 0x01;
1251 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags, time );
1252 X11DRV_send_keyboard_input( hwnd, vkey, scan, flags ^ KEYEVENTF_KEYUP, time );
1254 /* Keyboard hooks may have blocked processing lock keys causing our state
1255 * to be different than state on X server side. Although Windows allows hooks
1256 * to block changing state, we can't prevent it on X server side. Having
1257 * different states would cause us to try to adjust it again on the next
1258 * key event. We prevent that by overriding hooks and setting key states here. */
1259 if (get_async_key_state( keystate ) && (keystate[vkey] & 0x01) == prev_state)
1261 WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey, keystate[vkey]);
1262 keystate[vkey] ^= 0x01;
1263 set_async_key_state( keystate );
1267 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, UINT time )
1269 BYTE keystate[256];
1271 /* Note: X sets the below states on key down and clears them on key up.
1272 Windows triggers them on key down. */
1274 if (!get_async_key_state( keystate )) return;
1276 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1277 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1279 DWORD flags = 0;
1280 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1281 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1282 adjust_lock_state( keystate, hwnd, VK_CAPITAL, 0x3a, flags, time );
1285 /* Adjust the NUMLOCK state if it has been changed outside wine */
1286 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1288 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1289 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1290 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1291 adjust_lock_state( keystate, hwnd, VK_NUMLOCK, 0x45, flags, time );
1294 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1295 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1297 DWORD flags = 0;
1298 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1299 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1300 adjust_lock_state( keystate, hwnd, VK_SCROLL, 0x46, flags, time );
1304 /***********************************************************************
1305 * X11DRV_KeyEvent
1307 * Handle a X key event
1309 BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1311 XKeyEvent *event = &xev->xkey;
1312 char buf[24];
1313 char *Str = buf;
1314 KeySym keysym = 0;
1315 WORD vkey = 0, bScan;
1316 DWORD dwFlags;
1317 int ascii_chars;
1318 XIC xic = X11DRV_get_ic( hwnd );
1319 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1320 Status status = 0;
1322 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1323 event->type, event->window, event->state, event->keycode);
1325 if (event->type == KeyPress) update_user_time( event->time );
1327 /* Clients should pass only KeyPress events to XmbLookupString */
1328 if (xic && event->type == KeyPress)
1330 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1331 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1332 if (status == XBufferOverflow)
1334 Str = malloc( ascii_chars );
1335 if (Str == NULL)
1337 ERR_(key)("Failed to allocate memory!\n");
1338 return FALSE;
1340 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1343 else
1344 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1346 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1348 if (status == XLookupChars)
1350 X11DRV_XIMLookupChars( Str, ascii_chars );
1351 if (buf != Str)
1352 free( Str );
1353 return TRUE;
1356 pthread_mutex_lock( &kbd_mutex );
1358 /* If XKB extensions are used, the state mask for AltGr will use the group
1359 index instead of the modifier mask. The group index is set in bits
1360 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1361 pressed, look if the group index is different than 0. From XKB
1362 extension documentation, the group index for AltGr should be 2
1363 (event->state = 0x2000). It's probably better to not assume a
1364 predefined group index and find it dynamically
1366 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1367 /* Save also all possible modifier states. */
1368 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1370 if (TRACE_ON(key)){
1371 const char *ksname;
1373 ksname = XKeysymToString(keysym);
1374 if (!ksname)
1375 ksname = "No Name";
1376 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1377 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1378 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1380 if (buf != Str)
1381 free( Str );
1383 vkey = EVENT_event_to_vkey(xic,event);
1384 /* X returns keycode 0 for composed characters */
1385 if (!vkey && ascii_chars) vkey = VK_NONAME;
1386 bScan = keyc2scan[event->keycode] & 0xFF;
1388 TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
1389 event->keycode, vkey, bScan);
1391 pthread_mutex_unlock( &kbd_mutex );
1393 if (!vkey) return FALSE;
1395 dwFlags = 0;
1396 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1397 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1399 update_lock_state( hwnd, vkey, event->state, event_time );
1401 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1402 return TRUE;
1405 /**********************************************************************
1406 * X11DRV_KEYBOARD_DetectLayout
1408 * Called from X11DRV_InitKeyboard
1409 * This routine walks through the defined keyboard layouts and selects
1410 * whichever matches most closely.
1411 * kbd_section must be held.
1413 static void
1414 X11DRV_KEYBOARD_DetectLayout( Display *display )
1416 unsigned current, match, mismatch, seq, i, syms;
1417 int score, keyc, key, pkey, ok;
1418 KeySym keysym = 0;
1419 const char (*lkey)[MAIN_LEN][4];
1420 unsigned max_seq = 0;
1421 int max_score = INT_MIN, ismatch = 0;
1422 char ckey[256][4];
1424 syms = keysyms_per_keycode;
1425 if (syms > 4) {
1426 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1427 syms = 4;
1430 memset( ckey, 0, sizeof(ckey) );
1431 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1432 /* get data for keycode from X server */
1433 for (i = 0; i < syms; i++) {
1434 if (!(keysym = XkbKeycodeToKeysym( display, keyc, 0, i ))) continue;
1435 /* Allow both one-byte and two-byte national keysyms */
1436 if ((keysym < 0x8000) && (keysym != ' '))
1438 if (!XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1440 TRACE("XKB could not translate keysym %04lx\n", keysym);
1441 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1442 * with appropriate ShiftMask and Mode_switch, use XLookupString
1443 * to get character in the local encoding.
1445 ckey[keyc][i] = keysym & 0xFF;
1448 else {
1449 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1454 for (current = 0; main_key_tab[current].comment; current++) {
1455 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1456 match = 0;
1457 mismatch = 0;
1458 score = 0;
1459 seq = 0;
1460 lkey = main_key_tab[current].key;
1461 pkey = -1;
1462 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1463 if (ckey[keyc][0]) {
1464 /* search for a match in layout table */
1465 /* right now, we just find an absolute match for defined positions */
1466 /* (undefined positions are ignored, so if it's defined as "3#" in */
1467 /* the table, it's okay that the X server has "3#£", for example) */
1468 /* however, the score will be higher for longer matches */
1469 for (key = 0; key < MAIN_LEN; key++) {
1470 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1471 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1472 ok++;
1473 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1474 ok = -1;
1476 if (ok > 0) {
1477 score += ok;
1478 break;
1481 /* count the matches and mismatches */
1482 if (ok > 0) {
1483 match++;
1484 /* and how much the keycode order matches */
1485 if (key > pkey) seq++;
1486 pkey = key;
1487 } else {
1488 /* print spaces instead of \0's */
1489 char str[5];
1490 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1491 str[4] = 0;
1492 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, debugstr_a(str));
1493 mismatch++;
1494 score -= syms;
1498 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1499 match, mismatch, seq, score);
1500 if ((score > max_score) ||
1501 ((score == max_score) && (seq > max_seq))) {
1502 /* best match so far */
1503 kbd_layout = current;
1504 max_score = score;
1505 max_seq = seq;
1506 ismatch = !mismatch;
1509 /* we're done, report results if necessary */
1510 if (!ismatch)
1511 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1512 main_key_tab[kbd_layout].comment);
1514 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1518 /**********************************************************************
1519 * X11DRV_InitKeyboard
1521 void X11DRV_InitKeyboard( Display *display )
1523 XModifierKeymap *mmp;
1524 KeySym keysym;
1525 KeyCode *kcp;
1526 XKeyEvent e2;
1527 WORD scan, vkey;
1528 int keyc, i, keyn, syms;
1529 char ckey[4]={0,0,0,0};
1530 const char (*lkey)[MAIN_LEN][4];
1531 char vkey_used[256] = { 0 };
1533 /* Ranges of OEM, function key, and character virtual key codes.
1534 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1535 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1536 static const struct {
1537 WORD first, last;
1538 } vkey_ranges[] = {
1539 { VK_OEM_1, VK_OEM_3 },
1540 { VK_OEM_4, VK_OEM_8 },
1541 { VK_OEM_AX, VK_ICO_00 },
1542 { 0xe6, 0xe6 },
1543 { 0xe9, 0xf5 },
1544 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1545 { VK_F1, VK_F24 },
1546 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1547 { 0x41, 0x5a }, /* VK_A - VK_Z */
1548 { 0, 0 }
1550 int vkey_range;
1552 pthread_mutex_lock( &kbd_mutex );
1553 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1554 XFree( XGetKeyboardMapping( display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode ) );
1556 mmp = XGetModifierMapping(display);
1557 kcp = mmp->modifiermap;
1558 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1560 int j;
1562 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1563 if (*kcp)
1565 int k;
1567 for (k = 0; k < keysyms_per_keycode; k += 1)
1568 if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock)
1570 NumLockMask = 1 << i;
1571 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1573 else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock)
1575 ScrollLockMask = 1 << i;
1576 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1580 XFreeModifiermap(mmp);
1582 /* Detect the keyboard layout */
1583 X11DRV_KEYBOARD_DetectLayout( display );
1584 lkey = main_key_tab[kbd_layout].key;
1585 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1587 /* Now build two conversion arrays :
1588 * keycode -> vkey + scancode + extended
1589 * vkey + extended -> keycode */
1591 e2.display = display;
1592 e2.state = 0;
1593 e2.type = KeyPress;
1595 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1596 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1598 char buf[30];
1599 int have_chars;
1601 keysym = 0;
1602 e2.keycode = (KeyCode)keyc;
1603 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1604 vkey = 0; scan = 0;
1605 if (keysym) /* otherwise, keycode not used */
1607 if ((keysym >> 8) == 0xFF) /* non-character key */
1609 vkey = nonchar_key_vkey[keysym & 0xff];
1610 scan = nonchar_key_scan[keysym & 0xff];
1611 /* set extended bit when necessary */
1612 if (scan & 0x100) vkey |= 0x100;
1613 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1614 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1615 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1616 scan = 0x100;
1617 vkey |= 0x100;
1618 } else if (keysym == 0x20) { /* Spacebar */
1619 vkey = VK_SPACE;
1620 scan = 0x39;
1621 } else if (have_chars) {
1622 /* we seem to need to search the layout-dependent scancodes */
1623 int maxlen=0,maxval=-1,ok;
1624 for (i=0; i<syms; i++) {
1625 keysym = XkbKeycodeToKeysym( display, keyc, 0, i );
1626 if ((keysym<0x8000) && (keysym!=' '))
1628 if (!XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1630 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1631 * with appropriate ShiftMask and Mode_switch, use XLookupString
1632 * to get character in the local encoding.
1634 ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1636 } else {
1637 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1640 /* find key with longest match streak */
1641 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1642 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1643 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1644 if (!ok) i--; /* we overshot */
1645 if (ok||(i>maxlen)) {
1646 maxlen=i; maxval=keyn;
1648 if (ok) break;
1650 if (maxval>=0) {
1651 /* got it */
1652 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1653 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1654 scan = (*lscan)[maxval];
1655 vkey = (*lvkey)[maxval];
1659 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1660 keyc2vkey[e2.keycode] = vkey;
1661 keyc2scan[e2.keycode] = scan;
1662 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1663 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1664 vkey_used[(vkey & 0xff)] = 1;
1665 } /* for */
1667 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1668 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1670 vkey = keyc2vkey[keyc] & 0xff;
1671 if (vkey)
1672 continue;
1674 e2.keycode = (KeyCode)keyc;
1675 keysym = XLookupKeysym(&e2, 0);
1676 if (!keysym)
1677 continue;
1679 /* find a suitable layout-dependent VK code */
1680 /* (most Winelib apps ought to be able to work without layout tables!) */
1681 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1683 keysym = XLookupKeysym(&e2, i);
1684 if ((keysym >= XK_0 && keysym <= XK_9)
1685 || (keysym >= XK_A && keysym <= XK_Z)) {
1686 vkey = VKEY_IF_NOT_USED(keysym);
1690 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1692 keysym = XLookupKeysym(&e2, i);
1693 switch (keysym)
1695 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1696 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1697 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1698 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1699 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1700 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1701 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1702 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1703 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1704 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1705 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1709 if (vkey)
1711 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1712 keyc2vkey[e2.keycode] = vkey;
1714 } /* for */
1716 /* For any keycodes which still don't have a vkey, assign any spare
1717 * character, function key, or OEM virtual key code. */
1718 vkey_range = 0;
1719 vkey = vkey_ranges[vkey_range].first;
1720 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1722 if (keyc2vkey[keyc] & 0xff)
1723 continue;
1725 e2.keycode = (KeyCode)keyc;
1726 keysym = XLookupKeysym(&e2, 0);
1727 if (!keysym)
1728 continue;
1730 while (vkey && vkey_used[vkey])
1732 if (vkey == vkey_ranges[vkey_range].last)
1734 vkey_range++;
1735 vkey = vkey_ranges[vkey_range].first;
1737 else
1738 vkey++;
1741 if (!vkey)
1743 WARN("No more vkeys available!\n");
1744 break;
1747 if (TRACE_ON(keyboard))
1749 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1750 vkey, e2.keycode);
1751 TRACE("(");
1752 for (i = 0; i < keysyms_per_keycode; i += 1)
1754 const char *ksname;
1756 keysym = XLookupKeysym(&e2, i);
1757 ksname = XKeysymToString(keysym);
1758 if (!ksname)
1759 ksname = "NoSymbol";
1760 TRACE( "%lx (%s) ", keysym, ksname);
1762 TRACE(")\n");
1765 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1766 keyc2vkey[e2.keycode] = vkey;
1767 vkey_used[vkey] = 1;
1768 } /* for */
1769 #undef VKEY_IF_NOT_USED
1771 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1772 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1773 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1774 const char *ksname;
1775 keysym = XkbKeycodeToKeysym( display, keyc, 0, 0 );
1776 ksname = XKeysymToString(keysym);
1777 if (!ksname) ksname = "NoSymbol";
1779 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1781 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1782 keyc2scan[keyc]=scan++;
1785 pthread_mutex_unlock( &kbd_mutex );
1789 /***********************************************************************
1790 * ActivateKeyboardLayout (X11DRV.@)
1792 BOOL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1794 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1796 if (flags & KLF_SETFORPROCESS)
1798 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1799 FIXME("KLF_SETFORPROCESS not supported\n");
1800 return FALSE;
1803 return TRUE;
1807 /***********************************************************************
1808 * X11DRV_MappingNotify
1810 BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
1812 HWND hwnd;
1814 XRefreshKeyboardMapping(&event->xmapping);
1815 X11DRV_InitKeyboard( event->xmapping.display );
1817 hwnd = get_focus();
1818 if (!hwnd) hwnd = get_active_window();
1819 NtUserPostMessage( hwnd, WM_INPUTLANGCHANGEREQUEST,
1820 0 /*FIXME*/, (LPARAM)NtUserGetKeyboardLayout(0) );
1821 return TRUE;
1825 /***********************************************************************
1826 * VkKeyScanEx (X11DRV.@)
1828 * Note: Windows ignores HKL parameter and uses current active layout instead
1830 SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl )
1832 Display *display = thread_init_display();
1833 KeyCode keycode;
1834 KeySym keysym;
1835 int index;
1836 CHAR cChar;
1837 SHORT ret;
1839 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
1840 * is UTF-8 (multibyte encoding)?
1842 if (!ntdll_wcstoumbs( &wChar, 1, &cChar, 1, FALSE ))
1844 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1845 return -1;
1848 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1850 /* char->keysym (same for ANSI chars) */
1851 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1852 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1854 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1855 if (!keycode)
1857 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
1859 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
1860 TRACE(" ... returning ctrl char %#.2x\n", ret);
1861 return ret;
1863 /* It didn't work ... let's try with deadchar code. */
1864 TRACE("retrying with | 0xFE00\n");
1865 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
1868 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
1869 if (!keycode) return -1;
1871 pthread_mutex_lock( &kbd_mutex );
1873 /* keycode -> (keyc2vkey) vkey */
1874 ret = keyc2vkey[keycode];
1875 if (!ret)
1877 pthread_mutex_unlock( &kbd_mutex );
1878 TRACE("keycode for '%c' not found, returning -1\n", cChar);
1879 return -1;
1882 for (index = 0; index < 4; index++) /* find shift state */
1883 if (XkbKeycodeToKeysym( display, keycode, 0, index ) == keysym) break;
1885 pthread_mutex_unlock( &kbd_mutex );
1887 switch (index)
1889 case 0: break;
1890 case 1: ret += 0x0100; break;
1891 case 2: ret += 0x0600; break;
1892 case 3: ret += 0x0700; break;
1893 default:
1894 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
1895 return -1;
1898 index : 0 adds 0x0000
1899 index : 1 adds 0x0100 (shift)
1900 index : ? adds 0x0200 (ctrl)
1901 index : 2 adds 0x0600 (ctrl+alt)
1902 index : 3 adds 0x0700 (ctrl+alt+shift)
1905 TRACE(" ... returning %#.2x\n", ret);
1906 return ret;
1909 /***********************************************************************
1910 * MapVirtualKeyEx (X11DRV.@)
1912 UINT X11DRV_MapVirtualKeyEx( UINT wCode, UINT wMapType, HKL hkl )
1914 UINT ret = 0;
1915 int keyc;
1916 Display *display = thread_init_display();
1918 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1920 pthread_mutex_lock( &kbd_mutex );
1922 switch(wMapType)
1924 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
1925 case MAPVK_VK_TO_VSC_EX:
1926 switch (wCode)
1928 case VK_SHIFT: wCode = VK_LSHIFT; break;
1929 case VK_CONTROL: wCode = VK_LCONTROL; break;
1930 case VK_MENU: wCode = VK_LMENU; break;
1933 /* let's do vkey -> keycode -> scan */
1934 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1936 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1938 ret = keyc2scan[keyc] & 0xFF;
1939 break;
1943 /* set scan code prefix */
1944 if (wMapType == MAPVK_VK_TO_VSC_EX &&
1945 (wCode == VK_RCONTROL || wCode == VK_RMENU))
1946 ret |= 0xe000;
1947 break;
1949 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
1950 case MAPVK_VSC_TO_VK_EX:
1952 /* let's do scan -> keycode -> vkey */
1953 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1954 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1956 ret = keyc2vkey[keyc] & 0xFF;
1957 /* Only stop if it's not a numpad vkey; otherwise keep
1958 looking for a potential better vkey. */
1959 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
1960 break;
1963 if (wMapType == MAPVK_VSC_TO_VK)
1964 switch (ret)
1966 case VK_LSHIFT:
1967 case VK_RSHIFT:
1968 ret = VK_SHIFT; break;
1969 case VK_LCONTROL:
1970 case VK_RCONTROL:
1971 ret = VK_CONTROL; break;
1972 case VK_LMENU:
1973 case VK_RMENU:
1974 ret = VK_MENU; break;
1977 break;
1979 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
1981 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1982 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
1983 * key.. Looks like something is wrong with the MS docs?
1984 * This is only true for letters, for example VK_0 returns '0' not ')'.
1985 * - hence we use the lock mask to ensure this happens.
1987 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1988 XKeyEvent e;
1989 KeySym keysym;
1990 int len;
1991 char s[10];
1993 e.display = display;
1994 e.state = 0;
1995 e.keycode = 0;
1996 e.type = KeyPress;
1998 /* We exit on the first keycode found, to speed up the thing. */
1999 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2000 { /* Find a keycode that could have generated this virtual key */
2001 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2002 { /* We filter the extended bit, we don't know it */
2003 e.keycode = keyc; /* Store it temporarily */
2004 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2005 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2006 state), so set it to 0, we'll find another one */
2011 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2012 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2014 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2015 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2016 * in order to produce a locale dependent numeric separator.
2018 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2020 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2021 if (!e.keycode)
2022 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2025 if (!e.keycode)
2027 WARN("Unknown virtual key %X !!!\n", wCode);
2028 break;
2030 TRACE("Found keycode %u\n",e.keycode);
2032 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2033 if (len)
2035 WCHAR wch;
2036 if (ntdll_umbstowcs( s, len, &wch, 1 )) ret = RtlUpcaseUnicodeChar( wch );
2038 break;
2041 default: /* reserved */
2042 FIXME("Unknown wMapType %d !\n", wMapType);
2043 break;
2046 pthread_mutex_unlock( &kbd_mutex );
2047 TRACE( "returning 0x%x.\n", ret );
2048 return ret;
2051 /***********************************************************************
2052 * GetKeyNameText (X11DRV.@)
2054 INT X11DRV_GetKeyNameText( LONG lParam, LPWSTR lpBuffer, INT nSize )
2056 Display *display = thread_init_display();
2057 int vkey, ansi, scanCode;
2058 KeyCode keyc;
2059 int keyi;
2060 KeySym keys;
2061 char *name;
2063 scanCode = lParam >> 16;
2064 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2066 vkey = X11DRV_MapVirtualKeyEx( scanCode, MAPVK_VSC_TO_VK_EX, NtUserGetKeyboardLayout(0) );
2068 /* handle "don't care" bit (0x02000000) */
2069 if (!(lParam & 0x02000000)) {
2070 switch (vkey) {
2071 case VK_RSHIFT:
2072 /* R-Shift is "special" - it is an extended key with separate scan code */
2073 scanCode |= 0x100;
2074 /* fall through */
2075 case VK_LSHIFT:
2076 vkey = VK_SHIFT;
2077 break;
2078 case VK_LCONTROL:
2079 case VK_RCONTROL:
2080 vkey = VK_CONTROL;
2081 break;
2082 case VK_LMENU:
2083 case VK_RMENU:
2084 vkey = VK_MENU;
2085 break;
2089 ansi = X11DRV_MapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, NtUserGetKeyboardLayout(0) );
2090 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2092 /* first get the name of the "regular" keys which is the Upper case
2093 value of the keycap imprint. */
2094 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2095 (scanCode != 0x137) && /* PrtScn */
2096 (scanCode != 0x135) && /* numpad / */
2097 (scanCode != 0x37 ) && /* numpad * */
2098 (scanCode != 0x4a ) && /* numpad - */
2099 (scanCode != 0x4e ) ) /* numpad + */
2101 if (nSize >= 2)
2103 *lpBuffer = RtlUpcaseUnicodeChar( ansi );
2104 *(lpBuffer+1) = 0;
2105 return 1;
2107 else
2108 return 0;
2111 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2112 without "extended-key" flag. However Wine generates scancode
2113 *with* "extended-key" flag. Seems to occur *only* for the
2114 function keys. Soooo.. We will leave the table alone and
2115 fudge the lookup here till the other part is found and fixed!!! */
2117 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2118 (scanCode == 0x157) || (scanCode == 0x158))
2119 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2121 /* let's do scancode -> keycode -> keysym -> String */
2123 pthread_mutex_lock( &kbd_mutex );
2125 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2126 if ((keyc2scan[keyi]) == scanCode)
2127 break;
2128 if (keyi <= max_keycode)
2130 INT rc;
2132 keyc = (KeyCode) keyi;
2133 keys = XkbKeycodeToKeysym( display, keyc, 0, 0 );
2134 name = XKeysymToString(keys);
2136 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2138 char* idx = strrchr(name, '_');
2139 if (idx && (idx[1] == 'r' || idx[1] == 'R' || idx[1] == 'l' || idx[1] == 'L') && !idx[2])
2141 pthread_mutex_unlock( &kbd_mutex );
2142 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2143 scanCode, keyc, keys, debugstr_an(name,idx-name));
2144 rc = ntdll_umbstowcs( name, idx - name + 1, lpBuffer, nSize );
2145 if (!rc) rc = nSize;
2146 lpBuffer[--rc] = 0;
2147 return rc;
2151 if (name)
2153 pthread_mutex_unlock( &kbd_mutex );
2154 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2155 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2156 rc = ntdll_umbstowcs( name, strlen(name) + 1, lpBuffer, nSize );
2157 if (!rc) rc = nSize;
2158 lpBuffer[--rc] = 0;
2159 return rc;
2163 /* Finally issue WARN for unknown keys */
2165 pthread_mutex_unlock( &kbd_mutex );
2166 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",(int)lParam,lpBuffer,nSize,vkey,ansi);
2167 *lpBuffer = 0;
2168 return 0;
2171 /***********************************************************************
2172 * X11DRV_KEYBOARD_MapDeadKeysym
2174 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2176 switch (keysym)
2178 /* symbolic ASCII is the same as defined in rfc1345 */
2179 #ifdef XK_dead_tilde
2180 case XK_dead_tilde :
2181 #endif
2182 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2183 return '~'; /* '? */
2184 #ifdef XK_dead_acute
2185 case XK_dead_acute :
2186 #endif
2187 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2188 return 0xb4; /* '' */
2189 #ifdef XK_dead_circumflex
2190 case XK_dead_circumflex:
2191 #endif
2192 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2193 return '^'; /* '> */
2194 #ifdef XK_dead_grave
2195 case XK_dead_grave :
2196 #endif
2197 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2198 return '`'; /* '! */
2199 #ifdef XK_dead_diaeresis
2200 case XK_dead_diaeresis :
2201 #endif
2202 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2203 return 0xa8; /* ': */
2204 #ifdef XK_dead_cedilla
2205 case XK_dead_cedilla :
2206 return 0xb8; /* ', */
2207 #endif
2208 #ifdef XK_dead_macron
2209 case XK_dead_macron :
2210 return '-'; /* 'm isn't defined on iso-8859-x */
2211 #endif
2212 #ifdef XK_dead_breve
2213 case XK_dead_breve :
2214 return 0xa2; /* '( */
2215 #endif
2216 #ifdef XK_dead_abovedot
2217 case XK_dead_abovedot :
2218 return 0xff; /* '. */
2219 #endif
2220 #ifdef XK_dead_abovering
2221 case XK_dead_abovering :
2222 return '0'; /* '0 isn't defined on iso-8859-x */
2223 #endif
2224 #ifdef XK_dead_doubleacute
2225 case XK_dead_doubleacute :
2226 return 0xbd; /* '" */
2227 #endif
2228 #ifdef XK_dead_caron
2229 case XK_dead_caron :
2230 return 0xb7; /* '< */
2231 #endif
2232 #ifdef XK_dead_ogonek
2233 case XK_dead_ogonek :
2234 return 0xb2; /* '; */
2235 #endif
2236 /* FIXME: I don't know this three.
2237 case XK_dead_iota :
2238 return 'i';
2239 case XK_dead_voiced_sound :
2240 return 'v';
2241 case XK_dead_semivoiced_sound :
2242 return 's';
2245 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2246 return 0;
2249 /***********************************************************************
2250 * ToUnicodeEx (X11DRV.@)
2252 * The ToUnicode function translates the specified virtual-key code and keyboard
2253 * state to the corresponding Windows character or characters.
2255 * If the specified key is a dead key, the return value is negative. Otherwise,
2256 * it is one of the following values:
2257 * Value Meaning
2258 * 0 The specified virtual key has no translation for the current state of the keyboard.
2259 * 1 One Windows character was copied to the buffer.
2260 * 2 Two characters were copied to the buffer. This usually happens when a
2261 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2262 * be composed with the specified virtual key to form a single character.
2264 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2267 INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2268 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl )
2270 Display *display = thread_init_display();
2271 XKeyEvent e;
2272 KeySym keysym = 0;
2273 INT ret;
2274 int keyc;
2275 char buf[10];
2276 char *lpChar = buf;
2277 HWND focus;
2278 XIC xic;
2279 Status status = 0;
2281 if (scanCode & 0x8000)
2283 TRACE_(key)("Key UP, doing nothing\n" );
2284 return 0;
2287 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2289 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2290 return 0;
2293 e.display = display;
2294 e.keycode = 0;
2295 e.state = 0;
2296 e.type = KeyPress;
2298 focus = x11drv_thread_data()->last_xic_hwnd;
2299 if (!focus)
2301 focus = get_focus();
2302 if (focus) focus = NtUserGetAncestor( focus, GA_ROOT );
2303 if (!focus) focus = get_active_window();
2305 e.window = X11DRV_get_whole_window( focus );
2306 xic = X11DRV_get_ic( focus );
2308 pthread_mutex_lock( &kbd_mutex );
2310 if (lpKeyState[VK_SHIFT] & 0x80)
2312 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2313 e.state |= ShiftMask;
2315 if (lpKeyState[VK_CAPITAL] & 0x01)
2317 TRACE_(key)("LockMask = %04x\n", LockMask);
2318 e.state |= LockMask;
2320 if (lpKeyState[VK_CONTROL] & 0x80)
2322 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2323 e.state |= ControlMask;
2325 if (lpKeyState[VK_NUMLOCK] & 0x01)
2327 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2328 e.state |= NumLockMask;
2331 /* Restore saved AltGr state */
2332 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2333 e.state |= AltGrMask;
2335 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2336 virtKey, scanCode, e.state);
2338 /* We exit on the first keycode found, to speed up the thing. */
2339 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2340 { /* Find a keycode that could have generated this virtual key */
2341 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2342 { /* We filter the extended bit, we don't know it */
2343 e.keycode = keyc; /* Store it temporarily */
2344 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2345 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2346 state), so set it to 0, we'll find another one */
2351 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2352 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2354 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2355 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2357 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2358 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2359 * in order to produce a locale dependent numeric separator.
2361 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2363 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2364 if (!e.keycode)
2365 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2368 /* Ctrl-Space generates space on Windows */
2369 if (e.state == ControlMask && virtKey == VK_SPACE)
2371 bufW[0] = ' ';
2372 ret = 1;
2373 goto found;
2376 if (!e.keycode && virtKey != VK_NONAME)
2378 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2379 pthread_mutex_unlock( &kbd_mutex );
2380 return 0;
2382 else TRACE_(key)("Found keycode %u\n",e.keycode);
2384 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2385 e.type, e.window, e.state, e.keycode);
2387 /* Clients should pass only KeyPress events to XmbLookupString,
2388 * e.type was set to KeyPress above.
2390 if (xic)
2392 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2393 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2394 if (status == XBufferOverflow)
2396 lpChar = malloc( ret );
2397 if (lpChar == NULL)
2399 ERR_(key)("Failed to allocate memory!\n");
2400 pthread_mutex_unlock( &kbd_mutex );
2401 return 0;
2403 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2406 else
2407 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2409 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2411 if (TRACE_ON(key))
2413 const char *ksname;
2415 ksname = XKeysymToString(keysym);
2416 if (!ksname) ksname = "No Name";
2417 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2418 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2419 keysym, ksname, ret, debugstr_an(lpChar, ret));
2422 if (ret == 0)
2424 char dead_char;
2426 #ifdef XK_EuroSign
2427 /* An ugly hack for EuroSign: X can't translate it to a character
2428 for some locales. */
2429 if (keysym == XK_EuroSign)
2431 bufW[0] = 0x20AC;
2432 ret = 1;
2433 goto found;
2435 #endif
2436 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2437 /* Here we change it back. */
2438 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2440 bufW[0] = 0x09;
2441 ret = 1;
2442 goto found;
2445 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2446 if (dead_char)
2448 ntdll_umbstowcs( &dead_char, 1, bufW, bufW_size );
2449 ret = -1;
2450 goto found;
2453 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2455 /* Unicode direct mapping */
2456 bufW[0] = keysym & 0xffff;
2457 ret = 1;
2458 goto found;
2460 else if ((keysym >> 8) == 0x1008FF) {
2461 bufW[0] = 0;
2462 ret = 0;
2463 goto found;
2465 else
2467 const char *ksname;
2469 ksname = XKeysymToString(keysym);
2470 if (!ksname)
2471 ksname = "No Name";
2472 if ((keysym >> 8) != 0xff)
2474 WARN_(key)("no char for keysym %04lx (%s) :\n",
2475 keysym, ksname);
2476 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2477 virtKey, scanCode, e.keycode, e.state);
2481 else { /* ret != 0 */
2482 /* We have a special case to handle : Shift + arrow, shift + home, ...
2483 X returns a char for it, but Windows doesn't. Let's eat it. */
2484 if (!(e.state & NumLockMask) /* NumLock is off */
2485 && (e.state & ShiftMask) /* Shift is pressed */
2486 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2488 lpChar[0] = 0;
2489 ret = 0;
2492 /* more areas where X returns characters but Windows does not
2493 CTRL + number or CTRL + symbol */
2494 if (e.state & ControlMask)
2496 if (((keysym>=33) && (keysym < '@')) ||
2497 (keysym == '`') ||
2498 (keysym == XK_Tab))
2500 lpChar[0] = 0;
2501 ret = 0;
2505 /* We have another special case for delete key (XK_Delete) on an
2506 extended keyboard. X returns a char for it, but Windows doesn't */
2507 if (keysym == XK_Delete)
2509 lpChar[0] = 0;
2510 ret = 0;
2512 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2513 && (keysym == XK_KP_Decimal))
2515 lpChar[0] = 0;
2516 ret = 0;
2518 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2519 && (keysym == XK_Return || keysym == XK_KP_Enter))
2521 if (lpKeyState[VK_SHIFT] & 0x80)
2523 lpChar[0] = 0;
2524 ret = 0;
2526 else
2528 lpChar[0] = '\n';
2529 ret = 1;
2533 /* Hack to detect an XLookupString hard-coded to Latin1 */
2534 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2536 bufW[0] = (BYTE)lpChar[0];
2537 goto found;
2540 /* perform translation to unicode */
2541 if(ret)
2543 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2544 ret = ntdll_umbstowcs( lpChar, ret, bufW, bufW_size );
2548 found:
2549 if (buf != lpChar)
2550 free( lpChar );
2552 pthread_mutex_unlock( &kbd_mutex );
2554 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2555 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2556 if (1 <= ret && ret < bufW_size)
2557 bufW[ret] = 0;
2559 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2560 return ret;
2563 /***********************************************************************
2564 * Beep (X11DRV.@)
2566 void X11DRV_Beep(void)
2568 XBell(gdi_display, 0);