strmbase: Implement BaseControlWindow.
[wine/multimedia.git] / dlls / winex11.drv / keyboard.c
blob3b91d8faf46003bcbab0d4a0359b58d7892b7188
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 * set_async_key_state
1181 static void set_async_key_state( const BYTE state[256] )
1183 SERVER_START_REQ( set_key_state )
1185 req->tid = GetCurrentThreadId();
1186 req->async = 1;
1187 wine_server_add_data( req, state, 256 );
1188 wine_server_call( req );
1190 SERVER_END_REQ;
1193 static void update_key_state( BYTE *keystate, BYTE key, int down )
1195 if (down)
1197 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1198 keystate[key] |= 0x80;
1200 else keystate[key] &= ~0x80;
1203 /***********************************************************************
1204 * X11DRV_KeymapNotify
1206 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1208 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1209 * from wine to another application and back.
1210 * Toggle keys are handled in HandleEvent.
1212 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1214 int i, j;
1215 BYTE keystate[256];
1216 WORD vkey;
1217 BOOL changed = FALSE;
1218 struct {
1219 WORD vkey;
1220 BOOL pressed;
1221 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1223 if (!get_async_key_state( keystate )) return;
1225 memset(modifiers, 0, sizeof(modifiers));
1227 /* the minimum keycode is always greater or equal to 8, so we can
1228 * skip the first 8 values, hence start at 1
1230 for (i = 1; i < 32; i++)
1232 for (j = 0; j < 8; j++)
1234 int m;
1236 vkey = keyc2vkey[(i * 8) + j];
1238 switch(vkey & 0xff)
1240 case VK_LMENU:
1241 case VK_RMENU:
1242 case VK_LCONTROL:
1243 case VK_RCONTROL:
1244 case VK_LSHIFT:
1245 case VK_RSHIFT:
1246 m = (vkey & 0xff) - VK_LSHIFT;
1247 /* Take the vkey from the first keycode we encounter for this modifier */
1248 if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
1249 if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1250 break;
1255 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1257 int m = vkey - VK_LSHIFT;
1258 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1260 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1261 modifiers[m].vkey, keystate[vkey]);
1263 update_key_state( keystate, vkey, modifiers[m].pressed );
1264 changed = TRUE;
1268 if (!changed) return;
1270 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1271 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1272 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1273 set_async_key_state( keystate );
1276 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1278 BYTE keystate[256];
1280 /* Note: X sets the below states on key down and clears them on key up.
1281 Windows triggers them on key down. */
1283 if (!get_async_key_state( keystate )) return;
1285 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1286 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1288 DWORD flags = 0;
1289 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1290 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1291 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1292 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1295 /* Adjust the NUMLOCK state if it has been changed outside wine */
1296 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1298 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1299 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1300 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1301 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1302 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1305 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1306 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1308 DWORD flags = 0;
1309 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1310 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1311 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1312 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1316 /***********************************************************************
1317 * X11DRV_KeyEvent
1319 * Handle a X key event
1321 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1323 XKeyEvent *event = &xev->xkey;
1324 char buf[24];
1325 char *Str = buf;
1326 KeySym keysym = 0;
1327 WORD vkey = 0, bScan;
1328 DWORD dwFlags;
1329 int ascii_chars;
1330 XIC xic = X11DRV_get_ic( hwnd );
1331 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1332 Status status = 0;
1334 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1335 event->type, event->window, event->state, event->keycode);
1337 if (event->type == KeyPress) update_user_time( event->time );
1339 wine_tsx11_lock();
1340 /* Clients should pass only KeyPress events to XmbLookupString */
1341 if (xic && event->type == KeyPress)
1343 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1344 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1345 if (status == XBufferOverflow)
1347 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1348 if (Str == NULL)
1350 ERR_(key)("Failed to allocate memory!\n");
1351 wine_tsx11_unlock();
1352 return;
1354 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1357 else
1358 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1359 wine_tsx11_unlock();
1361 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1363 if (status == XLookupChars)
1365 X11DRV_XIMLookupChars( Str, ascii_chars );
1366 if (buf != Str)
1367 HeapFree(GetProcessHeap(), 0, Str);
1368 return;
1371 /* If XKB extensions are used, the state mask for AltGr will use the group
1372 index instead of the modifier mask. The group index is set in bits
1373 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1374 pressed, look if the group index is different than 0. From XKB
1375 extension documentation, the group index for AltGr should be 2
1376 (event->state = 0x2000). It's probably better to not assume a
1377 predefined group index and find it dynamically
1379 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1380 /* Save also all possible modifier states. */
1381 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1383 if (TRACE_ON(key)){
1384 const char *ksname;
1386 wine_tsx11_lock();
1387 ksname = XKeysymToString(keysym);
1388 wine_tsx11_unlock();
1389 if (!ksname)
1390 ksname = "No Name";
1391 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1392 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1393 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1395 if (buf != Str)
1396 HeapFree(GetProcessHeap(), 0, Str);
1398 wine_tsx11_lock();
1399 vkey = EVENT_event_to_vkey(xic,event);
1400 /* X returns keycode 0 for composed characters */
1401 if (!vkey && ascii_chars) vkey = VK_NONAME;
1402 wine_tsx11_unlock();
1404 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1405 event->keycode, vkey);
1407 if (!vkey) return;
1409 dwFlags = 0;
1410 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1411 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1413 update_lock_state( hwnd, vkey, event->state, event_time );
1415 bScan = keyc2scan[event->keycode] & 0xFF;
1416 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1418 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1421 /**********************************************************************
1422 * X11DRV_KEYBOARD_DetectLayout
1424 * Called from X11DRV_InitKeyboard
1425 * This routine walks through the defined keyboard layouts and selects
1426 * whichever matches most closely.
1427 * X11 lock must be held.
1429 static void
1430 X11DRV_KEYBOARD_DetectLayout( Display *display )
1432 unsigned current, match, mismatch, seq, i, syms;
1433 int score, keyc, key, pkey, ok;
1434 KeySym keysym = 0;
1435 const char (*lkey)[MAIN_LEN][4];
1436 unsigned max_seq = 0;
1437 int max_score = 0, ismatch = 0;
1438 char ckey[256][4];
1440 syms = keysyms_per_keycode;
1441 if (syms > 4) {
1442 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1443 syms = 4;
1446 memset( ckey, 0, sizeof(ckey) );
1447 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1448 /* get data for keycode from X server */
1449 for (i = 0; i < syms; i++) {
1450 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1451 /* Allow both one-byte and two-byte national keysyms */
1452 if ((keysym < 0x8000) && (keysym != ' '))
1454 #ifdef HAVE_XKB
1455 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1456 #endif
1458 TRACE("XKB could not translate keysym %04lx\n", keysym);
1459 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1460 * with appropriate ShiftMask and Mode_switch, use XLookupString
1461 * to get character in the local encoding.
1463 ckey[keyc][i] = keysym & 0xFF;
1466 else {
1467 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1472 for (current = 0; main_key_tab[current].comment; current++) {
1473 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1474 match = 0;
1475 mismatch = 0;
1476 score = 0;
1477 seq = 0;
1478 lkey = main_key_tab[current].key;
1479 pkey = -1;
1480 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1481 if (ckey[keyc][0]) {
1482 /* search for a match in layout table */
1483 /* right now, we just find an absolute match for defined positions */
1484 /* (undefined positions are ignored, so if it's defined as "3#" in */
1485 /* the table, it's okay that the X server has "3#£", for example) */
1486 /* however, the score will be higher for longer matches */
1487 for (key = 0; key < MAIN_LEN; key++) {
1488 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1489 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1490 ok++;
1491 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1492 ok = -1;
1494 if (ok > 0) {
1495 score += ok;
1496 break;
1499 /* count the matches and mismatches */
1500 if (ok > 0) {
1501 match++;
1502 /* and how much the keycode order matches */
1503 if (key > pkey) seq++;
1504 pkey = key;
1505 } else {
1506 /* print spaces instead of \0's */
1507 char str[5];
1508 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1509 str[4] = 0;
1510 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1511 mismatch++;
1512 score -= syms;
1516 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1517 match, mismatch, seq, score);
1518 if ((score > max_score) ||
1519 ((score == max_score) && (seq > max_seq))) {
1520 /* best match so far */
1521 kbd_layout = current;
1522 max_score = score;
1523 max_seq = seq;
1524 ismatch = !mismatch;
1527 /* we're done, report results if necessary */
1528 if (!ismatch)
1529 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1530 main_key_tab[kbd_layout].comment);
1532 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1535 static HKL get_locale_kbd_layout(void)
1537 ULONG_PTR layout;
1538 LANGID langid;
1540 /* FIXME:
1542 * layout = main_key_tab[kbd_layout].lcid;
1544 * Winword uses return value of GetKeyboardLayout as a codepage
1545 * to translate ANSI keyboard messages to unicode. But we have
1546 * a problem with it: for instance Polish keyboard layout is
1547 * identical to the US one, and therefore instead of the Polish
1548 * locale id we return the US one.
1551 layout = GetUserDefaultLCID();
1554 * Microsoft Office expects this value to be something specific
1555 * for Japanese and Korean Windows with an IME the value is 0xe001
1556 * We should probably check to see if an IME exists and if so then
1557 * set this word properly.
1559 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1560 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1561 layout |= 0xe001 << 16; /* IME */
1562 else
1563 layout |= layout << 16;
1565 return (HKL)layout;
1568 /***********************************************************************
1569 * GetKeyboardLayoutName (X11DRV.@)
1571 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1573 static const WCHAR formatW[] = {'%','0','8','x',0};
1574 DWORD layout;
1576 layout = HandleToUlong( get_locale_kbd_layout() );
1577 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1578 sprintfW(name, formatW, layout);
1579 TRACE("returning %s\n", debugstr_w(name));
1580 return TRUE;
1583 static void set_kbd_layout_preload_key(void)
1585 static const WCHAR preload[] =
1586 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1587 static const WCHAR one[] = {'1',0};
1589 HKEY hkey;
1590 WCHAR layout[KL_NAMELENGTH];
1592 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1593 return;
1595 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1597 RegCloseKey(hkey);
1598 return;
1600 if (X11DRV_GetKeyboardLayoutName(layout))
1601 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1603 RegCloseKey(hkey);
1606 /**********************************************************************
1607 * X11DRV_InitKeyboard
1609 void X11DRV_InitKeyboard( Display *display )
1611 KeySym *ksp;
1612 XModifierKeymap *mmp;
1613 KeySym keysym;
1614 KeyCode *kcp;
1615 XKeyEvent e2;
1616 WORD scan, vkey;
1617 int keyc, i, keyn, syms;
1618 char ckey[4]={0,0,0,0};
1619 const char (*lkey)[MAIN_LEN][4];
1620 char vkey_used[256] = { 0 };
1622 /* Ranges of OEM, function key, and character virtual key codes.
1623 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1624 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1625 static const struct {
1626 WORD first, last;
1627 } vkey_ranges[] = {
1628 { VK_OEM_1, VK_OEM_3 },
1629 { VK_OEM_4, VK_ICO_00 },
1630 { 0xe6, 0xe6 },
1631 { 0xe9, 0xf5 },
1632 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1633 { VK_F1, VK_F24 },
1634 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1635 { 0x41, 0x5a }, /* VK_A - VK_Z */
1636 { 0, 0 }
1638 int vkey_range;
1640 set_kbd_layout_preload_key();
1642 wine_tsx11_lock();
1643 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1644 ksp = XGetKeyboardMapping(display, min_keycode,
1645 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1646 /* We are only interested in keysyms_per_keycode.
1647 There is no need to hold a local copy of the keysyms table */
1648 XFree(ksp);
1650 mmp = XGetModifierMapping(display);
1651 kcp = mmp->modifiermap;
1652 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1654 int j;
1656 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1657 if (*kcp)
1659 int k;
1661 for (k = 0; k < keysyms_per_keycode; k += 1)
1662 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1664 NumLockMask = 1 << i;
1665 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1667 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1669 ScrollLockMask = 1 << i;
1670 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1674 XFreeModifiermap(mmp);
1676 /* Detect the keyboard layout */
1677 X11DRV_KEYBOARD_DetectLayout( display );
1678 lkey = main_key_tab[kbd_layout].key;
1679 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1681 /* Now build two conversion arrays :
1682 * keycode -> vkey + scancode + extended
1683 * vkey + extended -> keycode */
1685 e2.display = display;
1686 e2.state = 0;
1687 e2.type = KeyPress;
1689 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1690 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1692 char buf[30];
1693 int have_chars;
1695 keysym = 0;
1696 e2.keycode = (KeyCode)keyc;
1697 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1698 vkey = 0; scan = 0;
1699 if (keysym) /* otherwise, keycode not used */
1701 if ((keysym >> 8) == 0xFF) /* non-character key */
1703 vkey = nonchar_key_vkey[keysym & 0xff];
1704 scan = nonchar_key_scan[keysym & 0xff];
1705 /* set extended bit when necessary */
1706 if (scan & 0x100) vkey |= 0x100;
1707 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1708 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1709 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1710 scan = 0x100;
1711 vkey |= 0x100;
1712 } else if (keysym == 0x20) { /* Spacebar */
1713 vkey = VK_SPACE;
1714 scan = 0x39;
1715 } else if (have_chars) {
1716 /* we seem to need to search the layout-dependent scancodes */
1717 int maxlen=0,maxval=-1,ok;
1718 for (i=0; i<syms; i++) {
1719 keysym = keycode_to_keysym(display, keyc, i);
1720 if ((keysym<0x8000) && (keysym!=' '))
1722 #ifdef HAVE_XKB
1723 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1724 #endif
1726 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1727 * with appropriate ShiftMask and Mode_switch, use XLookupString
1728 * to get character in the local encoding.
1730 ckey[i] = keysym & 0xFF;
1732 } else {
1733 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1736 /* find key with longest match streak */
1737 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1738 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1739 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1740 if (!ok) i--; /* we overshot */
1741 if (ok||(i>maxlen)) {
1742 maxlen=i; maxval=keyn;
1744 if (ok) break;
1746 if (maxval>=0) {
1747 /* got it */
1748 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1749 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1750 scan = (*lscan)[maxval];
1751 vkey = (*lvkey)[maxval];
1755 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1756 keyc2vkey[e2.keycode] = vkey;
1757 keyc2scan[e2.keycode] = scan;
1758 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1759 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1760 vkey_used[(vkey & 0xff)] = 1;
1761 } /* for */
1763 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1764 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1766 vkey = keyc2vkey[keyc] & 0xff;
1767 if (vkey)
1768 continue;
1770 e2.keycode = (KeyCode)keyc;
1771 keysym = XLookupKeysym(&e2, 0);
1772 if (!keysym)
1773 continue;
1775 /* find a suitable layout-dependent VK code */
1776 /* (most Winelib apps ought to be able to work without layout tables!) */
1777 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1779 keysym = XLookupKeysym(&e2, i);
1780 if ((keysym >= XK_0 && keysym <= XK_9)
1781 || (keysym >= XK_A && keysym <= XK_Z)) {
1782 vkey = VKEY_IF_NOT_USED(keysym);
1786 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1788 keysym = XLookupKeysym(&e2, i);
1789 switch (keysym)
1791 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1792 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1793 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1794 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1795 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1796 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1797 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1798 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1799 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1800 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1801 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1805 if (vkey)
1807 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1808 keyc2vkey[e2.keycode] = vkey;
1810 } /* for */
1812 /* For any keycodes which still don't have a vkey, assign any spare
1813 * character, function key, or OEM virtual key code. */
1814 vkey_range = 0;
1815 vkey = vkey_ranges[vkey_range].first;
1816 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1818 if (keyc2vkey[keyc] & 0xff)
1819 continue;
1821 e2.keycode = (KeyCode)keyc;
1822 keysym = XLookupKeysym(&e2, 0);
1823 if (!keysym)
1824 continue;
1826 while (vkey && vkey_used[vkey])
1828 if (vkey == vkey_ranges[vkey_range].last)
1830 vkey_range++;
1831 vkey = vkey_ranges[vkey_range].first;
1833 else
1834 vkey++;
1837 if (!vkey)
1839 WARN("No more vkeys available!\n");
1840 break;
1843 if (TRACE_ON(keyboard))
1845 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1846 vkey, e2.keycode);
1847 TRACE("(");
1848 for (i = 0; i < keysyms_per_keycode; i += 1)
1850 const char *ksname;
1852 keysym = XLookupKeysym(&e2, i);
1853 ksname = XKeysymToString(keysym);
1854 if (!ksname)
1855 ksname = "NoSymbol";
1856 TRACE( "%lx (%s) ", keysym, ksname);
1858 TRACE(")\n");
1861 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1862 keyc2vkey[e2.keycode] = vkey;
1863 vkey_used[vkey] = 1;
1864 } /* for */
1865 #undef VKEY_IF_NOT_USED
1867 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1868 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1869 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1870 const char *ksname;
1871 keysym = keycode_to_keysym(display, keyc, 0);
1872 ksname = XKeysymToString(keysym);
1873 if (!ksname) ksname = "NoSymbol";
1875 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1877 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1878 keyc2scan[keyc]=scan++;
1881 wine_tsx11_unlock();
1884 static BOOL match_x11_keyboard_layout(HKL hkl)
1886 const DWORD isIME = 0xE0000000;
1887 HKL xHkl = get_locale_kbd_layout();
1889 /* if the layout is an IME, only match the low word (LCID) */
1890 if (((ULONG_PTR)hkl & isIME) == isIME)
1891 return (LOWORD(hkl) == LOWORD(xHkl));
1892 else
1893 return (hkl == xHkl);
1896 /**********************************************************************
1897 * GetAsyncKeyState (X11DRV.@)
1899 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1901 /* Photoshop livelocks unless mouse events are included here */
1902 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1903 return -1;
1907 /***********************************************************************
1908 * GetKeyboardLayout (X11DRV.@)
1910 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1912 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1914 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1915 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1917 else
1918 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1920 return get_locale_kbd_layout();
1924 /***********************************************************************
1925 * LoadKeyboardLayout (X11DRV.@)
1927 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1929 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1930 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1931 return 0;
1935 /***********************************************************************
1936 * UnloadKeyboardLayout (X11DRV.@)
1938 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1940 FIXME("%p: stub!\n", hkl);
1941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1942 return FALSE;
1946 /***********************************************************************
1947 * ActivateKeyboardLayout (X11DRV.@)
1949 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1951 HKL oldHkl = 0;
1952 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1954 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1955 if (flags & KLF_SETFORPROCESS)
1957 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1958 FIXME("KLF_SETFORPROCESS not supported\n");
1959 return 0;
1962 if (flags)
1963 FIXME("flags %x not supported\n",flags);
1965 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1967 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1968 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1969 return 0;
1972 if (!match_x11_keyboard_layout(hkl))
1974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1975 FIXME("setting keyboard of different locales not supported\n");
1976 return 0;
1979 oldHkl = thread_data->kbd_layout;
1980 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1982 thread_data->kbd_layout = hkl;
1984 return oldHkl;
1988 /***********************************************************************
1989 * X11DRV_MappingNotify
1991 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1993 HWND hwnd;
1995 wine_tsx11_lock();
1996 XRefreshKeyboardMapping(&event->xmapping);
1997 wine_tsx11_unlock();
1998 X11DRV_InitKeyboard( event->xmapping.display );
2000 hwnd = GetFocus();
2001 if (!hwnd) hwnd = GetActiveWindow();
2002 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2003 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2007 /***********************************************************************
2008 * VkKeyScanEx (X11DRV.@)
2010 * Note: Windows ignores HKL parameter and uses current active layout instead
2012 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2014 Display *display = thread_init_display();
2015 KeyCode keycode;
2016 KeySym keysym;
2017 int i, index;
2018 CHAR cChar;
2019 SHORT ret;
2021 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2022 * is UTF-8 (multibyte encoding)?
2024 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2026 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2027 return -1;
2030 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2032 /* char->keysym (same for ANSI chars) */
2033 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2034 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2036 wine_tsx11_lock();
2037 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2038 if (!keycode)
2040 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2042 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2043 TRACE(" ... returning ctrl char %#.2x\n", ret);
2044 wine_tsx11_unlock();
2045 return ret;
2047 /* It didn't work ... let's try with deadchar code. */
2048 TRACE("retrying with | 0xFE00\n");
2049 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2051 wine_tsx11_unlock();
2053 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2055 /* keycode -> (keyc2vkey) vkey */
2056 ret = keyc2vkey[keycode];
2058 if (!keycode || !ret)
2060 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2061 return -1;
2064 index = -1;
2065 wine_tsx11_lock();
2066 for (i = 0; i < 4; i++) /* find shift state */
2068 if (keycode_to_keysym(display, keycode, i) == keysym)
2070 index = i;
2071 break;
2074 wine_tsx11_unlock();
2076 switch (index)
2078 default:
2079 case -1:
2080 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2081 return -1;
2083 case 0: break;
2084 case 1: ret += 0x0100; break;
2085 case 2: ret += 0x0600; break;
2086 case 3: ret += 0x0700; break;
2089 index : 0 adds 0x0000
2090 index : 1 adds 0x0100 (shift)
2091 index : ? adds 0x0200 (ctrl)
2092 index : 2 adds 0x0600 (ctrl+alt)
2093 index : 3 adds 0x0700 (ctrl+alt+shift)
2096 TRACE(" ... returning %#.2x\n", ret);
2097 return ret;
2100 /***********************************************************************
2101 * MapVirtualKeyEx (X11DRV.@)
2103 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2105 Display *display = thread_init_display();
2107 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2109 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2110 if (!match_x11_keyboard_layout(hkl))
2111 FIXME("keyboard layout %p is not supported\n", hkl);
2113 switch(wMapType)
2115 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2116 case MAPVK_VK_TO_VSC_EX:
2118 int keyc;
2120 switch (wCode)
2122 case VK_SHIFT: wCode = VK_LSHIFT; break;
2123 case VK_CONTROL: wCode = VK_LCONTROL; break;
2124 case VK_MENU: wCode = VK_LMENU; break;
2127 /* let's do vkey -> keycode -> scan */
2128 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2129 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2131 if (keyc > max_keycode)
2133 TRACE("returning no scan-code.\n");
2134 return 0;
2136 returnMVK (keyc2scan[keyc] & 0xFF);
2138 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2139 case MAPVK_VSC_TO_VK_EX:
2141 int keyc;
2142 UINT vkey = 0;
2144 /* let's do scan -> keycode -> vkey */
2145 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2146 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2148 vkey = keyc2vkey[keyc] & 0xFF;
2149 /* Only stop if it's not a numpad vkey; otherwise keep
2150 looking for a potential better vkey. */
2151 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2152 break;
2155 if (vkey == 0)
2157 TRACE("returning no vkey-code.\n");
2158 return 0;
2161 if (wMapType == MAPVK_VSC_TO_VK)
2162 switch (vkey)
2164 case VK_LSHIFT:
2165 case VK_RSHIFT:
2166 vkey = VK_SHIFT; break;
2167 case VK_LCONTROL:
2168 case VK_RCONTROL:
2169 vkey = VK_CONTROL; break;
2170 case VK_LMENU:
2171 case VK_RMENU:
2172 vkey = VK_MENU; break;
2175 returnMVK (vkey);
2177 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2179 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2180 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2181 * key.. Looks like something is wrong with the MS docs?
2182 * This is only true for letters, for example VK_0 returns '0' not ')'.
2183 * - hence we use the lock mask to ensure this happens.
2185 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2186 XKeyEvent e;
2187 KeySym keysym;
2188 int keyc, len;
2189 char s[10];
2191 e.display = display;
2192 e.state = 0;
2193 e.keycode = 0;
2194 e.type = KeyPress;
2196 wine_tsx11_lock();
2198 /* We exit on the first keycode found, to speed up the thing. */
2199 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2200 { /* Find a keycode that could have generated this virtual key */
2201 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2202 { /* We filter the extended bit, we don't know it */
2203 e.keycode = keyc; /* Store it temporarily */
2204 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2205 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2206 state), so set it to 0, we'll find another one */
2211 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2212 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2214 if (wCode==VK_DECIMAL)
2215 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2217 if (!e.keycode)
2219 WARN("Unknown virtual key %X !!!\n", wCode);
2220 wine_tsx11_unlock();
2221 return 0; /* whatever */
2223 TRACE("Found keycode %u\n",e.keycode);
2225 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2226 wine_tsx11_unlock();
2228 if (len)
2230 WCHAR wch;
2231 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2232 returnMVK(toupperW(wch));
2234 TRACE("returning no ANSI.\n");
2235 return 0;
2237 default: /* reserved */
2238 FIXME("Unknown wMapType %d !\n", wMapType);
2239 return 0;
2241 return 0;
2244 /***********************************************************************
2245 * GetKeyNameText (X11DRV.@)
2247 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2249 Display *display = thread_init_display();
2250 int vkey, ansi, scanCode;
2251 KeyCode keyc;
2252 int keyi;
2253 KeySym keys;
2254 char *name;
2256 scanCode = lParam >> 16;
2257 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2259 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2261 /* handle "don't care" bit (0x02000000) */
2262 if (!(lParam & 0x02000000)) {
2263 switch (vkey) {
2264 case VK_RSHIFT:
2265 /* R-Shift is "special" - it is an extended key with separate scan code */
2266 scanCode |= 0x100;
2267 /* fall through */
2268 case VK_LSHIFT:
2269 vkey = VK_SHIFT;
2270 break;
2271 case VK_LCONTROL:
2272 case VK_RCONTROL:
2273 vkey = VK_CONTROL;
2274 break;
2275 case VK_LMENU:
2276 case VK_RMENU:
2277 vkey = VK_MENU;
2278 break;
2282 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2283 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2285 /* first get the name of the "regular" keys which is the Upper case
2286 value of the keycap imprint. */
2287 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2288 (scanCode != 0x137) && /* PrtScn */
2289 (scanCode != 0x135) && /* numpad / */
2290 (scanCode != 0x37 ) && /* numpad * */
2291 (scanCode != 0x4a ) && /* numpad - */
2292 (scanCode != 0x4e ) ) /* numpad + */
2294 if (nSize >= 2)
2296 *lpBuffer = toupperW((WCHAR)ansi);
2297 *(lpBuffer+1) = 0;
2298 return 1;
2300 else
2301 return 0;
2304 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2305 without "extended-key" flag. However Wine generates scancode
2306 *with* "extended-key" flag. Seems to occur *only* for the
2307 function keys. Soooo.. We will leave the table alone and
2308 fudge the lookup here till the other part is found and fixed!!! */
2310 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2311 (scanCode == 0x157) || (scanCode == 0x158))
2312 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2314 /* let's do scancode -> keycode -> keysym -> String */
2316 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2317 if ((keyc2scan[keyi]) == scanCode)
2318 break;
2319 if (keyi <= max_keycode)
2321 INT rc;
2323 wine_tsx11_lock();
2324 keyc = (KeyCode) keyi;
2325 keys = keycode_to_keysym(display, keyc, 0);
2326 name = XKeysymToString(keys);
2327 wine_tsx11_unlock();
2329 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2331 char* idx = strrchr(name, '_');
2332 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2334 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2335 scanCode, keyc, keys, debugstr_an(name,idx-name));
2336 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2337 if (!rc) rc = nSize;
2338 lpBuffer[--rc] = 0;
2339 return rc;
2343 if (name)
2345 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2346 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2347 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2348 if (!rc) rc = nSize;
2349 lpBuffer[--rc] = 0;
2350 return rc;
2354 /* Finally issue WARN for unknown keys */
2356 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2357 *lpBuffer = 0;
2358 return 0;
2361 /***********************************************************************
2362 * X11DRV_KEYBOARD_MapDeadKeysym
2364 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2366 switch (keysym)
2368 /* symbolic ASCII is the same as defined in rfc1345 */
2369 #ifdef XK_dead_tilde
2370 case XK_dead_tilde :
2371 #endif
2372 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2373 return '~'; /* '? */
2374 #ifdef XK_dead_acute
2375 case XK_dead_acute :
2376 #endif
2377 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2378 return 0xb4; /* '' */
2379 #ifdef XK_dead_circumflex
2380 case XK_dead_circumflex:
2381 #endif
2382 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2383 return '^'; /* '> */
2384 #ifdef XK_dead_grave
2385 case XK_dead_grave :
2386 #endif
2387 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2388 return '`'; /* '! */
2389 #ifdef XK_dead_diaeresis
2390 case XK_dead_diaeresis :
2391 #endif
2392 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2393 return 0xa8; /* ': */
2394 #ifdef XK_dead_cedilla
2395 case XK_dead_cedilla :
2396 return 0xb8; /* ', */
2397 #endif
2398 #ifdef XK_dead_macron
2399 case XK_dead_macron :
2400 return '-'; /* 'm isn't defined on iso-8859-x */
2401 #endif
2402 #ifdef XK_dead_breve
2403 case XK_dead_breve :
2404 return 0xa2; /* '( */
2405 #endif
2406 #ifdef XK_dead_abovedot
2407 case XK_dead_abovedot :
2408 return 0xff; /* '. */
2409 #endif
2410 #ifdef XK_dead_abovering
2411 case XK_dead_abovering :
2412 return '0'; /* '0 isn't defined on iso-8859-x */
2413 #endif
2414 #ifdef XK_dead_doubleacute
2415 case XK_dead_doubleacute :
2416 return 0xbd; /* '" */
2417 #endif
2418 #ifdef XK_dead_caron
2419 case XK_dead_caron :
2420 return 0xb7; /* '< */
2421 #endif
2422 #ifdef XK_dead_ogonek
2423 case XK_dead_ogonek :
2424 return 0xb2; /* '; */
2425 #endif
2426 /* FIXME: I don't know this three.
2427 case XK_dead_iota :
2428 return 'i';
2429 case XK_dead_voiced_sound :
2430 return 'v';
2431 case XK_dead_semivoiced_sound :
2432 return 's';
2435 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2436 return 0;
2439 /***********************************************************************
2440 * ToUnicodeEx (X11DRV.@)
2442 * The ToUnicode function translates the specified virtual-key code and keyboard
2443 * state to the corresponding Windows character or characters.
2445 * If the specified key is a dead key, the return value is negative. Otherwise,
2446 * it is one of the following values:
2447 * Value Meaning
2448 * 0 The specified virtual key has no translation for the current state of the keyboard.
2449 * 1 One Windows character was copied to the buffer.
2450 * 2 Two characters were copied to the buffer. This usually happens when a
2451 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2452 * be composed with the specified virtual key to form a single character.
2454 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2457 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2458 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2460 Display *display = thread_init_display();
2461 XKeyEvent e;
2462 KeySym keysym = 0;
2463 INT ret;
2464 int keyc;
2465 char buf[10];
2466 char *lpChar = buf;
2467 HWND focus;
2468 XIC xic;
2469 Status status = 0;
2471 if (scanCode & 0x8000)
2473 TRACE_(key)("Key UP, doing nothing\n" );
2474 return 0;
2477 if (!match_x11_keyboard_layout(hkl))
2478 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2480 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2482 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2483 return 0;
2486 e.display = display;
2487 e.keycode = 0;
2488 e.state = 0;
2489 e.type = KeyPress;
2491 focus = x11drv_thread_data()->last_xic_hwnd;
2492 if (!focus)
2494 focus = GetFocus();
2495 if (focus) focus = GetAncestor( focus, GA_ROOT );
2496 if (!focus) focus = GetActiveWindow();
2498 e.window = X11DRV_get_whole_window( focus );
2499 xic = X11DRV_get_ic( focus );
2501 if (lpKeyState[VK_SHIFT] & 0x80)
2503 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2504 e.state |= ShiftMask;
2506 if (lpKeyState[VK_CAPITAL] & 0x01)
2508 TRACE_(key)("LockMask = %04x\n", LockMask);
2509 e.state |= LockMask;
2511 if (lpKeyState[VK_CONTROL] & 0x80)
2513 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2514 e.state |= ControlMask;
2516 if (lpKeyState[VK_NUMLOCK] & 0x01)
2518 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2519 e.state |= NumLockMask;
2522 /* Restore saved AltGr state */
2523 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2524 e.state |= AltGrMask;
2526 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2527 virtKey, scanCode, e.state);
2528 wine_tsx11_lock();
2529 /* We exit on the first keycode found, to speed up the thing. */
2530 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2531 { /* Find a keycode that could have generated this virtual key */
2532 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2533 { /* We filter the extended bit, we don't know it */
2534 e.keycode = keyc; /* Store it temporarily */
2535 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2536 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2537 state), so set it to 0, we'll find another one */
2542 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2543 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2545 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2546 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2548 if (virtKey==VK_DECIMAL)
2549 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2551 if (virtKey==VK_SEPARATOR)
2552 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2554 if (!e.keycode && virtKey != VK_NONAME)
2556 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2557 wine_tsx11_unlock();
2558 return 0;
2560 else TRACE_(key)("Found keycode %u\n",e.keycode);
2562 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2563 e.type, e.window, e.state, e.keycode);
2565 /* Clients should pass only KeyPress events to XmbLookupString,
2566 * e.type was set to KeyPress above.
2568 if (xic)
2570 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2571 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2572 if (status == XBufferOverflow)
2574 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2575 if (lpChar == NULL)
2577 ERR_(key)("Failed to allocate memory!\n");
2578 wine_tsx11_unlock();
2579 return 0;
2581 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2584 else
2585 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2586 wine_tsx11_unlock();
2588 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2590 if (TRACE_ON(key))
2592 const char *ksname;
2594 wine_tsx11_lock();
2595 ksname = XKeysymToString(keysym);
2596 wine_tsx11_unlock();
2597 if (!ksname) ksname = "No Name";
2598 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2599 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2600 keysym, ksname, ret, debugstr_an(lpChar, ret));
2603 if (ret == 0)
2605 char dead_char;
2607 #ifdef XK_EuroSign
2608 /* An ugly hack for EuroSign: X can't translate it to a character
2609 for some locales. */
2610 if (keysym == XK_EuroSign)
2612 bufW[0] = 0x20AC;
2613 ret = 1;
2614 goto found;
2616 #endif
2617 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2618 /* Here we change it back. */
2619 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2621 bufW[0] = 0x09;
2622 ret = 1;
2623 goto found;
2626 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2627 if (dead_char)
2629 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2630 ret = -1;
2631 goto found;
2634 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2636 /* Unicode direct mapping */
2637 bufW[0] = keysym & 0xffff;
2638 ret = 1;
2639 goto found;
2641 else if ((keysym >> 8) == 0x1008FF) {
2642 bufW[0] = 0;
2643 ret = 0;
2644 goto found;
2646 else
2648 const char *ksname;
2650 wine_tsx11_lock();
2651 ksname = XKeysymToString(keysym);
2652 wine_tsx11_unlock();
2653 if (!ksname)
2654 ksname = "No Name";
2655 if ((keysym >> 8) != 0xff)
2657 WARN_(key)("no char for keysym %04lx (%s) :\n",
2658 keysym, ksname);
2659 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2660 virtKey, scanCode, e.keycode, e.state);
2664 else { /* ret != 0 */
2665 /* We have a special case to handle : Shift + arrow, shift + home, ...
2666 X returns a char for it, but Windows doesn't. Let's eat it. */
2667 if (!(e.state & NumLockMask) /* NumLock is off */
2668 && (e.state & ShiftMask) /* Shift is pressed */
2669 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2671 lpChar[0] = 0;
2672 ret = 0;
2675 /* more areas where X returns characters but Windows does not
2676 CTRL + number or CTRL + symbol */
2677 if (e.state & ControlMask)
2679 if (((keysym>=33) && (keysym < 'A')) ||
2680 ((keysym > 'Z') && (keysym < 'a')) ||
2681 (keysym == XK_Tab))
2683 lpChar[0] = 0;
2684 ret = 0;
2688 /* We have another special case for delete key (XK_Delete) on an
2689 extended keyboard. X returns a char for it, but Windows doesn't */
2690 if (keysym == XK_Delete)
2692 lpChar[0] = 0;
2693 ret = 0;
2695 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2696 && (keysym == XK_KP_Decimal))
2698 lpChar[0] = 0;
2699 ret = 0;
2701 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2702 && (keysym == XK_Return || keysym == XK_KP_Enter))
2704 lpChar[0] = '\n';
2705 ret = 1;
2708 /* Hack to detect an XLookupString hard-coded to Latin1 */
2709 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2711 bufW[0] = (BYTE)lpChar[0];
2712 goto found;
2715 /* perform translation to unicode */
2716 if(ret)
2718 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2719 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2723 found:
2724 if (buf != lpChar)
2725 HeapFree(GetProcessHeap(), 0, lpChar);
2727 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2728 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2729 if (1 <= ret && ret < bufW_size)
2730 bufW[ret] = 0;
2732 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2733 return ret;
2736 /***********************************************************************
2737 * Beep (X11DRV.@)
2739 void CDECL X11DRV_Beep(void)
2741 wine_tsx11_lock();
2742 XBell(gdi_display, 0);
2743 wine_tsx11_unlock();