schedsvc: Retry opening a .job file only in case of sharing violation.
[wine.git] / dlls / winex11.drv / keyboard.c
blob62c115c8ca5163932524b306545db52df7b8d57f
1 /*
2 * X11 keyboard driver
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
35 #endif
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
41 #define NONAMELESSUNION
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wingdi.h"
46 #include "winuser.h"
47 #include "winreg.h"
48 #include "winnls.h"
49 #include "ime.h"
50 #include "x11drv.h"
51 #include "wine/server.h"
52 #include "wine/unicode.h"
53 #include "wine/debug.h"
55 /* log format (add 0-padding as appropriate):
56 keycode %u as in output from xev
57 keysym %lx as in X11/keysymdef.h
58 vkey %X as in winuser.h
59 scancode %x
61 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
62 WINE_DECLARE_DEBUG_CHANNEL(key);
64 static int min_keycode, max_keycode, keysyms_per_keycode;
65 static KeySym *key_mapping;
66 static WORD keyc2vkey[256], keyc2scan[256];
68 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
70 static CRITICAL_SECTION kbd_section;
71 static CRITICAL_SECTION_DEBUG critsect_debug =
73 0, 0, &kbd_section,
74 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": kbd_section") }
77 static CRITICAL_SECTION kbd_section = { &critsect_debug, -1, 0, 0, 0, 0 };
79 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
81 /* Keyboard translation tables */
82 #define MAIN_LEN 49
83 static const WORD main_key_scan_qwerty[MAIN_LEN] =
85 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
86 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
87 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
88 /* q w e r t y u i o p [ ] */
89 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
90 /* a s d f g h j k l ; ' \ */
91 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
92 /* z x c v b n m , . / */
93 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
94 0x56 /* the 102nd key (actually to the right of l-shift) */
97 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
99 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
100 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
101 /* q w e r t y u i o p [ ] */
102 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
103 /* a s d f g h j k l ; ' \ */
104 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
105 /* \ z x c v b n m , . / */
106 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
107 0x56, /* the 102nd key (actually to the right of l-shift) */
110 static const WORD main_key_scan_dvorak[MAIN_LEN] =
112 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
113 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
114 /* ' , . p y f g c r l / = */
115 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
116 /* a o e u i d h t n s - \ */
117 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
118 /* ; q j k x b m w v z */
119 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
120 0x56 /* the 102nd key (actually to the right of l-shift) */
123 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
125 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
126 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
127 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
128 /* q w e r t y u i o p @ [ */
129 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
130 /* a s d f g h j k l ; : ] */
131 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
132 /* z x c v b n m , . / */
133 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
134 0x56 /* the 102nd key (actually to the right of l-shift) */
137 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
139 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
140 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
141 /* q w e r t y u i o p @ [ */
142 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
143 /* a s d f g h j k l ; : ] */
144 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
145 /* z x c v b n m , . / */
146 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
147 0x73 /* the 102nd key (actually to the right of l-shift) */
151 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
153 /* NOTE: this layout must concur with the scan codes layout above */
154 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
155 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
156 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
157 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
158 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
161 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
163 /* NOTE: this layout must concur with the scan codes layout above */
164 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
165 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
166 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
167 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
168 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
171 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
173 /* NOTE: this layout must concur with the scan codes layout above */
174 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
175 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
176 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
177 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
178 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
181 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
183 /* NOTE: this layout must concur with the scan codes layout above */
184 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
185 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
186 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
187 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
188 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
191 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
193 /* NOTE: this layout must concur with the scan codes layout above */
194 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
195 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
196 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
197 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
198 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
201 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
203 /* NOTE: this layout must concur with the scan codes layout above */
204 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
205 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
206 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
207 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
208 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
211 static const WORD main_key_vkey_azerty[MAIN_LEN] =
213 /* NOTE: this layout must concur with the scan codes layout above */
214 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
215 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
216 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
217 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
218 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
221 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
223 /* NOTE: this layout must concur with the scan codes layout above */
224 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
225 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
226 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
227 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
228 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
231 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
233 /* the VK mappings for the main keyboard will be auto-assigned as before,
234 so what we have here is just the character tables */
235 /* order: Normal, Shift, AltGr, Shift-AltGr */
236 /* We recommend you write just what is guaranteed to be correct (i.e. what's
237 written on the keycaps), not the bunch of special characters behind AltGr
238 and Shift-AltGr if it can vary among different X servers */
239 /* These tables serve to guess the keyboard type and scancode mapping.
240 Complete modeling is not important, identification/discrimination is. */
241 /* Remember that your 102nd key (to the right of l-shift) should be on a
242 separate line, see existing tables */
243 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
244 /* Remember to also add your new table to the layout index table far below! */
246 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
247 static const char main_key_US[MAIN_LEN][4] =
249 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
250 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
251 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
252 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
255 /*** United States keyboard layout (phantom key version) */
256 /* (XFree86 reports the <> key even if it's not physically there) */
257 static const char main_key_US_phantom[MAIN_LEN][4] =
259 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
260 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
261 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
262 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
263 "<>" /* the phantom key */
266 /*** United States keyboard layout (dvorak version) */
267 static const char main_key_US_dvorak[MAIN_LEN][4] =
269 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
270 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
271 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
272 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
275 /*** British keyboard layout */
276 static const char main_key_UK[MAIN_LEN][4] =
278 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
279 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
280 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
281 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
282 "\\|"
285 /*** French keyboard layout (setxkbmap fr) */
286 static const char main_key_FR[MAIN_LEN][4] =
288 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
289 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
290 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
291 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
292 "<>"
295 /*** Icelandic keyboard layout (setxkbmap is) */
296 static const char main_key_IS[MAIN_LEN][4] =
298 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
299 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
300 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
301 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
302 "<>"
305 /* All german keyb layout tables have the acute/apostrophe symbol next to
306 * the BACKSPACE key removed (replaced with NULL which is ignored by the
307 * detection code).
308 * This was done because the mapping of the acute (and apostrophe) is done
309 * differently in various xkb-data/xkeyboard-config versions. Some replace
310 * the acute with a normal apostrophe, so that the apostrophe is found twice
311 * on the keyboard (one next to BACKSPACE and one next to ENTER).
312 * Others put the acute and grave accents on the key left of BACKSPACE.
313 * More information on the fd.o bugtracker:
314 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
315 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
316 * among PC and Mac keyboards, so these are not listed.
319 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
320 static const char main_key_DE[MAIN_LEN][4] =
322 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
323 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
325 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
326 "<>"
329 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
330 static const char main_key_SG[MAIN_LEN][4] =
332 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
333 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
334 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
335 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
336 "<>"
339 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
340 static const char main_key_SF[MAIN_LEN][4] =
342 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
343 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
344 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
345 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
346 "<>"
349 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
350 static const char main_key_NO[MAIN_LEN][4] =
352 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
353 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
354 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
355 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
356 "<>"
359 /*** Danish keyboard layout (setxkbmap dk) */
360 static const char main_key_DA[MAIN_LEN][4] =
362 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
363 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
364 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
365 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
366 "<>"
369 /*** Swedish keyboard layout (setxkbmap se) */
370 static const char main_key_SE[MAIN_LEN][4] =
372 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
373 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
374 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
375 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
376 "<>"
379 /*** Estonian keyboard layout (setxkbmap ee) */
380 static const char main_key_ET[MAIN_LEN][4] =
382 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
383 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
384 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
385 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
386 "<>"
389 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
390 static const char main_key_CF[MAIN_LEN][4] =
392 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
393 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
394 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
395 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
396 "\xab\xbb\xb0"
399 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
400 static const char main_key_CA_fr[MAIN_LEN][4] =
402 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
403 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
404 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
405 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
406 "\xab\xbb"
409 /*** Canadian keyboard layout (setxkbmap ca) */
410 static const char main_key_CA[MAIN_LEN][4] =
412 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
413 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
414 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
415 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
416 "\xf9\xd9"
419 /*** Portuguese keyboard layout (setxkbmap pt) */
420 static const char main_key_PT[MAIN_LEN][4] =
422 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
423 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
424 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
425 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
426 "<>"
429 /*** Italian keyboard layout (setxkbmap it) */
430 static const char main_key_IT[MAIN_LEN][4] =
432 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
433 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
434 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
435 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
436 "<>"
439 /*** Finnish keyboard layout (setxkbmap fi) */
440 static const char main_key_FI[MAIN_LEN][4] =
442 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
443 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
444 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
445 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
446 "<>"
449 /*** Bulgarian bds keyboard layout */
450 static const char main_key_BG_bds[MAIN_LEN][4] =
452 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
453 "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","]};",
454 "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",
455 "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",
456 "<>" /* the phantom key */
459 /*** Bulgarian phonetic keyboard layout */
460 static const char main_key_BG_phonetic[MAIN_LEN][4] =
462 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
463 "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",
464 "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",
465 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
466 "<>" /* the phantom key */
469 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
470 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
471 static const char main_key_BY[MAIN_LEN][4] =
473 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
474 "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","]}''",
475 "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","\\|/|",
476 "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",
480 /*** Russian keyboard layout (contributed by Pavel Roskin) */
481 static const char main_key_RU[MAIN_LEN][4] =
483 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
484 "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",
485 "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","\\|",
486 "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","/?"
489 /*** Russian keyboard layout (phantom key version) */
490 static const char main_key_RU_phantom[MAIN_LEN][4] =
492 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
493 "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",
494 "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","\\|",
495 "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","/?",
496 "<>" /* the phantom key */
499 /*** Russian keyboard layout KOI8-R */
500 static const char main_key_RU_koi8r[MAIN_LEN][4] =
502 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
503 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
504 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
505 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
506 "<>" /* the phantom key */
509 /*** Russian keyboard layout cp1251 */
510 static const char main_key_RU_cp1251[MAIN_LEN][4] =
512 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
513 "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",
514 "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","\\|",
515 "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","/?",
516 "<>" /* the phantom key */
519 /*** Russian phonetic keyboard layout */
520 static const char main_key_RU_phonetic[MAIN_LEN][4] =
522 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
523 "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",
524 "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",";:","'\"","\\|",
525 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
526 "<>" /* the phantom key */
529 /*** Ukrainian keyboard layout KOI8-U */
530 static const char main_key_UA[MAIN_LEN][4] =
532 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
533 "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",
534 "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","\\|\\|",
535 "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","/?/?",
536 "<>" /* the phantom key */
539 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
540 /*** (as it appears on most of keyboards sold today) */
541 static const char main_key_UA_std[MAIN_LEN][4] =
543 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
544 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
545 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
546 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
547 "<>" /* the phantom key */
550 /*** Russian keyboard layout KOI8-R (pair to the previous) */
551 static const char main_key_RU_std[MAIN_LEN][4] =
553 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
554 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
555 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
556 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
557 "<>" /* the phantom key */
560 /*** Spanish keyboard layout (setxkbmap es) */
561 static const char main_key_ES[MAIN_LEN][4] =
563 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
564 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
565 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
566 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
567 "<>"
570 /*** Belgian keyboard layout ***/
571 static const char main_key_BE[MAIN_LEN][4] =
573 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
574 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
575 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
576 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
577 "<>\\"
580 /*** Hungarian keyboard layout (setxkbmap hu) */
581 static const char main_key_HU[MAIN_LEN][4] =
583 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
584 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
585 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
586 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
587 "\xed\xcd"
590 /*** Polish (programmer's) keyboard layout ***/
591 static const char main_key_PL[MAIN_LEN][4] =
593 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
594 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
595 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
596 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
597 "<>|"
600 /*** Slovenian keyboard layout (setxkbmap si) ***/
601 static const char main_key_SI[MAIN_LEN][4] =
603 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
604 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
605 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
606 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
607 "<>"
610 /*** Serbian keyboard layout (setxkbmap sr) ***/
611 static const char main_key_SR[MAIN_LEN][4] =
613 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
614 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
615 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
616 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
617 "<>" /* the phantom key */
620 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
621 static const char main_key_US_SR[MAIN_LEN][4] =
623 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
624 "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","]}[]",
625 "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","\\|-_",
626 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
627 "<>" /* the phantom key */
630 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
631 static const char main_key_HR_jelly[MAIN_LEN][4] =
633 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
634 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
635 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
636 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
637 "<>|"
640 /*** Croatian keyboard layout (setxkbmap hr) ***/
641 static const char main_key_HR[MAIN_LEN][4] =
643 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
644 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
645 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
646 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
647 "<>"
650 /*** Japanese 106 keyboard layout ***/
651 static const char main_key_JA_jp106[MAIN_LEN][4] =
653 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
654 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
655 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
656 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
657 "\\_",
660 static const char main_key_JA_macjp[MAIN_LEN][4] =
662 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
663 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
664 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
665 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
666 "__",
669 /*** Japanese pc98x1 keyboard layout ***/
670 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
672 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
673 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
674 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
675 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
676 "\\_",
679 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
680 static const char main_key_PT_br[MAIN_LEN][4] =
682 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
683 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
684 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
685 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
688 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
689 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
691 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
692 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
693 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
694 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
697 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
698 static const char main_key_US_intl[MAIN_LEN][4] =
700 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
701 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
702 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
703 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
706 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
707 - dead_abovering replaced with degree - no symbol in iso8859-2
708 - brokenbar replaced with bar */
709 static const char main_key_SK[MAIN_LEN][4] =
711 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
712 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
713 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
714 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
715 "<>"
718 /*** Czech keyboard layout (setxkbmap cz) */
719 static const char main_key_CZ[MAIN_LEN][4] =
721 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
722 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
723 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
724 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
725 "\\"
728 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
729 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
731 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
732 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
733 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
734 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
735 "\\"
738 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
739 static const char main_key_SK_prog[MAIN_LEN][4] =
741 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
742 "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","[{","]}",
743 "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",";:","'\"","\\|",
744 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
745 "<>"
748 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
749 static const char main_key_CS[MAIN_LEN][4] =
751 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
752 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
753 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
754 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
755 "<>\\|"
758 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
759 static const char main_key_LA[MAIN_LEN][4] =
761 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
762 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
763 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
764 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
765 "<>"
768 /*** Lithuanian keyboard layout (setxkbmap lt) */
769 static const char main_key_LT_B[MAIN_LEN][4] =
771 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
772 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
773 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
774 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
775 "\xaa\xac"
778 /*** Turkish keyboard Layout */
779 static const char main_key_TK[MAIN_LEN][4] =
781 "\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
782 "qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
783 "aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
784 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
787 /*** Turkish keyboard layout (setxkbmap tr) */
788 static const char main_key_TR[MAIN_LEN][4] =
790 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
791 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
792 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
793 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
794 "<>"
797 /*** Turkish F keyboard layout (setxkbmap trf) */
798 static const char main_key_TR_F[MAIN_LEN][4] =
800 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
801 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
802 "uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
803 "jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
804 "<>"
807 /*** Israelian keyboard layout (setxkbmap us,il) */
808 static const char main_key_IL[MAIN_LEN][4] =
810 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
811 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
812 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
813 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
814 "<>"
817 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
818 static const char main_key_IL_phonetic[MAIN_LEN][4] =
820 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
821 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
822 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
823 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
824 "<>"
827 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
828 static const char main_key_IL_saharon[MAIN_LEN][4] =
830 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
831 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
832 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
833 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
834 "<>"
837 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
838 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
839 message since they have different characters in gr and el XFree86 layouts. */
840 static const char main_key_EL[MAIN_LEN][4] =
842 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
843 "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","[{","]}",
844 "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","'\"","\\|",
845 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
846 "<>"
849 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
850 static const char main_key_th[MAIN_LEN][4] =
852 "`~_%","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",
853 "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,",
854 "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",
855 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
858 /*** VNC keyboard layout */
859 static const WORD main_key_scan_vnc[MAIN_LEN] =
861 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
862 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,
863 0x56
866 static const WORD main_key_vkey_vnc[MAIN_LEN] =
868 '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,
869 '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',
870 VK_OEM_102
873 static const char main_key_vnc[MAIN_LEN][4] =
875 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
876 "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"
879 /*** Dutch keyboard layout (setxkbmap nl) ***/
880 static const char main_key_NL[MAIN_LEN][4] =
882 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
883 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
884 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
885 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
886 "[]"
891 /*** Layout table. Add your keyboard mappings to this list */
892 static const struct {
893 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
894 in the appropriate dlls/kernel/nls/.nls file */
895 const char *comment;
896 const char (*key)[MAIN_LEN][4];
897 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
898 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
899 } main_key_tab[]={
900 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
902 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
903 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
906 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
907 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
908 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
909 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
913 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
917 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
919 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
920 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
936 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
938 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
939 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
940 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
941 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
943 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
944 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
948 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
949 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
953 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
955 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
956 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
957 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
958 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
959 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
960 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
961 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
963 {0, NULL, NULL, NULL, NULL} /* sentinel */
965 static unsigned kbd_layout=0; /* index into above table of layouts */
967 /* maybe more of these scancodes should be extended? */
968 /* extended must be set for ALT_R, CTRL_R,
969 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
970 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
971 /* FIXME should we set extended bit for NumLock ? My
972 * Windows does ... DF */
973 /* Yes, to distinguish based on scan codes, also
974 for PrtScn key ... GA */
976 static const WORD nonchar_key_vkey[256] =
978 /* unused */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
980 /* special keys */
981 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
982 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
983 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
984 /* Japanese special keys */
985 0, VK_KANJI, VK_NONCONVERT, VK_CONVERT, /* FF20 */
986 VK_DBE_ROMAN, 0, 0, VK_DBE_HIRAGANA,
987 0, 0, VK_DBE_SBCSCHAR, 0, 0, 0, 0, 0, /* FF28 */
988 /* Korean special keys (FF31-) */
989 VK_DBE_ALPHANUMERIC, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
990 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
991 /* unused */
992 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
993 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
994 /* cursor keys */
995 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
996 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
997 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
998 /* misc keys */
999 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
1000 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
1001 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1002 /* keypad keys */
1003 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
1004 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1005 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
1006 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
1007 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
1008 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1009 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1010 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
1011 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
1012 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
1013 * in order to produce a locale dependent numeric separator.
1015 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1016 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1017 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1018 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1019 /* function keys */
1020 VK_F1, VK_F2,
1021 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1022 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1023 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1024 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1025 /* modifier keys */
1026 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1027 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1028 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1029 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1030 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1033 static const WORD nonchar_key_scan[256] =
1035 /* unused */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1037 /* special keys */
1038 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1039 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1040 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1041 /* Japanese special keys */
1042 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */
1043 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1044 /* Korean special keys (FF31-) */
1045 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1047 /* unused */
1048 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1049 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1050 /* cursor keys */
1051 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1053 /* misc keys */
1054 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1055 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1057 /* keypad keys */
1058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1061 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1062 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1064 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1065 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1066 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1067 /* function keys */
1068 0x3B, 0x3C,
1069 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1070 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1073 /* modifier keys */
1074 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1075 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1080 static const WORD xfree86_vendor_key_vkey[256] =
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1084 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1085 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1086 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1087 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1088 0, 0, 0, VK_BROWSER_HOME,
1089 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1090 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1091 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1092 0, 0, 0, 0,
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1097 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1098 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1099 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1100 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1101 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1102 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1103 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1104 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1105 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1106 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1107 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1108 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1109 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1110 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1111 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1112 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1113 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1114 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1115 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1116 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1117 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1120 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1122 #ifdef HAVE_XKB
1123 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1124 #endif
1125 return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index];
1128 /* Returns the Windows virtual key code associated with the X event <e> */
1129 /* kbd_section must be held */
1130 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1132 KeySym keysym = 0;
1133 Status status;
1134 char buf[24];
1136 /* Clients should pass only KeyPress events to XmbLookupString */
1137 if (xic && e->type == KeyPress)
1138 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1139 else
1140 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1142 if ((e->state & NumLockMask) &&
1143 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1144 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1145 /* Only the Keypad keys 0-9 and . send different keysyms
1146 * depending on the NumLock state */
1147 return nonchar_key_vkey[keysym & 0xFF];
1149 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1150 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1151 if ((e->state & ControlMask) && (keysym == XK_Break))
1152 return VK_CANCEL;
1154 TRACE_(key)("e->keycode = %u\n", e->keycode);
1156 return keyc2vkey[e->keycode];
1160 /***********************************************************************
1161 * X11DRV_send_keyboard_input
1163 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1165 INPUT input;
1167 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1169 input.type = INPUT_KEYBOARD;
1170 input.u.ki.wVk = vkey;
1171 input.u.ki.wScan = scan;
1172 input.u.ki.dwFlags = flags;
1173 input.u.ki.time = time;
1174 input.u.ki.dwExtraInfo = 0;
1176 __wine_send_input( hwnd, &input );
1180 /***********************************************************************
1181 * get_async_key_state
1183 static BOOL get_async_key_state( BYTE state[256] )
1185 BOOL ret;
1187 SERVER_START_REQ( get_key_state )
1189 req->tid = 0;
1190 req->key = -1;
1191 wine_server_set_reply( req, state, 256 );
1192 ret = !wine_server_call( req );
1194 SERVER_END_REQ;
1195 return ret;
1198 /***********************************************************************
1199 * set_async_key_state
1201 static void set_async_key_state( const BYTE state[256] )
1203 SERVER_START_REQ( set_key_state )
1205 req->tid = GetCurrentThreadId();
1206 req->async = 1;
1207 wine_server_add_data( req, state, 256 );
1208 wine_server_call( req );
1210 SERVER_END_REQ;
1213 static void update_key_state( BYTE *keystate, BYTE key, int down )
1215 if (down)
1217 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1218 keystate[key] |= 0x80;
1220 else keystate[key] &= ~0x80;
1223 /***********************************************************************
1224 * X11DRV_KeymapNotify
1226 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1228 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1229 * from wine to another application and back.
1230 * Toggle keys are handled in HandleEvent.
1232 BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1234 int i, j;
1235 BYTE keystate[256];
1236 WORD vkey;
1237 BOOL changed = FALSE;
1238 struct {
1239 WORD vkey;
1240 BOOL pressed;
1241 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1242 BOOL lwin_pressed = FALSE, rwin_pressed = FALSE;
1244 if (!get_async_key_state( keystate )) return FALSE;
1246 memset(modifiers, 0, sizeof(modifiers));
1248 EnterCriticalSection( &kbd_section );
1250 /* the minimum keycode is always greater or equal to 8, so we can
1251 * skip the first 8 values, hence start at 1
1253 for (i = 1; i < 32; i++)
1255 for (j = 0; j < 8; j++)
1257 int m;
1259 vkey = keyc2vkey[(i * 8) + j];
1261 switch(vkey & 0xff)
1263 case VK_LMENU:
1264 case VK_RMENU:
1265 case VK_LCONTROL:
1266 case VK_RCONTROL:
1267 case VK_LSHIFT:
1268 case VK_RSHIFT:
1269 m = (vkey & 0xff) - VK_LSHIFT;
1270 /* Take the vkey from the first keycode we encounter for this modifier */
1271 if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
1272 if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1273 break;
1274 case VK_LWIN:
1275 if (event->xkeymap.key_vector[i] & (1<<j)) lwin_pressed = TRUE;
1276 break;
1277 case VK_RWIN:
1278 if (event->xkeymap.key_vector[i] & (1<<j)) rwin_pressed = TRUE;
1279 break;
1284 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1286 int m = vkey - VK_LSHIFT;
1287 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1289 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1290 modifiers[m].vkey, keystate[vkey]);
1292 update_key_state( keystate, vkey, modifiers[m].pressed );
1293 changed = TRUE;
1297 if (!(keystate[VK_LWIN] & 0x80) != !lwin_pressed)
1299 TRACE( "Adjusting state for VK_LWIN. State before %#.2x\n", keystate[VK_LWIN]);
1300 update_key_state( keystate, VK_LWIN, lwin_pressed );
1301 changed = TRUE;
1303 if (!(keystate[VK_RWIN] & 0x80) != !rwin_pressed)
1305 TRACE( "Adjusting state for VK_RWIN. State before %#.2x\n", keystate[VK_RWIN]);
1306 update_key_state( keystate, VK_RWIN, rwin_pressed );
1307 changed = TRUE;
1310 LeaveCriticalSection( &kbd_section );
1311 if (!changed) return FALSE;
1313 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1314 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1315 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1316 update_key_state( keystate, VK_LWIN, keystate[VK_LWIN] & 0x80 );
1317 update_key_state( keystate, VK_RWIN, keystate[VK_RWIN] & 0x80 );
1318 set_async_key_state( keystate );
1319 return TRUE;
1322 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1324 BYTE keystate[256];
1326 /* Note: X sets the below states on key down and clears them on key up.
1327 Windows triggers them on key down. */
1329 if (!get_async_key_state( keystate )) return;
1331 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1332 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1334 DWORD flags = 0;
1335 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1336 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1337 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1338 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1341 /* Adjust the NUMLOCK state if it has been changed outside wine */
1342 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1344 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1345 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1346 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1347 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1348 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1351 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1352 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1354 DWORD flags = 0;
1355 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1356 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1357 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1358 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1362 /***********************************************************************
1363 * X11DRV_KeyEvent
1365 * Handle a X key event
1367 BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1369 XKeyEvent *event = &xev->xkey;
1370 char buf[24];
1371 char *Str = buf;
1372 KeySym keysym = 0;
1373 WORD vkey = 0, bScan;
1374 DWORD dwFlags;
1375 int ascii_chars;
1376 XIC xic = X11DRV_get_ic( hwnd );
1377 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1378 Status status = 0;
1380 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1381 event->type, event->window, event->state, event->keycode);
1383 if (event->type == KeyPress) update_user_time( event->time );
1385 /* Clients should pass only KeyPress events to XmbLookupString */
1386 if (xic && event->type == KeyPress)
1388 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1389 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1390 if (status == XBufferOverflow)
1392 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1393 if (Str == NULL)
1395 ERR_(key)("Failed to allocate memory!\n");
1396 return FALSE;
1398 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1401 else
1402 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1404 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1406 if (status == XLookupChars)
1408 X11DRV_XIMLookupChars( Str, ascii_chars );
1409 if (buf != Str)
1410 HeapFree(GetProcessHeap(), 0, Str);
1411 return TRUE;
1414 EnterCriticalSection( &kbd_section );
1416 /* If XKB extensions are used, the state mask for AltGr will use the group
1417 index instead of the modifier mask. The group index is set in bits
1418 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1419 pressed, look if the group index is different than 0. From XKB
1420 extension documentation, the group index for AltGr should be 2
1421 (event->state = 0x2000). It's probably better to not assume a
1422 predefined group index and find it dynamically
1424 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1425 /* Save also all possible modifier states. */
1426 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1428 if (TRACE_ON(key)){
1429 const char *ksname;
1431 ksname = XKeysymToString(keysym);
1432 if (!ksname)
1433 ksname = "No Name";
1434 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1435 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1436 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1438 if (buf != Str)
1439 HeapFree(GetProcessHeap(), 0, Str);
1441 vkey = EVENT_event_to_vkey(xic,event);
1442 /* X returns keycode 0 for composed characters */
1443 if (!vkey && ascii_chars) vkey = VK_NONAME;
1444 bScan = keyc2scan[event->keycode] & 0xFF;
1446 TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
1447 event->keycode, vkey, bScan);
1449 LeaveCriticalSection( &kbd_section );
1451 if (!vkey) return FALSE;
1453 dwFlags = 0;
1454 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1455 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1457 update_lock_state( hwnd, vkey, event->state, event_time );
1459 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1460 return TRUE;
1463 /**********************************************************************
1464 * X11DRV_KEYBOARD_DetectLayout
1466 * Called from X11DRV_InitKeyboard
1467 * This routine walks through the defined keyboard layouts and selects
1468 * whichever matches most closely.
1469 * kbd_section must be held.
1471 static void
1472 X11DRV_KEYBOARD_DetectLayout( Display *display )
1474 unsigned current, match, mismatch, seq, i, syms;
1475 int score, keyc, key, pkey, ok;
1476 KeySym keysym = 0;
1477 const char (*lkey)[MAIN_LEN][4];
1478 unsigned max_seq = 0;
1479 int max_score = 0, ismatch = 0;
1480 char ckey[256][4];
1482 syms = keysyms_per_keycode;
1483 if (syms > 4) {
1484 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1485 syms = 4;
1488 memset( ckey, 0, sizeof(ckey) );
1489 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1490 /* get data for keycode from X server */
1491 for (i = 0; i < syms; i++) {
1492 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1493 /* Allow both one-byte and two-byte national keysyms */
1494 if ((keysym < 0x8000) && (keysym != ' '))
1496 #ifdef HAVE_XKB
1497 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1498 #endif
1500 TRACE("XKB could not translate keysym %04lx\n", keysym);
1501 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1502 * with appropriate ShiftMask and Mode_switch, use XLookupString
1503 * to get character in the local encoding.
1505 ckey[keyc][i] = keysym & 0xFF;
1508 else {
1509 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1514 for (current = 0; main_key_tab[current].comment; current++) {
1515 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1516 match = 0;
1517 mismatch = 0;
1518 score = 0;
1519 seq = 0;
1520 lkey = main_key_tab[current].key;
1521 pkey = -1;
1522 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1523 if (ckey[keyc][0]) {
1524 /* search for a match in layout table */
1525 /* right now, we just find an absolute match for defined positions */
1526 /* (undefined positions are ignored, so if it's defined as "3#" in */
1527 /* the table, it's okay that the X server has "3#£", for example) */
1528 /* however, the score will be higher for longer matches */
1529 for (key = 0; key < MAIN_LEN; key++) {
1530 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1531 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1532 ok++;
1533 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1534 ok = -1;
1536 if (ok > 0) {
1537 score += ok;
1538 break;
1541 /* count the matches and mismatches */
1542 if (ok > 0) {
1543 match++;
1544 /* and how much the keycode order matches */
1545 if (key > pkey) seq++;
1546 pkey = key;
1547 } else {
1548 /* print spaces instead of \0's */
1549 char str[5];
1550 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1551 str[4] = 0;
1552 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1553 mismatch++;
1554 score -= syms;
1558 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1559 match, mismatch, seq, score);
1560 if ((score > max_score) ||
1561 ((score == max_score) && (seq > max_seq))) {
1562 /* best match so far */
1563 kbd_layout = current;
1564 max_score = score;
1565 max_seq = seq;
1566 ismatch = !mismatch;
1569 /* we're done, report results if necessary */
1570 if (!ismatch)
1571 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1572 main_key_tab[kbd_layout].comment);
1574 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1577 static HKL get_locale_kbd_layout(void)
1579 ULONG_PTR layout;
1580 LANGID langid;
1582 /* FIXME:
1584 * layout = main_key_tab[kbd_layout].lcid;
1586 * Winword uses return value of GetKeyboardLayout as a codepage
1587 * to translate ANSI keyboard messages to unicode. But we have
1588 * a problem with it: for instance Polish keyboard layout is
1589 * identical to the US one, and therefore instead of the Polish
1590 * locale id we return the US one.
1593 layout = GetUserDefaultLCID();
1596 * Microsoft Office expects this value to be something specific
1597 * for Japanese and Korean Windows with an IME the value is 0xe001
1598 * We should probably check to see if an IME exists and if so then
1599 * set this word properly.
1601 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1602 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1603 layout = MAKELONG( layout, 0xe001 ); /* IME */
1604 else
1605 layout |= layout << 16;
1607 return (HKL)layout;
1610 /***********************************************************************
1611 * GetKeyboardLayoutName (X11DRV.@)
1613 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1615 static const WCHAR formatW[] = {'%','0','8','x',0};
1616 DWORD layout;
1618 layout = HandleToUlong( get_locale_kbd_layout() );
1619 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1620 sprintfW(name, formatW, layout);
1621 TRACE("returning %s\n", debugstr_w(name));
1622 return TRUE;
1625 static void set_kbd_layout_preload_key(void)
1627 static const WCHAR preload[] =
1628 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1629 static const WCHAR one[] = {'1',0};
1631 HKEY hkey;
1632 WCHAR layout[KL_NAMELENGTH];
1634 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1635 return;
1637 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1639 RegCloseKey(hkey);
1640 return;
1642 if (X11DRV_GetKeyboardLayoutName(layout))
1643 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1645 RegCloseKey(hkey);
1648 /**********************************************************************
1649 * X11DRV_InitKeyboard
1651 void X11DRV_InitKeyboard( Display *display )
1653 XModifierKeymap *mmp;
1654 KeySym keysym;
1655 KeyCode *kcp;
1656 XKeyEvent e2;
1657 WORD scan, vkey;
1658 int keyc, i, keyn, syms;
1659 char ckey[4]={0,0,0,0};
1660 const char (*lkey)[MAIN_LEN][4];
1661 char vkey_used[256] = { 0 };
1663 /* Ranges of OEM, function key, and character virtual key codes.
1664 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1665 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1666 static const struct {
1667 WORD first, last;
1668 } vkey_ranges[] = {
1669 { VK_OEM_1, VK_OEM_3 },
1670 { VK_OEM_4, VK_ICO_00 },
1671 { 0xe6, 0xe6 },
1672 { 0xe9, 0xf5 },
1673 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1674 { VK_F1, VK_F24 },
1675 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1676 { 0x41, 0x5a }, /* VK_A - VK_Z */
1677 { 0, 0 }
1679 int vkey_range;
1681 set_kbd_layout_preload_key();
1683 EnterCriticalSection( &kbd_section );
1684 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1685 if (key_mapping) XFree( key_mapping );
1686 key_mapping = XGetKeyboardMapping(display, min_keycode,
1687 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1689 mmp = XGetModifierMapping(display);
1690 kcp = mmp->modifiermap;
1691 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1693 int j;
1695 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1696 if (*kcp)
1698 int k;
1700 for (k = 0; k < keysyms_per_keycode; k += 1)
1701 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1703 NumLockMask = 1 << i;
1704 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1706 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1708 ScrollLockMask = 1 << i;
1709 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1713 XFreeModifiermap(mmp);
1715 /* Detect the keyboard layout */
1716 X11DRV_KEYBOARD_DetectLayout( display );
1717 lkey = main_key_tab[kbd_layout].key;
1718 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1720 /* Now build two conversion arrays :
1721 * keycode -> vkey + scancode + extended
1722 * vkey + extended -> keycode */
1724 e2.display = display;
1725 e2.state = 0;
1726 e2.type = KeyPress;
1728 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1729 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1731 char buf[30];
1732 int have_chars;
1734 keysym = 0;
1735 e2.keycode = (KeyCode)keyc;
1736 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1737 vkey = 0; scan = 0;
1738 if (keysym) /* otherwise, keycode not used */
1740 if ((keysym >> 8) == 0xFF) /* non-character key */
1742 vkey = nonchar_key_vkey[keysym & 0xff];
1743 scan = nonchar_key_scan[keysym & 0xff];
1744 /* set extended bit when necessary */
1745 if (scan & 0x100) vkey |= 0x100;
1746 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1747 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1748 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1749 scan = 0x100;
1750 vkey |= 0x100;
1751 } else if (keysym == 0x20) { /* Spacebar */
1752 vkey = VK_SPACE;
1753 scan = 0x39;
1754 } else if (have_chars) {
1755 /* we seem to need to search the layout-dependent scancodes */
1756 int maxlen=0,maxval=-1,ok;
1757 for (i=0; i<syms; i++) {
1758 keysym = keycode_to_keysym(display, keyc, i);
1759 if ((keysym<0x8000) && (keysym!=' '))
1761 #ifdef HAVE_XKB
1762 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1763 #endif
1765 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1766 * with appropriate ShiftMask and Mode_switch, use XLookupString
1767 * to get character in the local encoding.
1769 ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1771 } else {
1772 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1775 /* find key with longest match streak */
1776 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1777 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1778 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1779 if (!ok) i--; /* we overshot */
1780 if (ok||(i>maxlen)) {
1781 maxlen=i; maxval=keyn;
1783 if (ok) break;
1785 if (maxval>=0) {
1786 /* got it */
1787 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1788 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1789 scan = (*lscan)[maxval];
1790 vkey = (*lvkey)[maxval];
1794 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1795 keyc2vkey[e2.keycode] = vkey;
1796 keyc2scan[e2.keycode] = scan;
1797 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1798 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1799 vkey_used[(vkey & 0xff)] = 1;
1800 } /* for */
1802 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1803 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1805 vkey = keyc2vkey[keyc] & 0xff;
1806 if (vkey)
1807 continue;
1809 e2.keycode = (KeyCode)keyc;
1810 keysym = XLookupKeysym(&e2, 0);
1811 if (!keysym)
1812 continue;
1814 /* find a suitable layout-dependent VK code */
1815 /* (most Winelib apps ought to be able to work without layout tables!) */
1816 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1818 keysym = XLookupKeysym(&e2, i);
1819 if ((keysym >= XK_0 && keysym <= XK_9)
1820 || (keysym >= XK_A && keysym <= XK_Z)) {
1821 vkey = VKEY_IF_NOT_USED(keysym);
1825 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1827 keysym = XLookupKeysym(&e2, i);
1828 switch (keysym)
1830 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1831 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1832 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1833 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1834 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1835 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1836 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1837 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1838 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1839 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1840 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1844 if (vkey)
1846 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1847 keyc2vkey[e2.keycode] = vkey;
1849 } /* for */
1851 /* For any keycodes which still don't have a vkey, assign any spare
1852 * character, function key, or OEM virtual key code. */
1853 vkey_range = 0;
1854 vkey = vkey_ranges[vkey_range].first;
1855 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1857 if (keyc2vkey[keyc] & 0xff)
1858 continue;
1860 e2.keycode = (KeyCode)keyc;
1861 keysym = XLookupKeysym(&e2, 0);
1862 if (!keysym)
1863 continue;
1865 while (vkey && vkey_used[vkey])
1867 if (vkey == vkey_ranges[vkey_range].last)
1869 vkey_range++;
1870 vkey = vkey_ranges[vkey_range].first;
1872 else
1873 vkey++;
1876 if (!vkey)
1878 WARN("No more vkeys available!\n");
1879 break;
1882 if (TRACE_ON(keyboard))
1884 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1885 vkey, e2.keycode);
1886 TRACE("(");
1887 for (i = 0; i < keysyms_per_keycode; i += 1)
1889 const char *ksname;
1891 keysym = XLookupKeysym(&e2, i);
1892 ksname = XKeysymToString(keysym);
1893 if (!ksname)
1894 ksname = "NoSymbol";
1895 TRACE( "%lx (%s) ", keysym, ksname);
1897 TRACE(")\n");
1900 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1901 keyc2vkey[e2.keycode] = vkey;
1902 vkey_used[vkey] = 1;
1903 } /* for */
1904 #undef VKEY_IF_NOT_USED
1906 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1907 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1908 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1909 const char *ksname;
1910 keysym = keycode_to_keysym(display, keyc, 0);
1911 ksname = XKeysymToString(keysym);
1912 if (!ksname) ksname = "NoSymbol";
1914 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1916 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1917 keyc2scan[keyc]=scan++;
1920 LeaveCriticalSection( &kbd_section );
1923 static BOOL match_x11_keyboard_layout(HKL hkl)
1925 const DWORD isIME = 0xE0000000;
1926 HKL xHkl = get_locale_kbd_layout();
1928 /* if the layout is an IME, only match the low word (LCID) */
1929 if (((ULONG_PTR)hkl & isIME) == isIME)
1930 return (LOWORD(hkl) == LOWORD(xHkl));
1931 else
1932 return (hkl == xHkl);
1936 /***********************************************************************
1937 * GetKeyboardLayout (X11DRV.@)
1939 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1941 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1943 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1944 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1946 else
1947 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1949 return get_locale_kbd_layout();
1953 /***********************************************************************
1954 * LoadKeyboardLayout (X11DRV.@)
1956 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1958 FIXME("%s, %04x: semi-stub! Returning default layout.\n", debugstr_w(name), flags);
1959 return get_locale_kbd_layout();
1963 /***********************************************************************
1964 * UnloadKeyboardLayout (X11DRV.@)
1966 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1968 FIXME("%p: stub!\n", hkl);
1969 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1970 return FALSE;
1974 /***********************************************************************
1975 * ActivateKeyboardLayout (X11DRV.@)
1977 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1979 HKL oldHkl = 0;
1980 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1982 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1983 if (flags & KLF_SETFORPROCESS)
1985 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1986 FIXME("KLF_SETFORPROCESS not supported\n");
1987 return 0;
1990 if (flags)
1991 FIXME("flags %x not supported\n",flags);
1993 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1995 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1996 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1997 return 0;
2000 if (!match_x11_keyboard_layout(hkl))
2002 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2003 FIXME("setting keyboard of different locales not supported\n");
2004 return 0;
2007 oldHkl = thread_data->kbd_layout;
2008 if (!oldHkl) oldHkl = get_locale_kbd_layout();
2010 thread_data->kbd_layout = hkl;
2012 return oldHkl;
2016 /***********************************************************************
2017 * X11DRV_MappingNotify
2019 BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
2021 HWND hwnd;
2023 XRefreshKeyboardMapping(&event->xmapping);
2024 X11DRV_InitKeyboard( event->xmapping.display );
2026 hwnd = GetFocus();
2027 if (!hwnd) hwnd = GetActiveWindow();
2028 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2029 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2030 return TRUE;
2034 /***********************************************************************
2035 * VkKeyScanEx (X11DRV.@)
2037 * Note: Windows ignores HKL parameter and uses current active layout instead
2039 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2041 Display *display = thread_init_display();
2042 KeyCode keycode;
2043 KeySym keysym;
2044 int index;
2045 CHAR cChar;
2046 SHORT ret;
2048 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2049 * is UTF-8 (multibyte encoding)?
2051 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2053 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2054 return -1;
2057 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2059 /* char->keysym (same for ANSI chars) */
2060 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2061 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2063 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2064 if (!keycode)
2066 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2068 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2069 TRACE(" ... returning ctrl char %#.2x\n", ret);
2070 return ret;
2072 /* It didn't work ... let's try with deadchar code. */
2073 TRACE("retrying with | 0xFE00\n");
2074 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2077 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2078 if (!keycode) return -1;
2080 EnterCriticalSection( &kbd_section );
2082 /* keycode -> (keyc2vkey) vkey */
2083 ret = keyc2vkey[keycode];
2084 if (!ret)
2086 LeaveCriticalSection( &kbd_section );
2087 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2088 return -1;
2091 for (index = 0; index < 4; index++) /* find shift state */
2092 if (keycode_to_keysym(display, keycode, index) == keysym) break;
2094 LeaveCriticalSection( &kbd_section );
2096 switch (index)
2098 case 0: break;
2099 case 1: ret += 0x0100; break;
2100 case 2: ret += 0x0600; break;
2101 case 3: ret += 0x0700; break;
2102 default:
2103 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2104 return -1;
2107 index : 0 adds 0x0000
2108 index : 1 adds 0x0100 (shift)
2109 index : ? adds 0x0200 (ctrl)
2110 index : 2 adds 0x0600 (ctrl+alt)
2111 index : 3 adds 0x0700 (ctrl+alt+shift)
2114 TRACE(" ... returning %#.2x\n", ret);
2115 return ret;
2118 /***********************************************************************
2119 * MapVirtualKeyEx (X11DRV.@)
2121 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2123 UINT ret = 0;
2124 int keyc;
2125 Display *display = thread_init_display();
2127 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2128 if (!match_x11_keyboard_layout(hkl))
2129 FIXME("keyboard layout %p is not supported\n", hkl);
2131 EnterCriticalSection( &kbd_section );
2133 switch(wMapType)
2135 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2136 case MAPVK_VK_TO_VSC_EX:
2137 switch (wCode)
2139 case VK_SHIFT: wCode = VK_LSHIFT; break;
2140 case VK_CONTROL: wCode = VK_LCONTROL; break;
2141 case VK_MENU: wCode = VK_LMENU; break;
2144 /* let's do vkey -> keycode -> scan */
2145 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2147 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2149 ret = keyc2scan[keyc] & 0xFF;
2150 break;
2153 break;
2155 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2156 case MAPVK_VSC_TO_VK_EX:
2158 /* let's do scan -> keycode -> vkey */
2159 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2160 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2162 ret = keyc2vkey[keyc] & 0xFF;
2163 /* Only stop if it's not a numpad vkey; otherwise keep
2164 looking for a potential better vkey. */
2165 if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
2166 break;
2169 if (wMapType == MAPVK_VSC_TO_VK)
2170 switch (ret)
2172 case VK_LSHIFT:
2173 case VK_RSHIFT:
2174 ret = VK_SHIFT; break;
2175 case VK_LCONTROL:
2176 case VK_RCONTROL:
2177 ret = VK_CONTROL; break;
2178 case VK_LMENU:
2179 case VK_RMENU:
2180 ret = VK_MENU; break;
2183 break;
2185 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2187 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2188 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2189 * key.. Looks like something is wrong with the MS docs?
2190 * This is only true for letters, for example VK_0 returns '0' not ')'.
2191 * - hence we use the lock mask to ensure this happens.
2193 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2194 XKeyEvent e;
2195 KeySym keysym;
2196 int len;
2197 char s[10];
2199 e.display = display;
2200 e.state = 0;
2201 e.keycode = 0;
2202 e.type = KeyPress;
2204 /* We exit on the first keycode found, to speed up the thing. */
2205 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2206 { /* Find a keycode that could have generated this virtual key */
2207 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2208 { /* We filter the extended bit, we don't know it */
2209 e.keycode = keyc; /* Store it temporarily */
2210 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2211 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2212 state), so set it to 0, we'll find another one */
2217 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2218 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2220 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2221 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2222 * in order to produce a locale dependent numeric separator.
2224 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2226 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2227 if (!e.keycode)
2228 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2231 if (!e.keycode)
2233 WARN("Unknown virtual key %X !!!\n", wCode);
2234 break;
2236 TRACE("Found keycode %u\n",e.keycode);
2238 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2239 if (len)
2241 WCHAR wch;
2242 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) ret = toupperW(wch);
2244 break;
2247 default: /* reserved */
2248 FIXME("Unknown wMapType %d !\n", wMapType);
2249 break;
2252 LeaveCriticalSection( &kbd_section );
2253 TRACE( "returning 0x%x.\n", ret );
2254 return ret;
2257 /***********************************************************************
2258 * GetKeyNameText (X11DRV.@)
2260 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2262 Display *display = thread_init_display();
2263 int vkey, ansi, scanCode;
2264 KeyCode keyc;
2265 int keyi;
2266 KeySym keys;
2267 char *name;
2269 scanCode = lParam >> 16;
2270 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2272 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2274 /* handle "don't care" bit (0x02000000) */
2275 if (!(lParam & 0x02000000)) {
2276 switch (vkey) {
2277 case VK_RSHIFT:
2278 /* R-Shift is "special" - it is an extended key with separate scan code */
2279 scanCode |= 0x100;
2280 /* fall through */
2281 case VK_LSHIFT:
2282 vkey = VK_SHIFT;
2283 break;
2284 case VK_LCONTROL:
2285 case VK_RCONTROL:
2286 vkey = VK_CONTROL;
2287 break;
2288 case VK_LMENU:
2289 case VK_RMENU:
2290 vkey = VK_MENU;
2291 break;
2295 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2296 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2298 /* first get the name of the "regular" keys which is the Upper case
2299 value of the keycap imprint. */
2300 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2301 (scanCode != 0x137) && /* PrtScn */
2302 (scanCode != 0x135) && /* numpad / */
2303 (scanCode != 0x37 ) && /* numpad * */
2304 (scanCode != 0x4a ) && /* numpad - */
2305 (scanCode != 0x4e ) ) /* numpad + */
2307 if (nSize >= 2)
2309 *lpBuffer = toupperW((WCHAR)ansi);
2310 *(lpBuffer+1) = 0;
2311 return 1;
2313 else
2314 return 0;
2317 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2318 without "extended-key" flag. However Wine generates scancode
2319 *with* "extended-key" flag. Seems to occur *only* for the
2320 function keys. Soooo.. We will leave the table alone and
2321 fudge the lookup here till the other part is found and fixed!!! */
2323 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2324 (scanCode == 0x157) || (scanCode == 0x158))
2325 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2327 /* let's do scancode -> keycode -> keysym -> String */
2329 EnterCriticalSection( &kbd_section );
2331 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2332 if ((keyc2scan[keyi]) == scanCode)
2333 break;
2334 if (keyi <= max_keycode)
2336 INT rc;
2338 keyc = (KeyCode) keyi;
2339 keys = keycode_to_keysym(display, keyc, 0);
2340 name = XKeysymToString(keys);
2342 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2344 char* idx = strrchr(name, '_');
2345 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2347 LeaveCriticalSection( &kbd_section );
2348 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2349 scanCode, keyc, keys, debugstr_an(name,idx-name));
2350 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2351 if (!rc) rc = nSize;
2352 lpBuffer[--rc] = 0;
2353 return rc;
2357 if (name)
2359 LeaveCriticalSection( &kbd_section );
2360 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2361 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2362 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2363 if (!rc) rc = nSize;
2364 lpBuffer[--rc] = 0;
2365 return rc;
2369 /* Finally issue WARN for unknown keys */
2371 LeaveCriticalSection( &kbd_section );
2372 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2373 *lpBuffer = 0;
2374 return 0;
2377 /***********************************************************************
2378 * X11DRV_KEYBOARD_MapDeadKeysym
2380 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2382 switch (keysym)
2384 /* symbolic ASCII is the same as defined in rfc1345 */
2385 #ifdef XK_dead_tilde
2386 case XK_dead_tilde :
2387 #endif
2388 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2389 return '~'; /* '? */
2390 #ifdef XK_dead_acute
2391 case XK_dead_acute :
2392 #endif
2393 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2394 return 0xb4; /* '' */
2395 #ifdef XK_dead_circumflex
2396 case XK_dead_circumflex:
2397 #endif
2398 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2399 return '^'; /* '> */
2400 #ifdef XK_dead_grave
2401 case XK_dead_grave :
2402 #endif
2403 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2404 return '`'; /* '! */
2405 #ifdef XK_dead_diaeresis
2406 case XK_dead_diaeresis :
2407 #endif
2408 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2409 return 0xa8; /* ': */
2410 #ifdef XK_dead_cedilla
2411 case XK_dead_cedilla :
2412 return 0xb8; /* ', */
2413 #endif
2414 #ifdef XK_dead_macron
2415 case XK_dead_macron :
2416 return '-'; /* 'm isn't defined on iso-8859-x */
2417 #endif
2418 #ifdef XK_dead_breve
2419 case XK_dead_breve :
2420 return 0xa2; /* '( */
2421 #endif
2422 #ifdef XK_dead_abovedot
2423 case XK_dead_abovedot :
2424 return 0xff; /* '. */
2425 #endif
2426 #ifdef XK_dead_abovering
2427 case XK_dead_abovering :
2428 return '0'; /* '0 isn't defined on iso-8859-x */
2429 #endif
2430 #ifdef XK_dead_doubleacute
2431 case XK_dead_doubleacute :
2432 return 0xbd; /* '" */
2433 #endif
2434 #ifdef XK_dead_caron
2435 case XK_dead_caron :
2436 return 0xb7; /* '< */
2437 #endif
2438 #ifdef XK_dead_ogonek
2439 case XK_dead_ogonek :
2440 return 0xb2; /* '; */
2441 #endif
2442 /* FIXME: I don't know this three.
2443 case XK_dead_iota :
2444 return 'i';
2445 case XK_dead_voiced_sound :
2446 return 'v';
2447 case XK_dead_semivoiced_sound :
2448 return 's';
2451 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2452 return 0;
2455 /***********************************************************************
2456 * ToUnicodeEx (X11DRV.@)
2458 * The ToUnicode function translates the specified virtual-key code and keyboard
2459 * state to the corresponding Windows character or characters.
2461 * If the specified key is a dead key, the return value is negative. Otherwise,
2462 * it is one of the following values:
2463 * Value Meaning
2464 * 0 The specified virtual key has no translation for the current state of the keyboard.
2465 * 1 One Windows character was copied to the buffer.
2466 * 2 Two characters were copied to the buffer. This usually happens when a
2467 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2468 * be composed with the specified virtual key to form a single character.
2470 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2473 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2474 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2476 Display *display = thread_init_display();
2477 XKeyEvent e;
2478 KeySym keysym = 0;
2479 INT ret;
2480 int keyc;
2481 char buf[10];
2482 char *lpChar = buf;
2483 HWND focus;
2484 XIC xic;
2485 Status status = 0;
2487 if (scanCode & 0x8000)
2489 TRACE_(key)("Key UP, doing nothing\n" );
2490 return 0;
2493 if (!match_x11_keyboard_layout(hkl))
2494 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2496 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2498 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2499 return 0;
2502 e.display = display;
2503 e.keycode = 0;
2504 e.state = 0;
2505 e.type = KeyPress;
2507 focus = x11drv_thread_data()->last_xic_hwnd;
2508 if (!focus)
2510 focus = GetFocus();
2511 if (focus) focus = GetAncestor( focus, GA_ROOT );
2512 if (!focus) focus = GetActiveWindow();
2514 e.window = X11DRV_get_whole_window( focus );
2515 xic = X11DRV_get_ic( focus );
2517 EnterCriticalSection( &kbd_section );
2519 if (lpKeyState[VK_SHIFT] & 0x80)
2521 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2522 e.state |= ShiftMask;
2524 if (lpKeyState[VK_CAPITAL] & 0x01)
2526 TRACE_(key)("LockMask = %04x\n", LockMask);
2527 e.state |= LockMask;
2529 if (lpKeyState[VK_CONTROL] & 0x80)
2531 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2532 e.state |= ControlMask;
2534 if (lpKeyState[VK_NUMLOCK] & 0x01)
2536 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2537 e.state |= NumLockMask;
2540 /* Restore saved AltGr state */
2541 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2542 e.state |= AltGrMask;
2544 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2545 virtKey, scanCode, e.state);
2547 /* We exit on the first keycode found, to speed up the thing. */
2548 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2549 { /* Find a keycode that could have generated this virtual key */
2550 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2551 { /* We filter the extended bit, we don't know it */
2552 e.keycode = keyc; /* Store it temporarily */
2553 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2554 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2555 state), so set it to 0, we'll find another one */
2560 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2561 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2563 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2564 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2566 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2567 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2568 * in order to produce a locale dependent numeric separator.
2570 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2572 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2573 if (!e.keycode)
2574 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2577 /* Ctrl-Space generates space on Windows */
2578 if (e.state == ControlMask && virtKey == VK_SPACE)
2580 bufW[0] = ' ';
2581 ret = 1;
2582 goto found;
2585 if (!e.keycode && virtKey != VK_NONAME)
2587 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2588 LeaveCriticalSection( &kbd_section );
2589 return 0;
2591 else TRACE_(key)("Found keycode %u\n",e.keycode);
2593 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2594 e.type, e.window, e.state, e.keycode);
2596 /* Clients should pass only KeyPress events to XmbLookupString,
2597 * e.type was set to KeyPress above.
2599 if (xic)
2601 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2602 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2603 if (status == XBufferOverflow)
2605 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2606 if (lpChar == NULL)
2608 ERR_(key)("Failed to allocate memory!\n");
2609 LeaveCriticalSection( &kbd_section );
2610 return 0;
2612 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2615 else
2616 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2618 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2620 if (TRACE_ON(key))
2622 const char *ksname;
2624 ksname = XKeysymToString(keysym);
2625 if (!ksname) ksname = "No Name";
2626 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2627 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2628 keysym, ksname, ret, debugstr_an(lpChar, ret));
2631 if (ret == 0)
2633 char dead_char;
2635 #ifdef XK_EuroSign
2636 /* An ugly hack for EuroSign: X can't translate it to a character
2637 for some locales. */
2638 if (keysym == XK_EuroSign)
2640 bufW[0] = 0x20AC;
2641 ret = 1;
2642 goto found;
2644 #endif
2645 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2646 /* Here we change it back. */
2647 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2649 bufW[0] = 0x09;
2650 ret = 1;
2651 goto found;
2654 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2655 if (dead_char)
2657 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2658 ret = -1;
2659 goto found;
2662 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2664 /* Unicode direct mapping */
2665 bufW[0] = keysym & 0xffff;
2666 ret = 1;
2667 goto found;
2669 else if ((keysym >> 8) == 0x1008FF) {
2670 bufW[0] = 0;
2671 ret = 0;
2672 goto found;
2674 else
2676 const char *ksname;
2678 ksname = XKeysymToString(keysym);
2679 if (!ksname)
2680 ksname = "No Name";
2681 if ((keysym >> 8) != 0xff)
2683 WARN_(key)("no char for keysym %04lx (%s) :\n",
2684 keysym, ksname);
2685 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2686 virtKey, scanCode, e.keycode, e.state);
2690 else { /* ret != 0 */
2691 /* We have a special case to handle : Shift + arrow, shift + home, ...
2692 X returns a char for it, but Windows doesn't. Let's eat it. */
2693 if (!(e.state & NumLockMask) /* NumLock is off */
2694 && (e.state & ShiftMask) /* Shift is pressed */
2695 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2697 lpChar[0] = 0;
2698 ret = 0;
2701 /* more areas where X returns characters but Windows does not
2702 CTRL + number or CTRL + symbol */
2703 if (e.state & ControlMask)
2705 if (((keysym>=33) && (keysym < '@')) ||
2706 (keysym == '`') ||
2707 (keysym == XK_Tab))
2709 lpChar[0] = 0;
2710 ret = 0;
2714 /* We have another special case for delete key (XK_Delete) on an
2715 extended keyboard. X returns a char for it, but Windows doesn't */
2716 if (keysym == XK_Delete)
2718 lpChar[0] = 0;
2719 ret = 0;
2721 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2722 && (keysym == XK_KP_Decimal))
2724 lpChar[0] = 0;
2725 ret = 0;
2727 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2728 && (keysym == XK_Return || keysym == XK_KP_Enter))
2730 if (lpKeyState[VK_SHIFT] & 0x80)
2732 lpChar[0] = 0;
2733 ret = 0;
2735 else
2737 lpChar[0] = '\n';
2738 ret = 1;
2742 /* Hack to detect an XLookupString hard-coded to Latin1 */
2743 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2745 bufW[0] = (BYTE)lpChar[0];
2746 goto found;
2749 /* perform translation to unicode */
2750 if(ret)
2752 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2753 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2757 found:
2758 if (buf != lpChar)
2759 HeapFree(GetProcessHeap(), 0, lpChar);
2761 LeaveCriticalSection( &kbd_section );
2763 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2764 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2765 if (1 <= ret && ret < bufW_size)
2766 bufW[ret] = 0;
2768 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2769 return ret;
2772 /***********************************************************************
2773 * Beep (X11DRV.@)
2775 void CDECL X11DRV_Beep(void)
2777 XBell(gdi_display, 0);