regedit: Fix qword entries export.
[wine/multimedia.git] / dlls / winex11.drv / keyboard.c
blob7e49ffba24da2008a863752bc493139254abbe14
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 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
998 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
999 * in order to produce a locale dependent numeric separator.
1001 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1002 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1003 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1004 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1005 /* function keys */
1006 VK_F1, VK_F2,
1007 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1008 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1009 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1010 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1011 /* modifier keys */
1012 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1013 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1014 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1016 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1019 static const WORD nonchar_key_scan[256] =
1021 /* unused */
1022 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1023 /* special keys */
1024 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1025 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1026 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1027 /* unused */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1034 /* cursor keys */
1035 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1037 /* misc keys */
1038 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1039 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1041 /* keypad keys */
1042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1046 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1047 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1048 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1049 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1050 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1051 /* function keys */
1052 0x3B, 0x3C,
1053 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1054 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1057 /* modifier keys */
1058 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1059 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1064 static const WORD xfree86_vendor_key_vkey[256] =
1066 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1067 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1068 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1069 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1070 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1071 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1072 0, 0, 0, VK_BROWSER_HOME,
1073 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1074 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1075 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1076 0, 0, 0, 0,
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1097 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1098 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1099 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1100 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1101 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1104 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1106 #ifdef HAVE_XKB
1107 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1108 #endif
1109 return XKeycodeToKeysym(display, keycode, index);
1112 /* Returns the Windows virtual key code associated with the X event <e> */
1113 /* x11 lock must be held */
1114 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1116 KeySym keysym = 0;
1117 Status status;
1118 char buf[24];
1120 /* Clients should pass only KeyPress events to XmbLookupString */
1121 if (xic && e->type == KeyPress)
1122 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1123 else
1124 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1126 if ((e->state & NumLockMask) &&
1127 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1128 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1129 /* Only the Keypad keys 0-9 and . send different keysyms
1130 * depending on the NumLock state */
1131 return nonchar_key_vkey[keysym & 0xFF];
1133 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1134 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1135 if ((e->state & ControlMask) && (keysym == XK_Break))
1136 return VK_CANCEL;
1138 TRACE_(key)("e->keycode = %u\n", e->keycode);
1140 return keyc2vkey[e->keycode];
1144 /***********************************************************************
1145 * X11DRV_send_keyboard_input
1147 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1149 INPUT input;
1151 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1153 input.type = INPUT_KEYBOARD;
1154 input.u.ki.wVk = vkey;
1155 input.u.ki.wScan = scan;
1156 input.u.ki.dwFlags = flags;
1157 input.u.ki.time = time;
1158 input.u.ki.dwExtraInfo = 0;
1160 __wine_send_input( hwnd, &input );
1164 /***********************************************************************
1165 * get_async_key_state
1167 static BOOL get_async_key_state( BYTE state[256] )
1169 BOOL ret;
1171 SERVER_START_REQ( get_key_state )
1173 req->tid = 0;
1174 req->key = -1;
1175 wine_server_set_reply( req, state, 256 );
1176 ret = !wine_server_call( req );
1178 SERVER_END_REQ;
1179 return ret;
1182 /***********************************************************************
1183 * set_async_key_state
1185 static void set_async_key_state( const BYTE state[256] )
1187 SERVER_START_REQ( set_key_state )
1189 req->tid = GetCurrentThreadId();
1190 req->async = 1;
1191 wine_server_add_data( req, state, 256 );
1192 wine_server_call( req );
1194 SERVER_END_REQ;
1197 static void update_key_state( BYTE *keystate, BYTE key, int down )
1199 if (down)
1201 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1202 keystate[key] |= 0x80;
1204 else keystate[key] &= ~0x80;
1207 /***********************************************************************
1208 * X11DRV_KeymapNotify
1210 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1212 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1213 * from wine to another application and back.
1214 * Toggle keys are handled in HandleEvent.
1216 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1218 int i, j;
1219 BYTE keystate[256];
1220 WORD vkey;
1221 BOOL changed = FALSE;
1222 struct {
1223 WORD vkey;
1224 BOOL pressed;
1225 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1227 if (!get_async_key_state( keystate )) return;
1229 memset(modifiers, 0, sizeof(modifiers));
1231 /* the minimum keycode is always greater or equal to 8, so we can
1232 * skip the first 8 values, hence start at 1
1234 for (i = 1; i < 32; i++)
1236 for (j = 0; j < 8; j++)
1238 int m;
1240 vkey = keyc2vkey[(i * 8) + j];
1242 switch(vkey & 0xff)
1244 case VK_LMENU:
1245 case VK_RMENU:
1246 case VK_LCONTROL:
1247 case VK_RCONTROL:
1248 case VK_LSHIFT:
1249 case VK_RSHIFT:
1250 m = (vkey & 0xff) - VK_LSHIFT;
1251 /* Take the vkey from the first keycode we encounter for this modifier */
1252 if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
1253 if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1254 break;
1259 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1261 int m = vkey - VK_LSHIFT;
1262 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1264 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1265 modifiers[m].vkey, keystate[vkey]);
1267 update_key_state( keystate, vkey, modifiers[m].pressed );
1268 changed = TRUE;
1272 if (!changed) return;
1274 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1275 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1276 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1277 set_async_key_state( keystate );
1280 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1282 BYTE keystate[256];
1284 /* Note: X sets the below states on key down and clears them on key up.
1285 Windows triggers them on key down. */
1287 if (!get_async_key_state( keystate )) return;
1289 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1290 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1292 DWORD flags = 0;
1293 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1294 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1295 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1296 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1299 /* Adjust the NUMLOCK state if it has been changed outside wine */
1300 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1302 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1303 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1304 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1305 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1306 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1309 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1310 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1312 DWORD flags = 0;
1313 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1314 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1315 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1316 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1320 /***********************************************************************
1321 * X11DRV_KeyEvent
1323 * Handle a X key event
1325 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1327 XKeyEvent *event = &xev->xkey;
1328 char buf[24];
1329 char *Str = buf;
1330 KeySym keysym = 0;
1331 WORD vkey = 0, bScan;
1332 DWORD dwFlags;
1333 int ascii_chars;
1334 XIC xic = X11DRV_get_ic( hwnd );
1335 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1336 Status status = 0;
1338 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1339 event->type, event->window, event->state, event->keycode);
1341 if (event->type == KeyPress) update_user_time( event->time );
1343 wine_tsx11_lock();
1344 /* Clients should pass only KeyPress events to XmbLookupString */
1345 if (xic && event->type == KeyPress)
1347 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1348 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1349 if (status == XBufferOverflow)
1351 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1352 if (Str == NULL)
1354 ERR_(key)("Failed to allocate memory!\n");
1355 wine_tsx11_unlock();
1356 return;
1358 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1361 else
1362 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1363 wine_tsx11_unlock();
1365 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1367 if (status == XLookupChars)
1369 X11DRV_XIMLookupChars( Str, ascii_chars );
1370 if (buf != Str)
1371 HeapFree(GetProcessHeap(), 0, Str);
1372 return;
1375 /* If XKB extensions are used, the state mask for AltGr will use the group
1376 index instead of the modifier mask. The group index is set in bits
1377 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1378 pressed, look if the group index is different than 0. From XKB
1379 extension documentation, the group index for AltGr should be 2
1380 (event->state = 0x2000). It's probably better to not assume a
1381 predefined group index and find it dynamically
1383 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1384 /* Save also all possible modifier states. */
1385 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1387 if (TRACE_ON(key)){
1388 const char *ksname;
1390 wine_tsx11_lock();
1391 ksname = XKeysymToString(keysym);
1392 wine_tsx11_unlock();
1393 if (!ksname)
1394 ksname = "No Name";
1395 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1396 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1397 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1399 if (buf != Str)
1400 HeapFree(GetProcessHeap(), 0, Str);
1402 wine_tsx11_lock();
1403 vkey = EVENT_event_to_vkey(xic,event);
1404 /* X returns keycode 0 for composed characters */
1405 if (!vkey && ascii_chars) vkey = VK_NONAME;
1406 wine_tsx11_unlock();
1408 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1409 event->keycode, vkey);
1411 if (!vkey) return;
1413 dwFlags = 0;
1414 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1415 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1417 update_lock_state( hwnd, vkey, event->state, event_time );
1419 bScan = keyc2scan[event->keycode] & 0xFF;
1420 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1422 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1425 /**********************************************************************
1426 * X11DRV_KEYBOARD_DetectLayout
1428 * Called from X11DRV_InitKeyboard
1429 * This routine walks through the defined keyboard layouts and selects
1430 * whichever matches most closely.
1431 * X11 lock must be held.
1433 static void
1434 X11DRV_KEYBOARD_DetectLayout( Display *display )
1436 unsigned current, match, mismatch, seq, i, syms;
1437 int score, keyc, key, pkey, ok;
1438 KeySym keysym = 0;
1439 const char (*lkey)[MAIN_LEN][4];
1440 unsigned max_seq = 0;
1441 int max_score = 0, ismatch = 0;
1442 char ckey[256][4];
1444 syms = keysyms_per_keycode;
1445 if (syms > 4) {
1446 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1447 syms = 4;
1450 memset( ckey, 0, sizeof(ckey) );
1451 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1452 /* get data for keycode from X server */
1453 for (i = 0; i < syms; i++) {
1454 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1455 /* Allow both one-byte and two-byte national keysyms */
1456 if ((keysym < 0x8000) && (keysym != ' '))
1458 #ifdef HAVE_XKB
1459 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1460 #endif
1462 TRACE("XKB could not translate keysym %04lx\n", keysym);
1463 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1464 * with appropriate ShiftMask and Mode_switch, use XLookupString
1465 * to get character in the local encoding.
1467 ckey[keyc][i] = keysym & 0xFF;
1470 else {
1471 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1476 for (current = 0; main_key_tab[current].comment; current++) {
1477 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1478 match = 0;
1479 mismatch = 0;
1480 score = 0;
1481 seq = 0;
1482 lkey = main_key_tab[current].key;
1483 pkey = -1;
1484 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1485 if (ckey[keyc][0]) {
1486 /* search for a match in layout table */
1487 /* right now, we just find an absolute match for defined positions */
1488 /* (undefined positions are ignored, so if it's defined as "3#" in */
1489 /* the table, it's okay that the X server has "3#£", for example) */
1490 /* however, the score will be higher for longer matches */
1491 for (key = 0; key < MAIN_LEN; key++) {
1492 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1493 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1494 ok++;
1495 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1496 ok = -1;
1498 if (ok > 0) {
1499 score += ok;
1500 break;
1503 /* count the matches and mismatches */
1504 if (ok > 0) {
1505 match++;
1506 /* and how much the keycode order matches */
1507 if (key > pkey) seq++;
1508 pkey = key;
1509 } else {
1510 /* print spaces instead of \0's */
1511 char str[5];
1512 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1513 str[4] = 0;
1514 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1515 mismatch++;
1516 score -= syms;
1520 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1521 match, mismatch, seq, score);
1522 if ((score > max_score) ||
1523 ((score == max_score) && (seq > max_seq))) {
1524 /* best match so far */
1525 kbd_layout = current;
1526 max_score = score;
1527 max_seq = seq;
1528 ismatch = !mismatch;
1531 /* we're done, report results if necessary */
1532 if (!ismatch)
1533 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1534 main_key_tab[kbd_layout].comment);
1536 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1539 static HKL get_locale_kbd_layout(void)
1541 ULONG_PTR layout;
1542 LANGID langid;
1544 /* FIXME:
1546 * layout = main_key_tab[kbd_layout].lcid;
1548 * Winword uses return value of GetKeyboardLayout as a codepage
1549 * to translate ANSI keyboard messages to unicode. But we have
1550 * a problem with it: for instance Polish keyboard layout is
1551 * identical to the US one, and therefore instead of the Polish
1552 * locale id we return the US one.
1555 layout = GetUserDefaultLCID();
1558 * Microsoft Office expects this value to be something specific
1559 * for Japanese and Korean Windows with an IME the value is 0xe001
1560 * We should probably check to see if an IME exists and if so then
1561 * set this word properly.
1563 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1564 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1565 layout |= 0xe001 << 16; /* IME */
1566 else
1567 layout |= layout << 16;
1569 return (HKL)layout;
1572 /***********************************************************************
1573 * GetKeyboardLayoutName (X11DRV.@)
1575 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1577 static const WCHAR formatW[] = {'%','0','8','x',0};
1578 DWORD layout;
1580 layout = HandleToUlong( get_locale_kbd_layout() );
1581 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1582 sprintfW(name, formatW, layout);
1583 TRACE("returning %s\n", debugstr_w(name));
1584 return TRUE;
1587 static void set_kbd_layout_preload_key(void)
1589 static const WCHAR preload[] =
1590 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1591 static const WCHAR one[] = {'1',0};
1593 HKEY hkey;
1594 WCHAR layout[KL_NAMELENGTH];
1596 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1597 return;
1599 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1601 RegCloseKey(hkey);
1602 return;
1604 if (X11DRV_GetKeyboardLayoutName(layout))
1605 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1607 RegCloseKey(hkey);
1610 /**********************************************************************
1611 * X11DRV_InitKeyboard
1613 void X11DRV_InitKeyboard( Display *display )
1615 KeySym *ksp;
1616 XModifierKeymap *mmp;
1617 KeySym keysym;
1618 KeyCode *kcp;
1619 XKeyEvent e2;
1620 WORD scan, vkey;
1621 int keyc, i, keyn, syms;
1622 char ckey[4]={0,0,0,0};
1623 const char (*lkey)[MAIN_LEN][4];
1624 char vkey_used[256] = { 0 };
1626 /* Ranges of OEM, function key, and character virtual key codes.
1627 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1628 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1629 static const struct {
1630 WORD first, last;
1631 } vkey_ranges[] = {
1632 { VK_OEM_1, VK_OEM_3 },
1633 { VK_OEM_4, VK_ICO_00 },
1634 { 0xe6, 0xe6 },
1635 { 0xe9, 0xf5 },
1636 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1637 { VK_F1, VK_F24 },
1638 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1639 { 0x41, 0x5a }, /* VK_A - VK_Z */
1640 { 0, 0 }
1642 int vkey_range;
1644 set_kbd_layout_preload_key();
1646 wine_tsx11_lock();
1647 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1648 ksp = XGetKeyboardMapping(display, min_keycode,
1649 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1650 /* We are only interested in keysyms_per_keycode.
1651 There is no need to hold a local copy of the keysyms table */
1652 XFree(ksp);
1654 mmp = XGetModifierMapping(display);
1655 kcp = mmp->modifiermap;
1656 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1658 int j;
1660 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1661 if (*kcp)
1663 int k;
1665 for (k = 0; k < keysyms_per_keycode; k += 1)
1666 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1668 NumLockMask = 1 << i;
1669 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1671 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1673 ScrollLockMask = 1 << i;
1674 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1678 XFreeModifiermap(mmp);
1680 /* Detect the keyboard layout */
1681 X11DRV_KEYBOARD_DetectLayout( display );
1682 lkey = main_key_tab[kbd_layout].key;
1683 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1685 /* Now build two conversion arrays :
1686 * keycode -> vkey + scancode + extended
1687 * vkey + extended -> keycode */
1689 e2.display = display;
1690 e2.state = 0;
1691 e2.type = KeyPress;
1693 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1694 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1696 char buf[30];
1697 int have_chars;
1699 keysym = 0;
1700 e2.keycode = (KeyCode)keyc;
1701 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1702 vkey = 0; scan = 0;
1703 if (keysym) /* otherwise, keycode not used */
1705 if ((keysym >> 8) == 0xFF) /* non-character key */
1707 vkey = nonchar_key_vkey[keysym & 0xff];
1708 scan = nonchar_key_scan[keysym & 0xff];
1709 /* set extended bit when necessary */
1710 if (scan & 0x100) vkey |= 0x100;
1711 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1712 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1713 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1714 scan = 0x100;
1715 vkey |= 0x100;
1716 } else if (keysym == 0x20) { /* Spacebar */
1717 vkey = VK_SPACE;
1718 scan = 0x39;
1719 } else if (have_chars) {
1720 /* we seem to need to search the layout-dependent scancodes */
1721 int maxlen=0,maxval=-1,ok;
1722 for (i=0; i<syms; i++) {
1723 keysym = keycode_to_keysym(display, keyc, i);
1724 if ((keysym<0x8000) && (keysym!=' '))
1726 #ifdef HAVE_XKB
1727 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1728 #endif
1730 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1731 * with appropriate ShiftMask and Mode_switch, use XLookupString
1732 * to get character in the local encoding.
1734 ckey[i] = keysym & 0xFF;
1736 } else {
1737 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1740 /* find key with longest match streak */
1741 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1742 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1743 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1744 if (!ok) i--; /* we overshot */
1745 if (ok||(i>maxlen)) {
1746 maxlen=i; maxval=keyn;
1748 if (ok) break;
1750 if (maxval>=0) {
1751 /* got it */
1752 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1753 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1754 scan = (*lscan)[maxval];
1755 vkey = (*lvkey)[maxval];
1759 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1760 keyc2vkey[e2.keycode] = vkey;
1761 keyc2scan[e2.keycode] = scan;
1762 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1763 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1764 vkey_used[(vkey & 0xff)] = 1;
1765 } /* for */
1767 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1768 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1770 vkey = keyc2vkey[keyc] & 0xff;
1771 if (vkey)
1772 continue;
1774 e2.keycode = (KeyCode)keyc;
1775 keysym = XLookupKeysym(&e2, 0);
1776 if (!keysym)
1777 continue;
1779 /* find a suitable layout-dependent VK code */
1780 /* (most Winelib apps ought to be able to work without layout tables!) */
1781 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1783 keysym = XLookupKeysym(&e2, i);
1784 if ((keysym >= XK_0 && keysym <= XK_9)
1785 || (keysym >= XK_A && keysym <= XK_Z)) {
1786 vkey = VKEY_IF_NOT_USED(keysym);
1790 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1792 keysym = XLookupKeysym(&e2, i);
1793 switch (keysym)
1795 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1796 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1797 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1798 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1799 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1800 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1801 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1802 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1803 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1804 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1805 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1809 if (vkey)
1811 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1812 keyc2vkey[e2.keycode] = vkey;
1814 } /* for */
1816 /* For any keycodes which still don't have a vkey, assign any spare
1817 * character, function key, or OEM virtual key code. */
1818 vkey_range = 0;
1819 vkey = vkey_ranges[vkey_range].first;
1820 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1822 if (keyc2vkey[keyc] & 0xff)
1823 continue;
1825 e2.keycode = (KeyCode)keyc;
1826 keysym = XLookupKeysym(&e2, 0);
1827 if (!keysym)
1828 continue;
1830 while (vkey && vkey_used[vkey])
1832 if (vkey == vkey_ranges[vkey_range].last)
1834 vkey_range++;
1835 vkey = vkey_ranges[vkey_range].first;
1837 else
1838 vkey++;
1841 if (!vkey)
1843 WARN("No more vkeys available!\n");
1844 break;
1847 if (TRACE_ON(keyboard))
1849 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1850 vkey, e2.keycode);
1851 TRACE("(");
1852 for (i = 0; i < keysyms_per_keycode; i += 1)
1854 const char *ksname;
1856 keysym = XLookupKeysym(&e2, i);
1857 ksname = XKeysymToString(keysym);
1858 if (!ksname)
1859 ksname = "NoSymbol";
1860 TRACE( "%lx (%s) ", keysym, ksname);
1862 TRACE(")\n");
1865 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1866 keyc2vkey[e2.keycode] = vkey;
1867 vkey_used[vkey] = 1;
1868 } /* for */
1869 #undef VKEY_IF_NOT_USED
1871 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1872 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1873 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1874 const char *ksname;
1875 keysym = keycode_to_keysym(display, keyc, 0);
1876 ksname = XKeysymToString(keysym);
1877 if (!ksname) ksname = "NoSymbol";
1879 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1881 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1882 keyc2scan[keyc]=scan++;
1885 wine_tsx11_unlock();
1888 static BOOL match_x11_keyboard_layout(HKL hkl)
1890 const DWORD isIME = 0xE0000000;
1891 HKL xHkl = get_locale_kbd_layout();
1893 /* if the layout is an IME, only match the low word (LCID) */
1894 if (((ULONG_PTR)hkl & isIME) == isIME)
1895 return (LOWORD(hkl) == LOWORD(xHkl));
1896 else
1897 return (hkl == xHkl);
1900 /**********************************************************************
1901 * GetAsyncKeyState (X11DRV.@)
1903 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1905 /* Photoshop livelocks unless mouse events are included here */
1906 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1907 return -1;
1911 /***********************************************************************
1912 * GetKeyboardLayout (X11DRV.@)
1914 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1916 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1918 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1919 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1921 else
1922 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1924 return get_locale_kbd_layout();
1928 /***********************************************************************
1929 * LoadKeyboardLayout (X11DRV.@)
1931 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1933 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1934 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1935 return 0;
1939 /***********************************************************************
1940 * UnloadKeyboardLayout (X11DRV.@)
1942 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1944 FIXME("%p: stub!\n", hkl);
1945 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1946 return FALSE;
1950 /***********************************************************************
1951 * ActivateKeyboardLayout (X11DRV.@)
1953 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1955 HKL oldHkl = 0;
1956 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1958 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1959 if (flags & KLF_SETFORPROCESS)
1961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1962 FIXME("KLF_SETFORPROCESS not supported\n");
1963 return 0;
1966 if (flags)
1967 FIXME("flags %x not supported\n",flags);
1969 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1971 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1972 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1973 return 0;
1976 if (!match_x11_keyboard_layout(hkl))
1978 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1979 FIXME("setting keyboard of different locales not supported\n");
1980 return 0;
1983 oldHkl = thread_data->kbd_layout;
1984 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1986 thread_data->kbd_layout = hkl;
1988 return oldHkl;
1992 /***********************************************************************
1993 * X11DRV_MappingNotify
1995 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1997 HWND hwnd;
1999 wine_tsx11_lock();
2000 XRefreshKeyboardMapping(&event->xmapping);
2001 wine_tsx11_unlock();
2002 X11DRV_InitKeyboard( event->xmapping.display );
2004 hwnd = GetFocus();
2005 if (!hwnd) hwnd = GetActiveWindow();
2006 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2007 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2011 /***********************************************************************
2012 * VkKeyScanEx (X11DRV.@)
2014 * Note: Windows ignores HKL parameter and uses current active layout instead
2016 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2018 Display *display = thread_init_display();
2019 KeyCode keycode;
2020 KeySym keysym;
2021 int i, index;
2022 CHAR cChar;
2023 SHORT ret;
2025 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2026 * is UTF-8 (multibyte encoding)?
2028 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2030 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2031 return -1;
2034 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2036 /* char->keysym (same for ANSI chars) */
2037 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2038 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2040 wine_tsx11_lock();
2041 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2042 if (!keycode)
2044 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2046 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2047 TRACE(" ... returning ctrl char %#.2x\n", ret);
2048 wine_tsx11_unlock();
2049 return ret;
2051 /* It didn't work ... let's try with deadchar code. */
2052 TRACE("retrying with | 0xFE00\n");
2053 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2055 wine_tsx11_unlock();
2057 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2059 /* keycode -> (keyc2vkey) vkey */
2060 ret = keyc2vkey[keycode];
2062 if (!keycode || !ret)
2064 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2065 return -1;
2068 index = -1;
2069 wine_tsx11_lock();
2070 for (i = 0; i < 4; i++) /* find shift state */
2072 if (keycode_to_keysym(display, keycode, i) == keysym)
2074 index = i;
2075 break;
2078 wine_tsx11_unlock();
2080 switch (index)
2082 default:
2083 case -1:
2084 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2085 return -1;
2087 case 0: break;
2088 case 1: ret += 0x0100; break;
2089 case 2: ret += 0x0600; break;
2090 case 3: ret += 0x0700; break;
2093 index : 0 adds 0x0000
2094 index : 1 adds 0x0100 (shift)
2095 index : ? adds 0x0200 (ctrl)
2096 index : 2 adds 0x0600 (ctrl+alt)
2097 index : 3 adds 0x0700 (ctrl+alt+shift)
2100 TRACE(" ... returning %#.2x\n", ret);
2101 return ret;
2104 /***********************************************************************
2105 * MapVirtualKeyEx (X11DRV.@)
2107 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2109 Display *display = thread_init_display();
2111 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2113 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2114 if (!match_x11_keyboard_layout(hkl))
2115 FIXME("keyboard layout %p is not supported\n", hkl);
2117 switch(wMapType)
2119 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2120 case MAPVK_VK_TO_VSC_EX:
2122 int keyc;
2124 switch (wCode)
2126 case VK_SHIFT: wCode = VK_LSHIFT; break;
2127 case VK_CONTROL: wCode = VK_LCONTROL; break;
2128 case VK_MENU: wCode = VK_LMENU; break;
2131 /* let's do vkey -> keycode -> scan */
2132 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2133 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2135 if (keyc > max_keycode)
2137 TRACE("returning no scan-code.\n");
2138 return 0;
2140 returnMVK (keyc2scan[keyc] & 0xFF);
2142 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2143 case MAPVK_VSC_TO_VK_EX:
2145 int keyc;
2146 UINT vkey = 0;
2148 /* let's do scan -> keycode -> vkey */
2149 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2150 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2152 vkey = keyc2vkey[keyc] & 0xFF;
2153 /* Only stop if it's not a numpad vkey; otherwise keep
2154 looking for a potential better vkey. */
2155 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2156 break;
2159 if (vkey == 0)
2161 TRACE("returning no vkey-code.\n");
2162 return 0;
2165 if (wMapType == MAPVK_VSC_TO_VK)
2166 switch (vkey)
2168 case VK_LSHIFT:
2169 case VK_RSHIFT:
2170 vkey = VK_SHIFT; break;
2171 case VK_LCONTROL:
2172 case VK_RCONTROL:
2173 vkey = VK_CONTROL; break;
2174 case VK_LMENU:
2175 case VK_RMENU:
2176 vkey = VK_MENU; break;
2179 returnMVK (vkey);
2181 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2183 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2184 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2185 * key.. Looks like something is wrong with the MS docs?
2186 * This is only true for letters, for example VK_0 returns '0' not ')'.
2187 * - hence we use the lock mask to ensure this happens.
2189 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2190 XKeyEvent e;
2191 KeySym keysym;
2192 int keyc, len;
2193 char s[10];
2195 e.display = display;
2196 e.state = 0;
2197 e.keycode = 0;
2198 e.type = KeyPress;
2200 wine_tsx11_lock();
2202 /* We exit on the first keycode found, to speed up the thing. */
2203 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2204 { /* Find a keycode that could have generated this virtual key */
2205 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2206 { /* We filter the extended bit, we don't know it */
2207 e.keycode = keyc; /* Store it temporarily */
2208 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2209 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2210 state), so set it to 0, we'll find another one */
2215 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2216 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2218 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2219 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2220 * in order to produce a locale dependent numeric separator.
2222 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2224 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2225 if (!e.keycode)
2226 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2229 if (!e.keycode)
2231 WARN("Unknown virtual key %X !!!\n", wCode);
2232 wine_tsx11_unlock();
2233 return 0; /* whatever */
2235 TRACE("Found keycode %u\n",e.keycode);
2237 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2238 wine_tsx11_unlock();
2240 if (len)
2242 WCHAR wch;
2243 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2244 returnMVK(toupperW(wch));
2246 TRACE("returning no ANSI.\n");
2247 return 0;
2249 default: /* reserved */
2250 FIXME("Unknown wMapType %d !\n", wMapType);
2251 return 0;
2253 return 0;
2256 /***********************************************************************
2257 * GetKeyNameText (X11DRV.@)
2259 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2261 Display *display = thread_init_display();
2262 int vkey, ansi, scanCode;
2263 KeyCode keyc;
2264 int keyi;
2265 KeySym keys;
2266 char *name;
2268 scanCode = lParam >> 16;
2269 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2271 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2273 /* handle "don't care" bit (0x02000000) */
2274 if (!(lParam & 0x02000000)) {
2275 switch (vkey) {
2276 case VK_RSHIFT:
2277 /* R-Shift is "special" - it is an extended key with separate scan code */
2278 scanCode |= 0x100;
2279 /* fall through */
2280 case VK_LSHIFT:
2281 vkey = VK_SHIFT;
2282 break;
2283 case VK_LCONTROL:
2284 case VK_RCONTROL:
2285 vkey = VK_CONTROL;
2286 break;
2287 case VK_LMENU:
2288 case VK_RMENU:
2289 vkey = VK_MENU;
2290 break;
2294 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2295 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2297 /* first get the name of the "regular" keys which is the Upper case
2298 value of the keycap imprint. */
2299 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2300 (scanCode != 0x137) && /* PrtScn */
2301 (scanCode != 0x135) && /* numpad / */
2302 (scanCode != 0x37 ) && /* numpad * */
2303 (scanCode != 0x4a ) && /* numpad - */
2304 (scanCode != 0x4e ) ) /* numpad + */
2306 if (nSize >= 2)
2308 *lpBuffer = toupperW((WCHAR)ansi);
2309 *(lpBuffer+1) = 0;
2310 return 1;
2312 else
2313 return 0;
2316 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2317 without "extended-key" flag. However Wine generates scancode
2318 *with* "extended-key" flag. Seems to occur *only* for the
2319 function keys. Soooo.. We will leave the table alone and
2320 fudge the lookup here till the other part is found and fixed!!! */
2322 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2323 (scanCode == 0x157) || (scanCode == 0x158))
2324 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2326 /* let's do scancode -> keycode -> keysym -> String */
2328 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2329 if ((keyc2scan[keyi]) == scanCode)
2330 break;
2331 if (keyi <= max_keycode)
2333 INT rc;
2335 wine_tsx11_lock();
2336 keyc = (KeyCode) keyi;
2337 keys = keycode_to_keysym(display, keyc, 0);
2338 name = XKeysymToString(keys);
2339 wine_tsx11_unlock();
2341 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2343 char* idx = strrchr(name, '_');
2344 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2346 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2347 scanCode, keyc, keys, debugstr_an(name,idx-name));
2348 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2349 if (!rc) rc = nSize;
2350 lpBuffer[--rc] = 0;
2351 return rc;
2355 if (name)
2357 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2358 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2359 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2360 if (!rc) rc = nSize;
2361 lpBuffer[--rc] = 0;
2362 return rc;
2366 /* Finally issue WARN for unknown keys */
2368 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2369 *lpBuffer = 0;
2370 return 0;
2373 /***********************************************************************
2374 * X11DRV_KEYBOARD_MapDeadKeysym
2376 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2378 switch (keysym)
2380 /* symbolic ASCII is the same as defined in rfc1345 */
2381 #ifdef XK_dead_tilde
2382 case XK_dead_tilde :
2383 #endif
2384 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2385 return '~'; /* '? */
2386 #ifdef XK_dead_acute
2387 case XK_dead_acute :
2388 #endif
2389 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2390 return 0xb4; /* '' */
2391 #ifdef XK_dead_circumflex
2392 case XK_dead_circumflex:
2393 #endif
2394 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2395 return '^'; /* '> */
2396 #ifdef XK_dead_grave
2397 case XK_dead_grave :
2398 #endif
2399 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2400 return '`'; /* '! */
2401 #ifdef XK_dead_diaeresis
2402 case XK_dead_diaeresis :
2403 #endif
2404 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2405 return 0xa8; /* ': */
2406 #ifdef XK_dead_cedilla
2407 case XK_dead_cedilla :
2408 return 0xb8; /* ', */
2409 #endif
2410 #ifdef XK_dead_macron
2411 case XK_dead_macron :
2412 return '-'; /* 'm isn't defined on iso-8859-x */
2413 #endif
2414 #ifdef XK_dead_breve
2415 case XK_dead_breve :
2416 return 0xa2; /* '( */
2417 #endif
2418 #ifdef XK_dead_abovedot
2419 case XK_dead_abovedot :
2420 return 0xff; /* '. */
2421 #endif
2422 #ifdef XK_dead_abovering
2423 case XK_dead_abovering :
2424 return '0'; /* '0 isn't defined on iso-8859-x */
2425 #endif
2426 #ifdef XK_dead_doubleacute
2427 case XK_dead_doubleacute :
2428 return 0xbd; /* '" */
2429 #endif
2430 #ifdef XK_dead_caron
2431 case XK_dead_caron :
2432 return 0xb7; /* '< */
2433 #endif
2434 #ifdef XK_dead_ogonek
2435 case XK_dead_ogonek :
2436 return 0xb2; /* '; */
2437 #endif
2438 /* FIXME: I don't know this three.
2439 case XK_dead_iota :
2440 return 'i';
2441 case XK_dead_voiced_sound :
2442 return 'v';
2443 case XK_dead_semivoiced_sound :
2444 return 's';
2447 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2448 return 0;
2451 /***********************************************************************
2452 * ToUnicodeEx (X11DRV.@)
2454 * The ToUnicode function translates the specified virtual-key code and keyboard
2455 * state to the corresponding Windows character or characters.
2457 * If the specified key is a dead key, the return value is negative. Otherwise,
2458 * it is one of the following values:
2459 * Value Meaning
2460 * 0 The specified virtual key has no translation for the current state of the keyboard.
2461 * 1 One Windows character was copied to the buffer.
2462 * 2 Two characters were copied to the buffer. This usually happens when a
2463 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2464 * be composed with the specified virtual key to form a single character.
2466 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2469 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2470 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2472 Display *display = thread_init_display();
2473 XKeyEvent e;
2474 KeySym keysym = 0;
2475 INT ret;
2476 int keyc;
2477 char buf[10];
2478 char *lpChar = buf;
2479 HWND focus;
2480 XIC xic;
2481 Status status = 0;
2483 if (scanCode & 0x8000)
2485 TRACE_(key)("Key UP, doing nothing\n" );
2486 return 0;
2489 if (!match_x11_keyboard_layout(hkl))
2490 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2492 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2494 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2495 return 0;
2498 e.display = display;
2499 e.keycode = 0;
2500 e.state = 0;
2501 e.type = KeyPress;
2503 focus = x11drv_thread_data()->last_xic_hwnd;
2504 if (!focus)
2506 focus = GetFocus();
2507 if (focus) focus = GetAncestor( focus, GA_ROOT );
2508 if (!focus) focus = GetActiveWindow();
2510 e.window = X11DRV_get_whole_window( focus );
2511 xic = X11DRV_get_ic( focus );
2513 if (lpKeyState[VK_SHIFT] & 0x80)
2515 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2516 e.state |= ShiftMask;
2518 if (lpKeyState[VK_CAPITAL] & 0x01)
2520 TRACE_(key)("LockMask = %04x\n", LockMask);
2521 e.state |= LockMask;
2523 if (lpKeyState[VK_CONTROL] & 0x80)
2525 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2526 e.state |= ControlMask;
2528 if (lpKeyState[VK_NUMLOCK] & 0x01)
2530 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2531 e.state |= NumLockMask;
2534 /* Restore saved AltGr state */
2535 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2536 e.state |= AltGrMask;
2538 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2539 virtKey, scanCode, e.state);
2540 wine_tsx11_lock();
2541 /* We exit on the first keycode found, to speed up the thing. */
2542 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2543 { /* Find a keycode that could have generated this virtual key */
2544 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2545 { /* We filter the extended bit, we don't know it */
2546 e.keycode = keyc; /* Store it temporarily */
2547 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2548 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2549 state), so set it to 0, we'll find another one */
2554 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2555 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2557 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2558 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2560 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2561 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2562 * in order to produce a locale dependent numeric separator.
2564 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2566 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2567 if (!e.keycode)
2568 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2571 if (!e.keycode && virtKey != VK_NONAME)
2573 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2574 wine_tsx11_unlock();
2575 return 0;
2577 else TRACE_(key)("Found keycode %u\n",e.keycode);
2579 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2580 e.type, e.window, e.state, e.keycode);
2582 /* Clients should pass only KeyPress events to XmbLookupString,
2583 * e.type was set to KeyPress above.
2585 if (xic)
2587 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2588 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2589 if (status == XBufferOverflow)
2591 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2592 if (lpChar == NULL)
2594 ERR_(key)("Failed to allocate memory!\n");
2595 wine_tsx11_unlock();
2596 return 0;
2598 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2601 else
2602 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2603 wine_tsx11_unlock();
2605 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2607 if (TRACE_ON(key))
2609 const char *ksname;
2611 wine_tsx11_lock();
2612 ksname = XKeysymToString(keysym);
2613 wine_tsx11_unlock();
2614 if (!ksname) ksname = "No Name";
2615 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2616 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2617 keysym, ksname, ret, debugstr_an(lpChar, ret));
2620 if (ret == 0)
2622 char dead_char;
2624 #ifdef XK_EuroSign
2625 /* An ugly hack for EuroSign: X can't translate it to a character
2626 for some locales. */
2627 if (keysym == XK_EuroSign)
2629 bufW[0] = 0x20AC;
2630 ret = 1;
2631 goto found;
2633 #endif
2634 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2635 /* Here we change it back. */
2636 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2638 bufW[0] = 0x09;
2639 ret = 1;
2640 goto found;
2643 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2644 if (dead_char)
2646 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2647 ret = -1;
2648 goto found;
2651 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2653 /* Unicode direct mapping */
2654 bufW[0] = keysym & 0xffff;
2655 ret = 1;
2656 goto found;
2658 else if ((keysym >> 8) == 0x1008FF) {
2659 bufW[0] = 0;
2660 ret = 0;
2661 goto found;
2663 else
2665 const char *ksname;
2667 wine_tsx11_lock();
2668 ksname = XKeysymToString(keysym);
2669 wine_tsx11_unlock();
2670 if (!ksname)
2671 ksname = "No Name";
2672 if ((keysym >> 8) != 0xff)
2674 WARN_(key)("no char for keysym %04lx (%s) :\n",
2675 keysym, ksname);
2676 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2677 virtKey, scanCode, e.keycode, e.state);
2681 else { /* ret != 0 */
2682 /* We have a special case to handle : Shift + arrow, shift + home, ...
2683 X returns a char for it, but Windows doesn't. Let's eat it. */
2684 if (!(e.state & NumLockMask) /* NumLock is off */
2685 && (e.state & ShiftMask) /* Shift is pressed */
2686 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2688 lpChar[0] = 0;
2689 ret = 0;
2692 /* more areas where X returns characters but Windows does not
2693 CTRL + number or CTRL + symbol */
2694 if (e.state & ControlMask)
2696 if (((keysym>=33) && (keysym < 'A')) ||
2697 ((keysym > 'Z') && (keysym < 'a')) ||
2698 (keysym == XK_Tab))
2700 lpChar[0] = 0;
2701 ret = 0;
2705 /* We have another special case for delete key (XK_Delete) on an
2706 extended keyboard. X returns a char for it, but Windows doesn't */
2707 if (keysym == XK_Delete)
2709 lpChar[0] = 0;
2710 ret = 0;
2712 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2713 && (keysym == XK_KP_Decimal))
2715 lpChar[0] = 0;
2716 ret = 0;
2718 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2719 && (keysym == XK_Return || keysym == XK_KP_Enter))
2721 lpChar[0] = '\n';
2722 ret = 1;
2725 /* Hack to detect an XLookupString hard-coded to Latin1 */
2726 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2728 bufW[0] = (BYTE)lpChar[0];
2729 goto found;
2732 /* perform translation to unicode */
2733 if(ret)
2735 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2736 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2740 found:
2741 if (buf != lpChar)
2742 HeapFree(GetProcessHeap(), 0, lpChar);
2744 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2745 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2746 if (1 <= ret && ret < bufW_size)
2747 bufW[ret] = 0;
2749 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2750 return ret;
2753 /***********************************************************************
2754 * Beep (X11DRV.@)
2756 void CDECL X11DRV_Beep(void)
2758 wine_tsx11_lock();
2759 XBell(gdi_display, 0);
2760 wine_tsx11_unlock();