wineboot: Italian translation update.
[wine/wine-gecko.git] / dlls / winex11.drv / keyboard.c
blobe044d6d0f1eda1c952d42d2803200b8837699aaf
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 bScan = keyc2scan[event->keycode] & 0xFF;
1492 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1494 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1497 /**********************************************************************
1498 * X11DRV_KEYBOARD_DetectLayout
1500 * Called from X11DRV_InitKeyboard
1501 * This routine walks through the defined keyboard layouts and selects
1502 * whichever matches most closely.
1503 * X11 lock must be held.
1505 static void
1506 X11DRV_KEYBOARD_DetectLayout( Display *display )
1508 unsigned current, match, mismatch, seq, i, syms;
1509 int score, keyc, key, pkey, ok;
1510 KeySym keysym = 0;
1511 const char (*lkey)[MAIN_LEN][4];
1512 unsigned max_seq = 0;
1513 int max_score = 0, ismatch = 0;
1514 char ckey[256][4];
1516 syms = keysyms_per_keycode;
1517 if (syms > 4) {
1518 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1519 syms = 4;
1522 memset( ckey, 0, sizeof(ckey) );
1523 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1524 /* get data for keycode from X server */
1525 for (i = 0; i < syms; i++) {
1526 if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1527 /* Allow both one-byte and two-byte national keysyms */
1528 if ((keysym < 0x8000) && (keysym != ' '))
1530 #ifdef HAVE_XKB
1531 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1532 #endif
1534 TRACE("XKB could not translate keysym %04lx\n", keysym);
1535 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1536 * with appropriate ShiftMask and Mode_switch, use XLookupString
1537 * to get character in the local encoding.
1539 ckey[keyc][i] = keysym & 0xFF;
1542 else {
1543 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1548 for (current = 0; main_key_tab[current].comment; current++) {
1549 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1550 match = 0;
1551 mismatch = 0;
1552 score = 0;
1553 seq = 0;
1554 lkey = main_key_tab[current].key;
1555 pkey = -1;
1556 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1557 if (ckey[keyc][0]) {
1558 /* search for a match in layout table */
1559 /* right now, we just find an absolute match for defined positions */
1560 /* (undefined positions are ignored, so if it's defined as "3#" in */
1561 /* the table, it's okay that the X server has "3#£", for example) */
1562 /* however, the score will be higher for longer matches */
1563 for (key = 0; key < MAIN_LEN; key++) {
1564 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1565 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1566 ok++;
1567 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1568 ok = -1;
1570 if (ok > 0) {
1571 score += ok;
1572 break;
1575 /* count the matches and mismatches */
1576 if (ok > 0) {
1577 match++;
1578 /* and how much the keycode order matches */
1579 if (key > pkey) seq++;
1580 pkey = key;
1581 } else {
1582 /* print spaces instead of \0's */
1583 char str[5];
1584 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1585 str[4] = 0;
1586 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1587 mismatch++;
1588 score -= syms;
1592 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1593 match, mismatch, seq, score);
1594 if ((score > max_score) ||
1595 ((score == max_score) && (seq > max_seq))) {
1596 /* best match so far */
1597 kbd_layout = current;
1598 max_score = score;
1599 max_seq = seq;
1600 ismatch = !mismatch;
1603 /* we're done, report results if necessary */
1604 if (!ismatch)
1605 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1606 main_key_tab[kbd_layout].comment);
1608 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1611 static HKL get_locale_kbd_layout(void)
1613 ULONG_PTR layout;
1614 LANGID langid;
1616 /* FIXME:
1618 * layout = main_key_tab[kbd_layout].lcid;
1620 * Winword uses return value of GetKeyboardLayout as a codepage
1621 * to translate ANSI keyboard messages to unicode. But we have
1622 * a problem with it: for instance Polish keyboard layout is
1623 * identical to the US one, and therefore instead of the Polish
1624 * locale id we return the US one.
1627 layout = GetUserDefaultLCID();
1630 * Microsoft Office expects this value to be something specific
1631 * for Japanese and Korean Windows with an IME the value is 0xe001
1632 * We should probably check to see if an IME exists and if so then
1633 * set this word properly.
1635 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1636 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1637 layout |= 0xe001 << 16; /* IME */
1638 else
1639 layout |= layout << 16;
1641 return (HKL)layout;
1644 /***********************************************************************
1645 * GetKeyboardLayoutName (X11DRV.@)
1647 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1649 static const WCHAR formatW[] = {'%','0','8','x',0};
1650 DWORD layout;
1652 layout = HandleToUlong( get_locale_kbd_layout() );
1653 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1654 sprintfW(name, formatW, layout);
1655 TRACE("returning %s\n", debugstr_w(name));
1656 return TRUE;
1659 static void set_kbd_layout_preload_key(void)
1661 static const WCHAR preload[] =
1662 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1663 static const WCHAR one[] = {'1',0};
1665 HKEY hkey;
1666 WCHAR layout[KL_NAMELENGTH];
1668 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1669 return;
1671 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1673 RegCloseKey(hkey);
1674 return;
1676 if (X11DRV_GetKeyboardLayoutName(layout))
1677 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1679 RegCloseKey(hkey);
1682 /**********************************************************************
1683 * X11DRV_InitKeyboard
1685 void X11DRV_InitKeyboard( Display *display )
1687 KeySym *ksp;
1688 XModifierKeymap *mmp;
1689 KeySym keysym;
1690 KeyCode *kcp;
1691 XKeyEvent e2;
1692 WORD scan, vkey;
1693 int keyc, i, keyn, syms;
1694 char ckey[4]={0,0,0,0};
1695 const char (*lkey)[MAIN_LEN][4];
1696 char vkey_used[256] = { 0 };
1698 /* Ranges of OEM, function key, and character virtual key codes.
1699 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1700 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1701 static const struct {
1702 WORD first, last;
1703 } vkey_ranges[] = {
1704 { VK_OEM_1, VK_OEM_3 },
1705 { VK_OEM_4, VK_ICO_00 },
1706 { 0xe6, 0xe6 },
1707 { 0xe9, 0xf5 },
1708 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1709 { VK_F1, VK_F24 },
1710 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1711 { 0x41, 0x5a }, /* VK_A - VK_Z */
1712 { 0, 0 }
1714 int vkey_range;
1716 set_kbd_layout_preload_key();
1718 wine_tsx11_lock();
1719 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1720 ksp = XGetKeyboardMapping(display, min_keycode,
1721 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1722 /* We are only interested in keysyms_per_keycode.
1723 There is no need to hold a local copy of the keysyms table */
1724 XFree(ksp);
1726 mmp = XGetModifierMapping(display);
1727 kcp = mmp->modifiermap;
1728 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1730 int j;
1732 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1733 if (*kcp)
1735 int k;
1737 for (k = 0; k < keysyms_per_keycode; k += 1)
1738 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1740 NumLockMask = 1 << i;
1741 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1743 else if (XKeycodeToKeysym(display, *kcp, k) == XK_Scroll_Lock)
1745 ScrollLockMask = 1 << i;
1746 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1750 XFreeModifiermap(mmp);
1752 /* Detect the keyboard layout */
1753 X11DRV_KEYBOARD_DetectLayout( display );
1754 lkey = main_key_tab[kbd_layout].key;
1755 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1757 /* Now build two conversion arrays :
1758 * keycode -> vkey + scancode + extended
1759 * vkey + extended -> keycode */
1761 e2.display = display;
1762 e2.state = 0;
1763 e2.type = KeyPress;
1765 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1766 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1768 char buf[30];
1769 int have_chars;
1771 keysym = 0;
1772 e2.keycode = (KeyCode)keyc;
1773 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1774 vkey = 0; scan = 0;
1775 if (keysym) /* otherwise, keycode not used */
1777 if ((keysym >> 8) == 0xFF) /* non-character key */
1779 vkey = nonchar_key_vkey[keysym & 0xff];
1780 scan = nonchar_key_scan[keysym & 0xff];
1781 /* set extended bit when necessary */
1782 if (scan & 0x100) vkey |= 0x100;
1783 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1784 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1785 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1786 scan = 0x100;
1787 vkey |= 0x100;
1788 } else if (keysym == 0x20) { /* Spacebar */
1789 vkey = VK_SPACE;
1790 scan = 0x39;
1791 } else if (have_chars) {
1792 /* we seem to need to search the layout-dependent scancodes */
1793 int maxlen=0,maxval=-1,ok;
1794 for (i=0; i<syms; i++) {
1795 keysym = XKeycodeToKeysym(display, keyc, i);
1796 if ((keysym<0x8000) && (keysym!=' '))
1798 #ifdef HAVE_XKB
1799 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1800 #endif
1802 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1803 * with appropriate ShiftMask and Mode_switch, use XLookupString
1804 * to get character in the local encoding.
1806 ckey[i] = keysym & 0xFF;
1808 } else {
1809 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1812 /* find key with longest match streak */
1813 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1814 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1815 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1816 if (!ok) i--; /* we overshot */
1817 if (ok||(i>maxlen)) {
1818 maxlen=i; maxval=keyn;
1820 if (ok) break;
1822 if (maxval>=0) {
1823 /* got it */
1824 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1825 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1826 scan = (*lscan)[maxval];
1827 vkey = (*lvkey)[maxval];
1831 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1832 keyc2vkey[e2.keycode] = vkey;
1833 keyc2scan[e2.keycode] = scan;
1834 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1835 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1836 vkey_used[(vkey & 0xff)] = 1;
1837 } /* for */
1839 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1840 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1842 vkey = keyc2vkey[keyc] & 0xff;
1843 if (vkey)
1844 continue;
1846 e2.keycode = (KeyCode)keyc;
1847 keysym = XLookupKeysym(&e2, 0);
1848 if (!keysym)
1849 continue;
1851 /* find a suitable layout-dependent VK code */
1852 /* (most Winelib apps ought to be able to work without layout tables!) */
1853 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1855 keysym = XLookupKeysym(&e2, i);
1856 if ((keysym >= XK_0 && keysym <= XK_9)
1857 || (keysym >= XK_A && keysym <= XK_Z)) {
1858 vkey = VKEY_IF_NOT_USED(keysym);
1862 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1864 keysym = XLookupKeysym(&e2, i);
1865 switch (keysym)
1867 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1868 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1869 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1870 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1871 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1872 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1873 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1874 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1875 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1876 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1877 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1881 if (vkey)
1883 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1884 keyc2vkey[e2.keycode] = vkey;
1886 } /* for */
1888 /* For any keycodes which still don't have a vkey, assign any spare
1889 * character, function key, or OEM virtual key code. */
1890 vkey_range = 0;
1891 vkey = vkey_ranges[vkey_range].first;
1892 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1894 if (keyc2vkey[keyc] & 0xff)
1895 continue;
1897 e2.keycode = (KeyCode)keyc;
1898 keysym = XLookupKeysym(&e2, 0);
1899 if (!keysym)
1900 continue;
1902 while (vkey && vkey_used[vkey])
1904 if (vkey == vkey_ranges[vkey_range].last)
1906 vkey_range++;
1907 vkey = vkey_ranges[vkey_range].first;
1909 else
1910 vkey++;
1913 if (!vkey)
1915 WARN("No more vkeys available!\n");
1916 break;
1919 if (TRACE_ON(keyboard))
1921 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1922 vkey, e2.keycode);
1923 TRACE("(");
1924 for (i = 0; i < keysyms_per_keycode; i += 1)
1926 const char *ksname;
1928 keysym = XLookupKeysym(&e2, i);
1929 ksname = XKeysymToString(keysym);
1930 if (!ksname)
1931 ksname = "NoSymbol";
1932 TRACE( "%lx (%s) ", keysym, ksname);
1934 TRACE(")\n");
1937 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1938 keyc2vkey[e2.keycode] = vkey;
1939 vkey_used[vkey] = 1;
1940 } /* for */
1941 #undef VKEY_IF_NOT_USED
1943 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1944 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1945 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1946 const char *ksname;
1947 keysym = XKeycodeToKeysym(display, keyc, 0);
1948 ksname = XKeysymToString(keysym);
1949 if (!ksname) ksname = "NoSymbol";
1951 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1953 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1954 keyc2scan[keyc]=scan++;
1957 wine_tsx11_unlock();
1960 static BOOL match_x11_keyboard_layout(HKL hkl)
1962 const DWORD isIME = 0xE0000000;
1963 HKL xHkl = get_locale_kbd_layout();
1965 /* if the layout is an IME, only match the low word (LCID) */
1966 if (((ULONG_PTR)hkl & isIME) == isIME)
1967 return (LOWORD(hkl) == LOWORD(xHkl));
1968 else
1969 return (hkl == xHkl);
1972 /**********************************************************************
1973 * GetAsyncKeyState (X11DRV.@)
1975 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1977 SHORT retval;
1979 /* Photoshop livelocks unless mouse events are included here */
1980 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1982 retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1983 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1984 key_state_table[key] &= ~0x40;
1985 TRACE_(key)("(%X) -> %x\n", key, retval);
1986 return retval;
1990 /***********************************************************************
1991 * GetKeyboardLayout (X11DRV.@)
1993 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1995 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1997 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1998 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
2000 else
2001 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
2003 return get_locale_kbd_layout();
2007 /***********************************************************************
2008 * LoadKeyboardLayout (X11DRV.@)
2010 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
2012 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
2013 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2014 return 0;
2018 /***********************************************************************
2019 * UnloadKeyboardLayout (X11DRV.@)
2021 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
2023 FIXME("%p: stub!\n", hkl);
2024 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2025 return FALSE;
2029 /***********************************************************************
2030 * ActivateKeyboardLayout (X11DRV.@)
2032 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
2034 HKL oldHkl = 0;
2035 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
2037 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
2038 if (flags & KLF_SETFORPROCESS)
2040 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2041 FIXME("KLF_SETFORPROCESS not supported\n");
2042 return 0;
2045 if (flags)
2046 FIXME("flags %x not supported\n",flags);
2048 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
2050 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2051 FIXME("HKL_NEXT and HKL_PREV not supported\n");
2052 return 0;
2055 if (!match_x11_keyboard_layout(hkl))
2057 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2058 FIXME("setting keyboard of different locales not supported\n");
2059 return 0;
2062 oldHkl = thread_data->kbd_layout;
2063 if (!oldHkl) oldHkl = get_locale_kbd_layout();
2065 thread_data->kbd_layout = hkl;
2067 return oldHkl;
2071 /***********************************************************************
2072 * X11DRV_MappingNotify
2074 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
2076 HWND hwnd;
2078 wine_tsx11_lock();
2079 XRefreshKeyboardMapping(&event->xmapping);
2080 wine_tsx11_unlock();
2081 X11DRV_InitKeyboard( event->xmapping.display );
2083 hwnd = GetFocus();
2084 if (!hwnd) hwnd = GetActiveWindow();
2085 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2086 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2090 /***********************************************************************
2091 * VkKeyScanEx (X11DRV.@)
2093 * Note: Windows ignores HKL parameter and uses current active layout instead
2095 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2097 Display *display = thread_init_display();
2098 KeyCode keycode;
2099 KeySym keysym;
2100 int i, index;
2101 CHAR cChar;
2102 SHORT ret;
2104 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2105 * is UTF-8 (multibyte encoding)?
2107 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2109 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2110 return -1;
2113 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2115 /* char->keysym (same for ANSI chars) */
2116 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2117 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2119 wine_tsx11_lock();
2120 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2121 if (!keycode)
2123 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2125 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2126 TRACE(" ... returning ctrl char %#.2x\n", ret);
2127 wine_tsx11_unlock();
2128 return ret;
2130 /* It didn't work ... let's try with deadchar code. */
2131 TRACE("retrying with | 0xFE00\n");
2132 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2134 wine_tsx11_unlock();
2136 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2138 /* keycode -> (keyc2vkey) vkey */
2139 ret = keyc2vkey[keycode];
2141 if (!keycode || !ret)
2143 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2144 return -1;
2147 index = -1;
2148 wine_tsx11_lock();
2149 for (i = 0; i < 4; i++) /* find shift state */
2151 if (XKeycodeToKeysym(display, keycode, i) == keysym)
2153 index = i;
2154 break;
2157 wine_tsx11_unlock();
2159 switch (index)
2161 default:
2162 case -1:
2163 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2164 return -1;
2166 case 0: break;
2167 case 1: ret += 0x0100; break;
2168 case 2: ret += 0x0600; break;
2169 case 3: ret += 0x0700; break;
2172 index : 0 adds 0x0000
2173 index : 1 adds 0x0100 (shift)
2174 index : ? adds 0x0200 (ctrl)
2175 index : 2 adds 0x0600 (ctrl+alt)
2176 index : 3 adds 0x0700 (ctrl+alt+shift)
2179 TRACE(" ... returning %#.2x\n", ret);
2180 return ret;
2183 /***********************************************************************
2184 * MapVirtualKeyEx (X11DRV.@)
2186 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2188 Display *display = thread_init_display();
2190 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2192 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2193 if (!match_x11_keyboard_layout(hkl))
2194 FIXME("keyboard layout %p is not supported\n", hkl);
2196 switch(wMapType)
2198 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2199 case MAPVK_VK_TO_VSC_EX:
2201 int keyc;
2203 switch (wCode)
2205 case VK_SHIFT: wCode = VK_LSHIFT; break;
2206 case VK_CONTROL: wCode = VK_LCONTROL; break;
2207 case VK_MENU: wCode = VK_LMENU; break;
2210 /* let's do vkey -> keycode -> scan */
2211 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2212 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2214 if (keyc > max_keycode)
2216 TRACE("returning no scan-code.\n");
2217 return 0;
2219 returnMVK (keyc2scan[keyc] & 0xFF);
2221 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2222 case MAPVK_VSC_TO_VK_EX:
2224 int keyc;
2225 UINT vkey = 0;
2227 /* let's do scan -> keycode -> vkey */
2228 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2229 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2231 vkey = keyc2vkey[keyc] & 0xFF;
2232 /* Only stop if it's not a numpad vkey; otherwise keep
2233 looking for a potential better vkey. */
2234 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2235 break;
2238 if (vkey == 0)
2240 TRACE("returning no vkey-code.\n");
2241 return 0;
2244 if (wMapType == MAPVK_VSC_TO_VK)
2245 switch (vkey)
2247 case VK_LSHIFT:
2248 case VK_RSHIFT:
2249 vkey = VK_SHIFT; break;
2250 case VK_LCONTROL:
2251 case VK_RCONTROL:
2252 vkey = VK_CONTROL; break;
2253 case VK_LMENU:
2254 case VK_RMENU:
2255 vkey = VK_MENU; break;
2258 returnMVK (vkey);
2260 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2262 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2263 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2264 * key.. Looks like something is wrong with the MS docs?
2265 * This is only true for letters, for example VK_0 returns '0' not ')'.
2266 * - hence we use the lock mask to ensure this happens.
2268 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2269 XKeyEvent e;
2270 KeySym keysym;
2271 int keyc, len;
2272 char s[10];
2274 e.display = display;
2275 e.state = 0;
2276 e.keycode = 0;
2277 e.type = KeyPress;
2279 wine_tsx11_lock();
2281 /* We exit on the first keycode found, to speed up the thing. */
2282 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2283 { /* Find a keycode that could have generated this virtual key */
2284 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2285 { /* We filter the extended bit, we don't know it */
2286 e.keycode = keyc; /* Store it temporarily */
2287 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2288 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2289 state), so set it to 0, we'll find another one */
2294 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2295 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2297 if (wCode==VK_DECIMAL)
2298 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2300 if (!e.keycode)
2302 WARN("Unknown virtual key %X !!!\n", wCode);
2303 wine_tsx11_unlock();
2304 return 0; /* whatever */
2306 TRACE("Found keycode %u\n",e.keycode);
2308 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2309 wine_tsx11_unlock();
2311 if (len)
2313 WCHAR wch;
2314 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2315 returnMVK(toupperW(wch));
2317 TRACE("returning no ANSI.\n");
2318 return 0;
2320 default: /* reserved */
2321 FIXME("Unknown wMapType %d !\n", wMapType);
2322 return 0;
2324 return 0;
2327 /***********************************************************************
2328 * GetKeyNameText (X11DRV.@)
2330 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2332 Display *display = thread_init_display();
2333 int vkey, ansi, scanCode;
2334 KeyCode keyc;
2335 int keyi;
2336 KeySym keys;
2337 char *name;
2339 scanCode = lParam >> 16;
2340 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2342 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2344 /* handle "don't care" bit (0x02000000) */
2345 if (!(lParam & 0x02000000)) {
2346 switch (vkey) {
2347 case VK_RSHIFT:
2348 /* R-Shift is "special" - it is an extended key with separate scan code */
2349 scanCode |= 0x100;
2350 case VK_LSHIFT:
2351 vkey = VK_SHIFT;
2352 break;
2353 case VK_LCONTROL:
2354 case VK_RCONTROL:
2355 vkey = VK_CONTROL;
2356 break;
2357 case VK_LMENU:
2358 case VK_RMENU:
2359 vkey = VK_MENU;
2360 break;
2364 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2365 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2367 /* first get the name of the "regular" keys which is the Upper case
2368 value of the keycap imprint. */
2369 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2370 (scanCode != 0x137) && /* PrtScn */
2371 (scanCode != 0x135) && /* numpad / */
2372 (scanCode != 0x37 ) && /* numpad * */
2373 (scanCode != 0x4a ) && /* numpad - */
2374 (scanCode != 0x4e ) ) /* numpad + */
2376 if ((nSize >= 2) && lpBuffer)
2378 *lpBuffer = toupperW((WCHAR)ansi);
2379 *(lpBuffer+1) = 0;
2380 return 1;
2382 else
2383 return 0;
2386 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2387 without "extended-key" flag. However Wine generates scancode
2388 *with* "extended-key" flag. Seems to occur *only* for the
2389 function keys. Soooo.. We will leave the table alone and
2390 fudge the lookup here till the other part is found and fixed!!! */
2392 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2393 (scanCode == 0x157) || (scanCode == 0x158))
2394 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2396 /* let's do scancode -> keycode -> keysym -> String */
2398 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2399 if ((keyc2scan[keyi]) == scanCode)
2400 break;
2401 if (keyi <= max_keycode)
2403 wine_tsx11_lock();
2404 keyc = (KeyCode) keyi;
2405 keys = XKeycodeToKeysym(display, keyc, 0);
2406 name = XKeysymToString(keys);
2407 wine_tsx11_unlock();
2408 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2409 scanCode, keyc, (int)keys, name);
2410 if (lpBuffer && nSize && name)
2411 return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2414 /* Finally issue WARN for unknown keys */
2416 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2417 if (lpBuffer && nSize)
2418 *lpBuffer = 0;
2419 return 0;
2422 /***********************************************************************
2423 * X11DRV_KEYBOARD_MapDeadKeysym
2425 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2427 switch (keysym)
2429 /* symbolic ASCII is the same as defined in rfc1345 */
2430 #ifdef XK_dead_tilde
2431 case XK_dead_tilde :
2432 #endif
2433 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2434 return '~'; /* '? */
2435 #ifdef XK_dead_acute
2436 case XK_dead_acute :
2437 #endif
2438 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2439 return 0xb4; /* '' */
2440 #ifdef XK_dead_circumflex
2441 case XK_dead_circumflex:
2442 #endif
2443 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2444 return '^'; /* '> */
2445 #ifdef XK_dead_grave
2446 case XK_dead_grave :
2447 #endif
2448 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2449 return '`'; /* '! */
2450 #ifdef XK_dead_diaeresis
2451 case XK_dead_diaeresis :
2452 #endif
2453 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2454 return 0xa8; /* ': */
2455 #ifdef XK_dead_cedilla
2456 case XK_dead_cedilla :
2457 return 0xb8; /* ', */
2458 #endif
2459 #ifdef XK_dead_macron
2460 case XK_dead_macron :
2461 return '-'; /* 'm isn't defined on iso-8859-x */
2462 #endif
2463 #ifdef XK_dead_breve
2464 case XK_dead_breve :
2465 return 0xa2; /* '( */
2466 #endif
2467 #ifdef XK_dead_abovedot
2468 case XK_dead_abovedot :
2469 return 0xff; /* '. */
2470 #endif
2471 #ifdef XK_dead_abovering
2472 case XK_dead_abovering :
2473 return '0'; /* '0 isn't defined on iso-8859-x */
2474 #endif
2475 #ifdef XK_dead_doubleacute
2476 case XK_dead_doubleacute :
2477 return 0xbd; /* '" */
2478 #endif
2479 #ifdef XK_dead_caron
2480 case XK_dead_caron :
2481 return 0xb7; /* '< */
2482 #endif
2483 #ifdef XK_dead_ogonek
2484 case XK_dead_ogonek :
2485 return 0xb2; /* '; */
2486 #endif
2487 /* FIXME: I don't know this three.
2488 case XK_dead_iota :
2489 return 'i';
2490 case XK_dead_voiced_sound :
2491 return 'v';
2492 case XK_dead_semivoiced_sound :
2493 return 's';
2496 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2497 return 0;
2500 /***********************************************************************
2501 * ToUnicodeEx (X11DRV.@)
2503 * The ToUnicode function translates the specified virtual-key code and keyboard
2504 * state to the corresponding Windows character or characters.
2506 * If the specified key is a dead key, the return value is negative. Otherwise,
2507 * it is one of the following values:
2508 * Value Meaning
2509 * 0 The specified virtual key has no translation for the current state of the keyboard.
2510 * 1 One Windows character was copied to the buffer.
2511 * 2 Two characters were copied to the buffer. This usually happens when a
2512 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2513 * be composed with the specified virtual key to form a single character.
2515 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2518 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2519 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2521 Display *display = thread_init_display();
2522 XKeyEvent e;
2523 KeySym keysym = 0;
2524 INT ret;
2525 int keyc;
2526 char buf[10];
2527 char *lpChar = buf;
2528 HWND focus;
2529 XIC xic;
2530 Status status = 0;
2532 if (scanCode & 0x8000)
2534 TRACE("Key UP, doing nothing\n" );
2535 return 0;
2538 if (!match_x11_keyboard_layout(hkl))
2539 FIXME("keyboard layout %p is not supported\n", hkl);
2541 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2543 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2544 return 0;
2547 e.display = display;
2548 e.keycode = 0;
2549 e.state = 0;
2550 e.type = KeyPress;
2552 focus = GetFocus();
2553 if (focus) focus = GetAncestor( focus, GA_ROOT );
2554 if (!focus) focus = GetActiveWindow();
2555 e.window = X11DRV_get_whole_window( focus );
2556 xic = X11DRV_get_ic( focus );
2558 if (lpKeyState[VK_SHIFT] & 0x80)
2560 TRACE("ShiftMask = %04x\n", ShiftMask);
2561 e.state |= ShiftMask;
2563 if (lpKeyState[VK_CAPITAL] & 0x01)
2565 TRACE("LockMask = %04x\n", LockMask);
2566 e.state |= LockMask;
2568 if (lpKeyState[VK_CONTROL] & 0x80)
2570 TRACE("ControlMask = %04x\n", ControlMask);
2571 e.state |= ControlMask;
2573 if (lpKeyState[VK_NUMLOCK] & 0x01)
2575 TRACE("NumLockMask = %04x\n", NumLockMask);
2576 e.state |= NumLockMask;
2579 /* Restore saved AltGr state */
2580 TRACE("AltGrMask = %04x\n", AltGrMask);
2581 e.state |= AltGrMask;
2583 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2584 virtKey, scanCode, e.state);
2585 wine_tsx11_lock();
2586 /* We exit on the first keycode found, to speed up the thing. */
2587 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2588 { /* Find a keycode that could have generated this virtual key */
2589 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2590 { /* We filter the extended bit, we don't know it */
2591 e.keycode = keyc; /* Store it temporarily */
2592 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2593 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2594 state), so set it to 0, we'll find another one */
2599 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2600 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2602 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2603 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2605 if (virtKey==VK_DECIMAL)
2606 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2608 if (virtKey==VK_SEPARATOR)
2609 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2611 if (!e.keycode && virtKey != VK_NONAME)
2613 WARN("Unknown virtual key %X !!!\n", virtKey);
2614 wine_tsx11_unlock();
2615 return 0;
2617 else TRACE("Found keycode %u\n",e.keycode);
2619 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2620 e.type, e.window, e.state, e.keycode);
2622 /* Clients should pass only KeyPress events to XmbLookupString,
2623 * e.type was set to KeyPress above.
2625 if (xic)
2627 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2628 TRACE("XmbLookupString needs %d byte(s)\n", ret);
2629 if (status == XBufferOverflow)
2631 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2632 if (lpChar == NULL)
2634 ERR("Failed to allocate memory!\n");
2635 wine_tsx11_unlock();
2636 return 0;
2638 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2641 else
2642 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2643 wine_tsx11_unlock();
2645 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2647 if (TRACE_ON(key))
2649 const char *ksname;
2651 wine_tsx11_lock();
2652 ksname = XKeysymToString(keysym);
2653 wine_tsx11_unlock();
2654 if (!ksname) ksname = "No Name";
2655 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2656 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2657 keysym, ksname, ret, debugstr_an(lpChar, ret));
2660 if (ret == 0)
2662 char dead_char;
2664 #ifdef XK_EuroSign
2665 /* An ugly hack for EuroSign: X can't translate it to a character
2666 for some locales. */
2667 if (keysym == XK_EuroSign)
2669 bufW[0] = 0x20AC;
2670 ret = 1;
2671 goto found;
2673 #endif
2674 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2675 /* Here we change it back. */
2676 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2678 bufW[0] = 0x09;
2679 ret = 1;
2680 goto found;
2683 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2684 if (dead_char)
2686 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2687 ret = -1;
2688 goto found;
2691 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2693 /* Unicode direct mapping */
2694 bufW[0] = keysym & 0xffff;
2695 ret = 1;
2696 goto found;
2698 else if ((keysym >> 8) == 0x1008FF) {
2699 bufW[0] = 0;
2700 ret = 0;
2701 goto found;
2703 else
2705 const char *ksname;
2707 wine_tsx11_lock();
2708 ksname = XKeysymToString(keysym);
2709 wine_tsx11_unlock();
2710 if (!ksname)
2711 ksname = "No Name";
2712 if ((keysym >> 8) != 0xff)
2714 WARN("no char for keysym %04lx (%s) :\n",
2715 keysym, ksname);
2716 WARN("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2717 virtKey, scanCode, e.keycode, e.state);
2721 else { /* ret != 0 */
2722 /* We have a special case to handle : Shift + arrow, shift + home, ...
2723 X returns a char for it, but Windows doesn't. Let's eat it. */
2724 if (!(e.state & NumLockMask) /* NumLock is off */
2725 && (e.state & ShiftMask) /* Shift is pressed */
2726 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2728 lpChar[0] = 0;
2729 ret = 0;
2732 /* more areas where X returns characters but Windows does not
2733 CTRL + number or CTRL + symbol */
2734 if (e.state & ControlMask)
2736 if (((keysym>=33) && (keysym < 'A')) ||
2737 ((keysym > 'Z') && (keysym < 'a')) ||
2738 (keysym == XK_Tab))
2740 lpChar[0] = 0;
2741 ret = 0;
2745 /* We have another special case for delete key (XK_Delete) on an
2746 extended keyboard. X returns a char for it, but Windows doesn't */
2747 if (keysym == XK_Delete)
2749 lpChar[0] = 0;
2750 ret = 0;
2752 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2753 && (keysym == XK_KP_Decimal))
2755 lpChar[0] = 0;
2756 ret = 0;
2758 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2759 && (keysym == XK_Return || keysym == XK_KP_Enter))
2761 lpChar[0] = '\n';
2762 ret = 1;
2765 /* Hack to detect an XLookupString hard-coded to Latin1 */
2766 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2768 bufW[0] = (BYTE)lpChar[0];
2769 goto found;
2772 /* perform translation to unicode */
2773 if(ret)
2775 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2776 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2780 found:
2781 if (buf != lpChar)
2782 HeapFree(GetProcessHeap(), 0, lpChar);
2783 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2784 return ret;
2787 /***********************************************************************
2788 * Beep (X11DRV.@)
2790 void CDECL X11DRV_Beep(void)
2792 wine_tsx11_lock();
2793 XBell(gdi_display, 0);
2794 wine_tsx11_unlock();