comctl32: Never release state image list.
[wine/multimedia.git] / dlls / winex11.drv / keyboard.c
blob160b98689c2b4ace8a95756dcd4b4df327fc2e39
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 static int min_keycode, max_keycode, keysyms_per_keycode;
64 static WORD keyc2vkey[256], keyc2scan[256];
66 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
68 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
70 /* Keyboard translation tables */
71 #define MAIN_LEN 49
72 static const WORD main_key_scan_qwerty[MAIN_LEN] =
74 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
75 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
76 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
77 /* q w e r t y u i o p [ ] */
78 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
79 /* a s d f g h j k l ; ' \ */
80 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
81 /* z x c v b n m , . / */
82 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
83 0x56 /* the 102nd key (actually to the right of l-shift) */
86 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
88 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
89 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
90 /* q w e r t y u i o p [ ] */
91 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
92 /* a s d f g h j k l ; ' \ */
93 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
94 /* \ z x c v b n m , . / */
95 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
96 0x56, /* the 102nd key (actually to the right of l-shift) */
99 static const WORD main_key_scan_dvorak[MAIN_LEN] =
101 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
102 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
103 /* ' , . p y f g c r l / = */
104 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
105 /* a o e u i d h t n s - \ */
106 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
107 /* ; q j k x b m w v z */
108 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
109 0x56 /* the 102nd key (actually to the right of l-shift) */
112 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
114 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
115 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
116 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
117 /* q w e r t y u i o p @ [ */
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
119 /* a s d f g h j k l ; : ] */
120 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
121 /* z x c v b n m , . / */
122 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
123 0x56 /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
128 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
129 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
130 /* q w e r t y u i o p @ [ */
131 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
132 /* a s d f g h j k l ; : ] */
133 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
134 /* z x c v b n m , . / */
135 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
136 0x73 /* the 102nd key (actually to the right of l-shift) */
140 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
142 /* NOTE: this layout must concur with the scan codes layout above */
143 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
144 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
145 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
146 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
147 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
150 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
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_macjp[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_7,VK_OEM_5,
164 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
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_v2[MAIN_LEN] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
176 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
177 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
184 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
185 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
186 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
187 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_abnt_qwerty[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','Y','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_8,VK_OEM_5,
196 VK_OEM_7,'Z','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_azerty[MAIN_LEN] =
202 /* NOTE: this layout must concur with the scan codes layout above */
203 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
204 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
205 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
206 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
207 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
210 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
212 /* NOTE: this layout must concur with the scan codes layout above */
213 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
214 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
215 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
216 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
217 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
220 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
222 /* the VK mappings for the main keyboard will be auto-assigned as before,
223 so what we have here is just the character tables */
224 /* order: Normal, Shift, AltGr, Shift-AltGr */
225 /* We recommend you write just what is guaranteed to be correct (i.e. what's
226 written on the keycaps), not the bunch of special characters behind AltGr
227 and Shift-AltGr if it can vary among different X servers */
228 /* These tables serve to guess the keyboard type and scancode mapping.
229 Complete modeling is not important, identification/discrimination is. */
230 /* Remember that your 102nd key (to the right of l-shift) should be on a
231 separate line, see existing tables */
232 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
233 /* Remember to also add your new table to the layout index table far below! */
235 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
236 static const char main_key_US[MAIN_LEN][4] =
238 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
239 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
240 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
241 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
244 /*** United States keyboard layout (phantom key version) */
245 /* (XFree86 reports the <> key even if it's not physically there) */
246 static const char main_key_US_phantom[MAIN_LEN][4] =
248 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
249 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
251 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
252 "<>" /* the phantom key */
255 /*** United States keyboard layout (dvorak version) */
256 static const char main_key_US_dvorak[MAIN_LEN][4] =
258 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
259 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
260 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
261 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
264 /*** British keyboard layout */
265 static const char main_key_UK[MAIN_LEN][4] =
267 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
268 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
269 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
270 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
271 "\\|"
274 /*** French keyboard layout (setxkbmap fr) */
275 static const char main_key_FR[MAIN_LEN][4] =
277 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
278 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
279 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
280 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
281 "<>"
284 /*** Icelandic keyboard layout (setxkbmap is) */
285 static const char main_key_IS[MAIN_LEN][4] =
287 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
288 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
290 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
291 "<>"
294 /* All german keyb layout tables have the acute/apostrophe symbol next to
295 * the BACKSPACE key removed (replaced with NULL which is ignored by the
296 * detection code).
297 * This was done because the mapping of the acute (and apostrophe) is done
298 * differently in various xkb-data/xkeyboard-config versions. Some replace
299 * the acute with a normal apostrophe, so that the apostrophe is found twice
300 * on the keyboard (one next to BACKSPACE and one next to ENTER).
301 * Others put the acute and grave accents on the key left of BACKSPACE.
302 * More information on the fd.o bugtracker:
303 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
304 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
305 * among PC and Mac keyboards, so these are not listed.
308 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
309 static const char main_key_DE[MAIN_LEN][4] =
311 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","",
312 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
313 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
314 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
315 "<>"
318 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
319 static const char main_key_SG[MAIN_LEN][4] =
321 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
322 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
323 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
324 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
325 "<>"
328 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
329 static const char main_key_SF[MAIN_LEN][4] =
331 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
332 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
333 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
334 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
335 "<>"
338 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
339 static const char main_key_NO[MAIN_LEN][4] =
341 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
342 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
343 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
344 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
345 "<>"
348 /*** Danish keyboard layout (setxkbmap dk) */
349 static const char main_key_DA[MAIN_LEN][4] =
351 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
352 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
353 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
354 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
355 "<>"
358 /*** Swedish keyboard layout (setxkbmap se) */
359 static const char main_key_SE[MAIN_LEN][4] =
361 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
362 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
363 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
364 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
365 "<>"
368 /*** Estonian keyboard layout (setxkbmap ee) */
369 static const char main_key_ET[MAIN_LEN][4] =
371 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
372 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
373 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
374 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
375 "<>"
378 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
379 static const char main_key_CF[MAIN_LEN][4] =
381 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
382 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
383 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
384 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
385 "«»°"
388 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
389 static const char main_key_CA_fr[MAIN_LEN][4] =
391 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
392 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
393 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
394 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
395 "«»"
398 /*** Canadian keyboard layout (setxkbmap ca) */
399 static const char main_key_CA[MAIN_LEN][4] =
401 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
402 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
403 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
404 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
405 "ùÙ"
408 /*** Portuguese keyboard layout (setxkbmap pt) */
409 static const char main_key_PT[MAIN_LEN][4] =
411 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
412 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
413 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
414 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
415 "<>"
418 /*** Italian keyboard layout (setxkbmap it) */
419 static const char main_key_IT[MAIN_LEN][4] =
421 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
422 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
423 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
424 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
425 "<>"
428 /*** Finnish keyboard layout (setxkbmap fi) */
429 static const char main_key_FI[MAIN_LEN][4] =
431 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
432 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
433 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
434 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
435 "<>"
438 /*** Bulgarian bds keyboard layout */
439 static const char main_key_BG_bds[MAIN_LEN][4] =
441 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
442 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
443 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
444 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
445 "<>" /* the phantom key */
448 /*** Bulgarian phonetic keyboard layout */
449 static const char main_key_BG_phonetic[MAIN_LEN][4] =
451 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
452 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
453 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
454 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
455 "<>" /* the phantom key */
458 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
459 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
460 static const char main_key_BY[MAIN_LEN][4] =
462 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
463 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
464 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
465 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
469 /*** Russian keyboard layout (contributed by Pavel Roskin) */
470 static const char main_key_RU[MAIN_LEN][4] =
472 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
473 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
474 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
475 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
478 /*** Russian keyboard layout (phantom key version) */
479 static const char main_key_RU_phantom[MAIN_LEN][4] =
481 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
482 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
483 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
484 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
485 "<>" /* the phantom key */
488 /*** Russian keyboard layout KOI8-R */
489 static const char main_key_RU_koi8r[MAIN_LEN][4] =
491 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
492 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
493 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
494 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
495 "<>" /* the phantom key */
498 /*** Russian keyboard layout cp1251 */
499 static const char main_key_RU_cp1251[MAIN_LEN][4] =
501 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
502 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
503 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
504 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
505 "<>" /* the phantom key */
508 /*** Russian phonetic keyboard layout */
509 static const char main_key_RU_phonetic[MAIN_LEN][4] =
511 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
512 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
513 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
514 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
515 "<>" /* the phantom key */
518 /*** Ukrainian keyboard layout KOI8-U */
519 static const char main_key_UA[MAIN_LEN][4] =
521 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
522 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
523 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
524 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
525 "<>" /* the phantom key */
528 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
529 /*** (as it appears on most of keyboards sold today) */
530 static const char main_key_UA_std[MAIN_LEN][4] =
532 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
533 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
534 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
535 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
536 "<>" /* the phantom key */
539 /*** Russian keyboard layout KOI8-R (pair to the previous) */
540 static const char main_key_RU_std[MAIN_LEN][4] =
542 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
543 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
544 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
545 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
546 "<>" /* the phantom key */
549 /*** Spanish keyboard layout (setxkbmap es) */
550 static const char main_key_ES[MAIN_LEN][4] =
552 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
553 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
554 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
555 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
556 "<>"
559 /*** Belgian keyboard layout ***/
560 static const char main_key_BE[MAIN_LEN][4] =
562 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
563 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
564 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
565 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
566 "<>\\"
569 /*** Hungarian keyboard layout (setxkbmap hu) */
570 static const char main_key_HU[MAIN_LEN][4] =
572 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
573 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
574 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
575 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
576 "íÍ"
579 /*** Polish (programmer's) keyboard layout ***/
580 static const char main_key_PL[MAIN_LEN][4] =
582 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
583 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
584 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
585 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
586 "<>|"
589 /*** Slovenian keyboard layout (setxkbmap si) ***/
590 static const char main_key_SI[MAIN_LEN][4] =
592 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
593 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
594 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
595 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
596 "<>"
599 /*** Serbian keyboard layout (setxkbmap sr) ***/
600 static const char main_key_SR[MAIN_LEN][4] =
602 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
603 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
604 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
605 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
606 "<>" /* the phantom key */
609 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
610 static const char main_key_US_SR[MAIN_LEN][4] =
612 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
613 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
614 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
615 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
616 "<>" /* the phantom key */
619 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
620 static const char main_key_HR_jelly[MAIN_LEN][4] =
622 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
623 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
624 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
625 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
626 "<>|"
629 /*** Croatian keyboard layout (setxkbmap hr) ***/
630 static const char main_key_HR[MAIN_LEN][4] =
632 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
633 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
634 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
635 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
636 "<>"
639 /*** Japanese 106 keyboard layout ***/
640 static const char main_key_JA_jp106[MAIN_LEN][4] =
642 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
643 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
644 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
645 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
646 "\\_",
649 static const char main_key_JA_macjp[MAIN_LEN][4] =
651 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
652 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
653 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
654 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
655 "__",
658 /*** Japanese pc98x1 keyboard layout ***/
659 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
661 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
662 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
663 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
664 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
665 "\\_",
668 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
669 static const char main_key_PT_br[MAIN_LEN][4] =
671 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
672 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
673 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
674 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
677 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
678 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
680 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
681 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
682 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
683 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
686 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
687 static const char main_key_US_intl[MAIN_LEN][4] =
689 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
690 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
691 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
692 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
695 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
696 - dead_abovering replaced with degree - no symbol in iso8859-2
697 - brokenbar replaced with bar */
698 static const char main_key_SK[MAIN_LEN][4] =
700 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
701 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
702 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
703 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
704 "<>"
707 /*** Czech keyboard layout (setxkbmap cz) */
708 static const char main_key_CZ[MAIN_LEN][4] =
710 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
711 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
712 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
713 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
714 "\\"
717 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
718 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
720 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
721 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
722 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
723 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
724 "\\"
727 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
728 static const char main_key_SK_prog[MAIN_LEN][4] =
730 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
731 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
732 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
733 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
734 "<>"
737 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
738 static const char main_key_CS[MAIN_LEN][4] =
740 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
741 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
742 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
743 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
744 "<>\\|"
747 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
748 static const char main_key_LA[MAIN_LEN][4] =
750 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
751 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
752 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
753 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
754 "<>"
757 /*** Lithuanian keyboard layout (setxkbmap lt) */
758 static const char main_key_LT_B[MAIN_LEN][4] =
760 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
761 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
762 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
763 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
764 "ª¬"
767 /*** Turkish keyboard Layout */
768 static const char main_key_TK[MAIN_LEN][4] =
770 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
771 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
772 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
773 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
776 /*** Turkish keyboard layout (setxkbmap tr) */
777 static const char main_key_TR[MAIN_LEN][4] =
779 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
780 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
781 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
782 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
783 "<>"
786 /*** Turkish F keyboard layout (setxkbmap trf) */
787 static const char main_key_TR_F[MAIN_LEN][4] =
789 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
790 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
791 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
792 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
793 "<>"
796 /*** Israelian keyboard layout (setxkbmap us,il) */
797 static const char main_key_IL[MAIN_LEN][4] =
799 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
800 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
801 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
802 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
803 "<>"
806 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
807 static const char main_key_IL_phonetic[MAIN_LEN][4] =
809 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
810 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
811 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
812 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
813 "<>"
816 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
817 static const char main_key_IL_saharon[MAIN_LEN][4] =
819 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
820 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
821 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
822 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
823 "<>"
826 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
827 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
828 message since they have different characters in gr and el XFree86 layouts. */
829 static const char main_key_EL[MAIN_LEN][4] =
831 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
832 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
833 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
834 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
835 "<>"
838 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
839 static const char main_key_th[MAIN_LEN][4] =
841 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
842 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
843 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
844 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
847 /*** VNC keyboard layout */
848 static const WORD main_key_scan_vnc[MAIN_LEN] =
850 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
851 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,
852 0x56
855 static const WORD main_key_vkey_vnc[MAIN_LEN] =
857 '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,
858 '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',
859 VK_OEM_102
862 static const char main_key_vnc[MAIN_LEN][4] =
864 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
865 "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"
868 /*** Dutch keyboard layout (setxkbmap nl) ***/
869 static const char main_key_NL[MAIN_LEN][4] =
871 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
872 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
873 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
874 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
875 "[]"
880 /*** Layout table. Add your keyboard mappings to this list */
881 static const struct {
882 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
883 in the appropriate dlls/kernel/nls/.nls file */
884 const char *comment;
885 const char (*key)[MAIN_LEN][4];
886 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
887 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
888 } main_key_tab[]={
889 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
892 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
895 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
896 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
897 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
898 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
902 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
906 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
908 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
909 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
913 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
925 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
927 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
928 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
929 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
930 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
932 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
933 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
938 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
948 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0, NULL, NULL, NULL, NULL} /* sentinel */
954 static unsigned kbd_layout=0; /* index into above table of layouts */
956 /* maybe more of these scancodes should be extended? */
957 /* extended must be set for ALT_R, CTRL_R,
958 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
959 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
960 /* FIXME should we set extended bit for NumLock ? My
961 * Windows does ... DF */
962 /* Yes, to distinguish based on scan codes, also
963 for PrtScn key ... GA */
965 static const WORD nonchar_key_vkey[256] =
967 /* unused */
968 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
969 /* special keys */
970 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
971 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
972 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
973 /* unused */
974 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
975 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
976 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
977 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
978 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
980 /* cursor keys */
981 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
982 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
983 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
984 /* misc keys */
985 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
986 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
987 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
988 /* keypad keys */
989 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
990 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
991 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
992 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
993 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
994 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
995 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
996 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
997 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
998 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
999 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1000 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1001 /* function keys */
1002 VK_F1, VK_F2,
1003 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1004 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1005 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1007 /* modifier keys */
1008 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1009 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1010 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1012 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1015 static const WORD nonchar_key_scan[256] =
1017 /* unused */
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1019 /* special keys */
1020 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1021 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1022 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1023 /* unused */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1030 /* cursor keys */
1031 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1033 /* misc keys */
1034 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1035 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1037 /* keypad keys */
1038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1042 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1044 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1045 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1046 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1047 /* function keys */
1048 0x3B, 0x3C,
1049 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1050 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1053 /* modifier keys */
1054 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1055 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1060 static const WORD xfree86_vendor_key_vkey[256] =
1062 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1063 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1064 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1065 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1066 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1067 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1068 0, 0, 0, VK_BROWSER_HOME,
1069 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1070 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1071 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1072 0, 0, 0, 0,
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1097 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1100 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1102 #ifdef HAVE_XKB
1103 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1104 #endif
1105 return XKeycodeToKeysym(display, keycode, index);
1108 /* Returns the Windows virtual key code associated with the X event <e> */
1109 /* x11 lock must be held */
1110 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1112 KeySym keysym = 0;
1113 Status status;
1114 char buf[24];
1116 /* Clients should pass only KeyPress events to XmbLookupString */
1117 if (xic && e->type == KeyPress)
1118 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1119 else
1120 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1122 if ((e->state & NumLockMask) &&
1123 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1124 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1125 /* Only the Keypad keys 0-9 and . send different keysyms
1126 * depending on the NumLock state */
1127 return nonchar_key_vkey[keysym & 0xFF];
1129 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1130 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1131 if ((e->state & ControlMask) && (keysym == XK_Break))
1132 return VK_CANCEL;
1134 TRACE_(key)("e->keycode = %u\n", e->keycode);
1136 return keyc2vkey[e->keycode];
1140 /***********************************************************************
1141 * X11DRV_send_keyboard_input
1143 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1145 INPUT input;
1147 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1149 input.type = INPUT_KEYBOARD;
1150 input.u.ki.wVk = vkey;
1151 input.u.ki.wScan = scan;
1152 input.u.ki.dwFlags = flags;
1153 input.u.ki.time = time;
1154 input.u.ki.dwExtraInfo = 0;
1156 __wine_send_input( hwnd, &input );
1160 /***********************************************************************
1161 * get_async_key_state
1163 static BOOL get_async_key_state( BYTE state[256] )
1165 BOOL ret;
1167 SERVER_START_REQ( get_key_state )
1169 req->tid = 0;
1170 req->key = -1;
1171 wine_server_set_reply( req, state, 256 );
1172 ret = !wine_server_call( req );
1174 SERVER_END_REQ;
1175 return ret;
1178 /***********************************************************************
1179 * X11DRV_KeymapNotify
1181 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1183 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1184 * from wine to another application and back.
1185 * Toggle keys are handled in HandleEvent.
1187 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1189 int i, j;
1190 DWORD time = GetCurrentTime();
1191 BYTE keystate[256];
1192 WORD vkey;
1193 struct {
1194 WORD vkey;
1195 WORD scan;
1196 BOOL pressed;
1197 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1199 if (!get_async_key_state( keystate )) return;
1201 memset(modifiers, 0, sizeof(modifiers));
1203 /* the minimum keycode is always greater or equal to 8, so we can
1204 * skip the first 8 values, hence start at 1
1206 for (i = 1; i < 32; i++)
1208 for (j = 0; j < 8; j++)
1210 int m;
1212 vkey = keyc2vkey[(i * 8) + j];
1214 switch(vkey & 0xff)
1216 case VK_LMENU:
1217 case VK_RMENU:
1218 case VK_LCONTROL:
1219 case VK_RCONTROL:
1220 case VK_LSHIFT:
1221 case VK_RSHIFT:
1222 m = (vkey & 0xff) - VK_LSHIFT;
1223 /* Take the vkey and scan from the first keycode we encounter
1224 for this modifier. */
1225 if (!modifiers[m].vkey)
1227 modifiers[m].vkey = vkey;
1228 modifiers[m].scan = keyc2scan[(i * 8) + j];
1230 if (event->xkeymap.key_vector[i] & (1<<j))
1231 modifiers[m].pressed = TRUE;
1232 break;
1237 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1239 int m = vkey - VK_LSHIFT;
1240 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1242 DWORD flags = modifiers[m].vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1243 if (!modifiers[m].pressed) flags |= KEYEVENTF_KEYUP;
1245 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1246 modifiers[m].vkey, keystate[vkey]);
1248 /* Fake key being pressed inside wine */
1249 X11DRV_send_keyboard_input( hwnd, vkey, modifiers[m].scan & 0xff, flags, time );
1254 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1256 BYTE keystate[256];
1258 /* Note: X sets the below states on key down and clears them on key up.
1259 Windows triggers them on key down. */
1261 if (!get_async_key_state( keystate )) return;
1263 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1264 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1266 DWORD flags = 0;
1267 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1268 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1269 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1270 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1273 /* Adjust the NUMLOCK state if it has been changed outside wine */
1274 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1276 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1277 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1278 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1279 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1280 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1283 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1284 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1286 DWORD flags = 0;
1287 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1288 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1289 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1290 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1294 /***********************************************************************
1295 * X11DRV_KeyEvent
1297 * Handle a X key event
1299 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1301 XKeyEvent *event = &xev->xkey;
1302 char buf[24];
1303 char *Str = buf;
1304 KeySym keysym = 0;
1305 WORD vkey = 0, bScan;
1306 DWORD dwFlags;
1307 int ascii_chars;
1308 XIC xic = X11DRV_get_ic( hwnd );
1309 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1310 Status status = 0;
1312 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1313 event->type, event->window, event->state, event->keycode);
1315 if (event->type == KeyPress) update_user_time( event->time );
1317 wine_tsx11_lock();
1318 /* Clients should pass only KeyPress events to XmbLookupString */
1319 if (xic && event->type == KeyPress)
1321 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1322 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1323 if (status == XBufferOverflow)
1325 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1326 if (Str == NULL)
1328 ERR_(key)("Failed to allocate memory!\n");
1329 wine_tsx11_unlock();
1330 return;
1332 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1335 else
1336 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1337 wine_tsx11_unlock();
1339 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1341 if (status == XLookupChars)
1343 X11DRV_XIMLookupChars( Str, ascii_chars );
1344 if (buf != Str)
1345 HeapFree(GetProcessHeap(), 0, Str);
1346 return;
1349 /* If XKB extensions are used, the state mask for AltGr will use the group
1350 index instead of the modifier mask. The group index is set in bits
1351 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1352 pressed, look if the group index is different than 0. From XKB
1353 extension documentation, the group index for AltGr should be 2
1354 (event->state = 0x2000). It's probably better to not assume a
1355 predefined group index and find it dynamically
1357 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1358 /* Save also all possible modifier states. */
1359 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1361 if (TRACE_ON(key)){
1362 const char *ksname;
1364 wine_tsx11_lock();
1365 ksname = XKeysymToString(keysym);
1366 wine_tsx11_unlock();
1367 if (!ksname)
1368 ksname = "No Name";
1369 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1370 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1371 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1373 if (buf != Str)
1374 HeapFree(GetProcessHeap(), 0, Str);
1376 wine_tsx11_lock();
1377 vkey = EVENT_event_to_vkey(xic,event);
1378 /* X returns keycode 0 for composed characters */
1379 if (!vkey && ascii_chars) vkey = VK_NONAME;
1380 wine_tsx11_unlock();
1382 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1383 event->keycode, vkey);
1385 if (!vkey) return;
1387 dwFlags = 0;
1388 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1389 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1391 update_lock_state( hwnd, vkey, event->state, event_time );
1393 bScan = keyc2scan[event->keycode] & 0xFF;
1394 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1396 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1399 /**********************************************************************
1400 * X11DRV_KEYBOARD_DetectLayout
1402 * Called from X11DRV_InitKeyboard
1403 * This routine walks through the defined keyboard layouts and selects
1404 * whichever matches most closely.
1405 * X11 lock must be held.
1407 static void
1408 X11DRV_KEYBOARD_DetectLayout( Display *display )
1410 unsigned current, match, mismatch, seq, i, syms;
1411 int score, keyc, key, pkey, ok;
1412 KeySym keysym = 0;
1413 const char (*lkey)[MAIN_LEN][4];
1414 unsigned max_seq = 0;
1415 int max_score = 0, ismatch = 0;
1416 char ckey[256][4];
1418 syms = keysyms_per_keycode;
1419 if (syms > 4) {
1420 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1421 syms = 4;
1424 memset( ckey, 0, sizeof(ckey) );
1425 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1426 /* get data for keycode from X server */
1427 for (i = 0; i < syms; i++) {
1428 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1429 /* Allow both one-byte and two-byte national keysyms */
1430 if ((keysym < 0x8000) && (keysym != ' '))
1432 #ifdef HAVE_XKB
1433 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1434 #endif
1436 TRACE("XKB could not translate keysym %04lx\n", keysym);
1437 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1438 * with appropriate ShiftMask and Mode_switch, use XLookupString
1439 * to get character in the local encoding.
1441 ckey[keyc][i] = keysym & 0xFF;
1444 else {
1445 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1450 for (current = 0; main_key_tab[current].comment; current++) {
1451 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1452 match = 0;
1453 mismatch = 0;
1454 score = 0;
1455 seq = 0;
1456 lkey = main_key_tab[current].key;
1457 pkey = -1;
1458 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1459 if (ckey[keyc][0]) {
1460 /* search for a match in layout table */
1461 /* right now, we just find an absolute match for defined positions */
1462 /* (undefined positions are ignored, so if it's defined as "3#" in */
1463 /* the table, it's okay that the X server has "3#£", for example) */
1464 /* however, the score will be higher for longer matches */
1465 for (key = 0; key < MAIN_LEN; key++) {
1466 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1467 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1468 ok++;
1469 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1470 ok = -1;
1472 if (ok > 0) {
1473 score += ok;
1474 break;
1477 /* count the matches and mismatches */
1478 if (ok > 0) {
1479 match++;
1480 /* and how much the keycode order matches */
1481 if (key > pkey) seq++;
1482 pkey = key;
1483 } else {
1484 /* print spaces instead of \0's */
1485 char str[5];
1486 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1487 str[4] = 0;
1488 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1489 mismatch++;
1490 score -= syms;
1494 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1495 match, mismatch, seq, score);
1496 if ((score > max_score) ||
1497 ((score == max_score) && (seq > max_seq))) {
1498 /* best match so far */
1499 kbd_layout = current;
1500 max_score = score;
1501 max_seq = seq;
1502 ismatch = !mismatch;
1505 /* we're done, report results if necessary */
1506 if (!ismatch)
1507 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1508 main_key_tab[kbd_layout].comment);
1510 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1513 static HKL get_locale_kbd_layout(void)
1515 ULONG_PTR layout;
1516 LANGID langid;
1518 /* FIXME:
1520 * layout = main_key_tab[kbd_layout].lcid;
1522 * Winword uses return value of GetKeyboardLayout as a codepage
1523 * to translate ANSI keyboard messages to unicode. But we have
1524 * a problem with it: for instance Polish keyboard layout is
1525 * identical to the US one, and therefore instead of the Polish
1526 * locale id we return the US one.
1529 layout = GetUserDefaultLCID();
1532 * Microsoft Office expects this value to be something specific
1533 * for Japanese and Korean Windows with an IME the value is 0xe001
1534 * We should probably check to see if an IME exists and if so then
1535 * set this word properly.
1537 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1538 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1539 layout |= 0xe001 << 16; /* IME */
1540 else
1541 layout |= layout << 16;
1543 return (HKL)layout;
1546 /***********************************************************************
1547 * GetKeyboardLayoutName (X11DRV.@)
1549 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1551 static const WCHAR formatW[] = {'%','0','8','x',0};
1552 DWORD layout;
1554 layout = HandleToUlong( get_locale_kbd_layout() );
1555 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1556 sprintfW(name, formatW, layout);
1557 TRACE("returning %s\n", debugstr_w(name));
1558 return TRUE;
1561 static void set_kbd_layout_preload_key(void)
1563 static const WCHAR preload[] =
1564 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1565 static const WCHAR one[] = {'1',0};
1567 HKEY hkey;
1568 WCHAR layout[KL_NAMELENGTH];
1570 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1571 return;
1573 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1575 RegCloseKey(hkey);
1576 return;
1578 if (X11DRV_GetKeyboardLayoutName(layout))
1579 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1581 RegCloseKey(hkey);
1584 /**********************************************************************
1585 * X11DRV_InitKeyboard
1587 void X11DRV_InitKeyboard( Display *display )
1589 KeySym *ksp;
1590 XModifierKeymap *mmp;
1591 KeySym keysym;
1592 KeyCode *kcp;
1593 XKeyEvent e2;
1594 WORD scan, vkey;
1595 int keyc, i, keyn, syms;
1596 char ckey[4]={0,0,0,0};
1597 const char (*lkey)[MAIN_LEN][4];
1598 char vkey_used[256] = { 0 };
1600 /* Ranges of OEM, function key, and character virtual key codes.
1601 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1602 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1603 static const struct {
1604 WORD first, last;
1605 } vkey_ranges[] = {
1606 { VK_OEM_1, VK_OEM_3 },
1607 { VK_OEM_4, VK_ICO_00 },
1608 { 0xe6, 0xe6 },
1609 { 0xe9, 0xf5 },
1610 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1611 { VK_F1, VK_F24 },
1612 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1613 { 0x41, 0x5a }, /* VK_A - VK_Z */
1614 { 0, 0 }
1616 int vkey_range;
1618 set_kbd_layout_preload_key();
1620 wine_tsx11_lock();
1621 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1622 ksp = XGetKeyboardMapping(display, min_keycode,
1623 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1624 /* We are only interested in keysyms_per_keycode.
1625 There is no need to hold a local copy of the keysyms table */
1626 XFree(ksp);
1628 mmp = XGetModifierMapping(display);
1629 kcp = mmp->modifiermap;
1630 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1632 int j;
1634 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1635 if (*kcp)
1637 int k;
1639 for (k = 0; k < keysyms_per_keycode; k += 1)
1640 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1642 NumLockMask = 1 << i;
1643 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1645 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1647 ScrollLockMask = 1 << i;
1648 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1652 XFreeModifiermap(mmp);
1654 /* Detect the keyboard layout */
1655 X11DRV_KEYBOARD_DetectLayout( display );
1656 lkey = main_key_tab[kbd_layout].key;
1657 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1659 /* Now build two conversion arrays :
1660 * keycode -> vkey + scancode + extended
1661 * vkey + extended -> keycode */
1663 e2.display = display;
1664 e2.state = 0;
1665 e2.type = KeyPress;
1667 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1668 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1670 char buf[30];
1671 int have_chars;
1673 keysym = 0;
1674 e2.keycode = (KeyCode)keyc;
1675 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1676 vkey = 0; scan = 0;
1677 if (keysym) /* otherwise, keycode not used */
1679 if ((keysym >> 8) == 0xFF) /* non-character key */
1681 vkey = nonchar_key_vkey[keysym & 0xff];
1682 scan = nonchar_key_scan[keysym & 0xff];
1683 /* set extended bit when necessary */
1684 if (scan & 0x100) vkey |= 0x100;
1685 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1686 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1687 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1688 scan = 0x100;
1689 vkey |= 0x100;
1690 } else if (keysym == 0x20) { /* Spacebar */
1691 vkey = VK_SPACE;
1692 scan = 0x39;
1693 } else if (have_chars) {
1694 /* we seem to need to search the layout-dependent scancodes */
1695 int maxlen=0,maxval=-1,ok;
1696 for (i=0; i<syms; i++) {
1697 keysym = keycode_to_keysym(display, keyc, i);
1698 if ((keysym<0x8000) && (keysym!=' '))
1700 #ifdef HAVE_XKB
1701 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1702 #endif
1704 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1705 * with appropriate ShiftMask and Mode_switch, use XLookupString
1706 * to get character in the local encoding.
1708 ckey[i] = keysym & 0xFF;
1710 } else {
1711 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1714 /* find key with longest match streak */
1715 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1716 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1717 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1718 if (!ok) i--; /* we overshot */
1719 if (ok||(i>maxlen)) {
1720 maxlen=i; maxval=keyn;
1722 if (ok) break;
1724 if (maxval>=0) {
1725 /* got it */
1726 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1727 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1728 scan = (*lscan)[maxval];
1729 vkey = (*lvkey)[maxval];
1733 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1734 keyc2vkey[e2.keycode] = vkey;
1735 keyc2scan[e2.keycode] = scan;
1736 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1737 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1738 vkey_used[(vkey & 0xff)] = 1;
1739 } /* for */
1741 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1742 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1744 vkey = keyc2vkey[keyc] & 0xff;
1745 if (vkey)
1746 continue;
1748 e2.keycode = (KeyCode)keyc;
1749 keysym = XLookupKeysym(&e2, 0);
1750 if (!keysym)
1751 continue;
1753 /* find a suitable layout-dependent VK code */
1754 /* (most Winelib apps ought to be able to work without layout tables!) */
1755 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1757 keysym = XLookupKeysym(&e2, i);
1758 if ((keysym >= XK_0 && keysym <= XK_9)
1759 || (keysym >= XK_A && keysym <= XK_Z)) {
1760 vkey = VKEY_IF_NOT_USED(keysym);
1764 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1766 keysym = XLookupKeysym(&e2, i);
1767 switch (keysym)
1769 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1770 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1771 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1772 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1773 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1774 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1775 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1776 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1777 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1778 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1779 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1783 if (vkey)
1785 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1786 keyc2vkey[e2.keycode] = vkey;
1788 } /* for */
1790 /* For any keycodes which still don't have a vkey, assign any spare
1791 * character, function key, or OEM virtual key code. */
1792 vkey_range = 0;
1793 vkey = vkey_ranges[vkey_range].first;
1794 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1796 if (keyc2vkey[keyc] & 0xff)
1797 continue;
1799 e2.keycode = (KeyCode)keyc;
1800 keysym = XLookupKeysym(&e2, 0);
1801 if (!keysym)
1802 continue;
1804 while (vkey && vkey_used[vkey])
1806 if (vkey == vkey_ranges[vkey_range].last)
1808 vkey_range++;
1809 vkey = vkey_ranges[vkey_range].first;
1811 else
1812 vkey++;
1815 if (!vkey)
1817 WARN("No more vkeys available!\n");
1818 break;
1821 if (TRACE_ON(keyboard))
1823 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1824 vkey, e2.keycode);
1825 TRACE("(");
1826 for (i = 0; i < keysyms_per_keycode; i += 1)
1828 const char *ksname;
1830 keysym = XLookupKeysym(&e2, i);
1831 ksname = XKeysymToString(keysym);
1832 if (!ksname)
1833 ksname = "NoSymbol";
1834 TRACE( "%lx (%s) ", keysym, ksname);
1836 TRACE(")\n");
1839 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1840 keyc2vkey[e2.keycode] = vkey;
1841 vkey_used[vkey] = 1;
1842 } /* for */
1843 #undef VKEY_IF_NOT_USED
1845 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1846 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1847 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1848 const char *ksname;
1849 keysym = keycode_to_keysym(display, keyc, 0);
1850 ksname = XKeysymToString(keysym);
1851 if (!ksname) ksname = "NoSymbol";
1853 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1855 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1856 keyc2scan[keyc]=scan++;
1859 wine_tsx11_unlock();
1862 static BOOL match_x11_keyboard_layout(HKL hkl)
1864 const DWORD isIME = 0xE0000000;
1865 HKL xHkl = get_locale_kbd_layout();
1867 /* if the layout is an IME, only match the low word (LCID) */
1868 if (((ULONG_PTR)hkl & isIME) == isIME)
1869 return (LOWORD(hkl) == LOWORD(xHkl));
1870 else
1871 return (hkl == xHkl);
1874 /**********************************************************************
1875 * GetAsyncKeyState (X11DRV.@)
1877 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1879 /* Photoshop livelocks unless mouse events are included here */
1880 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1881 return -1;
1885 /***********************************************************************
1886 * GetKeyboardLayout (X11DRV.@)
1888 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1890 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1892 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1893 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1895 else
1896 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1898 return get_locale_kbd_layout();
1902 /***********************************************************************
1903 * LoadKeyboardLayout (X11DRV.@)
1905 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1907 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1908 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1909 return 0;
1913 /***********************************************************************
1914 * UnloadKeyboardLayout (X11DRV.@)
1916 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1918 FIXME("%p: stub!\n", hkl);
1919 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1920 return FALSE;
1924 /***********************************************************************
1925 * ActivateKeyboardLayout (X11DRV.@)
1927 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1929 HKL oldHkl = 0;
1930 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1932 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1933 if (flags & KLF_SETFORPROCESS)
1935 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1936 FIXME("KLF_SETFORPROCESS not supported\n");
1937 return 0;
1940 if (flags)
1941 FIXME("flags %x not supported\n",flags);
1943 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1945 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1946 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1947 return 0;
1950 if (!match_x11_keyboard_layout(hkl))
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1953 FIXME("setting keyboard of different locales not supported\n");
1954 return 0;
1957 oldHkl = thread_data->kbd_layout;
1958 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1960 thread_data->kbd_layout = hkl;
1962 return oldHkl;
1966 /***********************************************************************
1967 * X11DRV_MappingNotify
1969 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1971 HWND hwnd;
1973 wine_tsx11_lock();
1974 XRefreshKeyboardMapping(&event->xmapping);
1975 wine_tsx11_unlock();
1976 X11DRV_InitKeyboard( event->xmapping.display );
1978 hwnd = GetFocus();
1979 if (!hwnd) hwnd = GetActiveWindow();
1980 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1981 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1985 /***********************************************************************
1986 * VkKeyScanEx (X11DRV.@)
1988 * Note: Windows ignores HKL parameter and uses current active layout instead
1990 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1992 Display *display = thread_init_display();
1993 KeyCode keycode;
1994 KeySym keysym;
1995 int i, index;
1996 CHAR cChar;
1997 SHORT ret;
1999 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2000 * is UTF-8 (multibyte encoding)?
2002 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2004 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2005 return -1;
2008 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2010 /* char->keysym (same for ANSI chars) */
2011 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2012 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2014 wine_tsx11_lock();
2015 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2016 if (!keycode)
2018 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2020 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2021 TRACE(" ... returning ctrl char %#.2x\n", ret);
2022 wine_tsx11_unlock();
2023 return ret;
2025 /* It didn't work ... let's try with deadchar code. */
2026 TRACE("retrying with | 0xFE00\n");
2027 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2029 wine_tsx11_unlock();
2031 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2033 /* keycode -> (keyc2vkey) vkey */
2034 ret = keyc2vkey[keycode];
2036 if (!keycode || !ret)
2038 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2039 return -1;
2042 index = -1;
2043 wine_tsx11_lock();
2044 for (i = 0; i < 4; i++) /* find shift state */
2046 if (keycode_to_keysym(display, keycode, i) == keysym)
2048 index = i;
2049 break;
2052 wine_tsx11_unlock();
2054 switch (index)
2056 default:
2057 case -1:
2058 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2059 return -1;
2061 case 0: break;
2062 case 1: ret += 0x0100; break;
2063 case 2: ret += 0x0600; break;
2064 case 3: ret += 0x0700; break;
2067 index : 0 adds 0x0000
2068 index : 1 adds 0x0100 (shift)
2069 index : ? adds 0x0200 (ctrl)
2070 index : 2 adds 0x0600 (ctrl+alt)
2071 index : 3 adds 0x0700 (ctrl+alt+shift)
2074 TRACE(" ... returning %#.2x\n", ret);
2075 return ret;
2078 /***********************************************************************
2079 * MapVirtualKeyEx (X11DRV.@)
2081 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2083 Display *display = thread_init_display();
2085 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2087 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2088 if (!match_x11_keyboard_layout(hkl))
2089 FIXME("keyboard layout %p is not supported\n", hkl);
2091 switch(wMapType)
2093 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2094 case MAPVK_VK_TO_VSC_EX:
2096 int keyc;
2098 switch (wCode)
2100 case VK_SHIFT: wCode = VK_LSHIFT; break;
2101 case VK_CONTROL: wCode = VK_LCONTROL; break;
2102 case VK_MENU: wCode = VK_LMENU; break;
2105 /* let's do vkey -> keycode -> scan */
2106 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2107 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2109 if (keyc > max_keycode)
2111 TRACE("returning no scan-code.\n");
2112 return 0;
2114 returnMVK (keyc2scan[keyc] & 0xFF);
2116 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2117 case MAPVK_VSC_TO_VK_EX:
2119 int keyc;
2120 UINT vkey = 0;
2122 /* let's do scan -> keycode -> vkey */
2123 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2124 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2126 vkey = keyc2vkey[keyc] & 0xFF;
2127 /* Only stop if it's not a numpad vkey; otherwise keep
2128 looking for a potential better vkey. */
2129 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2130 break;
2133 if (vkey == 0)
2135 TRACE("returning no vkey-code.\n");
2136 return 0;
2139 if (wMapType == MAPVK_VSC_TO_VK)
2140 switch (vkey)
2142 case VK_LSHIFT:
2143 case VK_RSHIFT:
2144 vkey = VK_SHIFT; break;
2145 case VK_LCONTROL:
2146 case VK_RCONTROL:
2147 vkey = VK_CONTROL; break;
2148 case VK_LMENU:
2149 case VK_RMENU:
2150 vkey = VK_MENU; break;
2153 returnMVK (vkey);
2155 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2157 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2158 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2159 * key.. Looks like something is wrong with the MS docs?
2160 * This is only true for letters, for example VK_0 returns '0' not ')'.
2161 * - hence we use the lock mask to ensure this happens.
2163 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2164 XKeyEvent e;
2165 KeySym keysym;
2166 int keyc, len;
2167 char s[10];
2169 e.display = display;
2170 e.state = 0;
2171 e.keycode = 0;
2172 e.type = KeyPress;
2174 wine_tsx11_lock();
2176 /* We exit on the first keycode found, to speed up the thing. */
2177 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2178 { /* Find a keycode that could have generated this virtual key */
2179 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2180 { /* We filter the extended bit, we don't know it */
2181 e.keycode = keyc; /* Store it temporarily */
2182 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2183 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2184 state), so set it to 0, we'll find another one */
2189 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2190 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2192 if (wCode==VK_DECIMAL)
2193 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2195 if (!e.keycode)
2197 WARN("Unknown virtual key %X !!!\n", wCode);
2198 wine_tsx11_unlock();
2199 return 0; /* whatever */
2201 TRACE("Found keycode %u\n",e.keycode);
2203 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2204 wine_tsx11_unlock();
2206 if (len)
2208 WCHAR wch;
2209 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2210 returnMVK(toupperW(wch));
2212 TRACE("returning no ANSI.\n");
2213 return 0;
2215 default: /* reserved */
2216 FIXME("Unknown wMapType %d !\n", wMapType);
2217 return 0;
2219 return 0;
2222 /***********************************************************************
2223 * GetKeyNameText (X11DRV.@)
2225 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2227 Display *display = thread_init_display();
2228 int vkey, ansi, scanCode;
2229 KeyCode keyc;
2230 int keyi;
2231 KeySym keys;
2232 char *name;
2234 scanCode = lParam >> 16;
2235 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2237 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2239 /* handle "don't care" bit (0x02000000) */
2240 if (!(lParam & 0x02000000)) {
2241 switch (vkey) {
2242 case VK_RSHIFT:
2243 /* R-Shift is "special" - it is an extended key with separate scan code */
2244 scanCode |= 0x100;
2245 /* fall through */
2246 case VK_LSHIFT:
2247 vkey = VK_SHIFT;
2248 break;
2249 case VK_LCONTROL:
2250 case VK_RCONTROL:
2251 vkey = VK_CONTROL;
2252 break;
2253 case VK_LMENU:
2254 case VK_RMENU:
2255 vkey = VK_MENU;
2256 break;
2260 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2261 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2263 /* first get the name of the "regular" keys which is the Upper case
2264 value of the keycap imprint. */
2265 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2266 (scanCode != 0x137) && /* PrtScn */
2267 (scanCode != 0x135) && /* numpad / */
2268 (scanCode != 0x37 ) && /* numpad * */
2269 (scanCode != 0x4a ) && /* numpad - */
2270 (scanCode != 0x4e ) ) /* numpad + */
2272 if ((nSize >= 2) && lpBuffer)
2274 *lpBuffer = toupperW((WCHAR)ansi);
2275 *(lpBuffer+1) = 0;
2276 return 1;
2278 else
2279 return 0;
2282 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2283 without "extended-key" flag. However Wine generates scancode
2284 *with* "extended-key" flag. Seems to occur *only* for the
2285 function keys. Soooo.. We will leave the table alone and
2286 fudge the lookup here till the other part is found and fixed!!! */
2288 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2289 (scanCode == 0x157) || (scanCode == 0x158))
2290 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2292 /* let's do scancode -> keycode -> keysym -> String */
2294 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2295 if ((keyc2scan[keyi]) == scanCode)
2296 break;
2297 if (keyi <= max_keycode)
2299 wine_tsx11_lock();
2300 keyc = (KeyCode) keyi;
2301 keys = keycode_to_keysym(display, keyc, 0);
2302 name = XKeysymToString(keys);
2303 wine_tsx11_unlock();
2305 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2307 char* idx = strrchr(name, '_');
2308 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2310 INT rc = 0;
2311 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2312 scanCode, keyc, keys, debugstr_an(name,idx-name));
2313 if (lpBuffer && nSize)
2315 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2316 if (rc > 0) lpBuffer[rc - 1] = 0;
2318 return rc;
2322 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2323 scanCode, keyc, (int)keys, debugstr_a(name));
2324 if (lpBuffer && nSize && name)
2325 return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2328 /* Finally issue WARN for unknown keys */
2330 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2331 if (lpBuffer && nSize)
2332 *lpBuffer = 0;
2333 return 0;
2336 /***********************************************************************
2337 * X11DRV_KEYBOARD_MapDeadKeysym
2339 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2341 switch (keysym)
2343 /* symbolic ASCII is the same as defined in rfc1345 */
2344 #ifdef XK_dead_tilde
2345 case XK_dead_tilde :
2346 #endif
2347 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2348 return '~'; /* '? */
2349 #ifdef XK_dead_acute
2350 case XK_dead_acute :
2351 #endif
2352 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2353 return 0xb4; /* '' */
2354 #ifdef XK_dead_circumflex
2355 case XK_dead_circumflex:
2356 #endif
2357 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2358 return '^'; /* '> */
2359 #ifdef XK_dead_grave
2360 case XK_dead_grave :
2361 #endif
2362 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2363 return '`'; /* '! */
2364 #ifdef XK_dead_diaeresis
2365 case XK_dead_diaeresis :
2366 #endif
2367 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2368 return 0xa8; /* ': */
2369 #ifdef XK_dead_cedilla
2370 case XK_dead_cedilla :
2371 return 0xb8; /* ', */
2372 #endif
2373 #ifdef XK_dead_macron
2374 case XK_dead_macron :
2375 return '-'; /* 'm isn't defined on iso-8859-x */
2376 #endif
2377 #ifdef XK_dead_breve
2378 case XK_dead_breve :
2379 return 0xa2; /* '( */
2380 #endif
2381 #ifdef XK_dead_abovedot
2382 case XK_dead_abovedot :
2383 return 0xff; /* '. */
2384 #endif
2385 #ifdef XK_dead_abovering
2386 case XK_dead_abovering :
2387 return '0'; /* '0 isn't defined on iso-8859-x */
2388 #endif
2389 #ifdef XK_dead_doubleacute
2390 case XK_dead_doubleacute :
2391 return 0xbd; /* '" */
2392 #endif
2393 #ifdef XK_dead_caron
2394 case XK_dead_caron :
2395 return 0xb7; /* '< */
2396 #endif
2397 #ifdef XK_dead_ogonek
2398 case XK_dead_ogonek :
2399 return 0xb2; /* '; */
2400 #endif
2401 /* FIXME: I don't know this three.
2402 case XK_dead_iota :
2403 return 'i';
2404 case XK_dead_voiced_sound :
2405 return 'v';
2406 case XK_dead_semivoiced_sound :
2407 return 's';
2410 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2411 return 0;
2414 /***********************************************************************
2415 * ToUnicodeEx (X11DRV.@)
2417 * The ToUnicode function translates the specified virtual-key code and keyboard
2418 * state to the corresponding Windows character or characters.
2420 * If the specified key is a dead key, the return value is negative. Otherwise,
2421 * it is one of the following values:
2422 * Value Meaning
2423 * 0 The specified virtual key has no translation for the current state of the keyboard.
2424 * 1 One Windows character was copied to the buffer.
2425 * 2 Two characters were copied to the buffer. This usually happens when a
2426 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2427 * be composed with the specified virtual key to form a single character.
2429 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2432 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2433 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2435 Display *display = thread_init_display();
2436 XKeyEvent e;
2437 KeySym keysym = 0;
2438 INT ret;
2439 int keyc;
2440 char buf[10];
2441 char *lpChar = buf;
2442 HWND focus;
2443 XIC xic;
2444 Status status = 0;
2446 if (scanCode & 0x8000)
2448 TRACE_(key)("Key UP, doing nothing\n" );
2449 return 0;
2452 if (!match_x11_keyboard_layout(hkl))
2453 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2455 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2457 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2458 return 0;
2461 e.display = display;
2462 e.keycode = 0;
2463 e.state = 0;
2464 e.type = KeyPress;
2466 focus = x11drv_thread_data()->last_xic_hwnd;
2467 if (!focus)
2469 focus = GetFocus();
2470 if (focus) focus = GetAncestor( focus, GA_ROOT );
2471 if (!focus) focus = GetActiveWindow();
2473 e.window = X11DRV_get_whole_window( focus );
2474 xic = X11DRV_get_ic( focus );
2476 if (lpKeyState[VK_SHIFT] & 0x80)
2478 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2479 e.state |= ShiftMask;
2481 if (lpKeyState[VK_CAPITAL] & 0x01)
2483 TRACE_(key)("LockMask = %04x\n", LockMask);
2484 e.state |= LockMask;
2486 if (lpKeyState[VK_CONTROL] & 0x80)
2488 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2489 e.state |= ControlMask;
2491 if (lpKeyState[VK_NUMLOCK] & 0x01)
2493 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2494 e.state |= NumLockMask;
2497 /* Restore saved AltGr state */
2498 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2499 e.state |= AltGrMask;
2501 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2502 virtKey, scanCode, e.state);
2503 wine_tsx11_lock();
2504 /* We exit on the first keycode found, to speed up the thing. */
2505 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2506 { /* Find a keycode that could have generated this virtual key */
2507 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2508 { /* We filter the extended bit, we don't know it */
2509 e.keycode = keyc; /* Store it temporarily */
2510 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2511 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2512 state), so set it to 0, we'll find another one */
2517 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2518 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2520 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2521 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2523 if (virtKey==VK_DECIMAL)
2524 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2526 if (virtKey==VK_SEPARATOR)
2527 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2529 if (!e.keycode && virtKey != VK_NONAME)
2531 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2532 wine_tsx11_unlock();
2533 return 0;
2535 else TRACE_(key)("Found keycode %u\n",e.keycode);
2537 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2538 e.type, e.window, e.state, e.keycode);
2540 /* Clients should pass only KeyPress events to XmbLookupString,
2541 * e.type was set to KeyPress above.
2543 if (xic)
2545 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2546 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2547 if (status == XBufferOverflow)
2549 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2550 if (lpChar == NULL)
2552 ERR_(key)("Failed to allocate memory!\n");
2553 wine_tsx11_unlock();
2554 return 0;
2556 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2559 else
2560 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2561 wine_tsx11_unlock();
2563 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2565 if (TRACE_ON(key))
2567 const char *ksname;
2569 wine_tsx11_lock();
2570 ksname = XKeysymToString(keysym);
2571 wine_tsx11_unlock();
2572 if (!ksname) ksname = "No Name";
2573 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2574 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2575 keysym, ksname, ret, debugstr_an(lpChar, ret));
2578 if (ret == 0)
2580 char dead_char;
2582 #ifdef XK_EuroSign
2583 /* An ugly hack for EuroSign: X can't translate it to a character
2584 for some locales. */
2585 if (keysym == XK_EuroSign)
2587 bufW[0] = 0x20AC;
2588 ret = 1;
2589 goto found;
2591 #endif
2592 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2593 /* Here we change it back. */
2594 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2596 bufW[0] = 0x09;
2597 ret = 1;
2598 goto found;
2601 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2602 if (dead_char)
2604 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2605 ret = -1;
2606 goto found;
2609 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2611 /* Unicode direct mapping */
2612 bufW[0] = keysym & 0xffff;
2613 ret = 1;
2614 goto found;
2616 else if ((keysym >> 8) == 0x1008FF) {
2617 bufW[0] = 0;
2618 ret = 0;
2619 goto found;
2621 else
2623 const char *ksname;
2625 wine_tsx11_lock();
2626 ksname = XKeysymToString(keysym);
2627 wine_tsx11_unlock();
2628 if (!ksname)
2629 ksname = "No Name";
2630 if ((keysym >> 8) != 0xff)
2632 WARN_(key)("no char for keysym %04lx (%s) :\n",
2633 keysym, ksname);
2634 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2635 virtKey, scanCode, e.keycode, e.state);
2639 else { /* ret != 0 */
2640 /* We have a special case to handle : Shift + arrow, shift + home, ...
2641 X returns a char for it, but Windows doesn't. Let's eat it. */
2642 if (!(e.state & NumLockMask) /* NumLock is off */
2643 && (e.state & ShiftMask) /* Shift is pressed */
2644 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2646 lpChar[0] = 0;
2647 ret = 0;
2650 /* more areas where X returns characters but Windows does not
2651 CTRL + number or CTRL + symbol */
2652 if (e.state & ControlMask)
2654 if (((keysym>=33) && (keysym < 'A')) ||
2655 ((keysym > 'Z') && (keysym < 'a')) ||
2656 (keysym == XK_Tab))
2658 lpChar[0] = 0;
2659 ret = 0;
2663 /* We have another special case for delete key (XK_Delete) on an
2664 extended keyboard. X returns a char for it, but Windows doesn't */
2665 if (keysym == XK_Delete)
2667 lpChar[0] = 0;
2668 ret = 0;
2670 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2671 && (keysym == XK_KP_Decimal))
2673 lpChar[0] = 0;
2674 ret = 0;
2676 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2677 && (keysym == XK_Return || keysym == XK_KP_Enter))
2679 lpChar[0] = '\n';
2680 ret = 1;
2683 /* Hack to detect an XLookupString hard-coded to Latin1 */
2684 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2686 bufW[0] = (BYTE)lpChar[0];
2687 goto found;
2690 /* perform translation to unicode */
2691 if(ret)
2693 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2694 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2698 found:
2699 if (buf != lpChar)
2700 HeapFree(GetProcessHeap(), 0, lpChar);
2702 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2703 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2704 if (1 <= ret && ret < bufW_size)
2705 bufW[ret] = 0;
2707 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2708 return ret;
2711 /***********************************************************************
2712 * Beep (X11DRV.@)
2714 void CDECL X11DRV_Beep(void)
2716 wine_tsx11_lock();
2717 XBell(gdi_display, 0);
2718 wine_tsx11_unlock();