push 6e61d6ca5bcaf95ac09a664b4ba4f88238c927be
[wine/hacks.git] / dlls / winex11.drv / keyboard.c
blob24057991b739ac9114128ac854b51b1161aa577b
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
42 #define NONAMELESSSTRUCT
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 "x11drv.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
54 /* log format (add 0-padding as appropriate):
55 keycode %u as in output from xev
56 keysym %lx as in X11/keysymdef.h
57 vkey %X as in winuser.h
58 scancode %x
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
63 /* key state table bits:
64 0x80 -> key is pressed
65 0x40 -> key got pressed since last time
66 0x01 -> key is toggled
68 BYTE key_state_table[256];
70 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
71 or a WM_KEYUP message */
73 static int min_keycode, max_keycode, keysyms_per_keycode;
74 static WORD keyc2vkey[256], keyc2scan[256];
76 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
78 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
80 /* Keyboard translation tables */
81 #define MAIN_LEN 49
82 static const WORD main_key_scan_qwerty[MAIN_LEN] =
84 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
85 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
86 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
87 /* q w e r t y u i o p [ ] */
88 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
89 /* a s d f g h j k l ; ' \ */
90 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
91 /* z x c v b n m , . / */
92 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
93 0x56 /* the 102nd key (actually to the right of l-shift) */
96 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
98 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
99 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
100 /* q w e r t y u i o p [ ] */
101 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
102 /* a s d f g h j k l ; ' \ */
103 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
104 /* \ z x c v b n m , . / */
105 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
106 0x56, /* the 102nd key (actually to the right of l-shift) */
109 static const WORD main_key_scan_dvorak[MAIN_LEN] =
111 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
112 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
113 /* ' , . p y f g c r l / = */
114 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
115 /* a o e u i d h t n s - \ */
116 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
117 /* ; q j k x b m w v z */
118 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
119 0x56 /* the 102nd key (actually to the right of l-shift) */
122 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
124 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
125 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
126 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
127 /* q w e r t y u i o p @ [ */
128 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
129 /* a s d f g h j k l ; : ] */
130 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
131 /* z x c v b n m , . / */
132 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
133 0x56 /* the 102nd key (actually to the right of l-shift) */
136 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
138 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
139 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
140 /* q w e r t y u i o p @ [ */
141 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
142 /* a s d f g h j k l ; : ] */
143 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
144 /* z x c v b n m , . / */
145 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
146 0x73 /* the 102nd key (actually to the right of l-shift) */
150 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
154 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
155 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
156 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
157 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
160 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
162 /* NOTE: this layout must concur with the scan codes layout above */
163 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
164 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
166 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
167 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
170 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
176 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
177 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
184 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
185 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
186 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
187 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
192 /* NOTE: this layout must concur with the scan codes layout above */
193 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
194 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
195 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
196 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
197 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
200 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
202 /* NOTE: this layout must concur with the scan codes layout above */
203 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
204 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
205 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
206 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
207 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
210 static const WORD main_key_vkey_azerty[MAIN_LEN] =
212 /* NOTE: this layout must concur with the scan codes layout above */
213 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
214 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
215 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
216 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
217 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
220 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
222 /* NOTE: this layout must concur with the scan codes layout above */
223 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
224 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
225 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
226 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
227 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
230 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
232 /* the VK mappings for the main keyboard will be auto-assigned as before,
233 so what we have here is just the character tables */
234 /* order: Normal, Shift, AltGr, Shift-AltGr */
235 /* We recommend you write just what is guaranteed to be correct (i.e. what's
236 written on the keycaps), not the bunch of special characters behind AltGr
237 and Shift-AltGr if it can vary among different X servers */
238 /* Remember that your 102nd key (to the right of l-shift) should be on a
239 separate line, see existing tables */
240 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
241 /* Remember to also add your new table to the layout index table far below! */
243 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
244 static const char main_key_US[MAIN_LEN][4] =
246 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
247 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
248 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
249 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
252 /*** United States keyboard layout (phantom key version) */
253 /* (XFree86 reports the <> key even if it's not physically there) */
254 static const char main_key_US_phantom[MAIN_LEN][4] =
256 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
257 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
258 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
259 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
260 "<>" /* the phantom key */
263 /*** United States keyboard layout (dvorak version) */
264 static const char main_key_US_dvorak[MAIN_LEN][4] =
266 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
267 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
268 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
269 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
272 /*** British keyboard layout */
273 static const char main_key_UK[MAIN_LEN][4] =
275 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
276 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
277 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
278 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
279 "\\|"
282 /*** French keyboard layout (setxkbmap fr) */
283 static const char main_key_FR[MAIN_LEN][4] =
285 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
286 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
287 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
288 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
289 "<>"
292 /*** Icelandic keyboard layout (setxkbmap is) */
293 static const char main_key_IS[MAIN_LEN][4] =
295 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
296 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
297 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
298 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
299 "<>"
302 /* All german keyb layout tables have the acute/apostrophe symbol next to
303 * the BACKSPACE key removed (replaced with NULL which is ignored by the
304 * detection code).
305 * This was done because the mapping of the acute (and apostrophe) is done
306 * differently in various xkb-data/xkeyboard-config versions. Some replace
307 * the acute with a normal apostrophe, so that the apostrophe is found twice
308 * on the keyboard (one next to BACKSPACE and one next to ENTER).
309 * Others put the acute and grave accents on the key left of BACKSPACE.
310 * More information on the fd.o bugtracker:
311 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
314 /*** German Logitech Desktop Pro keyboard layout */
315 static const char main_key_DE_logitech[MAIN_LEN][4] =
317 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","\0`",
318 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
319 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
320 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
321 "<>|"
324 /*** German keyboard layout (setxkbmap de) */
325 static const char main_key_DE[MAIN_LEN][4] =
327 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","\0`",
328 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
330 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
331 "<>|"
334 /*** German keyboard layout without dead keys */
335 static const char main_key_DE_nodead[MAIN_LEN][4] =
337 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","",
338 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
339 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
340 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
341 "<>"
344 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
345 static const char main_key_SG[MAIN_LEN][4] =
347 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
348 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
349 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
350 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
351 "<>"
354 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
355 static const char main_key_SF[MAIN_LEN][4] =
357 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
358 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
359 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
360 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
361 "<>"
364 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
365 static const char main_key_NO[MAIN_LEN][4] =
367 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
368 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
369 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
370 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
371 "<>"
374 /*** Danish keyboard layout (setxkbmap dk) */
375 static const char main_key_DA[MAIN_LEN][4] =
377 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
378 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
379 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
380 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
381 "<>"
384 /*** Swedish keyboard layout (setxkbmap se) */
385 static const char main_key_SE[MAIN_LEN][4] =
387 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
388 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
389 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
390 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
391 "<>"
394 /*** Estonian keyboard layout (setxkbmap ee) */
395 static const char main_key_ET[MAIN_LEN][4] =
397 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
398 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
399 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
400 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
401 "<>"
404 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
405 static const char main_key_CF[MAIN_LEN][4] =
407 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
408 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
409 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
410 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
411 "«»°"
414 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
415 static const char main_key_CA_fr[MAIN_LEN][4] =
417 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
418 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
419 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
420 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
421 "«»"
424 /*** Canadian keyboard layout (setxkbmap ca) */
425 static const char main_key_CA[MAIN_LEN][4] =
427 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
428 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
429 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
430 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
431 "ùÙ"
434 /*** Portuguese keyboard layout (setxkbmap pt) */
435 static const char main_key_PT[MAIN_LEN][4] =
437 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
438 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
439 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
440 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
441 "<>"
444 /*** Italian keyboard layout (setxkbmap it) */
445 static const char main_key_IT[MAIN_LEN][4] =
447 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
448 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
449 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
450 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
451 "<>"
454 /*** Finnish keyboard layout (setxkbmap fi) */
455 static const char main_key_FI[MAIN_LEN][4] =
457 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
458 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
459 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
460 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
461 "<>"
464 /*** Bulgarian bds keyboard layout */
465 static const char main_key_BG_bds[MAIN_LEN][4] =
467 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
468 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
469 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
470 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
471 "<>" /* the phantom key */
474 /*** Bulgarian phonetic keyboard layout */
475 static const char main_key_BG_phonetic[MAIN_LEN][4] =
477 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
478 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
479 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
480 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
481 "<>" /* the phantom key */
484 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
485 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
486 static const char main_key_BY[MAIN_LEN][4] =
488 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
489 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
490 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
491 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
495 /*** Russian keyboard layout (contributed by Pavel Roskin) */
496 static const char main_key_RU[MAIN_LEN][4] =
498 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
499 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
500 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
501 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
504 /*** Russian keyboard layout (phantom key version) */
505 static const char main_key_RU_phantom[MAIN_LEN][4] =
507 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
508 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
509 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
510 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
511 "<>" /* the phantom key */
514 /*** Russian keyboard layout KOI8-R */
515 static const char main_key_RU_koi8r[MAIN_LEN][4] =
517 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
518 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
519 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
520 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
521 "<>" /* the phantom key */
524 /*** Russian keyboard layout cp1251 */
525 static const char main_key_RU_cp1251[MAIN_LEN][4] =
527 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
528 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
529 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
530 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
531 "<>" /* the phantom key */
534 /*** Russian phonetic keyboard layout */
535 static const char main_key_RU_phonetic[MAIN_LEN][4] =
537 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
538 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
539 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
540 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
541 "<>" /* the phantom key */
544 /*** Ukrainian keyboard layout KOI8-U */
545 static const char main_key_UA[MAIN_LEN][4] =
547 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
548 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
549 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
550 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
551 "<>" /* the phantom key */
554 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
555 /*** (as it appears on most of keyboards sold today) */
556 static const char main_key_UA_std[MAIN_LEN][4] =
558 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
559 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
560 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
561 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
562 "<>" /* the phantom key */
565 /*** Russian keyboard layout KOI8-R (pair to the previous) */
566 static const char main_key_RU_std[MAIN_LEN][4] =
568 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
569 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
570 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
571 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
572 "<>" /* the phantom key */
575 /*** Spanish keyboard layout (setxkbmap es) */
576 static const char main_key_ES[MAIN_LEN][4] =
578 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
579 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
580 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
581 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
582 "<>"
585 /*** Belgian keyboard layout ***/
586 static const char main_key_BE[MAIN_LEN][4] =
588 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
589 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
590 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
591 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
592 "<>\\"
595 /*** Hungarian keyboard layout (setxkbmap hu) */
596 static const char main_key_HU[MAIN_LEN][4] =
598 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
599 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
600 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
601 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
602 "íÍ"
605 /*** Polish (programmer's) keyboard layout ***/
606 static const char main_key_PL[MAIN_LEN][4] =
608 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
609 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
610 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
611 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
612 "<>|"
615 /*** Slovenian keyboard layout (setxkbmap si) ***/
616 static const char main_key_SI[MAIN_LEN][4] =
618 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
619 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
620 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
621 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
622 "<>"
625 /*** Serbian keyboard layout (setxkbmap sr) ***/
626 static const char main_key_SR[MAIN_LEN][4] =
628 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
629 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
630 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
631 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
632 "<>" /* the phantom key */
635 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
636 static const char main_key_US_SR[MAIN_LEN][4] =
638 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
639 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
640 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
641 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
642 "<>" /* the phantom key */
645 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
646 static const char main_key_HR_jelly[MAIN_LEN][4] =
648 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
649 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
650 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
651 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
652 "<>|"
655 /*** Croatian keyboard layout (setxkbmap hr) ***/
656 static const char main_key_HR[MAIN_LEN][4] =
658 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
659 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
660 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
661 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
662 "<>"
665 /*** Japanese 106 keyboard layout ***/
666 static const char main_key_JA_jp106[MAIN_LEN][4] =
668 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
669 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
670 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
671 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
672 "\\_",
675 static const char main_key_JA_macjp[MAIN_LEN][4] =
677 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
678 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
679 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
680 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
681 "__",
684 /*** Japanese pc98x1 keyboard layout ***/
685 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
687 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
688 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
689 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
690 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
691 "\\_",
694 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
695 static const char main_key_PT_br[MAIN_LEN][4] =
697 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
698 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
699 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
700 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
703 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
704 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
706 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
707 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
708 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
709 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
712 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
713 static const char main_key_US_intl[MAIN_LEN][4] =
715 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
716 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
717 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
718 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
721 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
722 - dead_abovering replaced with degree - no symbol in iso8859-2
723 - brokenbar replaced with bar */
724 static const char main_key_SK[MAIN_LEN][4] =
726 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
727 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
728 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
729 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
730 "<>"
733 /*** Czech keyboard layout (setxkbmap cz) */
734 static const char main_key_CZ[MAIN_LEN][4] =
736 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
737 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
738 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
739 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
740 "\\"
743 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
744 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
746 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
747 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
748 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
749 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
750 "\\"
753 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
754 static const char main_key_SK_prog[MAIN_LEN][4] =
756 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
757 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
758 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
759 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
760 "<>"
763 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
764 static const char main_key_CS[MAIN_LEN][4] =
766 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
767 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
768 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
769 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
770 "<>\\|"
773 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
774 static const char main_key_LA[MAIN_LEN][4] =
776 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
777 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
778 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
779 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
780 "<>"
783 /*** Lithuanian keyboard layout (setxkbmap lt) */
784 static const char main_key_LT_B[MAIN_LEN][4] =
786 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
787 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
788 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
789 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
790 "ª¬"
793 /*** Turkish keyboard Layout */
794 static const char main_key_TK[MAIN_LEN][4] =
796 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
797 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
798 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
799 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
802 /*** Turkish keyboard layout (setxkbmap tr) */
803 static const char main_key_TR[MAIN_LEN][4] =
805 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
806 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
807 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
808 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
809 "<>"
812 /*** Turkish F keyboard layout (setxkbmap trf) */
813 static const char main_key_TR_F[MAIN_LEN][4] =
815 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
816 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
817 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
818 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
819 "<>"
822 /*** Israelian keyboard layout (setxkbmap us,il) */
823 static const char main_key_IL[MAIN_LEN][4] =
825 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
826 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
827 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
828 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
829 "<>"
832 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
833 static const char main_key_IL_phonetic[MAIN_LEN][4] =
835 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
836 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
837 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
838 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
839 "<>"
842 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
843 static const char main_key_IL_saharon[MAIN_LEN][4] =
845 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
846 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
847 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
848 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
849 "<>"
852 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
853 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
854 message since they have different characters in gr and el XFree86 layouts. */
855 static const char main_key_EL[MAIN_LEN][4] =
857 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
858 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
859 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
860 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
861 "<>"
864 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
865 static const char main_key_th[MAIN_LEN][4] =
867 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
868 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
869 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
870 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
873 /*** VNC keyboard layout */
874 static const WORD main_key_scan_vnc[MAIN_LEN] =
876 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
877 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,
878 0x56
881 static const WORD main_key_vkey_vnc[MAIN_LEN] =
883 '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,
884 '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',
885 VK_OEM_102
888 static const char main_key_vnc[MAIN_LEN][4] =
890 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
891 "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"
894 /*** Dutch keyboard layout (setxkbmap nl) ***/
895 static const char main_key_NL[MAIN_LEN][4] =
897 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
898 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
899 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
900 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
901 "[]"
906 /*** Layout table. Add your keyboard mappings to this list */
907 static const struct {
908 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
909 in the appropriate dlls/kernel/nls/.nls file */
910 const char *comment;
911 const char (*key)[MAIN_LEN][4];
912 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
913 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
914 } main_key_tab[]={
915 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
918 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
921 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
922 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
923 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
924 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
925 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
926 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
930 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
934 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
936 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
937 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
938 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
948 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
953 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
955 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
956 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
957 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
958 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
959 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
960 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
961 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
962 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
963 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
964 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
965 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
966 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
967 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
968 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
969 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
970 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
971 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
972 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
973 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
974 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
975 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
976 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
977 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
978 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
980 {0, NULL, NULL, NULL, NULL} /* sentinel */
982 static unsigned kbd_layout=0; /* index into above table of layouts */
984 /* maybe more of these scancodes should be extended? */
985 /* extended must be set for ALT_R, CTRL_R,
986 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
987 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
988 /* FIXME should we set extended bit for NumLock ? My
989 * Windows does ... DF */
990 /* Yes, to distinguish based on scan codes, also
991 for PrtScn key ... GA */
993 static const WORD nonchar_key_vkey[256] =
995 /* unused */
996 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
997 /* special keys */
998 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
999 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
1000 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
1001 /* unused */
1002 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
1003 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
1004 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
1005 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
1007 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
1008 /* cursor keys */
1009 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
1010 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1012 /* misc keys */
1013 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
1014 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1016 /* keypad keys */
1017 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
1018 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1019 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
1020 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
1021 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
1022 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1023 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1024 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
1025 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1026 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1027 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1028 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1029 /* function keys */
1030 VK_F1, VK_F2,
1031 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1032 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1033 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1034 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1035 /* modifier keys */
1036 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1037 VK_RCONTROL, VK_CAPITAL, 0, VK_MENU,
1038 VK_MENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1039 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1040 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1043 static const WORD nonchar_key_scan[256] =
1045 /* unused */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1047 /* special keys */
1048 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1049 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1050 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1051 /* unused */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1058 /* cursor keys */
1059 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1061 /* misc keys */
1062 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1063 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1065 /* keypad keys */
1066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1068 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1070 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1072 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1073 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1074 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1075 /* function keys */
1076 0x3B, 0x3C,
1077 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1078 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1081 /* modifier keys */
1082 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1083 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1088 static const WORD xfree86_vendor_key_vkey[256] =
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1092 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1093 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1094 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1095 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1096 0, 0, 0, VK_BROWSER_HOME,
1097 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1098 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1099 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1100 0, 0, 0, 0,
1101 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1102 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1103 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1104 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1105 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1106 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1107 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1108 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1109 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1110 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1111 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1112 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1113 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1114 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1115 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1116 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1117 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1118 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1119 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1120 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1121 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1122 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1123 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1124 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1125 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1128 /* Returns the Windows virtual key code associated with the X event <e> */
1129 /* x11 lock 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 void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD event_flags, DWORD time,
1164 DWORD dwExtraInfo, UINT injected_flags )
1166 UINT message;
1167 KBDLLHOOKSTRUCT hook;
1168 WORD flags, wVkStripped, wVkL, wVkR, vk_hook = wVk;
1169 LPARAM lParam = 0;
1171 wVk = LOBYTE(wVk);
1172 flags = LOBYTE(wScan);
1174 if (event_flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1175 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1177 /* strip left/right for menu, control, shift */
1178 switch (wVk)
1180 case VK_MENU:
1181 case VK_LMENU:
1182 case VK_RMENU:
1183 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1184 wVkStripped = VK_MENU;
1185 wVkL = VK_LMENU;
1186 wVkR = VK_RMENU;
1187 break;
1188 case VK_CONTROL:
1189 case VK_LCONTROL:
1190 case VK_RCONTROL:
1191 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1192 wVkStripped = VK_CONTROL;
1193 wVkL = VK_LCONTROL;
1194 wVkR = VK_RCONTROL;
1195 break;
1196 case VK_SHIFT:
1197 case VK_LSHIFT:
1198 case VK_RSHIFT:
1199 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1200 wVkStripped = VK_SHIFT;
1201 wVkL = VK_LSHIFT;
1202 wVkR = VK_RSHIFT;
1203 break;
1204 default:
1205 wVkStripped = wVkL = wVkR = wVk;
1208 if (event_flags & KEYEVENTF_KEYUP)
1210 message = WM_KEYUP;
1211 if (((key_state_table[VK_MENU] & 0x80) &&
1212 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1213 || !(key_state_table[VK_CONTROL] & 0x80)))
1214 || (wVkStripped == VK_F10))
1216 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1217 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1218 message = WM_SYSKEYUP;
1219 TrackSysKey = 0;
1221 flags |= KF_REPEAT | KF_UP;
1223 else
1225 message = WM_KEYDOWN;
1226 if (((key_state_table[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1227 !(key_state_table[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL)) ||
1228 (wVkStripped == VK_F10))
1230 message = WM_SYSKEYDOWN;
1231 TrackSysKey = wVkStripped;
1233 if (!(event_flags & KEYEVENTF_UNICODE) && key_state_table[wVk] & 0x80) flags |= KF_REPEAT;
1236 if (event_flags & KEYEVENTF_UNICODE)
1238 vk_hook = wVk = VK_PACKET;
1239 lParam = MAKELPARAM(1 /* repeat count */, wScan);
1240 TRACE_(key)("message=0x%04x wParam=0x%04X lParam=0x%08lx\n",
1241 message, wVk, lParam);
1244 /* Hook gets whatever key was sent. */
1245 hook.vkCode = vk_hook;
1246 hook.scanCode = wScan;
1247 hook.flags = (flags >> 8) | injected_flags;
1248 hook.time = time;
1249 hook.dwExtraInfo = dwExtraInfo;
1250 if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1252 if (!(event_flags & KEYEVENTF_UNICODE))
1254 if (event_flags & KEYEVENTF_KEYUP)
1256 key_state_table[wVk] &= ~0x80;
1257 key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1259 else
1261 if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1262 key_state_table[wVk] |= 0xc0;
1263 key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1266 if (key_state_table[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1268 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1270 lParam = MAKELPARAM(1 /* repeat count */, flags);
1272 TRACE_(key)(" message=0x%04x wParam=0x%04X, lParam=0x%08lx, InputKeyState=0x%x\n",
1273 message, wVk, lParam, key_state_table[wVk]);
1276 SERVER_START_REQ( send_hardware_message )
1278 req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1279 req->win = 0;
1280 req->msg = message;
1281 req->wparam = wVk;
1282 req->lparam = lParam;
1283 req->x = cursor_pos.x;
1284 req->y = cursor_pos.y;
1285 req->time = time;
1286 req->info = dwExtraInfo;
1287 wine_server_call( req );
1289 SERVER_END_REQ;
1293 /***********************************************************************
1294 * KEYBOARD_UpdateOneState
1296 * Updates internal state for <vkey>, depending on key <state> under X
1299 static inline void KEYBOARD_UpdateOneState ( WORD vkey, WORD scan, int state, DWORD time )
1301 /* Do something if internal table state != X state for keycode */
1302 if (((key_state_table[vkey & 0xff] & 0x80)!=0) != state)
1304 DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1306 if (!state) flags |= KEYEVENTF_KEYUP;
1308 TRACE("Adjusting state for vkey %#.2X. State before %#.2x\n",
1309 vkey, key_state_table[vkey & 0xff]);
1311 /* Fake key being pressed inside wine */
1312 X11DRV_send_keyboard_input( vkey & 0xff, scan & 0xff, flags, time, 0, 0 );
1314 TRACE("State after %#.2x\n", key_state_table[vkey & 0xff]);
1318 /***********************************************************************
1319 * X11DRV_KeymapNotify
1321 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1323 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1324 * from wine to another application and back.
1325 * Toggle keys are handled in HandleEvent.
1327 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1329 int i, j;
1330 DWORD time = GetCurrentTime();
1332 /* the minimum keycode is always greater or equal to 8, so we can
1333 * skip the first 8 values, hence start at 1
1335 for (i = 1; i < 32; i++)
1337 for (j = 0; j < 8; j++)
1339 WORD vkey = keyc2vkey[(i * 8) + j];
1340 WORD scan = keyc2scan[(i * 8) + j];
1341 int state = (event->xkeymap.key_vector[i] & (1<<j)) != 0;
1343 switch(vkey & 0xff)
1345 case VK_LMENU:
1346 case VK_RMENU:
1347 case VK_LCONTROL:
1348 case VK_RCONTROL:
1349 case VK_LSHIFT:
1350 case VK_RSHIFT:
1351 KEYBOARD_UpdateOneState( vkey, scan, state, time );
1352 break;
1358 static void update_lock_state(BYTE vkey, WORD scan, DWORD time)
1360 DWORD flags = vkey == VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0;
1362 if (key_state_table[vkey] & 0x80) flags ^= KEYEVENTF_KEYUP;
1364 X11DRV_send_keyboard_input( vkey, scan, flags, time, 0, 0 );
1365 X11DRV_send_keyboard_input( vkey, scan, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
1368 /***********************************************************************
1369 * X11DRV_KeyEvent
1371 * Handle a X key event
1373 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1375 XKeyEvent *event = &xev->xkey;
1376 char buf[24];
1377 char *Str = buf;
1378 KeySym keysym = 0;
1379 WORD vkey = 0, bScan;
1380 DWORD dwFlags;
1381 int ascii_chars;
1382 XIC xic = X11DRV_get_ic( hwnd );
1383 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1384 Status status = 0;
1386 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1387 event->type, event->window, event->state, event->keycode);
1389 wine_tsx11_lock();
1390 /* Clients should pass only KeyPress events to XmbLookupString */
1391 if (xic && event->type == KeyPress)
1393 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1394 TRACE("XmbLookupString needs %i byte(s)\n", ascii_chars);
1395 if (status == XBufferOverflow)
1397 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1398 if (Str == NULL)
1400 ERR("Failed to allocate memory!\n");
1401 wine_tsx11_unlock();
1402 return;
1404 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1407 else
1408 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1409 wine_tsx11_unlock();
1411 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1413 if (status == XLookupChars)
1415 X11DRV_XIMLookupChars( Str, ascii_chars );
1416 if (buf != Str)
1417 HeapFree(GetProcessHeap(), 0, Str);
1418 return;
1421 /* If XKB extensions are used, the state mask for AltGr will use the group
1422 index instead of the modifier mask. The group index is set in bits
1423 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1424 pressed, look if the group index is different than 0. From XKB
1425 extension documentation, the group index for AltGr should be 2
1426 (event->state = 0x2000). It's probably better to not assume a
1427 predefined group index and find it dynamically
1429 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1430 /* Save also all possible modifier states. */
1431 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1433 if (TRACE_ON(key)){
1434 const char *ksname;
1436 wine_tsx11_lock();
1437 ksname = XKeysymToString(keysym);
1438 wine_tsx11_unlock();
1439 if (!ksname)
1440 ksname = "No Name";
1441 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1442 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1443 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1445 if (buf != Str)
1446 HeapFree(GetProcessHeap(), 0, Str);
1448 wine_tsx11_lock();
1449 vkey = EVENT_event_to_vkey(xic,event);
1450 /* X returns keycode 0 for composed characters */
1451 if (!vkey && ascii_chars) vkey = VK_NONAME;
1452 wine_tsx11_unlock();
1454 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1455 event->keycode, vkey);
1457 if (!vkey) return;
1459 dwFlags = 0;
1460 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1461 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1464 /* Note: X sets the below states on key down and clears them on key up.
1465 Windows triggers them on key down. */
1467 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1468 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask) &&
1469 vkey != VK_CAPITAL)
1471 TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table[VK_CAPITAL]);
1472 update_lock_state(VK_CAPITAL, 0x3A, event_time);
1475 /* Adjust the NUMLOCK state if it has been changed outside wine */
1476 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask) &&
1477 (vkey & 0xff) != VK_NUMLOCK)
1479 TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table[VK_NUMLOCK]);
1480 update_lock_state(VK_NUMLOCK, 0x45, event_time);
1483 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1484 if (!(key_state_table[VK_SCROLL] & 0x01) != !(event->state & ScrollLockMask) &&
1485 vkey != VK_SCROLL)
1487 TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table[VK_SCROLL]);
1488 update_lock_state(VK_SCROLL, 0x46, event_time);
1491 /* we get this event repeatedly if we hold down the key (keyboard repeat) */
1492 if ((VK_F12 == vkey) && (event->type == KeyPress) && getenv("WINEDELAY")) {
1493 __wine_dbg_toggle_block();
1496 bScan = keyc2scan[event->keycode] & 0xFF;
1497 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1499 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1502 /**********************************************************************
1503 * X11DRV_KEYBOARD_DetectLayout
1505 * Called from X11DRV_InitKeyboard
1506 * This routine walks through the defined keyboard layouts and selects
1507 * whichever matches most closely.
1508 * X11 lock must be held.
1510 static void
1511 X11DRV_KEYBOARD_DetectLayout( Display *display )
1513 unsigned current, match, mismatch, seq, i, syms;
1514 int score, keyc, key, pkey, ok;
1515 KeySym keysym = 0;
1516 const char (*lkey)[MAIN_LEN][4];
1517 unsigned max_seq = 0;
1518 int max_score = 0, ismatch = 0;
1519 char ckey[256][4];
1521 syms = keysyms_per_keycode;
1522 if (syms > 4) {
1523 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1524 syms = 4;
1527 memset( ckey, 0, sizeof(ckey) );
1528 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1529 /* get data for keycode from X server */
1530 for (i = 0; i < syms; i++) {
1531 if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1532 /* Allow both one-byte and two-byte national keysyms */
1533 if ((keysym < 0x8000) && (keysym != ' '))
1535 #ifdef HAVE_XKB
1536 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1537 #endif
1539 TRACE("XKB could not translate keysym %04lx\n", keysym);
1540 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1541 * with appropriate ShiftMask and Mode_switch, use XLookupString
1542 * to get character in the local encoding.
1544 ckey[keyc][i] = keysym & 0xFF;
1547 else {
1548 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1553 for (current = 0; main_key_tab[current].comment; current++) {
1554 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1555 match = 0;
1556 mismatch = 0;
1557 score = 0;
1558 seq = 0;
1559 lkey = main_key_tab[current].key;
1560 pkey = -1;
1561 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1562 if (ckey[keyc][0]) {
1563 /* search for a match in layout table */
1564 /* right now, we just find an absolute match for defined positions */
1565 /* (undefined positions are ignored, so if it's defined as "3#" in */
1566 /* the table, it's okay that the X server has "3#£", for example) */
1567 /* however, the score will be higher for longer matches */
1568 for (key = 0; key < MAIN_LEN; key++) {
1569 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1570 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1571 ok++;
1572 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1573 ok = -1;
1575 if (ok > 0) {
1576 score += ok;
1577 break;
1580 /* count the matches and mismatches */
1581 if (ok > 0) {
1582 match++;
1583 /* and how much the keycode order matches */
1584 if (key > pkey) seq++;
1585 pkey = key;
1586 } else {
1587 /* print spaces instead of \0's */
1588 char str[5];
1589 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1590 str[4] = 0;
1591 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1592 mismatch++;
1593 score -= syms;
1597 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1598 match, mismatch, seq, score);
1599 if ((score > max_score) ||
1600 ((score == max_score) && (seq > max_seq))) {
1601 /* best match so far */
1602 kbd_layout = current;
1603 max_score = score;
1604 max_seq = seq;
1605 ismatch = !mismatch;
1608 /* we're done, report results if necessary */
1609 if (!ismatch)
1610 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1611 main_key_tab[kbd_layout].comment);
1613 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1616 static HKL get_locale_kbd_layout(void)
1618 ULONG_PTR layout;
1619 LANGID langid;
1621 /* FIXME:
1623 * layout = main_key_tab[kbd_layout].lcid;
1625 * Winword uses return value of GetKeyboardLayout as a codepage
1626 * to translate ANSI keyboard messages to unicode. But we have
1627 * a problem with it: for instance Polish keyboard layout is
1628 * identical to the US one, and therefore instead of the Polish
1629 * locale id we return the US one.
1632 layout = GetUserDefaultLCID();
1635 * Microsoft Office expects this value to be something specific
1636 * for Japanese and Korean Windows with an IME the value is 0xe001
1637 * We should probably check to see if an IME exists and if so then
1638 * set this word properly.
1640 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1641 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1642 layout |= 0xe001 << 16; /* IME */
1643 else
1644 layout |= layout << 16;
1646 return (HKL)layout;
1649 /***********************************************************************
1650 * GetKeyboardLayoutName (X11DRV.@)
1652 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1654 static const WCHAR formatW[] = {'%','0','8','x',0};
1655 DWORD layout;
1657 layout = HandleToUlong( get_locale_kbd_layout() );
1658 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1659 sprintfW(name, formatW, layout);
1660 TRACE("returning %s\n", debugstr_w(name));
1661 return TRUE;
1664 static void set_kbd_layout_preload_key(void)
1666 static const WCHAR preload[] =
1667 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1668 static const WCHAR one[] = {'1',0};
1670 HKEY hkey;
1671 WCHAR layout[KL_NAMELENGTH];
1673 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1674 return;
1676 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1678 RegCloseKey(hkey);
1679 return;
1681 if (X11DRV_GetKeyboardLayoutName(layout))
1682 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1684 RegCloseKey(hkey);
1687 /**********************************************************************
1688 * X11DRV_InitKeyboard
1690 void X11DRV_InitKeyboard( Display *display )
1692 KeySym *ksp;
1693 XModifierKeymap *mmp;
1694 KeySym keysym;
1695 KeyCode *kcp;
1696 XKeyEvent e2;
1697 WORD scan, vkey;
1698 int keyc, i, keyn, syms;
1699 char ckey[4]={0,0,0,0};
1700 const char (*lkey)[MAIN_LEN][4];
1701 char vkey_used[256] = { 0 };
1703 /* Ranges of OEM, function key, and character virtual key codes.
1704 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1705 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1706 static const struct {
1707 WORD first, last;
1708 } vkey_ranges[] = {
1709 { VK_OEM_1, VK_OEM_3 },
1710 { VK_OEM_4, VK_ICO_00 },
1711 { 0xe6, 0xe6 },
1712 { 0xe9, 0xf5 },
1713 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1714 { VK_F1, VK_F24 },
1715 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1716 { 0x41, 0x5a }, /* VK_A - VK_Z */
1717 { 0, 0 }
1719 int vkey_range;
1721 set_kbd_layout_preload_key();
1723 wine_tsx11_lock();
1724 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1725 ksp = XGetKeyboardMapping(display, min_keycode,
1726 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1727 /* We are only interested in keysyms_per_keycode.
1728 There is no need to hold a local copy of the keysyms table */
1729 XFree(ksp);
1731 mmp = XGetModifierMapping(display);
1732 kcp = mmp->modifiermap;
1733 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1735 int j;
1737 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1738 if (*kcp)
1740 int k;
1742 for (k = 0; k < keysyms_per_keycode; k += 1)
1743 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1745 NumLockMask = 1 << i;
1746 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1748 else if (XKeycodeToKeysym(display, *kcp, k) == XK_Scroll_Lock)
1750 ScrollLockMask = 1 << i;
1751 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1755 XFreeModifiermap(mmp);
1757 /* Detect the keyboard layout */
1758 X11DRV_KEYBOARD_DetectLayout( display );
1759 lkey = main_key_tab[kbd_layout].key;
1760 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1762 /* Now build two conversion arrays :
1763 * keycode -> vkey + scancode + extended
1764 * vkey + extended -> keycode */
1766 e2.display = display;
1767 e2.state = 0;
1768 e2.type = KeyPress;
1770 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1771 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1773 char buf[30];
1774 int have_chars;
1776 keysym = 0;
1777 e2.keycode = (KeyCode)keyc;
1778 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1779 vkey = 0; scan = 0;
1780 if (keysym) /* otherwise, keycode not used */
1782 if ((keysym >> 8) == 0xFF) /* non-character key */
1784 vkey = nonchar_key_vkey[keysym & 0xff];
1785 scan = nonchar_key_scan[keysym & 0xff];
1786 /* set extended bit when necessary */
1787 if (scan & 0x100) vkey |= 0x100;
1788 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1789 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1790 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1791 scan = 0x100;
1792 vkey |= 0x100;
1793 } else if (keysym == 0x20) { /* Spacebar */
1794 vkey = VK_SPACE;
1795 scan = 0x39;
1796 } else if (have_chars) {
1797 /* we seem to need to search the layout-dependent scancodes */
1798 int maxlen=0,maxval=-1,ok;
1799 for (i=0; i<syms; i++) {
1800 keysym = XKeycodeToKeysym(display, keyc, i);
1801 if ((keysym<0x8000) && (keysym!=' '))
1803 #ifdef HAVE_XKB
1804 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1805 #endif
1807 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1808 * with appropriate ShiftMask and Mode_switch, use XLookupString
1809 * to get character in the local encoding.
1811 ckey[i] = keysym & 0xFF;
1813 } else {
1814 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1817 /* find key with longest match streak */
1818 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1819 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1820 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1821 if (!ok) i--; /* we overshot */
1822 if (ok||(i>maxlen)) {
1823 maxlen=i; maxval=keyn;
1825 if (ok) break;
1827 if (maxval>=0) {
1828 /* got it */
1829 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1830 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1831 scan = (*lscan)[maxval];
1832 vkey = (*lvkey)[maxval];
1836 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1837 keyc2vkey[e2.keycode] = vkey;
1838 keyc2scan[e2.keycode] = scan;
1839 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1840 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1841 vkey_used[(vkey & 0xff)] = 1;
1842 } /* for */
1844 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1845 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1847 vkey = keyc2vkey[keyc] & 0xff;
1848 if (vkey)
1849 continue;
1851 e2.keycode = (KeyCode)keyc;
1852 keysym = XLookupKeysym(&e2, 0);
1853 if (!keysym)
1854 continue;
1856 /* find a suitable layout-dependent VK code */
1857 /* (most Winelib apps ought to be able to work without layout tables!) */
1858 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1860 keysym = XLookupKeysym(&e2, i);
1861 if ((keysym >= XK_0 && keysym <= XK_9)
1862 || (keysym >= XK_A && keysym <= XK_Z)) {
1863 vkey = VKEY_IF_NOT_USED(keysym);
1867 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1869 keysym = XLookupKeysym(&e2, i);
1870 switch (keysym)
1872 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1873 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1874 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1875 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1876 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1877 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1878 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1879 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1880 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1881 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1882 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1886 if (vkey)
1888 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1889 keyc2vkey[e2.keycode] = vkey;
1891 } /* for */
1893 /* For any keycodes which still don't have a vkey, assign any spare
1894 * character, function key, or OEM virtual key code. */
1895 vkey_range = 0;
1896 vkey = vkey_ranges[vkey_range].first;
1897 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1899 if (keyc2vkey[keyc] & 0xff)
1900 continue;
1902 e2.keycode = (KeyCode)keyc;
1903 keysym = XLookupKeysym(&e2, 0);
1904 if (!keysym)
1905 continue;
1907 while (vkey && vkey_used[vkey])
1909 if (vkey == vkey_ranges[vkey_range].last)
1911 vkey_range++;
1912 vkey = vkey_ranges[vkey_range].first;
1914 else
1915 vkey++;
1918 if (!vkey)
1920 WARN("No more vkeys available!\n");
1921 break;
1924 if (TRACE_ON(keyboard))
1926 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1927 vkey, e2.keycode);
1928 TRACE("(");
1929 for (i = 0; i < keysyms_per_keycode; i += 1)
1931 const char *ksname;
1933 keysym = XLookupKeysym(&e2, i);
1934 ksname = XKeysymToString(keysym);
1935 if (!ksname)
1936 ksname = "NoSymbol";
1937 TRACE( "%lx (%s) ", keysym, ksname);
1939 TRACE(")\n");
1942 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1943 keyc2vkey[e2.keycode] = vkey;
1944 vkey_used[vkey] = 1;
1945 } /* for */
1946 #undef VKEY_IF_NOT_USED
1948 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1949 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1950 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1951 const char *ksname;
1952 keysym = XKeycodeToKeysym(display, keyc, 0);
1953 ksname = XKeysymToString(keysym);
1954 if (!ksname) ksname = "NoSymbol";
1956 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1958 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1959 keyc2scan[keyc]=scan++;
1962 wine_tsx11_unlock();
1965 static BOOL match_x11_keyboard_layout(HKL hkl)
1967 const DWORD isIME = 0xE0000000;
1968 HKL xHkl = get_locale_kbd_layout();
1970 /* if the layout is an IME, only match the low word (LCID) */
1971 if (((ULONG_PTR)hkl & isIME) == isIME)
1972 return (LOWORD(hkl) == LOWORD(xHkl));
1973 else
1974 return (hkl == xHkl);
1977 /**********************************************************************
1978 * GetAsyncKeyState (X11DRV.@)
1980 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1982 SHORT retval;
1984 /* Photoshop livelocks unless mouse events are included here */
1985 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1987 retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1988 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1989 key_state_table[key] &= ~0x40;
1990 TRACE_(key)("(%X) -> %x\n", key, retval);
1991 return retval;
1995 /***********************************************************************
1996 * GetKeyboardLayout (X11DRV.@)
1998 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
2000 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
2002 struct x11drv_thread_data *thread_data = x11drv_thread_data();
2003 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
2005 else
2006 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
2008 return get_locale_kbd_layout();
2012 /***********************************************************************
2013 * LoadKeyboardLayout (X11DRV.@)
2015 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
2017 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
2018 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2019 return 0;
2023 /***********************************************************************
2024 * UnloadKeyboardLayout (X11DRV.@)
2026 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
2028 FIXME("%p: stub!\n", hkl);
2029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2030 return FALSE;
2034 /***********************************************************************
2035 * ActivateKeyboardLayout (X11DRV.@)
2037 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
2039 HKL oldHkl = 0;
2040 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
2042 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
2043 if (flags & KLF_SETFORPROCESS)
2045 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2046 FIXME("KLF_SETFORPROCESS not supported\n");
2047 return 0;
2050 if (flags)
2051 FIXME("flags %x not supported\n",flags);
2053 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
2055 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2056 FIXME("HKL_NEXT and HKL_PREV not supported\n");
2057 return 0;
2060 if (!match_x11_keyboard_layout(hkl))
2062 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2063 FIXME("setting keyboard of different locales not supported\n");
2064 return 0;
2067 oldHkl = thread_data->kbd_layout;
2068 if (!oldHkl) oldHkl = get_locale_kbd_layout();
2070 thread_data->kbd_layout = hkl;
2072 return oldHkl;
2076 /***********************************************************************
2077 * X11DRV_MappingNotify
2079 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
2081 HWND hwnd;
2083 wine_tsx11_lock();
2084 XRefreshKeyboardMapping(&event->xmapping);
2085 wine_tsx11_unlock();
2086 X11DRV_InitKeyboard( event->xmapping.display );
2088 hwnd = GetFocus();
2089 if (!hwnd) hwnd = GetActiveWindow();
2090 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2091 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2095 /***********************************************************************
2096 * VkKeyScanEx (X11DRV.@)
2098 * Note: Windows ignores HKL parameter and uses current active layout instead
2100 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2102 Display *display = thread_init_display();
2103 KeyCode keycode;
2104 KeySym keysym;
2105 int i, index;
2106 CHAR cChar;
2107 SHORT ret;
2109 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2110 * is UTF-8 (multibyte encoding)?
2112 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2114 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2115 return -1;
2118 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2120 /* char->keysym (same for ANSI chars) */
2121 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2122 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2124 wine_tsx11_lock();
2125 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2126 if (!keycode)
2128 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2130 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2131 TRACE(" ... returning ctrl char %#.2x\n", ret);
2132 wine_tsx11_unlock();
2133 return ret;
2135 /* It didn't work ... let's try with deadchar code. */
2136 TRACE("retrying with | 0xFE00\n");
2137 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2139 wine_tsx11_unlock();
2141 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2143 /* keycode -> (keyc2vkey) vkey */
2144 ret = keyc2vkey[keycode];
2146 if (!keycode || !ret)
2148 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2149 return -1;
2152 index = -1;
2153 wine_tsx11_lock();
2154 for (i = 0; i < 4; i++) /* find shift state */
2156 if (XKeycodeToKeysym(display, keycode, i) == keysym)
2158 index = i;
2159 break;
2162 wine_tsx11_unlock();
2164 switch (index)
2166 default:
2167 case -1:
2168 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2169 return -1;
2171 case 0: break;
2172 case 1: ret += 0x0100; break;
2173 case 2: ret += 0x0600; break;
2174 case 3: ret += 0x0700; break;
2177 index : 0 adds 0x0000
2178 index : 1 adds 0x0100 (shift)
2179 index : ? adds 0x0200 (ctrl)
2180 index : 2 adds 0x0600 (ctrl+alt)
2181 index : 3 adds 0x0700 (ctrl+alt+shift)
2184 TRACE(" ... returning %#.2x\n", ret);
2185 return ret;
2188 /***********************************************************************
2189 * MapVirtualKeyEx (X11DRV.@)
2191 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2193 Display *display = thread_init_display();
2195 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2197 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2198 if (!match_x11_keyboard_layout(hkl))
2199 FIXME("keyboard layout %p is not supported\n", hkl);
2201 switch(wMapType)
2203 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2204 case MAPVK_VK_TO_VSC_EX:
2206 int keyc;
2208 switch (wCode)
2210 case VK_SHIFT: wCode = VK_LSHIFT; break;
2211 case VK_CONTROL: wCode = VK_LCONTROL; break;
2212 case VK_MENU: wCode = VK_LMENU; break;
2215 /* let's do vkey -> keycode -> scan */
2216 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2217 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2219 if (keyc > max_keycode)
2221 TRACE("returning no scan-code.\n");
2222 return 0;
2224 returnMVK (keyc2scan[keyc] & 0xFF);
2226 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2227 case MAPVK_VSC_TO_VK_EX:
2229 int keyc;
2230 UINT vkey = 0;
2232 /* let's do scan -> keycode -> vkey */
2233 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2234 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2236 vkey = keyc2vkey[keyc] & 0xFF;
2237 /* Only stop if it's not a numpad vkey; otherwise keep
2238 looking for a potential better vkey. */
2239 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2240 break;
2243 if (vkey == 0)
2245 TRACE("returning no vkey-code.\n");
2246 return 0;
2249 if (wMapType == MAPVK_VSC_TO_VK)
2250 switch (vkey)
2252 case VK_LSHIFT:
2253 case VK_RSHIFT:
2254 vkey = VK_SHIFT; break;
2255 case VK_LCONTROL:
2256 case VK_RCONTROL:
2257 vkey = VK_CONTROL; break;
2258 case VK_LMENU:
2259 case VK_RMENU:
2260 vkey = VK_MENU; break;
2263 returnMVK (vkey);
2265 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2267 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2268 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2269 * key.. Looks like something is wrong with the MS docs?
2270 * This is only true for letters, for example VK_0 returns '0' not ')'.
2271 * - hence we use the lock mask to ensure this happens.
2273 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2274 XKeyEvent e;
2275 KeySym keysym;
2276 int keyc, len;
2277 char s[10];
2279 e.display = display;
2280 e.state = 0;
2281 e.keycode = 0;
2282 e.type = KeyPress;
2284 wine_tsx11_lock();
2286 /* We exit on the first keycode found, to speed up the thing. */
2287 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2288 { /* Find a keycode that could have generated this virtual key */
2289 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2290 { /* We filter the extended bit, we don't know it */
2291 e.keycode = keyc; /* Store it temporarily */
2292 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2293 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2294 state), so set it to 0, we'll find another one */
2299 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2300 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2302 if (wCode==VK_DECIMAL)
2303 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2305 if (!e.keycode)
2307 WARN("Unknown virtual key %X !!!\n", wCode);
2308 wine_tsx11_unlock();
2309 return 0; /* whatever */
2311 TRACE("Found keycode %u\n",e.keycode);
2313 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2314 wine_tsx11_unlock();
2316 if (len)
2318 WCHAR wch;
2319 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2320 returnMVK(toupperW(wch));
2322 TRACE("returning no ANSI.\n");
2323 return 0;
2325 default: /* reserved */
2326 FIXME("Unknown wMapType %d !\n", wMapType);
2327 return 0;
2329 return 0;
2332 /***********************************************************************
2333 * GetKeyNameText (X11DRV.@)
2335 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2337 Display *display = thread_init_display();
2338 int vkey, ansi, scanCode;
2339 KeyCode keyc;
2340 int keyi;
2341 KeySym keys;
2342 char *name;
2344 scanCode = lParam >> 16;
2345 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2347 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2349 /* handle "don't care" bit (0x02000000) */
2350 if (!(lParam & 0x02000000)) {
2351 switch (vkey) {
2352 case VK_RSHIFT:
2353 /* R-Shift is "special" - it is an extended key with separate scan code */
2354 scanCode |= 0x100;
2355 case VK_LSHIFT:
2356 vkey = VK_SHIFT;
2357 break;
2358 case VK_LCONTROL:
2359 case VK_RCONTROL:
2360 vkey = VK_CONTROL;
2361 break;
2362 case VK_LMENU:
2363 case VK_RMENU:
2364 vkey = VK_MENU;
2365 break;
2369 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2370 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2372 /* first get the name of the "regular" keys which is the Upper case
2373 value of the keycap imprint. */
2374 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2375 (scanCode != 0x137) && /* PrtScn */
2376 (scanCode != 0x135) && /* numpad / */
2377 (scanCode != 0x37 ) && /* numpad * */
2378 (scanCode != 0x4a ) && /* numpad - */
2379 (scanCode != 0x4e ) ) /* numpad + */
2381 if ((nSize >= 2) && lpBuffer)
2383 *lpBuffer = toupperW((WCHAR)ansi);
2384 *(lpBuffer+1) = 0;
2385 return 1;
2387 else
2388 return 0;
2391 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2392 without "extended-key" flag. However Wine generates scancode
2393 *with* "extended-key" flag. Seems to occur *only* for the
2394 function keys. Soooo.. We will leave the table alone and
2395 fudge the lookup here till the other part is found and fixed!!! */
2397 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2398 (scanCode == 0x157) || (scanCode == 0x158))
2399 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2401 /* let's do scancode -> keycode -> keysym -> String */
2403 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2404 if ((keyc2scan[keyi]) == scanCode)
2405 break;
2406 if (keyi <= max_keycode)
2408 wine_tsx11_lock();
2409 keyc = (KeyCode) keyi;
2410 keys = XKeycodeToKeysym(display, keyc, 0);
2411 name = XKeysymToString(keys);
2412 wine_tsx11_unlock();
2413 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2414 scanCode, keyc, (int)keys, name);
2415 if (lpBuffer && nSize && name)
2416 return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2419 /* Finally issue WARN for unknown keys */
2421 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2422 if (lpBuffer && nSize)
2423 *lpBuffer = 0;
2424 return 0;
2427 /***********************************************************************
2428 * X11DRV_KEYBOARD_MapDeadKeysym
2430 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2432 switch (keysym)
2434 /* symbolic ASCII is the same as defined in rfc1345 */
2435 #ifdef XK_dead_tilde
2436 case XK_dead_tilde :
2437 #endif
2438 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2439 return '~'; /* '? */
2440 #ifdef XK_dead_acute
2441 case XK_dead_acute :
2442 #endif
2443 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2444 return 0xb4; /* '' */
2445 #ifdef XK_dead_circumflex
2446 case XK_dead_circumflex:
2447 #endif
2448 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2449 return '^'; /* '> */
2450 #ifdef XK_dead_grave
2451 case XK_dead_grave :
2452 #endif
2453 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2454 return '`'; /* '! */
2455 #ifdef XK_dead_diaeresis
2456 case XK_dead_diaeresis :
2457 #endif
2458 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2459 return 0xa8; /* ': */
2460 #ifdef XK_dead_cedilla
2461 case XK_dead_cedilla :
2462 return 0xb8; /* ', */
2463 #endif
2464 #ifdef XK_dead_macron
2465 case XK_dead_macron :
2466 return '-'; /* 'm isn't defined on iso-8859-x */
2467 #endif
2468 #ifdef XK_dead_breve
2469 case XK_dead_breve :
2470 return 0xa2; /* '( */
2471 #endif
2472 #ifdef XK_dead_abovedot
2473 case XK_dead_abovedot :
2474 return 0xff; /* '. */
2475 #endif
2476 #ifdef XK_dead_abovering
2477 case XK_dead_abovering :
2478 return '0'; /* '0 isn't defined on iso-8859-x */
2479 #endif
2480 #ifdef XK_dead_doubleacute
2481 case XK_dead_doubleacute :
2482 return 0xbd; /* '" */
2483 #endif
2484 #ifdef XK_dead_caron
2485 case XK_dead_caron :
2486 return 0xb7; /* '< */
2487 #endif
2488 #ifdef XK_dead_ogonek
2489 case XK_dead_ogonek :
2490 return 0xb2; /* '; */
2491 #endif
2492 /* FIXME: I don't know this three.
2493 case XK_dead_iota :
2494 return 'i';
2495 case XK_dead_voiced_sound :
2496 return 'v';
2497 case XK_dead_semivoiced_sound :
2498 return 's';
2501 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2502 return 0;
2505 /***********************************************************************
2506 * ToUnicodeEx (X11DRV.@)
2508 * The ToUnicode function translates the specified virtual-key code and keyboard
2509 * state to the corresponding Windows character or characters.
2511 * If the specified key is a dead key, the return value is negative. Otherwise,
2512 * it is one of the following values:
2513 * Value Meaning
2514 * 0 The specified virtual key has no translation for the current state of the keyboard.
2515 * 1 One Windows character was copied to the buffer.
2516 * 2 Two characters were copied to the buffer. This usually happens when a
2517 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2518 * be composed with the specified virtual key to form a single character.
2520 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2523 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2524 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2526 Display *display = thread_init_display();
2527 XKeyEvent e;
2528 KeySym keysym = 0;
2529 INT ret;
2530 int keyc;
2531 char buf[10];
2532 char *lpChar = buf;
2533 HWND focus;
2534 XIC xic;
2535 Status status = 0;
2537 if (scanCode & 0x8000)
2539 TRACE("Key UP, doing nothing\n" );
2540 return 0;
2543 if (!match_x11_keyboard_layout(hkl))
2544 FIXME("keyboard layout %p is not supported\n", hkl);
2546 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2548 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2549 return 0;
2552 e.display = display;
2553 e.keycode = 0;
2554 e.state = 0;
2555 e.type = KeyPress;
2557 focus = GetFocus();
2558 if (focus) focus = GetAncestor( focus, GA_ROOT );
2559 if (!focus) focus = GetActiveWindow();
2560 e.window = X11DRV_get_whole_window( focus );
2561 xic = X11DRV_get_ic( focus );
2563 if (lpKeyState[VK_SHIFT] & 0x80)
2565 TRACE("ShiftMask = %04x\n", ShiftMask);
2566 e.state |= ShiftMask;
2568 if (lpKeyState[VK_CAPITAL] & 0x01)
2570 TRACE("LockMask = %04x\n", LockMask);
2571 e.state |= LockMask;
2573 if (lpKeyState[VK_CONTROL] & 0x80)
2575 TRACE("ControlMask = %04x\n", ControlMask);
2576 e.state |= ControlMask;
2578 if (lpKeyState[VK_NUMLOCK] & 0x01)
2580 TRACE("NumLockMask = %04x\n", NumLockMask);
2581 e.state |= NumLockMask;
2584 /* Restore saved AltGr state */
2585 TRACE("AltGrMask = %04x\n", AltGrMask);
2586 e.state |= AltGrMask;
2588 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2589 virtKey, scanCode, e.state);
2590 wine_tsx11_lock();
2591 /* We exit on the first keycode found, to speed up the thing. */
2592 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2593 { /* Find a keycode that could have generated this virtual key */
2594 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2595 { /* We filter the extended bit, we don't know it */
2596 e.keycode = keyc; /* Store it temporarily */
2597 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2598 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2599 state), so set it to 0, we'll find another one */
2604 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2605 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2607 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2608 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2610 if (virtKey==VK_DECIMAL)
2611 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2613 if (virtKey==VK_SEPARATOR)
2614 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2616 if (!e.keycode && virtKey != VK_NONAME)
2618 WARN("Unknown virtual key %X !!!\n", virtKey);
2619 wine_tsx11_unlock();
2620 return 0;
2622 else TRACE("Found keycode %u\n",e.keycode);
2624 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2625 e.type, e.window, e.state, e.keycode);
2627 /* Clients should pass only KeyPress events to XmbLookupString,
2628 * e.type was set to KeyPress above.
2630 if (xic)
2632 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2633 TRACE("XmbLookupString needs %d byte(s)\n", ret);
2634 if (status == XBufferOverflow)
2636 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2637 if (lpChar == NULL)
2639 ERR("Failed to allocate memory!\n");
2640 wine_tsx11_unlock();
2641 return 0;
2643 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2646 else
2647 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2648 wine_tsx11_unlock();
2650 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2652 if (TRACE_ON(key))
2654 const char *ksname;
2656 wine_tsx11_lock();
2657 ksname = XKeysymToString(keysym);
2658 wine_tsx11_unlock();
2659 if (!ksname) ksname = "No Name";
2660 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2661 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2662 keysym, ksname, ret, debugstr_an(lpChar, ret));
2665 if (ret == 0)
2667 char dead_char;
2669 #ifdef XK_EuroSign
2670 /* An ugly hack for EuroSign: X can't translate it to a character
2671 for some locales. */
2672 if (keysym == XK_EuroSign)
2674 bufW[0] = 0x20AC;
2675 ret = 1;
2676 goto found;
2678 #endif
2679 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2680 /* Here we change it back. */
2681 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2683 bufW[0] = 0x09;
2684 ret = 1;
2685 goto found;
2688 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2689 if (dead_char)
2691 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2692 ret = -1;
2693 goto found;
2696 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2698 /* Unicode direct mapping */
2699 bufW[0] = keysym & 0xffff;
2700 ret = 1;
2701 goto found;
2703 else if ((keysym >> 8) == 0x1008FF) {
2704 bufW[0] = 0;
2705 ret = 0;
2706 goto found;
2708 else
2710 const char *ksname;
2712 wine_tsx11_lock();
2713 ksname = XKeysymToString(keysym);
2714 wine_tsx11_unlock();
2715 if (!ksname)
2716 ksname = "No Name";
2717 if ((keysym >> 8) != 0xff)
2719 WARN("no char for keysym %04lx (%s) :\n",
2720 keysym, ksname);
2721 WARN("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2722 virtKey, scanCode, e.keycode, e.state);
2726 else { /* ret != 0 */
2727 /* We have a special case to handle : Shift + arrow, shift + home, ...
2728 X returns a char for it, but Windows doesn't. Let's eat it. */
2729 if (!(e.state & NumLockMask) /* NumLock is off */
2730 && (e.state & ShiftMask) /* Shift is pressed */
2731 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2733 lpChar[0] = 0;
2734 ret = 0;
2737 /* more areas where X returns characters but Windows does not
2738 CTRL + number or CTRL + symbol */
2739 if (e.state & ControlMask)
2741 if (((keysym>=33) && (keysym < 'A')) ||
2742 ((keysym > 'Z') && (keysym < 'a')) ||
2743 (keysym == XK_Tab))
2745 lpChar[0] = 0;
2746 ret = 0;
2750 /* We have another special case for delete key (XK_Delete) on an
2751 extended keyboard. X returns a char for it, but Windows doesn't */
2752 if (keysym == XK_Delete)
2754 lpChar[0] = 0;
2755 ret = 0;
2757 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2758 && (keysym == XK_KP_Decimal))
2760 lpChar[0] = 0;
2761 ret = 0;
2763 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2764 && (keysym == XK_Return || keysym == XK_KP_Enter))
2766 lpChar[0] = '\n';
2767 ret = 1;
2770 /* Hack to detect an XLookupString hard-coded to Latin1 */
2771 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2773 bufW[0] = (BYTE)lpChar[0];
2774 goto found;
2777 /* perform translation to unicode */
2778 if(ret)
2780 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2781 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2785 found:
2786 if (buf != lpChar)
2787 HeapFree(GetProcessHeap(), 0, lpChar);
2788 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2789 return ret;
2792 /***********************************************************************
2793 * Beep (X11DRV.@)
2795 void CDECL X11DRV_Beep(void)
2797 wine_tsx11_lock();
2798 XBell(gdi_display, 0);
2799 wine_tsx11_unlock();