msxml3/tests: Remove redundant NULL check before SysFreeString (Smatch).
[wine/multimedia.git] / dlls / winex11.drv / keyboard.c
blob99b16edc40432e99684770004d50010e3a609f34
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 "winnls.h"
48 #include "x11drv.h"
49 #include "wine/server.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
54 WINE_DECLARE_DEBUG_CHANNEL(key);
56 /* key state table bits:
57 0x80 -> key is pressed
58 0x40 -> key got pressed since last time
59 0x01 -> key is toggled
61 BYTE key_state_table[256];
63 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
64 or a WM_KEYUP message */
66 static int min_keycode, max_keycode, keysyms_per_keycode;
67 static WORD keyc2vkey[256], keyc2scan[256];
69 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
71 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
73 /* Keyboard translation tables */
74 #define MAIN_LEN 49
75 static const WORD main_key_scan_qwerty[MAIN_LEN] =
77 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
78 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
79 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
80 /* q w e r t y u i o p [ ] */
81 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
82 /* a s d f g h j k l ; ' \ */
83 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
84 /* z x c v b n m , . / */
85 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
86 0x56 /* the 102nd key (actually to the right of l-shift) */
89 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
91 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
92 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
93 /* q w e r t y u i o p [ ] */
94 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
95 /* a s d f g h j k l ; ' \ */
96 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
97 /* \ z x c v b n m , . / */
98 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
99 0x56, /* the 102nd key (actually to the right of l-shift) */
102 static const WORD main_key_scan_dvorak[MAIN_LEN] =
104 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
105 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
106 /* ' , . p y f g c r l / = */
107 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
108 /* a o e u i d h t n s - \ */
109 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
110 /* ; q j k x b m w v z */
111 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
112 0x56 /* the 102nd key (actually to the right of l-shift) */
115 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
117 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
118 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
119 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
120 /* q w e r t y u i o p @ [ */
121 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
122 /* a s d f g h j k l ; : ] */
123 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
124 /* z x c v b n m , . / */
125 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
126 0x56 /* the 102nd key (actually to the right of l-shift) */
129 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
131 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
132 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
133 /* q w e r t y u i o p @ [ */
134 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
135 /* a s d f g h j k l ; : ] */
136 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
137 /* z x c v b n m , . / */
138 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
139 0x73 /* the 102nd key (actually to the right of l-shift) */
143 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
145 /* NOTE: this layout must concur with the scan codes layout above */
146 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
147 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
148 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
149 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
150 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
153 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
155 /* NOTE: this layout must concur with the scan codes layout above */
156 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
157 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
158 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
159 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
160 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
163 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
165 /* NOTE: this layout must concur with the scan codes layout above */
166 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
167 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
168 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
169 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
170 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
173 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
175 /* NOTE: this layout must concur with the scan codes layout above */
176 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
177 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
178 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
179 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
180 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
183 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
185 /* NOTE: this layout must concur with the scan codes layout above */
186 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
187 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
188 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
189 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
190 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
193 static const WORD main_key_vkey_qwertz_105[MAIN_LEN] =
195 /* NOTE: this layout must concur with the scan codes layout above */
196 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
197 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
198 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
199 VK_OEM_102,'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2
202 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
204 /* NOTE: this layout must concur with the scan codes layout above */
205 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
206 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
207 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
208 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
209 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
212 static const WORD main_key_vkey_azerty[MAIN_LEN] =
214 /* NOTE: this layout must concur with the scan codes layout above */
215 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
216 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
217 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
218 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
219 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
222 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
224 /* NOTE: this layout must concur with the scan codes layout above */
225 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
226 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
227 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
228 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
229 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
232 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
234 /* the VK mappings for the main keyboard will be auto-assigned as before,
235 so what we have here is just the character tables */
236 /* order: Normal, Shift, AltGr, Shift-AltGr */
237 /* We recommend you write just what is guaranteed to be correct (i.e. what's
238 written on the keycaps), not the bunch of special characters behind AltGr
239 and Shift-AltGr if it can vary among different X servers */
240 /* Remember that your 102nd key (to the right of l-shift) should be on a
241 separate line, see existing tables */
242 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
243 /* Remember to also add your new table to the layout index table far below! */
245 /*** German Logitech Desktop Pro keyboard layout */
246 static const char main_key_DE_logitech[MAIN_LEN][4] =
248 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
249 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
251 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
252 "<>|"
255 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
256 static const char main_key_US[MAIN_LEN][4] =
258 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
259 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
260 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
261 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
264 /*** United States keyboard layout (phantom key version) */
265 /* (XFree86 reports the <> key even if it's not physically there) */
266 static const char main_key_US_phantom[MAIN_LEN][4] =
268 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
269 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
270 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
271 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
272 "<>" /* the phantom key */
275 /*** United States keyboard layout (dvorak version) */
276 static const char main_key_US_dvorak[MAIN_LEN][4] =
278 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
279 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
280 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
281 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
284 /*** British keyboard layout */
285 static const char main_key_UK[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 /*** French keyboard layout (setxkbmap fr) */
295 static const char main_key_FR[MAIN_LEN][4] =
297 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
298 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
299 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
300 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
301 "<>"
304 /*** Icelandic keyboard layout (setxkbmap is) */
305 static const char main_key_IS[MAIN_LEN][4] =
307 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
308 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
309 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
310 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
311 "<>"
314 /*** German keyboard layout (setxkbmap de) */
315 static const char main_key_DE[MAIN_LEN][4] =
317 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","´`",
318 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
319 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
320 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
321 "<>|"
324 /*** German keyboard layout without dead keys */
325 static const char main_key_DE_nodead[MAIN_LEN][4] =
327 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
328 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
330 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
331 "<>"
334 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
335 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
337 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
338 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
339 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
340 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
343 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
344 static const char main_key_SG[MAIN_LEN][4] =
346 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
347 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
348 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
349 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
350 "<>"
353 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
354 static const char main_key_SF[MAIN_LEN][4] =
356 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
357 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
358 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
359 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
360 "<>"
363 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
364 static const char main_key_NO[MAIN_LEN][4] =
366 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
367 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
368 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
369 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
370 "<>"
373 /*** Danish keyboard layout (setxkbmap dk) */
374 static const char main_key_DA[MAIN_LEN][4] =
376 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
377 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
378 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
379 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
380 "<>"
383 /*** Swedish keyboard layout (setxkbmap se) */
384 static const char main_key_SE[MAIN_LEN][4] =
386 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
387 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
388 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
389 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
390 "<>"
393 /*** Estonian keyboard layout (setxkbmap ee) */
394 static const char main_key_ET[MAIN_LEN][4] =
396 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
397 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
398 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
399 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
400 "<>"
403 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
404 static const char main_key_CF[MAIN_LEN][4] =
406 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
407 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
408 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
409 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
410 "«»°"
413 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
414 static const char main_key_CA_fr[MAIN_LEN][4] =
416 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
417 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
418 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
419 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
420 "«»"
423 /*** Canadian keyboard layout (setxkbmap ca) */
424 static const char main_key_CA[MAIN_LEN][4] =
426 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
427 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
428 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
429 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
430 "ùÙ"
433 /*** Portuguese keyboard layout (setxkbmap pt) */
434 static const char main_key_PT[MAIN_LEN][4] =
436 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
437 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
438 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
439 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
440 "<>"
443 /*** Italian keyboard layout (setxkbmap it) */
444 static const char main_key_IT[MAIN_LEN][4] =
446 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
447 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
448 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
449 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
450 "<>"
453 /*** Finnish keyboard layout (setxkbmap fi) */
454 static const char main_key_FI[MAIN_LEN][4] =
456 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
457 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
458 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
459 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
460 "<>"
463 /*** Bulgarian bds keyboard layout */
464 static const char main_key_BG_bds[MAIN_LEN][4] =
466 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
467 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
468 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
469 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
470 "<>" /* the phantom key */
473 /*** Bulgarian phonetic keyboard layout */
474 static const char main_key_BG_phonetic[MAIN_LEN][4] =
476 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
477 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
478 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
479 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
480 "<>" /* the phantom key */
483 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
484 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
485 static const char main_key_BY[MAIN_LEN][4] =
487 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
488 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
489 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
490 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
494 /*** Russian keyboard layout (contributed by Pavel Roskin) */
495 static const char main_key_RU[MAIN_LEN][4] =
497 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
498 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
499 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
500 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
503 /*** Russian keyboard layout (phantom key version) */
504 static const char main_key_RU_phantom[MAIN_LEN][4] =
506 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
507 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
508 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
509 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
510 "<>" /* the phantom key */
513 /*** Russian keyboard layout KOI8-R */
514 static const char main_key_RU_koi8r[MAIN_LEN][4] =
516 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
517 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
518 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
519 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
520 "<>" /* the phantom key */
523 /*** Russian keyboard layout cp1251 */
524 static const char main_key_RU_cp1251[MAIN_LEN][4] =
526 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
527 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
528 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
529 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
530 "<>" /* the phantom key */
533 /*** Russian phonetic keyboard layout */
534 static const char main_key_RU_phonetic[MAIN_LEN][4] =
536 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
537 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
538 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
539 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
540 "<>" /* the phantom key */
543 /*** Ukrainian keyboard layout KOI8-U */
544 static const char main_key_UA[MAIN_LEN][4] =
546 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
547 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
548 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
549 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
550 "<>" /* the phantom key */
553 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
554 /*** (as it appears on most of keyboards sold today) */
555 static const char main_key_UA_std[MAIN_LEN][4] =
557 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
558 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
559 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
560 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
561 "<>" /* the phantom key */
564 /*** Russian keyboard layout KOI8-R (pair to the previous) */
565 static const char main_key_RU_std[MAIN_LEN][4] =
567 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
568 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
569 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
570 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
571 "<>" /* the phantom key */
574 /*** Spanish keyboard layout (setxkbmap es) */
575 static const char main_key_ES[MAIN_LEN][4] =
577 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
578 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
579 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
580 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
581 "<>"
584 /*** Belgian keyboard layout ***/
585 static const char main_key_BE[MAIN_LEN][4] =
587 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
588 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
589 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
590 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
591 "<>\\"
594 /*** Hungarian keyboard layout (setxkbmap hu) */
595 static const char main_key_HU[MAIN_LEN][4] =
597 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
598 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
599 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
600 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
601 "íÍ"
604 /*** Polish (programmer's) keyboard layout ***/
605 static const char main_key_PL[MAIN_LEN][4] =
607 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
608 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
609 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
610 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
611 "<>|"
614 /*** Slovenian keyboard layout (setxkbmap si) ***/
615 static const char main_key_SI[MAIN_LEN][4] =
617 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
618 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
619 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
620 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
621 "<>"
624 /*** Serbian keyboard layout (setxkbmap sr) ***/
625 static const char main_key_SR[MAIN_LEN][4] =
627 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
628 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
629 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
630 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
631 "<>" /* the phantom key */
634 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
635 static const char main_key_US_SR[MAIN_LEN][4] =
637 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
638 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
639 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
640 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
641 "<>" /* the phantom key */
644 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
645 static const char main_key_HR_jelly[MAIN_LEN][4] =
647 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
648 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
649 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
650 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
651 "<>|"
654 /*** Croatian keyboard layout (setxkbmap hr) ***/
655 static const char main_key_HR[MAIN_LEN][4] =
657 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
658 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
659 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
660 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
661 "<>"
664 /*** Japanese 106 keyboard layout ***/
665 static const char main_key_JA_jp106[MAIN_LEN][4] =
667 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
668 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
669 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
670 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
671 "\\_",
674 static const char main_key_JA_macjp[MAIN_LEN][4] =
676 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
677 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
678 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
679 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
680 "__",
683 /*** Japanese pc98x1 keyboard layout ***/
684 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
686 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
687 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
688 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
689 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
690 "\\_",
693 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
694 static const char main_key_PT_br[MAIN_LEN][4] =
696 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
697 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
698 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
699 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
702 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
703 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
705 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
706 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
707 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
708 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
711 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
712 static const char main_key_US_intl[MAIN_LEN][4] =
714 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
715 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
716 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
717 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
720 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
721 - dead_abovering replaced with degree - no symbol in iso8859-2
722 - brokenbar replaced with bar */
723 static const char main_key_SK[MAIN_LEN][4] =
725 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
726 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
727 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
728 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
729 "<>"
732 /*** Czech keyboard layout (setxkbmap cz) */
733 static const char main_key_CZ[MAIN_LEN][4] =
735 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
736 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
737 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
738 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
739 "\\"
742 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
743 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
745 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
746 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
747 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
748 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
749 "\\"
752 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
753 static const char main_key_SK_prog[MAIN_LEN][4] =
755 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
756 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
757 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
758 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
759 "<>"
762 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
763 static const char main_key_CS[MAIN_LEN][4] =
765 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
766 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
767 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
768 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
769 "<>\\|"
772 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
773 static const char main_key_LA[MAIN_LEN][4] =
775 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
776 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
777 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
778 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
779 "<>"
782 /*** Lithuanian keyboard layout (setxkbmap lt) */
783 static const char main_key_LT_B[MAIN_LEN][4] =
785 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
786 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
787 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
788 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
789 "ª¬"
792 /*** Turkish keyboard Layout */
793 static const char main_key_TK[MAIN_LEN][4] =
795 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
796 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
797 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
798 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
801 /*** Turkish keyboard layout (setxkbmap tr) */
802 static const char main_key_TR[MAIN_LEN][4] =
804 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
805 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
806 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
807 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
808 "<>"
811 /*** Turkish F keyboard layout (setxkbmap trf) */
812 static const char main_key_TR_F[MAIN_LEN][4] =
814 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
815 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
816 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
817 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
818 "<>"
821 /*** Israelian keyboard layout (setxkbmap us,il) */
822 static const char main_key_IL[MAIN_LEN][4] =
824 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
825 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
826 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
827 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
828 "<>"
831 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
832 static const char main_key_IL_phonetic[MAIN_LEN][4] =
834 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
835 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
836 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
837 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
838 "<>"
841 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
842 static const char main_key_IL_saharon[MAIN_LEN][4] =
844 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
845 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
846 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
847 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
848 "<>"
851 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
852 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
853 message since they have different characters in gr and el XFree86 layouts. */
854 static const char main_key_EL[MAIN_LEN][4] =
856 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
857 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
858 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
859 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
860 "<>"
863 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
864 static const char main_key_th[MAIN_LEN][4] =
866 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
867 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
868 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
869 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
872 /*** VNC keyboard layout */
873 static const WORD main_key_scan_vnc[MAIN_LEN] =
875 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
876 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,
877 0x56
880 static const WORD main_key_vkey_vnc[MAIN_LEN] =
882 '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,
883 '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',
884 VK_OEM_102
887 static const char main_key_vnc[MAIN_LEN][4] =
889 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
890 "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"
893 /*** Dutch keyboard layout (setxkbmap nl) ***/
894 static const char main_key_NL[MAIN_LEN][4] =
896 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
897 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
898 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
899 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
900 "[]"
905 /*** Layout table. Add your keyboard mappings to this list */
906 static const struct {
907 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
908 in the appropriate dlls/kernel/nls/.nls file */
909 const char *comment;
910 const char (*key)[MAIN_LEN][4];
911 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
912 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
913 } main_key_tab[]={
914 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
917 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
920 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
921 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
922 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwertz_105},
923 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
924 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
925 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
926 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
928 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
929 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
930 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
934 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
936 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
937 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
938 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
948 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
953 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
955 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
956 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
957 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
958 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
959 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
960 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
961 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
962 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
963 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
964 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
965 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
966 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
967 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
968 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
969 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
970 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
971 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
972 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
973 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
974 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
975 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
976 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
977 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
978 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
980 {0, NULL, NULL, NULL, NULL} /* sentinel */
982 static unsigned kbd_layout=0; /* index into above table of layouts */
984 /* maybe more of these scancodes should be extended? */
985 /* extended must be set for ALT_R, CTRL_R,
986 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
987 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
988 /* FIXME should we set extended bit for NumLock ? My
989 * Windows does ... DF */
990 /* Yes, to distinguish based on scan codes, also
991 for PrtScn key ... GA */
993 static const WORD nonchar_key_vkey[256] =
995 /* unused */
996 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
997 /* special keys */
998 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
999 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
1000 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
1001 /* unused */
1002 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
1003 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
1004 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
1005 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
1007 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
1008 /* cursor keys */
1009 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
1010 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1012 /* misc keys */
1013 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
1014 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1016 /* keypad keys */
1017 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
1018 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1019 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
1020 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
1021 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
1022 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1023 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1024 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
1025 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1026 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1027 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1028 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1029 /* function keys */
1030 VK_F1, VK_F2,
1031 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1032 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
1033 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
1034 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1035 /* modifier keys */
1036 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1037 VK_RCONTROL, VK_CAPITAL, 0, VK_MENU,
1038 VK_MENU, VK_LMENU, VK_RMENU, 0, 0, 0, 0, 0, /* FFE8 */
1039 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1040 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1043 static const WORD nonchar_key_scan[256] =
1045 /* unused */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1047 /* special keys */
1048 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1049 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1050 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1051 /* unused */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1058 /* cursor keys */
1059 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1061 /* misc keys */
1062 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
1063 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1065 /* keypad keys */
1066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1068 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1070 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1072 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1073 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1074 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1075 /* function keys */
1076 0x3B, 0x3C,
1077 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1078 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
1079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1081 /* modifier keys */
1082 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1083 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
1084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1088 static const WORD xfree86_vendor_key_vkey[256] =
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1092 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1093 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1094 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1095 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1096 0, 0, 0, VK_BROWSER_HOME,
1097 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1098 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1099 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1100 0, 0, 0, 0,
1101 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1102 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1103 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1104 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1105 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1106 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1107 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1108 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1109 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1110 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1111 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1112 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1113 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1114 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1115 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1116 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1117 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1118 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1119 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1120 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1121 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1122 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1123 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1124 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1125 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1128 /* Returns the Windows virtual key code associated with the X event <e> */
1129 /* x11 lock must be held */
1130 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1132 KeySym keysym = 0;
1133 Status status;
1134 char buf[24];
1136 /* Clients should pass only KeyPress events to XmbLookupString */
1137 if (xic && e->type == KeyPress)
1138 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1139 else
1140 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1142 if ((e->state & NumLockMask) &&
1143 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1144 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1145 /* Only the Keypad keys 0-9 and . send different keysyms
1146 * depending on the NumLock state */
1147 return nonchar_key_vkey[keysym & 0xFF];
1149 TRACE_(key)("e->keycode = %x\n", e->keycode);
1151 return keyc2vkey[e->keycode];
1155 /***********************************************************************
1156 * X11DRV_send_keyboard_input
1158 void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD event_flags, DWORD time,
1159 DWORD dwExtraInfo, UINT injected_flags )
1161 UINT message;
1162 KBDLLHOOKSTRUCT hook;
1163 WORD flags, wVkStripped, wVkL, wVkR, vk_hook = wVk;
1165 wVk = LOBYTE(wVk);
1166 flags = LOBYTE(wScan);
1168 if (event_flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
1169 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1171 /* strip left/right for menu, control, shift */
1172 switch (wVk)
1174 case VK_MENU:
1175 case VK_LMENU:
1176 case VK_RMENU:
1177 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
1178 wVkStripped = VK_MENU;
1179 wVkL = VK_LMENU;
1180 wVkR = VK_RMENU;
1181 break;
1182 case VK_CONTROL:
1183 case VK_LCONTROL:
1184 case VK_RCONTROL:
1185 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
1186 wVkStripped = VK_CONTROL;
1187 wVkL = VK_LCONTROL;
1188 wVkR = VK_RCONTROL;
1189 break;
1190 case VK_SHIFT:
1191 case VK_LSHIFT:
1192 case VK_RSHIFT:
1193 wVk = (event_flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
1194 wVkStripped = VK_SHIFT;
1195 wVkL = VK_LSHIFT;
1196 wVkR = VK_RSHIFT;
1197 break;
1198 default:
1199 wVkStripped = wVkL = wVkR = wVk;
1202 if (event_flags & KEYEVENTF_KEYUP)
1204 message = WM_KEYUP;
1205 if ((key_state_table[VK_MENU] & 0x80) &&
1206 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1207 || !(key_state_table[VK_CONTROL] & 0x80)))
1209 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1210 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1211 message = WM_SYSKEYUP;
1212 TrackSysKey = 0;
1214 flags |= KF_REPEAT | KF_UP;
1216 else
1218 message = WM_KEYDOWN;
1219 if ((key_state_table[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
1220 !(key_state_table[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
1222 message = WM_SYSKEYDOWN;
1223 TrackSysKey = wVkStripped;
1225 if (key_state_table[wVk] & 0x80) flags |= KF_REPEAT;
1228 TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
1229 wVk, MAKELPARAM( 1, flags ), key_state_table[wVk] );
1231 /* Hook gets whatever key was sent. */
1232 hook.vkCode = vk_hook;
1233 hook.scanCode = wScan;
1234 hook.flags = (flags >> 8) | injected_flags;
1235 hook.time = time;
1236 hook.dwExtraInfo = dwExtraInfo;
1237 if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1239 if (event_flags & KEYEVENTF_KEYUP)
1241 key_state_table[wVk] &= ~0x80;
1242 key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1244 else
1246 if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1247 key_state_table[wVk] |= 0xc0;
1248 key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
1251 if (key_state_table[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
1253 if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
1255 SERVER_START_REQ( send_hardware_message )
1257 req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1258 req->win = 0;
1259 req->msg = message;
1260 req->wparam = wVk;
1261 req->lparam = MAKELPARAM( 1 /* repeat count */, flags );
1262 req->x = cursor_pos.x;
1263 req->y = cursor_pos.y;
1264 req->time = time;
1265 req->info = dwExtraInfo;
1266 wine_server_call( req );
1268 SERVER_END_REQ;
1272 /***********************************************************************
1273 * KEYBOARD_UpdateOneState
1275 * Updates internal state for <vkey>, depending on key <state> under X
1278 static inline void KEYBOARD_UpdateOneState ( WORD vkey, WORD scan, int state, DWORD time )
1280 /* Do something if internal table state != X state for keycode */
1281 if (((key_state_table[vkey & 0xff] & 0x80)!=0) != state)
1283 DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1285 if (!state) flags |= KEYEVENTF_KEYUP;
1287 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1288 vkey, key_state_table[vkey & 0xff]);
1290 /* Fake key being pressed inside wine */
1291 X11DRV_send_keyboard_input( vkey & 0xff, scan & 0xff, flags, time, 0, 0 );
1293 TRACE("State after %#.2x\n", key_state_table[vkey & 0xff]);
1297 /***********************************************************************
1298 * X11DRV_KeymapNotify
1300 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1302 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1303 * from wine to another application and back.
1304 * Toggle keys are handled in HandleEvent.
1306 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1308 int i, j;
1309 DWORD time = GetCurrentTime();
1311 /* the minimum keycode is always greater or equal to 8, so we can
1312 * skip the first 8 values, hence start at 1
1314 for (i = 1; i < 32; i++)
1316 for (j = 0; j < 8; j++)
1318 WORD vkey = keyc2vkey[(i * 8) + j];
1319 WORD scan = keyc2scan[(i * 8) + j];
1320 int state = (event->xkeymap.key_vector[i] & (1<<j)) != 0;
1322 switch(vkey & 0xff)
1324 case VK_LMENU:
1325 case VK_RMENU:
1326 case VK_LCONTROL:
1327 case VK_RCONTROL:
1328 case VK_LSHIFT:
1329 case VK_RSHIFT:
1330 KEYBOARD_UpdateOneState( vkey, scan, state, time );
1331 break;
1337 static void update_lock_state(BYTE vkey, WORD scan, DWORD time)
1339 DWORD flags = vkey == VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0;
1341 if (key_state_table[vkey] & 0x80) flags ^= KEYEVENTF_KEYUP;
1343 X11DRV_send_keyboard_input( vkey, scan, flags, time, 0, 0 );
1344 X11DRV_send_keyboard_input( vkey, scan, flags ^ KEYEVENTF_KEYUP, time, 0, 0 );
1347 /***********************************************************************
1348 * X11DRV_KeyEvent
1350 * Handle a X key event
1352 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1354 XKeyEvent *event = &xev->xkey;
1355 char buf[24];
1356 char *Str = buf;
1357 KeySym keysym = 0;
1358 WORD vkey = 0, bScan;
1359 DWORD dwFlags;
1360 int ascii_chars;
1361 XIC xic = X11DRV_get_ic( hwnd );
1362 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1363 Status status = 0;
1365 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1366 event->type, event->window, event->state, event->keycode);
1368 wine_tsx11_lock();
1369 /* Clients should pass only KeyPress events to XmbLookupString */
1370 if (xic && event->type == KeyPress)
1372 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1373 TRACE("XmbLookupString needs %i byte(s)\n", ascii_chars);
1374 if (status == XBufferOverflow)
1376 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1377 if (Str == NULL)
1379 ERR("Failed to allocate memory!\n");
1380 wine_tsx11_unlock();
1381 return;
1383 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1386 else
1387 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1388 wine_tsx11_unlock();
1390 TRACE_(key)("nbyte = %d, status 0x%x\n", ascii_chars, status);
1392 if (status == XLookupChars)
1394 X11DRV_XIMLookupChars( Str, ascii_chars );
1395 if (buf != Str)
1396 HeapFree(GetProcessHeap(), 0, Str);
1397 return;
1400 /* If XKB extensions are used, the state mask for AltGr will use the group
1401 index instead of the modifier mask. The group index is set in bits
1402 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1403 pressed, look if the group index is different than 0. From XKB
1404 extension documentation, the group index for AltGr should be 2
1405 (event->state = 0x2000). It's probably better to not assume a
1406 predefined group index and find it dynamically
1408 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1409 /* Save also all possible modifier states. */
1410 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1412 if (TRACE_ON(key)){
1413 const char *ksname;
1415 wine_tsx11_lock();
1416 ksname = XKeysymToString(keysym);
1417 wine_tsx11_unlock();
1418 if (!ksname)
1419 ksname = "No Name";
1420 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
1421 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1422 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1424 if (buf != Str)
1425 HeapFree(GetProcessHeap(), 0, Str);
1427 wine_tsx11_lock();
1428 vkey = EVENT_event_to_vkey(xic,event);
1429 /* X returns keycode 0 for composed characters */
1430 if (!vkey && ascii_chars) vkey = VK_NONAME;
1431 wine_tsx11_unlock();
1433 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1434 event->keycode, vkey);
1436 if (!vkey) return;
1438 dwFlags = 0;
1439 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1440 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1443 /* Note: X sets the below states on key down and clears them on key up.
1444 Windows triggers them on key down. */
1446 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1447 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask) &&
1448 vkey != VK_CAPITAL)
1450 TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table[VK_CAPITAL]);
1451 update_lock_state(VK_CAPITAL, 0x3A, event_time);
1454 /* Adjust the NUMLOCK state if it has been changed outside wine */
1455 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask) &&
1456 (vkey & 0xff) != VK_NUMLOCK)
1458 TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table[VK_NUMLOCK]);
1459 update_lock_state(VK_NUMLOCK, 0x45, event_time);
1462 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1463 if (!(key_state_table[VK_SCROLL] & 0x01) != !(event->state & ScrollLockMask) &&
1464 vkey != VK_SCROLL)
1466 TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table[VK_SCROLL]);
1467 update_lock_state(VK_SCROLL, 0x46, event_time);
1470 bScan = keyc2scan[event->keycode] & 0xFF;
1471 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1473 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1476 /**********************************************************************
1477 * X11DRV_KEYBOARD_DetectLayout
1479 * Called from X11DRV_InitKeyboard
1480 * This routine walks through the defined keyboard layouts and selects
1481 * whichever matches most closely.
1482 * X11 lock must be held.
1484 static void
1485 X11DRV_KEYBOARD_DetectLayout( Display *display )
1487 unsigned current, match, mismatch, seq, i, syms;
1488 int score, keyc, key, pkey, ok;
1489 KeySym keysym = 0;
1490 const char (*lkey)[MAIN_LEN][4];
1491 unsigned max_seq = 0;
1492 int max_score = 0, ismatch = 0;
1493 char ckey[256][4];
1495 syms = keysyms_per_keycode;
1496 if (syms > 4) {
1497 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1498 syms = 4;
1501 memset( ckey, 0, sizeof(ckey) );
1502 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1503 /* get data for keycode from X server */
1504 for (i = 0; i < syms; i++) {
1505 if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1506 /* Allow both one-byte and two-byte national keysyms */
1507 if ((keysym < 0x8000) && (keysym != ' '))
1509 #ifdef HAVE_XKB
1510 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1511 #endif
1513 TRACE("XKB could not translate keysym %ld\n", keysym);
1514 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1515 * with appropriate ShiftMask and Mode_switch, use XLookupString
1516 * to get character in the local encoding.
1518 ckey[keyc][i] = keysym & 0xFF;
1521 else {
1522 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1527 for (current = 0; main_key_tab[current].comment; current++) {
1528 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1529 match = 0;
1530 mismatch = 0;
1531 score = 0;
1532 seq = 0;
1533 lkey = main_key_tab[current].key;
1534 pkey = -1;
1535 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1536 if (ckey[keyc][0]) {
1537 /* search for a match in layout table */
1538 /* right now, we just find an absolute match for defined positions */
1539 /* (undefined positions are ignored, so if it's defined as "3#" in */
1540 /* the table, it's okay that the X server has "3#£", for example) */
1541 /* however, the score will be higher for longer matches */
1542 for (key = 0; key < MAIN_LEN; key++) {
1543 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1544 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1545 ok++;
1546 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1547 ok = -1;
1549 if (ok > 0) {
1550 score += ok;
1551 break;
1554 /* count the matches and mismatches */
1555 if (ok > 0) {
1556 match++;
1557 /* and how much the keycode order matches */
1558 if (key > pkey) seq++;
1559 pkey = key;
1560 } else {
1561 /* print spaces instead of \0's */
1562 char str[5];
1563 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1564 str[4] = 0;
1565 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %s\n", keysym, keyc, str );
1566 mismatch++;
1567 score -= syms;
1571 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1572 match, mismatch, seq, score);
1573 if ((score > max_score) ||
1574 ((score == max_score) && (seq > max_seq))) {
1575 /* best match so far */
1576 kbd_layout = current;
1577 max_score = score;
1578 max_seq = seq;
1579 ismatch = !mismatch;
1582 /* we're done, report results if necessary */
1583 if (!ismatch)
1584 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1585 main_key_tab[kbd_layout].comment);
1587 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1590 /**********************************************************************
1591 * X11DRV_InitKeyboard
1593 void X11DRV_InitKeyboard( Display *display )
1595 KeySym *ksp;
1596 XModifierKeymap *mmp;
1597 KeySym keysym;
1598 KeyCode *kcp;
1599 XKeyEvent e2;
1600 WORD scan, vkey, OEMvkey;
1601 int keyc, i, keyn, syms;
1602 char ckey[4]={0,0,0,0};
1603 const char (*lkey)[MAIN_LEN][4];
1604 char vkey_used[256] = { 0 };
1606 wine_tsx11_lock();
1607 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1608 ksp = XGetKeyboardMapping(display, min_keycode,
1609 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1610 /* We are only interested in keysyms_per_keycode.
1611 There is no need to hold a local copy of the keysyms table */
1612 XFree(ksp);
1614 mmp = XGetModifierMapping(display);
1615 kcp = mmp->modifiermap;
1616 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1618 int j;
1620 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1621 if (*kcp)
1623 int k;
1625 for (k = 0; k < keysyms_per_keycode; k += 1)
1626 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1628 NumLockMask = 1 << i;
1629 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1631 else if (XKeycodeToKeysym(display, *kcp, k) == XK_Scroll_Lock)
1633 ScrollLockMask = 1 << i;
1634 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1638 XFreeModifiermap(mmp);
1640 /* Detect the keyboard layout */
1641 X11DRV_KEYBOARD_DetectLayout( display );
1642 lkey = main_key_tab[kbd_layout].key;
1643 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1645 /* Now build two conversion arrays :
1646 * keycode -> vkey + scancode + extended
1647 * vkey + extended -> keycode */
1649 e2.display = display;
1650 e2.state = 0;
1652 OEMvkey = VK_OEM_8; /* next is available. */
1653 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1654 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1656 char buf[30];
1657 int have_chars;
1659 keysym = 0;
1660 e2.keycode = (KeyCode)keyc;
1661 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1662 vkey = 0; scan = 0;
1663 if (keysym) /* otherwise, keycode not used */
1665 if ((keysym >> 8) == 0xFF) /* non-character key */
1667 vkey = nonchar_key_vkey[keysym & 0xff];
1668 scan = nonchar_key_scan[keysym & 0xff];
1669 /* set extended bit when necessary */
1670 if (scan & 0x100) vkey |= 0x100;
1671 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1672 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1673 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1674 scan = 0x100;
1675 vkey |= 0x100;
1676 } else if (keysym == 0x20) { /* Spacebar */
1677 vkey = VK_SPACE;
1678 scan = 0x39;
1679 } else if (have_chars) {
1680 /* we seem to need to search the layout-dependent scancodes */
1681 int maxlen=0,maxval=-1,ok;
1682 for (i=0; i<syms; i++) {
1683 keysym = XKeycodeToKeysym(display, keyc, i);
1684 if ((keysym<0x8000) && (keysym!=' '))
1686 #ifdef HAVE_XKB
1687 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1688 #endif
1690 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1691 * with appropriate ShiftMask and Mode_switch, use XLookupString
1692 * to get character in the local encoding.
1694 ckey[i] = keysym & 0xFF;
1696 } else {
1697 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1700 /* find key with longest match streak */
1701 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1702 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1703 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1704 if (!ok) i--; /* we overshot */
1705 if (ok||(i>maxlen)) {
1706 maxlen=i; maxval=keyn;
1708 if (ok) break;
1710 if (maxval>=0) {
1711 /* got it */
1712 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1713 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1714 scan = (*lscan)[maxval];
1715 vkey = (*lvkey)[maxval];
1719 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1720 keyc2vkey[e2.keycode] = vkey;
1721 keyc2scan[e2.keycode] = scan;
1722 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1723 WARN("vkey %04x is being used by more than one keycode\n", vkey);
1724 vkey_used[(vkey & 0xff)] = 1;
1725 } /* for */
1727 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1728 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1730 vkey = keyc2vkey[keyc] & 0xff;
1731 if (vkey)
1732 continue;
1734 e2.keycode = (KeyCode)keyc;
1735 keysym = XLookupKeysym(&e2, 0);
1736 if (!keysym)
1737 continue;
1739 /* find a suitable layout-dependent VK code */
1740 /* (most Winelib apps ought to be able to work without layout tables!) */
1741 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1743 keysym = XLookupKeysym(&e2, i);
1744 if ((keysym >= XK_0 && keysym <= XK_9)
1745 || (keysym >= XK_A && keysym <= XK_Z)) {
1746 vkey = VKEY_IF_NOT_USED(keysym);
1750 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1752 keysym = XLookupKeysym(&e2, i);
1753 switch (keysym)
1755 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1756 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1757 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1758 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1759 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1760 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1761 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1762 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1763 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1764 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1765 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1769 if (!vkey)
1771 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1772 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1775 switch (++OEMvkey)
1777 case 0xc1 : OEMvkey=0xdb; break;
1778 case 0xe5 : OEMvkey=0xe9; break;
1779 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1781 } while (OEMvkey < 0xf5 && vkey_used[OEMvkey]);
1783 vkey = VKEY_IF_NOT_USED(OEMvkey);
1785 if (TRACE_ON(keyboard))
1787 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1788 OEMvkey, e2.keycode);
1789 TRACE("(");
1790 for (i = 0; i < keysyms_per_keycode; i += 1)
1792 const char *ksname;
1794 keysym = XLookupKeysym(&e2, i);
1795 ksname = XKeysymToString(keysym);
1796 if (!ksname)
1797 ksname = "NoSymbol";
1798 TRACE( "%lX (%s) ", keysym, ksname);
1800 TRACE(")\n");
1804 if (vkey)
1806 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1807 keyc2vkey[e2.keycode] = vkey;
1809 } /* for */
1810 #undef VKEY_IF_NOT_USED
1812 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1813 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1814 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1815 const char *ksname;
1816 keysym = XKeycodeToKeysym(display, keyc, 0);
1817 ksname = XKeysymToString(keysym);
1818 if (!ksname) ksname = "NoSymbol";
1820 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1822 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1823 keyc2scan[keyc]=scan++;
1826 wine_tsx11_unlock();
1830 /**********************************************************************
1831 * GetAsyncKeyState (X11DRV.@)
1833 SHORT X11DRV_GetAsyncKeyState(INT key)
1835 SHORT retval;
1837 /* Photoshop livelocks unless mouse events are included here */
1838 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1840 retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1841 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1842 key_state_table[key] &= ~0x40;
1843 TRACE_(key)("(%x) -> %x\n", key, retval);
1844 return retval;
1848 /***********************************************************************
1849 * GetKeyboardLayoutList (X11DRV.@)
1851 UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
1853 INT i;
1855 TRACE("%d, %p\n", size, hkl);
1857 if (!size)
1859 size = 4096; /* hope we will never have that many */
1860 hkl = NULL;
1863 for (i = 0; main_key_tab[i].comment && (i < size); i++)
1865 if (hkl)
1867 ULONG_PTR layout = main_key_tab[i].lcid;
1868 LANGID langid;
1870 /* see comment for GetKeyboardLayout */
1871 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1872 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1873 layout |= 0xe001 << 16; /* FIXME */
1874 else
1875 layout |= layout << 16;
1877 hkl[i] = (HKL)layout;
1880 return i;
1884 /***********************************************************************
1885 * GetKeyboardLayout (X11DRV.@)
1887 HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1889 ULONG_PTR layout;
1890 LANGID langid;
1892 if (dwThreadid && dwThreadid != GetCurrentThreadId())
1893 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1895 #if 0
1896 layout = main_key_tab[kbd_layout].lcid;
1897 #else
1898 /* FIXME:
1899 * Winword uses return value of GetKeyboardLayout as a codepage
1900 * to translate ANSI keyboard messages to unicode. But we have
1901 * a problem with it: for instance Polish keyboard layout is
1902 * identical to the US one, and therefore instead of the Polish
1903 * locale id we return the US one.
1905 layout = GetUserDefaultLCID();
1906 #endif
1908 * Microsoft Office expects this value to be something specific
1909 * for Japanese and Korean Windows with an IME the value is 0xe001
1910 * We should probably check to see if an IME exists and if so then
1911 * set this word properly.
1913 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1914 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1915 layout |= 0xe001 << 16; /* FIXME */
1916 else
1917 layout |= layout << 16;
1919 return (HKL)layout;
1923 /***********************************************************************
1924 * GetKeyboardLayoutName (X11DRV.@)
1926 BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1928 static const WCHAR formatW[] = {'%','0','8','l','x',0};
1929 DWORD layout;
1930 LANGID langid;
1932 layout = main_key_tab[kbd_layout].lcid;
1933 /* see comment for GetKeyboardLayout */
1934 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1935 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1936 layout |= 0xe001 << 16; /* FIXME */
1937 else
1938 layout |= layout << 16;
1940 sprintfW(name, formatW, layout);
1941 TRACE("returning %s\n", debugstr_w(name));
1942 return TRUE;
1946 /***********************************************************************
1947 * LoadKeyboardLayout (X11DRV.@)
1949 HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1951 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1953 return 0;
1957 /***********************************************************************
1958 * UnloadKeyboardLayout (X11DRV.@)
1960 BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
1962 FIXME("%p: stub!\n", hkl);
1963 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1964 return FALSE;
1968 /***********************************************************************
1969 * ActivateKeyboardLayout (X11DRV.@)
1971 HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1973 FIXME("%p, %04x: stub!\n", hkl, flags);
1974 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1975 return 0;
1979 /***********************************************************************
1980 * X11DRV_MappingNotify
1982 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1984 HWND hwnd;
1986 wine_tsx11_lock();
1987 XRefreshKeyboardMapping(&event->xmapping);
1988 wine_tsx11_unlock();
1989 X11DRV_InitKeyboard( event->xmapping.display );
1991 hwnd = GetFocus();
1992 if (!hwnd) hwnd = GetActiveWindow();
1993 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1994 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1998 /***********************************************************************
1999 * VkKeyScanEx (X11DRV.@)
2001 * Note: Windows ignores HKL parameter and uses current active layout instead
2003 SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2005 Display *display = thread_init_display();
2006 KeyCode keycode;
2007 KeySym keysym;
2008 int i, index;
2009 CHAR cChar;
2010 SHORT ret;
2012 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2013 * is UTF-8 (multibyte encoding)?
2015 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2017 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2018 return -1;
2021 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2023 /* char->keysym (same for ANSI chars) */
2024 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2025 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2027 wine_tsx11_lock();
2028 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2029 if (!keycode)
2031 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2033 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2034 TRACE(" ... returning ctrl char %#.2x\n", ret);
2035 wine_tsx11_unlock();
2036 return ret;
2038 /* It didn't work ... let's try with deadchar code. */
2039 TRACE("retrying with | 0xFE00\n");
2040 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2042 wine_tsx11_unlock();
2044 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
2045 cChar, keysym, keysym, keycode, keycode);
2047 /* keycode -> (keyc2vkey) vkey */
2048 ret = keyc2vkey[keycode];
2050 if (!keycode || !ret)
2052 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2053 return -1;
2056 index = -1;
2057 wine_tsx11_lock();
2058 for (i = 0; i < 4; i++) /* find shift state */
2060 if (XKeycodeToKeysym(display, keycode, i) == keysym)
2062 index = i;
2063 break;
2066 wine_tsx11_unlock();
2068 switch (index)
2070 default:
2071 case -1:
2072 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2073 return -1;
2075 case 0: break;
2076 case 1: ret += 0x0100; break;
2077 case 2: ret += 0x0600; break;
2078 case 3: ret += 0x0700; break;
2081 index : 0 adds 0x0000
2082 index : 1 adds 0x0100 (shift)
2083 index : ? adds 0x0200 (ctrl)
2084 index : 2 adds 0x0600 (ctrl+alt)
2085 index : 3 adds 0x0700 (ctrl+alt+shift)
2088 TRACE(" ... returning %#.2x\n", ret);
2089 return ret;
2092 /***********************************************************************
2093 * MapVirtualKeyEx (X11DRV.@)
2095 UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2097 Display *display = thread_init_display();
2099 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
2101 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2102 if (hkl != X11DRV_GetKeyboardLayout(0))
2103 FIXME("keyboard layout %p is not supported\n", hkl);
2105 switch(wMapType)
2107 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2108 case MAPVK_VK_TO_VSC_EX:
2110 int keyc;
2112 switch (wCode)
2114 case VK_SHIFT: wCode = VK_LSHIFT; break;
2115 case VK_CONTROL: wCode = VK_LCONTROL; break;
2116 case VK_MENU: wCode = VK_LMENU; break;
2119 /* let's do vkey -> keycode -> scan */
2120 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2121 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2123 if (keyc > max_keycode)
2125 TRACE("returning no scan-code.\n");
2126 return 0;
2128 returnMVK (keyc2scan[keyc] & 0xFF);
2130 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2131 case MAPVK_VSC_TO_VK_EX:
2133 int keyc;
2134 UINT vkey = 0;
2136 /* let's do scan -> keycode -> vkey */
2137 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2138 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2140 vkey = keyc2vkey[keyc] & 0xFF;
2141 /* Only stop if it's not a numpad vkey; otherwise keep
2142 looking for a potential better vkey. */
2143 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2144 break;
2147 if (vkey == 0)
2149 TRACE("returning no vkey-code.\n");
2150 return 0;
2153 if (wMapType == MAPVK_VSC_TO_VK)
2154 switch (vkey)
2156 case VK_LSHIFT:
2157 case VK_RSHIFT:
2158 vkey = VK_SHIFT; break;
2159 case VK_LCONTROL:
2160 case VK_RCONTROL:
2161 vkey = VK_CONTROL; break;
2162 case VK_LMENU:
2163 case VK_RMENU:
2164 vkey = VK_MENU; break;
2167 returnMVK (vkey);
2169 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2171 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2172 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2173 * key.. Looks like something is wrong with the MS docs?
2174 * This is only true for letters, for example VK_0 returns '0' not ')'.
2175 * - hence we use the lock mask to ensure this happens.
2177 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2178 XKeyEvent e;
2179 KeySym keysym;
2180 int keyc, len;
2181 char s[10];
2183 e.display = display;
2184 e.state = 0;
2185 e.keycode = 0;
2187 wine_tsx11_lock();
2189 /* We exit on the first keycode found, to speed up the thing. */
2190 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2191 { /* Find a keycode that could have generated this virtual key */
2192 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2193 { /* We filter the extended bit, we don't know it */
2194 e.keycode = keyc; /* Store it temporarily */
2195 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2196 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2197 state), so set it to 0, we'll find another one */
2202 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2203 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2205 if (wCode==VK_DECIMAL)
2206 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2208 if (!e.keycode)
2210 WARN("Unknown virtual key %X !!!\n", wCode);
2211 wine_tsx11_unlock();
2212 return 0; /* whatever */
2214 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2216 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2217 wine_tsx11_unlock();
2219 if (len)
2221 WCHAR wch;
2222 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2223 returnMVK(toupperW(wch));
2225 TRACE("returning no ANSI.\n");
2226 return 0;
2228 default: /* reserved */
2229 FIXME("Unknown wMapType %d !\n", wMapType);
2230 return 0;
2232 return 0;
2235 /***********************************************************************
2236 * GetKeyNameText (X11DRV.@)
2238 INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2240 Display *display = thread_init_display();
2241 int vkey, ansi, scanCode;
2242 KeyCode keyc;
2243 int keyi;
2244 KeySym keys;
2245 char *name;
2247 scanCode = lParam >> 16;
2248 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2250 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2252 /* handle "don't care" bit (0x02000000) */
2253 if (!(lParam & 0x02000000)) {
2254 switch (vkey) {
2255 case VK_RSHIFT:
2256 /* R-Shift is "special" - it is an extended key with separate scan code */
2257 scanCode |= 0x100;
2258 case VK_LSHIFT:
2259 vkey = VK_SHIFT;
2260 break;
2261 case VK_LCONTROL:
2262 case VK_RCONTROL:
2263 vkey = VK_CONTROL;
2264 break;
2265 case VK_LMENU:
2266 case VK_RMENU:
2267 vkey = VK_MENU;
2268 break;
2272 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2273 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
2275 /* first get the name of the "regular" keys which is the Upper case
2276 value of the keycap imprint. */
2277 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2278 (scanCode != 0x137) && /* PrtScn */
2279 (scanCode != 0x135) && /* numpad / */
2280 (scanCode != 0x37 ) && /* numpad * */
2281 (scanCode != 0x4a ) && /* numpad - */
2282 (scanCode != 0x4e ) ) /* numpad + */
2284 if ((nSize >= 2) && lpBuffer)
2286 *lpBuffer = toupperW((WCHAR)ansi);
2287 *(lpBuffer+1) = 0;
2288 return 1;
2290 else
2291 return 0;
2294 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2295 without "extended-key" flag. However Wine generates scancode
2296 *with* "extended-key" flag. Seems to occur *only* for the
2297 function keys. Soooo.. We will leave the table alone and
2298 fudge the lookup here till the other part is found and fixed!!! */
2300 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2301 (scanCode == 0x157) || (scanCode == 0x158))
2302 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2304 /* let's do scancode -> keycode -> keysym -> String */
2306 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2307 if ((keyc2scan[keyi]) == scanCode)
2308 break;
2309 if (keyi <= max_keycode)
2311 wine_tsx11_lock();
2312 keyc = (KeyCode) keyi;
2313 keys = XKeycodeToKeysym(display, keyc, 0);
2314 name = XKeysymToString(keys);
2315 wine_tsx11_unlock();
2316 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2317 scanCode, keyc, (int)keys, name);
2318 if (lpBuffer && nSize && name)
2320 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2321 lpBuffer[nSize - 1] = 0;
2322 return 1;
2326 /* Finally issue WARN for unknown keys */
2328 WARN("(%08x,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2329 if (lpBuffer && nSize)
2330 *lpBuffer = 0;
2331 return 0;
2334 /***********************************************************************
2335 * X11DRV_KEYBOARD_MapDeadKeysym
2337 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2339 switch (keysym)
2341 /* symbolic ASCII is the same as defined in rfc1345 */
2342 #ifdef XK_dead_tilde
2343 case XK_dead_tilde :
2344 #endif
2345 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2346 return '~'; /* '? */
2347 #ifdef XK_dead_acute
2348 case XK_dead_acute :
2349 #endif
2350 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2351 return 0xb4; /* '' */
2352 #ifdef XK_dead_circumflex
2353 case XK_dead_circumflex:
2354 #endif
2355 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2356 return '^'; /* '> */
2357 #ifdef XK_dead_grave
2358 case XK_dead_grave :
2359 #endif
2360 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2361 return '`'; /* '! */
2362 #ifdef XK_dead_diaeresis
2363 case XK_dead_diaeresis :
2364 #endif
2365 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2366 return 0xa8; /* ': */
2367 #ifdef XK_dead_cedilla
2368 case XK_dead_cedilla :
2369 return 0xb8; /* ', */
2370 #endif
2371 #ifdef XK_dead_macron
2372 case XK_dead_macron :
2373 return '-'; /* 'm isn't defined on iso-8859-x */
2374 #endif
2375 #ifdef XK_dead_breve
2376 case XK_dead_breve :
2377 return 0xa2; /* '( */
2378 #endif
2379 #ifdef XK_dead_abovedot
2380 case XK_dead_abovedot :
2381 return 0xff; /* '. */
2382 #endif
2383 #ifdef XK_dead_abovering
2384 case XK_dead_abovering :
2385 return '0'; /* '0 isn't defined on iso-8859-x */
2386 #endif
2387 #ifdef XK_dead_doubleacute
2388 case XK_dead_doubleacute :
2389 return 0xbd; /* '" */
2390 #endif
2391 #ifdef XK_dead_caron
2392 case XK_dead_caron :
2393 return 0xb7; /* '< */
2394 #endif
2395 #ifdef XK_dead_ogonek
2396 case XK_dead_ogonek :
2397 return 0xb2; /* '; */
2398 #endif
2399 /* FIXME: I don't know this three.
2400 case XK_dead_iota :
2401 return 'i';
2402 case XK_dead_voiced_sound :
2403 return 'v';
2404 case XK_dead_semivoiced_sound :
2405 return 's';
2408 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2409 return 0;
2412 /***********************************************************************
2413 * ToUnicodeEx (X11DRV.@)
2415 * The ToUnicode function translates the specified virtual-key code and keyboard
2416 * state to the corresponding Windows character or characters.
2418 * If the specified key is a dead key, the return value is negative. Otherwise,
2419 * it is one of the following values:
2420 * Value Meaning
2421 * 0 The specified virtual key has no translation for the current state of the keyboard.
2422 * 1 One Windows character was copied to the buffer.
2423 * 2 Two characters were copied to the buffer. This usually happens when a
2424 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2425 * be composed with the specified virtual key to form a single character.
2427 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2430 INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2431 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2433 Display *display = thread_init_display();
2434 XKeyEvent e;
2435 KeySym keysym = 0;
2436 INT ret;
2437 int keyc;
2438 char buf[10];
2439 char *lpChar = buf;
2440 HWND focus;
2441 XIC xic;
2442 Status status = 0;
2444 if (scanCode & 0x8000)
2446 TRACE("Key UP, doing nothing\n" );
2447 return 0;
2450 if (hkl != X11DRV_GetKeyboardLayout(0))
2451 FIXME("keyboard layout %p is not supported\n", hkl);
2453 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2455 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2456 return 0;
2459 e.display = display;
2460 e.keycode = 0;
2461 e.state = 0;
2462 e.type = KeyPress;
2464 focus = GetFocus();
2465 if (focus) focus = GetAncestor( focus, GA_ROOT );
2466 if (!focus) focus = GetActiveWindow();
2467 e.window = X11DRV_get_whole_window( focus );
2468 xic = X11DRV_get_ic( focus );
2470 if (lpKeyState[VK_SHIFT] & 0x80)
2472 TRACE("ShiftMask = %04x\n", ShiftMask);
2473 e.state |= ShiftMask;
2475 if (lpKeyState[VK_CAPITAL] & 0x01)
2477 TRACE("LockMask = %04x\n", LockMask);
2478 e.state |= LockMask;
2480 if (lpKeyState[VK_CONTROL] & 0x80)
2482 TRACE("ControlMask = %04x\n", ControlMask);
2483 e.state |= ControlMask;
2485 if (lpKeyState[VK_NUMLOCK] & 0x01)
2487 TRACE("NumLockMask = %04x\n", NumLockMask);
2488 e.state |= NumLockMask;
2491 /* Restore saved AltGr state */
2492 TRACE("AltGrMask = %04x\n", AltGrMask);
2493 e.state |= AltGrMask;
2495 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2496 virtKey, scanCode, e.state);
2497 wine_tsx11_lock();
2498 /* We exit on the first keycode found, to speed up the thing. */
2499 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2500 { /* Find a keycode that could have generated this virtual key */
2501 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2502 { /* We filter the extended bit, we don't know it */
2503 e.keycode = keyc; /* Store it temporarily */
2504 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2505 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2506 state), so set it to 0, we'll find another one */
2511 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2512 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2514 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2515 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2517 if (virtKey==VK_DECIMAL)
2518 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2520 if (virtKey==VK_SEPARATOR)
2521 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2523 if (!e.keycode && virtKey != VK_NONAME)
2525 WARN("Unknown virtual key %X !!!\n", virtKey);
2526 wine_tsx11_unlock();
2527 return 0;
2529 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2531 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2532 e.type, e.window, e.state, e.keycode);
2534 /* Clients should pass only KeyPress events to XmbLookupString,
2535 * e.type was set to KeyPress above.
2537 if (xic)
2539 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2540 TRACE("XmbLookupString needs %d byte(s)\n", ret);
2541 if (status == XBufferOverflow)
2543 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2544 if (lpChar == NULL)
2546 ERR("Failed to allocate memory!\n");
2547 wine_tsx11_unlock();
2548 return 0;
2550 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2553 else
2554 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2555 wine_tsx11_unlock();
2557 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2559 if (TRACE_ON(key))
2561 const char *ksname;
2563 wine_tsx11_lock();
2564 ksname = XKeysymToString(keysym);
2565 wine_tsx11_unlock();
2566 if (!ksname) ksname = "No Name";
2567 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
2568 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2569 keysym, ksname, ret, debugstr_an(lpChar, ret));
2572 if (ret == 0)
2574 char dead_char;
2576 #ifdef XK_EuroSign
2577 /* An ugly hack for EuroSign: X can't translate it to a character
2578 for some locales. */
2579 if (keysym == XK_EuroSign)
2581 bufW[0] = 0x20AC;
2582 ret = 1;
2583 goto found;
2585 #endif
2586 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2587 /* Here we change it back. */
2588 if (keysym == XK_ISO_Left_Tab)
2590 bufW[0] = 0x09;
2591 ret = 1;
2592 goto found;
2595 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2596 if (dead_char)
2598 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2599 ret = -1;
2600 goto found;
2603 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2605 /* Unicode direct mapping */
2606 bufW[0] = keysym & 0xffff;
2607 ret = 1;
2608 goto found;
2610 else if ((keysym >> 8) == 0x1008FF) {
2611 bufW[0] = 0;
2612 ret = 0;
2613 goto found;
2615 else
2617 const char *ksname;
2619 wine_tsx11_lock();
2620 ksname = XKeysymToString(keysym);
2621 wine_tsx11_unlock();
2622 if (!ksname)
2623 ksname = "No Name";
2624 if ((keysym >> 8) != 0xff)
2626 WARN("no char for keysym %04lX (%s) :\n",
2627 keysym, ksname);
2628 WARN("virtKey=%X, scanCode=%X, keycode=%X, state=%X\n",
2629 virtKey, scanCode, e.keycode, e.state);
2633 else { /* ret != 0 */
2634 /* We have a special case to handle : Shift + arrow, shift + home, ...
2635 X returns a char for it, but Windows doesn't. Let's eat it. */
2636 if (!(e.state & NumLockMask) /* NumLock is off */
2637 && (e.state & ShiftMask) /* Shift is pressed */
2638 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2640 lpChar[0] = 0;
2641 ret = 0;
2644 /* more areas where X returns characters but Windows does not
2645 CTRL + number or CTRL + symbol */
2646 if (e.state & ControlMask)
2648 if (((keysym>=33) && (keysym < 'A')) ||
2649 ((keysym > 'Z') && (keysym < 'a')))
2651 lpChar[0] = 0;
2652 ret = 0;
2656 /* We have another special case for delete key (XK_Delete) on an
2657 extended keyboard. X returns a char for it, but Windows doesn't */
2658 if (keysym == XK_Delete)
2660 lpChar[0] = 0;
2661 ret = 0;
2663 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2664 && (keysym == XK_KP_Decimal))
2666 lpChar[0] = 0;
2667 ret = 0;
2669 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2670 && (keysym == XK_Return || keysym == XK_KP_Enter))
2672 lpChar[0] = '\n';
2673 ret = 1;
2676 /* Hack to detect an XLookupString hard-coded to Latin1 */
2677 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2679 bufW[0] = (BYTE)lpChar[0];
2680 goto found;
2683 /* perform translation to unicode */
2684 if(ret)
2686 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2687 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2691 found:
2692 if (buf != lpChar)
2693 HeapFree(GetProcessHeap(), 0, lpChar);
2694 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
2695 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
2696 return ret;
2699 /***********************************************************************
2700 * Beep (X11DRV.@)
2702 void X11DRV_Beep(void)
2704 wine_tsx11_lock();
2705 XBell(gdi_display, 0);
2706 wine_tsx11_unlock();