push 9758e6fe7ae8fbab538c98c718d6619029bb3457
[wine/hacks.git] / dlls / winex11.drv / keyboard.c
blob773e8128b84a57d5471329ee0503400ff4cbd346
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, 0x138, 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 Str[24];
1356 KeySym keysym = 0;
1357 WORD vkey = 0, bScan;
1358 DWORD dwFlags;
1359 int ascii_chars;
1360 XIC xic = X11DRV_get_ic( hwnd );
1361 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1362 Status status = 0;
1364 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1365 event->type, event->window, event->state, event->keycode);
1367 wine_tsx11_lock();
1368 /* Clients should pass only KeyPress events to XmbLookupString */
1369 if (xic && event->type == KeyPress)
1370 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
1371 else
1372 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1373 wine_tsx11_unlock();
1375 TRACE_(key)("nbyte = %d, status 0x%x\n", ascii_chars, status);
1377 if (status == XBufferOverflow)
1378 ERR("Buffer Overflow need %i!\n",ascii_chars);
1380 if (status == XLookupChars)
1382 X11DRV_XIMLookupChars( Str, ascii_chars );
1383 return;
1386 /* If XKB extensions are used, the state mask for AltGr will use the group
1387 index instead of the modifier mask. The group index is set in bits
1388 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1389 pressed, look if the group index is different than 0. From XKB
1390 extension documentation, the group index for AltGr should be 2
1391 (event->state = 0x2000). It's probably better to not assume a
1392 predefined group index and find it dynamically
1394 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1395 /* Save also all possible modifier states. */
1396 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1398 if (TRACE_ON(key)){
1399 const char *ksname;
1401 wine_tsx11_lock();
1402 ksname = XKeysymToString(keysym);
1403 wine_tsx11_unlock();
1404 if (!ksname)
1405 ksname = "No Name";
1406 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
1407 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1408 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1411 wine_tsx11_lock();
1412 vkey = EVENT_event_to_vkey(xic,event);
1413 /* X returns keycode 0 for composed characters */
1414 if (!vkey && ascii_chars) vkey = VK_NONAME;
1415 wine_tsx11_unlock();
1417 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1418 event->keycode, vkey);
1420 if (!vkey) return;
1422 dwFlags = 0;
1423 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1424 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1427 /* Note: X sets the below states on key down and clears them on key up.
1428 Windows triggers them on key down. */
1430 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1431 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask) &&
1432 vkey != VK_CAPITAL)
1434 TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table[VK_CAPITAL]);
1435 update_lock_state(VK_CAPITAL, 0x3A, event_time);
1438 /* Adjust the NUMLOCK state if it has been changed outside wine */
1439 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask) &&
1440 (vkey & 0xff) != VK_NUMLOCK)
1442 TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table[VK_NUMLOCK]);
1443 update_lock_state(VK_NUMLOCK, 0x45, event_time);
1446 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1447 if (!(key_state_table[VK_SCROLL] & 0x01) != !(event->state & ScrollLockMask) &&
1448 vkey != VK_SCROLL)
1450 TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table[VK_SCROLL]);
1451 update_lock_state(VK_SCROLL, 0x46, event_time);
1454 /* we get this event repeatedly if we hold down the key (keyboard repeat) */
1455 if ((VK_F12 == vkey) && (event->type == KeyPress) && getenv("WINEDELAY")) {
1456 __wine_dbg_toggle_block();
1459 bScan = keyc2scan[event->keycode] & 0xFF;
1460 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1462 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1465 /**********************************************************************
1466 * X11DRV_KEYBOARD_DetectLayout
1468 * Called from X11DRV_InitKeyboard
1469 * This routine walks through the defined keyboard layouts and selects
1470 * whichever matches most closely.
1471 * X11 lock must be held.
1473 static void
1474 X11DRV_KEYBOARD_DetectLayout( Display *display )
1476 unsigned current, match, mismatch, seq, i, syms;
1477 int score, keyc, key, pkey, ok;
1478 KeySym keysym = 0;
1479 const char (*lkey)[MAIN_LEN][4];
1480 unsigned max_seq = 0;
1481 int max_score = 0, ismatch = 0;
1482 char ckey[256][4];
1484 syms = keysyms_per_keycode;
1485 if (syms > 4) {
1486 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1487 syms = 4;
1490 memset( ckey, 0, sizeof(ckey) );
1491 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1492 /* get data for keycode from X server */
1493 for (i = 0; i < syms; i++) {
1494 if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1495 /* Allow both one-byte and two-byte national keysyms */
1496 if ((keysym < 0x8000) && (keysym != ' '))
1498 #ifdef HAVE_XKB
1499 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1500 #endif
1502 TRACE("XKB could not translate keysym %ld\n", keysym);
1503 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1504 * with appropriate ShiftMask and Mode_switch, use XLookupString
1505 * to get character in the local encoding.
1507 ckey[keyc][i] = keysym & 0xFF;
1510 else {
1511 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1516 for (current = 0; main_key_tab[current].comment; current++) {
1517 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1518 match = 0;
1519 mismatch = 0;
1520 score = 0;
1521 seq = 0;
1522 lkey = main_key_tab[current].key;
1523 pkey = -1;
1524 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1525 if (ckey[keyc][0]) {
1526 /* search for a match in layout table */
1527 /* right now, we just find an absolute match for defined positions */
1528 /* (undefined positions are ignored, so if it's defined as "3#" in */
1529 /* the table, it's okay that the X server has "3#£", for example) */
1530 /* however, the score will be higher for longer matches */
1531 for (key = 0; key < MAIN_LEN; key++) {
1532 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1533 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1534 ok++;
1535 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1536 ok = -1;
1538 if (ok > 0) {
1539 score += ok;
1540 break;
1543 /* count the matches and mismatches */
1544 if (ok > 0) {
1545 match++;
1546 /* and how much the keycode order matches */
1547 if (key > pkey) seq++;
1548 pkey = key;
1549 } else {
1550 /* print spaces instead of \0's */
1551 char str[5];
1552 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1553 str[4] = 0;
1554 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %s\n", keysym, keyc, str );
1555 mismatch++;
1556 score -= syms;
1560 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1561 match, mismatch, seq, score);
1562 if ((score > max_score) ||
1563 ((score == max_score) && (seq > max_seq))) {
1564 /* best match so far */
1565 kbd_layout = current;
1566 max_score = score;
1567 max_seq = seq;
1568 ismatch = !mismatch;
1571 /* we're done, report results if necessary */
1572 if (!ismatch)
1573 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1574 main_key_tab[kbd_layout].comment);
1576 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1579 /**********************************************************************
1580 * X11DRV_InitKeyboard
1582 void X11DRV_InitKeyboard( Display *display )
1584 KeySym *ksp;
1585 XModifierKeymap *mmp;
1586 KeySym keysym;
1587 KeyCode *kcp;
1588 XKeyEvent e2;
1589 WORD scan, vkey, OEMvkey;
1590 int keyc, i, keyn, syms;
1591 char ckey[4]={0,0,0,0};
1592 const char (*lkey)[MAIN_LEN][4];
1593 char vkey_used[256] = { 0 };
1595 wine_tsx11_lock();
1596 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1597 ksp = XGetKeyboardMapping(display, min_keycode,
1598 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1599 /* We are only interested in keysyms_per_keycode.
1600 There is no need to hold a local copy of the keysyms table */
1601 XFree(ksp);
1603 mmp = XGetModifierMapping(display);
1604 kcp = mmp->modifiermap;
1605 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1607 int j;
1609 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1610 if (*kcp)
1612 int k;
1614 for (k = 0; k < keysyms_per_keycode; k += 1)
1615 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1617 NumLockMask = 1 << i;
1618 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1620 else if (XKeycodeToKeysym(display, *kcp, k) == XK_Scroll_Lock)
1622 ScrollLockMask = 1 << i;
1623 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1627 XFreeModifiermap(mmp);
1629 /* Detect the keyboard layout */
1630 X11DRV_KEYBOARD_DetectLayout( display );
1631 lkey = main_key_tab[kbd_layout].key;
1632 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1634 /* Now build two conversion arrays :
1635 * keycode -> vkey + scancode + extended
1636 * vkey + extended -> keycode */
1638 e2.display = display;
1639 e2.state = 0;
1641 OEMvkey = VK_OEM_8; /* next is available. */
1642 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1643 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1645 char buf[30];
1646 int have_chars;
1648 keysym = 0;
1649 e2.keycode = (KeyCode)keyc;
1650 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1651 vkey = 0; scan = 0;
1652 if (keysym) /* otherwise, keycode not used */
1654 if ((keysym >> 8) == 0xFF) /* non-character key */
1656 vkey = nonchar_key_vkey[keysym & 0xff];
1657 scan = nonchar_key_scan[keysym & 0xff];
1658 /* set extended bit when necessary */
1659 if (scan & 0x100) vkey |= 0x100;
1660 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1661 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1662 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1663 scan = 0x100;
1664 vkey |= 0x100;
1665 } else if (keysym == 0x20) { /* Spacebar */
1666 vkey = VK_SPACE;
1667 scan = 0x39;
1668 } else if (have_chars) {
1669 /* we seem to need to search the layout-dependent scancodes */
1670 int maxlen=0,maxval=-1,ok;
1671 for (i=0; i<syms; i++) {
1672 keysym = XKeycodeToKeysym(display, keyc, i);
1673 if ((keysym<0x8000) && (keysym!=' '))
1675 #ifdef HAVE_XKB
1676 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1677 #endif
1679 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1680 * with appropriate ShiftMask and Mode_switch, use XLookupString
1681 * to get character in the local encoding.
1683 ckey[i] = keysym & 0xFF;
1685 } else {
1686 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1689 /* find key with longest match streak */
1690 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1691 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1692 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1693 if (!ok) i--; /* we overshot */
1694 if (ok||(i>maxlen)) {
1695 maxlen=i; maxval=keyn;
1697 if (ok) break;
1699 if (maxval>=0) {
1700 /* got it */
1701 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1702 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1703 scan = (*lscan)[maxval];
1704 vkey = (*lvkey)[maxval];
1708 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1709 keyc2vkey[e2.keycode] = vkey;
1710 keyc2scan[e2.keycode] = scan;
1711 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1712 WARN("vkey %04x is being used by more than one keycode\n", vkey);
1713 vkey_used[(vkey & 0xff)] = 1;
1714 } /* for */
1716 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1717 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1719 vkey = keyc2vkey[keyc] & 0xff;
1720 if (vkey)
1721 continue;
1723 e2.keycode = (KeyCode)keyc;
1724 keysym = XLookupKeysym(&e2, 0);
1725 if (!keysym)
1726 continue;
1728 /* find a suitable layout-dependent VK code */
1729 /* (most Winelib apps ought to be able to work without layout tables!) */
1730 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1732 keysym = XLookupKeysym(&e2, i);
1733 if ((keysym >= XK_0 && keysym <= XK_9)
1734 || (keysym >= XK_A && keysym <= XK_Z)) {
1735 vkey = VKEY_IF_NOT_USED(keysym);
1739 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1741 keysym = XLookupKeysym(&e2, i);
1742 switch (keysym)
1744 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1745 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1746 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1747 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1748 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1749 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1750 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1751 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1752 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1753 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1754 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1758 if (!vkey)
1760 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1761 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1764 switch (++OEMvkey)
1766 case 0xc1 : OEMvkey=0xdb; break;
1767 case 0xe5 : OEMvkey=0xe9; break;
1768 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1770 } while (OEMvkey < 0xf5 && vkey_used[OEMvkey]);
1772 vkey = VKEY_IF_NOT_USED(OEMvkey);
1774 if (TRACE_ON(keyboard))
1776 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1777 OEMvkey, e2.keycode);
1778 TRACE("(");
1779 for (i = 0; i < keysyms_per_keycode; i += 1)
1781 const char *ksname;
1783 keysym = XLookupKeysym(&e2, i);
1784 ksname = XKeysymToString(keysym);
1785 if (!ksname)
1786 ksname = "NoSymbol";
1787 TRACE( "%lX (%s) ", keysym, ksname);
1789 TRACE(")\n");
1793 if (vkey)
1795 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1796 keyc2vkey[e2.keycode] = vkey;
1798 } /* for */
1799 #undef VKEY_IF_NOT_USED
1801 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1802 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1803 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1804 const char *ksname;
1805 keysym = XKeycodeToKeysym(display, keyc, 0);
1806 ksname = XKeysymToString(keysym);
1807 if (!ksname) ksname = "NoSymbol";
1809 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1811 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1812 keyc2scan[keyc]=scan++;
1815 wine_tsx11_unlock();
1819 /**********************************************************************
1820 * GetAsyncKeyState (X11DRV.@)
1822 SHORT X11DRV_GetAsyncKeyState(INT key)
1824 SHORT retval;
1826 /* Photoshop livelocks unless mouse events are included here */
1827 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1829 retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1830 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1831 key_state_table[key] &= ~0x40;
1832 TRACE_(key)("(%x) -> %x\n", key, retval);
1833 return retval;
1837 /***********************************************************************
1838 * GetKeyboardLayoutList (X11DRV.@)
1840 UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
1842 INT i;
1844 TRACE("%d, %p\n", size, hkl);
1846 if (!size)
1848 size = 4096; /* hope we will never have that many */
1849 hkl = NULL;
1852 for (i = 0; main_key_tab[i].comment && (i < size); i++)
1854 if (hkl)
1856 ULONG_PTR layout = main_key_tab[i].lcid;
1857 LANGID langid;
1859 /* see comment for GetKeyboardLayout */
1860 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1861 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1862 layout |= 0xe001 << 16; /* FIXME */
1863 else
1864 layout |= layout << 16;
1866 hkl[i] = (HKL)layout;
1869 return i;
1873 /***********************************************************************
1874 * GetKeyboardLayout (X11DRV.@)
1876 HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1878 ULONG_PTR layout;
1879 LANGID langid;
1881 if (dwThreadid && dwThreadid != GetCurrentThreadId())
1882 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1884 #if 0
1885 layout = main_key_tab[kbd_layout].lcid;
1886 #else
1887 /* FIXME:
1888 * Winword uses return value of GetKeyboardLayout as a codepage
1889 * to translate ANSI keyboard messages to unicode. But we have
1890 * a problem with it: for instance Polish keyboard layout is
1891 * identical to the US one, and therefore instead of the Polish
1892 * locale id we return the US one.
1894 layout = GetUserDefaultLCID();
1895 #endif
1897 * Microsoft Office expects this value to be something specific
1898 * for Japanese and Korean Windows with an IME the value is 0xe001
1899 * We should probably check to see if an IME exists and if so then
1900 * set this word properly.
1902 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1903 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1904 layout |= 0xe001 << 16; /* FIXME */
1905 else
1906 layout |= layout << 16;
1908 return (HKL)layout;
1912 /***********************************************************************
1913 * GetKeyboardLayoutName (X11DRV.@)
1915 BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1917 static const WCHAR formatW[] = {'%','0','8','l','x',0};
1918 DWORD layout;
1919 LANGID langid;
1921 layout = main_key_tab[kbd_layout].lcid;
1922 /* see comment for GetKeyboardLayout */
1923 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1924 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1925 layout |= 0xe001 << 16; /* FIXME */
1926 else
1927 layout |= layout << 16;
1929 sprintfW(name, formatW, layout);
1930 TRACE("returning %s\n", debugstr_w(name));
1931 return TRUE;
1935 /***********************************************************************
1936 * LoadKeyboardLayout (X11DRV.@)
1938 HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1940 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1942 return 0;
1946 /***********************************************************************
1947 * UnloadKeyboardLayout (X11DRV.@)
1949 BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
1951 FIXME("%p: stub!\n", hkl);
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1953 return FALSE;
1957 /***********************************************************************
1958 * ActivateKeyboardLayout (X11DRV.@)
1960 HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1962 FIXME("%p, %04x: stub!\n", hkl, flags);
1963 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1964 return 0;
1968 /***********************************************************************
1969 * X11DRV_MappingNotify
1971 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1973 HWND hwnd;
1975 wine_tsx11_lock();
1976 XRefreshKeyboardMapping(&event->xmapping);
1977 wine_tsx11_unlock();
1978 X11DRV_InitKeyboard( event->xmapping.display );
1980 hwnd = GetFocus();
1981 if (!hwnd) hwnd = GetActiveWindow();
1982 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1983 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1987 /***********************************************************************
1988 * VkKeyScanEx (X11DRV.@)
1990 * Note: Windows ignores HKL parameter and uses current active layout instead
1992 SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1994 Display *display = thread_init_display();
1995 KeyCode keycode;
1996 KeySym keysym;
1997 int i, index;
1998 CHAR cChar;
1999 SHORT ret;
2001 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2002 * is UTF-8 (multibyte encoding)?
2004 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2006 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2007 return -1;
2010 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2012 /* char->keysym (same for ANSI chars) */
2013 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2014 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2016 wine_tsx11_lock();
2017 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2018 if (!keycode)
2020 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2022 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2023 TRACE(" ... returning ctrl char %#.2x\n", ret);
2024 wine_tsx11_unlock();
2025 return ret;
2027 /* It didn't work ... let's try with deadchar code. */
2028 TRACE("retrying with | 0xFE00\n");
2029 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2031 wine_tsx11_unlock();
2033 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
2034 cChar, keysym, keysym, keycode, keycode);
2036 /* keycode -> (keyc2vkey) vkey */
2037 ret = keyc2vkey[keycode];
2039 if (!keycode || !ret)
2041 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2042 return -1;
2045 index = -1;
2046 wine_tsx11_lock();
2047 for (i = 0; i < 4; i++) /* find shift state */
2049 if (XKeycodeToKeysym(display, keycode, i) == keysym)
2051 index = i;
2052 break;
2055 wine_tsx11_unlock();
2057 switch (index)
2059 default:
2060 case -1:
2061 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2062 return -1;
2064 case 0: break;
2065 case 1: ret += 0x0100; break;
2066 case 2: ret += 0x0600; break;
2067 case 3: ret += 0x0700; break;
2070 index : 0 adds 0x0000
2071 index : 1 adds 0x0100 (shift)
2072 index : ? adds 0x0200 (ctrl)
2073 index : 2 adds 0x0600 (ctrl+alt)
2074 index : 3 adds 0x0700 (ctrl+alt+shift)
2077 TRACE(" ... returning %#.2x\n", ret);
2078 return ret;
2081 /***********************************************************************
2082 * MapVirtualKeyEx (X11DRV.@)
2084 UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2086 Display *display = thread_init_display();
2088 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
2090 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2091 if (hkl != X11DRV_GetKeyboardLayout(0))
2092 FIXME("keyboard layout %p is not supported\n", hkl);
2094 switch(wMapType)
2096 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2097 case MAPVK_VK_TO_VSC_EX:
2099 int keyc;
2101 switch (wCode)
2103 case VK_SHIFT: wCode = VK_LSHIFT; break;
2104 case VK_CONTROL: wCode = VK_LCONTROL; break;
2105 case VK_MENU: wCode = VK_LMENU; break;
2108 /* let's do vkey -> keycode -> scan */
2109 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2110 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2112 if (keyc > max_keycode)
2114 TRACE("returning no scan-code.\n");
2115 return 0;
2117 returnMVK (keyc2scan[keyc] & 0xFF);
2119 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2120 case MAPVK_VSC_TO_VK_EX:
2122 int keyc;
2123 UINT vkey = 0;
2125 /* let's do scan -> keycode -> vkey */
2126 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2127 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2129 vkey = keyc2vkey[keyc] & 0xFF;
2130 /* Only stop if it's not a numpad vkey; otherwise keep
2131 looking for a potential better vkey. */
2132 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2133 break;
2136 if (vkey == 0)
2138 TRACE("returning no vkey-code.\n");
2139 return 0;
2142 if (wMapType == MAPVK_VSC_TO_VK)
2143 switch (vkey)
2145 case VK_LSHIFT:
2146 case VK_RSHIFT:
2147 vkey = VK_SHIFT; break;
2148 case VK_LCONTROL:
2149 case VK_RCONTROL:
2150 vkey = VK_CONTROL; break;
2151 case VK_LMENU:
2152 case VK_RMENU:
2153 vkey = VK_MENU; break;
2156 returnMVK (vkey);
2158 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2160 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2161 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2162 * key.. Looks like something is wrong with the MS docs?
2163 * This is only true for letters, for example VK_0 returns '0' not ')'.
2164 * - hence we use the lock mask to ensure this happens.
2166 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2167 XKeyEvent e;
2168 KeySym keysym;
2169 int keyc, len;
2170 char s[10];
2172 e.display = display;
2173 e.state = 0;
2174 e.keycode = 0;
2176 wine_tsx11_lock();
2178 /* We exit on the first keycode found, to speed up the thing. */
2179 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2180 { /* Find a keycode that could have generated this virtual key */
2181 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2182 { /* We filter the extended bit, we don't know it */
2183 e.keycode = keyc; /* Store it temporarily */
2184 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2185 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2186 state), so set it to 0, we'll find another one */
2191 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2192 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2194 if (wCode==VK_DECIMAL)
2195 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2197 if (!e.keycode)
2199 WARN("Unknown virtual key %X !!!\n", wCode);
2200 wine_tsx11_unlock();
2201 return 0; /* whatever */
2203 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2205 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2206 wine_tsx11_unlock();
2208 if (len)
2210 WCHAR wch;
2211 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2212 returnMVK(toupperW(wch));
2214 TRACE("returning no ANSI.\n");
2215 return 0;
2217 default: /* reserved */
2218 FIXME("Unknown wMapType %d !\n", wMapType);
2219 return 0;
2221 return 0;
2224 /***********************************************************************
2225 * GetKeyNameText (X11DRV.@)
2227 INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2229 Display *display = thread_init_display();
2230 int vkey, ansi, scanCode;
2231 KeyCode keyc;
2232 int keyi;
2233 KeySym keys;
2234 char *name;
2236 scanCode = lParam >> 16;
2237 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2239 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2241 /* handle "don't care" bit (0x02000000) */
2242 if (!(lParam & 0x02000000)) {
2243 switch (vkey) {
2244 case VK_RSHIFT:
2245 /* R-Shift is "special" - it is an extended key with separate scan code */
2246 scanCode |= 0x100;
2247 case VK_LSHIFT:
2248 vkey = VK_SHIFT;
2249 break;
2250 case VK_LCONTROL:
2251 case VK_RCONTROL:
2252 vkey = VK_CONTROL;
2253 break;
2254 case VK_LMENU:
2255 case VK_RMENU:
2256 vkey = VK_MENU;
2257 break;
2261 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2262 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
2264 /* first get the name of the "regular" keys which is the Upper case
2265 value of the keycap imprint. */
2266 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2267 (scanCode != 0x137) && /* PrtScn */
2268 (scanCode != 0x135) && /* numpad / */
2269 (scanCode != 0x37 ) && /* numpad * */
2270 (scanCode != 0x4a ) && /* numpad - */
2271 (scanCode != 0x4e ) ) /* numpad + */
2273 if ((nSize >= 2) && lpBuffer)
2275 *lpBuffer = toupperW((WCHAR)ansi);
2276 *(lpBuffer+1) = 0;
2277 return 1;
2279 else
2280 return 0;
2283 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2284 without "extended-key" flag. However Wine generates scancode
2285 *with* "extended-key" flag. Seems to occur *only* for the
2286 function keys. Soooo.. We will leave the table alone and
2287 fudge the lookup here till the other part is found and fixed!!! */
2289 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2290 (scanCode == 0x157) || (scanCode == 0x158))
2291 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2293 /* let's do scancode -> keycode -> keysym -> String */
2295 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2296 if ((keyc2scan[keyi]) == scanCode)
2297 break;
2298 if (keyi <= max_keycode)
2300 wine_tsx11_lock();
2301 keyc = (KeyCode) keyi;
2302 keys = XKeycodeToKeysym(display, keyc, 0);
2303 name = XKeysymToString(keys);
2304 wine_tsx11_unlock();
2305 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2306 scanCode, keyc, (int)keys, name);
2307 if (lpBuffer && nSize && name)
2309 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2310 lpBuffer[nSize - 1] = 0;
2311 return 1;
2315 /* Finally issue WARN for unknown keys */
2317 WARN("(%08x,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2318 if (lpBuffer && nSize)
2319 *lpBuffer = 0;
2320 return 0;
2323 /***********************************************************************
2324 * X11DRV_KEYBOARD_MapDeadKeysym
2326 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2328 switch (keysym)
2330 /* symbolic ASCII is the same as defined in rfc1345 */
2331 #ifdef XK_dead_tilde
2332 case XK_dead_tilde :
2333 #endif
2334 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2335 return '~'; /* '? */
2336 #ifdef XK_dead_acute
2337 case XK_dead_acute :
2338 #endif
2339 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2340 return 0xb4; /* '' */
2341 #ifdef XK_dead_circumflex
2342 case XK_dead_circumflex:
2343 #endif
2344 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2345 return '^'; /* '> */
2346 #ifdef XK_dead_grave
2347 case XK_dead_grave :
2348 #endif
2349 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2350 return '`'; /* '! */
2351 #ifdef XK_dead_diaeresis
2352 case XK_dead_diaeresis :
2353 #endif
2354 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2355 return 0xa8; /* ': */
2356 #ifdef XK_dead_cedilla
2357 case XK_dead_cedilla :
2358 return 0xb8; /* ', */
2359 #endif
2360 #ifdef XK_dead_macron
2361 case XK_dead_macron :
2362 return '-'; /* 'm isn't defined on iso-8859-x */
2363 #endif
2364 #ifdef XK_dead_breve
2365 case XK_dead_breve :
2366 return 0xa2; /* '( */
2367 #endif
2368 #ifdef XK_dead_abovedot
2369 case XK_dead_abovedot :
2370 return 0xff; /* '. */
2371 #endif
2372 #ifdef XK_dead_abovering
2373 case XK_dead_abovering :
2374 return '0'; /* '0 isn't defined on iso-8859-x */
2375 #endif
2376 #ifdef XK_dead_doubleacute
2377 case XK_dead_doubleacute :
2378 return 0xbd; /* '" */
2379 #endif
2380 #ifdef XK_dead_caron
2381 case XK_dead_caron :
2382 return 0xb7; /* '< */
2383 #endif
2384 #ifdef XK_dead_ogonek
2385 case XK_dead_ogonek :
2386 return 0xb2; /* '; */
2387 #endif
2388 /* FIXME: I don't know this three.
2389 case XK_dead_iota :
2390 return 'i';
2391 case XK_dead_voiced_sound :
2392 return 'v';
2393 case XK_dead_semivoiced_sound :
2394 return 's';
2397 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2398 return 0;
2401 /***********************************************************************
2402 * ToUnicodeEx (X11DRV.@)
2404 * The ToUnicode function translates the specified virtual-key code and keyboard
2405 * state to the corresponding Windows character or characters.
2407 * If the specified key is a dead key, the return value is negative. Otherwise,
2408 * it is one of the following values:
2409 * Value Meaning
2410 * 0 The specified virtual key has no translation for the current state of the keyboard.
2411 * 1 One Windows character was copied to the buffer.
2412 * 2 Two characters were copied to the buffer. This usually happens when a
2413 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2414 * be composed with the specified virtual key to form a single character.
2416 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2419 INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2420 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2422 Display *display = thread_init_display();
2423 XKeyEvent e;
2424 KeySym keysym = 0;
2425 INT ret;
2426 int keyc;
2427 char lpChar[10];
2428 HWND focus;
2429 XIC xic;
2430 Status status = 0;
2432 if (scanCode & 0x8000)
2434 TRACE("Key UP, doing nothing\n" );
2435 return 0;
2438 if (hkl != X11DRV_GetKeyboardLayout(0))
2439 FIXME("keyboard layout %p is not supported\n", hkl);
2441 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2443 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2444 return 0;
2447 e.display = display;
2448 e.keycode = 0;
2449 e.state = 0;
2450 e.type = KeyPress;
2452 focus = GetFocus();
2453 if (focus) focus = GetAncestor( focus, GA_ROOT );
2454 if (!focus) focus = GetActiveWindow();
2455 e.window = X11DRV_get_whole_window( focus );
2456 xic = X11DRV_get_ic( focus );
2458 if (lpKeyState[VK_SHIFT] & 0x80)
2460 TRACE("ShiftMask = %04x\n", ShiftMask);
2461 e.state |= ShiftMask;
2463 if (lpKeyState[VK_CAPITAL] & 0x01)
2465 TRACE("LockMask = %04x\n", LockMask);
2466 e.state |= LockMask;
2468 if (lpKeyState[VK_CONTROL] & 0x80)
2470 TRACE("ControlMask = %04x\n", ControlMask);
2471 e.state |= ControlMask;
2473 if (lpKeyState[VK_NUMLOCK] & 0x01)
2475 TRACE("NumLockMask = %04x\n", NumLockMask);
2476 e.state |= NumLockMask;
2479 /* Restore saved AltGr state */
2480 TRACE("AltGrMask = %04x\n", AltGrMask);
2481 e.state |= AltGrMask;
2483 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2484 virtKey, scanCode, e.state);
2485 wine_tsx11_lock();
2486 /* We exit on the first keycode found, to speed up the thing. */
2487 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2488 { /* Find a keycode that could have generated this virtual key */
2489 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2490 { /* We filter the extended bit, we don't know it */
2491 e.keycode = keyc; /* Store it temporarily */
2492 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2493 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2494 state), so set it to 0, we'll find another one */
2499 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2500 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2502 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2503 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2505 if (virtKey==VK_DECIMAL)
2506 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2508 if (virtKey==VK_SEPARATOR)
2509 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2511 if (!e.keycode && virtKey != VK_NONAME)
2513 WARN("Unknown virtual key %X !!!\n", virtKey);
2514 wine_tsx11_unlock();
2515 return 0;
2517 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2519 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2520 e.type, e.window, e.state, e.keycode);
2522 /* Clients should pass only KeyPress events to XmbLookupString,
2523 * e.type was set to KeyPress above.
2525 if (xic)
2526 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, &status);
2527 else
2528 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
2529 wine_tsx11_unlock();
2531 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2533 if (status == XBufferOverflow)
2534 ERR("Buffer Overflow need %d!\n", ret);
2536 if (TRACE_ON(key))
2538 const char *ksname;
2540 wine_tsx11_lock();
2541 ksname = XKeysymToString(keysym);
2542 wine_tsx11_unlock();
2543 if (!ksname) ksname = "No Name";
2544 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
2545 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2546 keysym, ksname, ret, debugstr_an(lpChar, ret));
2549 if (ret == 0)
2551 char dead_char;
2553 #ifdef XK_EuroSign
2554 /* An ugly hack for EuroSign: X can't translate it to a character
2555 for some locales. */
2556 if (keysym == XK_EuroSign)
2558 bufW[0] = 0x20AC;
2559 ret = 1;
2560 goto found;
2562 #endif
2563 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2564 /* Here we change it back. */
2565 if (keysym == XK_ISO_Left_Tab)
2567 bufW[0] = 0x09;
2568 ret = 1;
2569 goto found;
2572 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2573 if (dead_char)
2575 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2576 ret = -1;
2577 goto found;
2580 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2582 /* Unicode direct mapping */
2583 bufW[0] = keysym & 0xffff;
2584 ret = 1;
2585 goto found;
2587 else if ((keysym >> 8) == 0x1008FF) {
2588 bufW[0] = 0;
2589 ret = 0;
2590 goto found;
2592 else
2594 const char *ksname;
2596 wine_tsx11_lock();
2597 ksname = XKeysymToString(keysym);
2598 wine_tsx11_unlock();
2599 if (!ksname)
2600 ksname = "No Name";
2601 if ((keysym >> 8) != 0xff)
2603 WARN("no char for keysym %04lX (%s) :\n",
2604 keysym, ksname);
2605 WARN("virtKey=%X, scanCode=%X, keycode=%X, state=%X\n",
2606 virtKey, scanCode, e.keycode, e.state);
2610 else { /* ret != 0 */
2611 /* We have a special case to handle : Shift + arrow, shift + home, ...
2612 X returns a char for it, but Windows doesn't. Let's eat it. */
2613 if (!(e.state & NumLockMask) /* NumLock is off */
2614 && (e.state & ShiftMask) /* Shift is pressed */
2615 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2617 lpChar[0] = 0;
2618 ret = 0;
2621 /* more areas where X returns characters but Windows does not
2622 CTRL + number or CTRL + symbol */
2623 if (e.state & ControlMask)
2625 if (((keysym>=33) && (keysym < 'A')) ||
2626 ((keysym > 'Z') && (keysym < 'a')))
2628 lpChar[0] = 0;
2629 ret = 0;
2633 /* We have another special case for delete key (XK_Delete) on an
2634 extended keyboard. X returns a char for it, but Windows doesn't */
2635 if (keysym == XK_Delete)
2637 lpChar[0] = 0;
2638 ret = 0;
2640 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2641 && (keysym == XK_KP_Decimal))
2643 lpChar[0] = 0;
2644 ret = 0;
2646 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2647 && (keysym == XK_Return || keysym == XK_KP_Enter))
2649 lpChar[0] = '\n';
2650 ret = 1;
2653 /* Hack to detect an XLookupString hard-coded to Latin1 */
2654 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2656 bufW[0] = (BYTE)lpChar[0];
2657 goto found;
2660 /* perform translation to unicode */
2661 if(ret)
2663 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2664 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2668 found:
2669 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
2670 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
2671 return ret;
2674 /***********************************************************************
2675 * Beep (X11DRV.@)
2677 void X11DRV_Beep(void)
2679 wine_tsx11_lock();
2680 XBell(gdi_display, 0);
2681 wine_tsx11_unlock();