user/tests: Fix a compiler warning, and remove some useless casts.
[wine/testsucceed.git] / dlls / winex11.drv / keyboard.c
blob05e6f4a73a62fac178060f3bb7465c7e5d78aca5
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_XKB
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 "wine/winuser16.h"
48 #include "winnls.h"
49 #include "win.h"
50 #include "x11drv.h"
51 #include "wine/server.h"
52 #include "wine/unicode.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
56 WINE_DECLARE_DEBUG_CHANNEL(key);
58 typedef union
60 struct
62 #ifndef BITFIELDS_BIGENDIAN
63 unsigned long count : 16;
64 #endif
65 unsigned long code : 8;
66 unsigned long extended : 1;
67 unsigned long unused : 2;
68 unsigned long win_internal : 2;
69 unsigned long context : 1;
70 unsigned long previous : 1;
71 unsigned long transition : 1;
72 #ifdef BITFIELDS_BIGENDIAN
73 unsigned long count : 16;
74 #endif
75 } lp1;
76 unsigned long lp2;
77 } KEYLP;
79 /* key state table bits:
80 0x80 -> key is pressed
81 0x40 -> key got pressed since last time
82 0x01 -> key is toggled
84 BYTE key_state_table[256];
86 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
87 or a WM_KEYUP message */
89 static int min_keycode, max_keycode, keysyms_per_keycode;
90 static WORD keyc2vkey[256], keyc2scan[256];
92 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
93 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
95 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
97 /* Keyboard translation tables */
98 #define MAIN_LEN 49
99 static const WORD main_key_scan_qwerty[MAIN_LEN] =
101 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
102 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
103 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
104 /* q w e r t y u i o p [ ] */
105 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
106 /* a s d f g h j k l ; ' \ */
107 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
108 /* z x c v b n m , . / */
109 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
110 0x56 /* the 102nd key (actually to the right of l-shift) */
113 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
115 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
116 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
117 /* q w e r t y u i o p [ ] */
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
119 /* a s d f g h j k l ; ' \ */
120 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
121 /* \ z x c v b n m , . / */
122 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
123 0x56, /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_scan_dvorak[MAIN_LEN] =
128 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
129 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
130 /* ' , . p y f g c r l / = */
131 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
132 /* a o e u i d h t n s - \ */
133 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
134 /* ; q j k x b m w v z */
135 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
136 0x56 /* the 102nd key (actually to the right of l-shift) */
139 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
141 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
142 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
143 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
144 /* q w e r t y u i o p @ [ */
145 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
146 /* a s d f g h j k l ; : ] */
147 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
148 /* z x c v b n m , . / */
149 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
150 0x56 /* the 102nd key (actually to the right of l-shift) */
154 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
156 /* NOTE: this layout must concur with the scan codes layout above */
157 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
158 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
159 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
160 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
161 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
164 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
166 /* NOTE: this layout must concur with the scan codes layout above */
167 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
168 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
169 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
170 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
171 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
174 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
176 /* NOTE: this layout must concur with the scan codes layout above */
177 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
178 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
179 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
180 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
181 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
184 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
186 /* NOTE: this layout must concur with the scan codes layout above */
187 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
188 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
189 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
190 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
191 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
194 static const WORD main_key_vkey_qwertz_105[MAIN_LEN] =
196 /* NOTE: this layout must concur with the scan codes layout above */
197 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
198 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
199 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
200 VK_OEM_102,'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2
203 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
205 /* NOTE: this layout must concur with the scan codes layout above */
206 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
207 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
208 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
209 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
210 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
213 static const WORD main_key_vkey_azerty[MAIN_LEN] =
215 /* NOTE: this layout must concur with the scan codes layout above */
216 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
217 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
218 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
219 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
220 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
223 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
225 /* NOTE: this layout must concur with the scan codes layout above */
226 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
227 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
228 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
229 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
230 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
233 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
235 /* the VK mappings for the main keyboard will be auto-assigned as before,
236 so what we have here is just the character tables */
237 /* order: Normal, Shift, AltGr, Shift-AltGr */
238 /* We recommend you write just what is guaranteed to be correct (i.e. what's
239 written on the keycaps), not the bunch of special characters behind AltGr
240 and Shift-AltGr if it can vary among different X servers */
241 /* Remember that your 102nd key (to the right of l-shift) should be on a
242 separate line, see existing tables */
243 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
244 /* Remember to also add your new table to the layout index table far below! */
246 /*** German Logitech Desktop Pro keyboard layout */
247 static const char main_key_DE_logitech[MAIN_LEN][4] =
249 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
250 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
251 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
252 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
253 "<>|"
256 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
257 static const char main_key_US[MAIN_LEN][4] =
259 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
260 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
261 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
262 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
265 /*** United States keyboard layout (phantom key version) */
266 /* (XFree86 reports the <> key even if it's not physically there) */
267 static const char main_key_US_phantom[MAIN_LEN][4] =
269 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
270 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
271 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
272 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
273 "<>" /* the phantom key */
276 /*** United States keyboard layout (dvorak version) */
277 static const char main_key_US_dvorak[MAIN_LEN][4] =
279 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
280 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
281 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
282 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
285 /*** British keyboard layout */
286 static const char main_key_UK[MAIN_LEN][4] =
288 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
289 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
290 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
291 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
292 "\\|"
295 /*** French keyboard layout (setxkbmap fr) */
296 static const char main_key_FR[MAIN_LEN][4] =
298 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
299 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
300 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
301 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
302 "<>"
305 /*** Icelandic keyboard layout (setxkbmap is) */
306 static const char main_key_IS[MAIN_LEN][4] =
308 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
309 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
310 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
311 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
312 "<>"
315 /*** German keyboard layout (setxkbmap de) */
316 static const char main_key_DE[MAIN_LEN][4] =
318 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","´`",
319 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
320 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
321 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
322 "<>|"
325 /*** German keyboard layout without dead keys */
326 static const char main_key_DE_nodead[MAIN_LEN][4] =
328 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
329 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
330 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
331 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
332 "<>"
335 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
336 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
338 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
339 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
340 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
341 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
344 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
345 static const char main_key_SG[MAIN_LEN][4] =
347 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
348 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
349 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
350 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
351 "<>"
354 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
355 static const char main_key_SF[MAIN_LEN][4] =
357 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
358 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
359 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
360 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
361 "<>"
364 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
365 static const char main_key_NO[MAIN_LEN][4] =
367 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
368 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
369 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
370 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
371 "<>"
374 /*** Danish keyboard layout (setxkbmap dk) */
375 static const char main_key_DA[MAIN_LEN][4] =
377 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
378 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
379 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
380 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
381 "<>"
384 /*** Swedish keyboard layout (setxkbmap se) */
385 static const char main_key_SE[MAIN_LEN][4] =
387 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
388 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
389 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
390 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
391 "<>"
394 /*** Estonian keyboard layout (setxkbmap ee) */
395 static const char main_key_ET[MAIN_LEN][4] =
397 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
398 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
399 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
400 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
401 "<>"
404 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
405 static const char main_key_CF[MAIN_LEN][4] =
407 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
408 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
409 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
410 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
411 "«»°"
414 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
415 static const char main_key_CA_fr[MAIN_LEN][4] =
417 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
418 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
419 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
420 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
421 "«»"
424 /*** Canadian keyboard layout (setxkbmap ca) */
425 static const char main_key_CA[MAIN_LEN][4] =
427 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
428 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
429 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
430 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
431 "ùÙ"
434 /*** Portuguese keyboard layout (setxkbmap pt) */
435 static const char main_key_PT[MAIN_LEN][4] =
437 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
438 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
439 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
440 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
441 "<>"
444 /*** Italian keyboard layout (setxkbmap it) */
445 static const char main_key_IT[MAIN_LEN][4] =
447 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
448 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
449 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
450 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
451 "<>"
454 /*** Finnish keyboard layout (setxkbmap fi) */
455 static const char main_key_FI[MAIN_LEN][4] =
457 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
458 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
459 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
460 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
461 "<>"
464 /*** Bulgarian bds keyboard layout */
465 static const char main_key_BG_bds[MAIN_LEN][4] =
467 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
468 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
469 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
470 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
471 "<>" /* the phantom key */
474 /*** Bulgarian phonetic keyboard layout */
475 static const char main_key_BG_phonetic[MAIN_LEN][4] =
477 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
478 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
479 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
480 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
481 "<>" /* the phantom key */
484 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
485 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
486 static const char main_key_BY[MAIN_LEN][4] =
488 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
489 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
490 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
491 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
495 /*** Russian keyboard layout (contributed by Pavel Roskin) */
496 static const char main_key_RU[MAIN_LEN][4] =
498 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
499 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
500 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
501 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
504 /*** Russian keyboard layout (phantom key version) */
505 static const char main_key_RU_phantom[MAIN_LEN][4] =
507 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
508 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
509 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
510 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
511 "<>" /* the phantom key */
514 /*** Russian keyboard layout KOI8-R */
515 static const char main_key_RU_koi8r[MAIN_LEN][4] =
517 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
518 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
519 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
520 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
521 "<>" /* the phantom key */
524 /*** Russian keyboard layout cp1251 */
525 static const char main_key_RU_cp1251[MAIN_LEN][4] =
527 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
528 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
529 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
530 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
531 "<>" /* the phantom key */
534 /*** Russian phonetic keyboard layout */
535 static const char main_key_RU_phonetic[MAIN_LEN][4] =
537 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
538 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
539 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
540 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
541 "<>" /* the phantom key */
544 /*** Ukrainian keyboard layout KOI8-U */
545 static const char main_key_UA[MAIN_LEN][4] =
547 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
548 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
549 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
550 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
551 "<>" /* the phantom key */
554 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
555 /*** (as it appears on most of keyboards sold today) */
556 static const char main_key_UA_std[MAIN_LEN][4] =
558 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
559 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
560 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
561 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
562 "<>" /* the phantom key */
565 /*** Russian keyboard layout KOI8-R (pair to the previous) */
566 static const char main_key_RU_std[MAIN_LEN][4] =
568 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
569 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
570 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
571 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
572 "<>" /* the phantom key */
575 /*** Spanish keyboard layout (setxkbmap es) */
576 static const char main_key_ES[MAIN_LEN][4] =
578 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
579 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
580 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
581 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
582 "<>"
585 /*** Belgian keyboard layout ***/
586 static const char main_key_BE[MAIN_LEN][4] =
588 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
589 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
590 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
591 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
592 "<>\\"
595 /*** Hungarian keyboard layout (setxkbmap hu) */
596 static const char main_key_HU[MAIN_LEN][4] =
598 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
599 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
600 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
601 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
602 "íÍ"
605 /*** Polish (programmer's) keyboard layout ***/
606 static const char main_key_PL[MAIN_LEN][4] =
608 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
609 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
610 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
611 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
612 "<>|"
615 /*** Slovenian keyboard layout (setxkbmap si) ***/
616 static const char main_key_SI[MAIN_LEN][4] =
618 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
619 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
620 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
621 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
622 "<>"
625 /*** Serbian keyboard layout (setxkbmap sr) ***/
626 static const char main_key_SR[MAIN_LEN][4] =
628 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
629 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
630 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
631 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
632 "<>" /* the phantom key */
635 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
636 static const char main_key_US_SR[MAIN_LEN][4] =
638 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
639 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
640 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
641 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
642 "<>" /* the phantom key */
645 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
646 static const char main_key_HR_jelly[MAIN_LEN][4] =
648 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
649 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
650 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
651 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
652 "<>|"
655 /*** Croatian keyboard layout (setxkbmap hr) ***/
656 static const char main_key_HR[MAIN_LEN][4] =
658 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
659 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
660 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
661 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
662 "<>"
665 /*** Japanese 106 keyboard layout ***/
666 static const char main_key_JA_jp106[MAIN_LEN][4] =
668 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
669 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
670 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
671 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
672 "\\_",
675 /*** Japanese pc98x1 keyboard layout ***/
676 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
678 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
679 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
680 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
681 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
682 "\\_",
685 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
686 static const char main_key_PT_br[MAIN_LEN][4] =
688 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
689 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
690 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
691 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
694 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
695 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
697 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
698 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
699 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
700 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
703 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
704 static const char main_key_US_intl[MAIN_LEN][4] =
706 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
707 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
708 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
709 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
712 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
713 - dead_abovering replaced with degree - no symbol in iso8859-2
714 - brokenbar replaced with bar */
715 static const char main_key_SK[MAIN_LEN][4] =
717 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
718 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
719 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
720 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
721 "<>"
724 /*** Czech keyboard layout (setxkbmap cz) */
725 static const char main_key_CZ[MAIN_LEN][4] =
727 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
728 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
729 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
730 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
731 "\\"
734 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
735 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
737 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
738 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
739 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
740 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
741 "\\"
744 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
745 static const char main_key_SK_prog[MAIN_LEN][4] =
747 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
748 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
749 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
750 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
751 "<>"
754 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
755 static const char main_key_CS[MAIN_LEN][4] =
757 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
758 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
759 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
760 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
761 "<>\\|"
764 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
765 static const char main_key_LA[MAIN_LEN][4] =
767 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
768 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
769 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
770 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
771 "<>"
774 /*** Lithuanian keyboard layout (setxkbmap lt) */
775 static const char main_key_LT_B[MAIN_LEN][4] =
777 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
778 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
779 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
780 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
781 "ª¬"
784 /*** Turkish keyboard Layout */
785 static const char main_key_TK[MAIN_LEN][4] =
787 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
788 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
789 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
790 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
793 /*** Turkish keyboard layout (setxkbmap tr) */
794 static const char main_key_TR[MAIN_LEN][4] =
796 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
797 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
798 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
799 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
800 "<>"
803 /*** Turkish F keyboard layout (setxkbmap trf) */
804 static const char main_key_TR_F[MAIN_LEN][4] =
806 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
807 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
808 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
809 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
810 "<>"
813 /*** Israelian keyboard layout (setxkbmap us,il) */
814 static const char main_key_IL[MAIN_LEN][4] =
816 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
817 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
818 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
819 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
820 "<>"
823 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
824 static const char main_key_IL_phonetic[MAIN_LEN][4] =
826 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
827 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
828 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
829 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
830 "<>"
833 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
834 static const char main_key_IL_saharon[MAIN_LEN][4] =
836 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
837 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
838 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
839 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
840 "<>"
843 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
844 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
845 message since they have different characters in gr and el XFree86 layouts. */
846 static const char main_key_EL[MAIN_LEN][4] =
848 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
849 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
850 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
851 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
852 "<>"
855 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
856 static const char main_key_th[MAIN_LEN][4] =
858 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
859 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
860 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
861 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
864 /*** VNC keyboard layout */
865 static const WORD main_key_scan_vnc[MAIN_LEN] =
867 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
868 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,
869 0x56
872 static const WORD main_key_vkey_vnc[MAIN_LEN] =
874 '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,
875 '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',
876 VK_OEM_102
879 static const char main_key_vnc[MAIN_LEN][4] =
881 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
882 "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"
885 /*** Dutch keyboard layout (setxkbmap nl) ***/
886 static const char main_key_NL[MAIN_LEN][4] =
888 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
889 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
890 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
891 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
892 "[]"
897 /*** Layout table. Add your keyboard mappings to this list */
898 static const struct {
899 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
900 in the appropriate dlls/kernel/nls/.nls file */
901 const char *comment;
902 const char (*key)[MAIN_LEN][4];
903 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
904 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
905 } main_key_tab[]={
906 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
908 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
909 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
912 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
913 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
914 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwertz_105},
915 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
916 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
917 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
918 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
922 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
926 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
928 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
929 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
933 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
938 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
945 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
947 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
948 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
949 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
950 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
952 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
953 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
955 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
956 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
957 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
958 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
959 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
960 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
961 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
962 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
963 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
964 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
965 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
966 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
967 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
968 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
969 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
971 {0, NULL, NULL, NULL, NULL} /* sentinel */
973 static unsigned kbd_layout=0; /* index into above table of layouts */
975 /* maybe more of these scancodes should be extended? */
976 /* extended must be set for ALT_R, CTRL_R,
977 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
978 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
979 /* FIXME should we set extended bit for NumLock ? My
980 * Windows does ... DF */
981 /* Yes, to distinguish based on scan codes, also
982 for PrtScn key ... GA */
984 static const WORD nonchar_key_vkey[256] =
986 /* unused */
987 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
988 /* special keys */
989 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
990 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
991 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
992 /* unused */
993 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
994 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
995 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
996 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
997 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
998 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
999 /* cursor keys */
1000 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
1001 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
1002 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1003 /* misc keys */
1004 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
1005 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1007 /* keypad keys */
1008 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
1009 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1010 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
1011 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
1012 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
1013 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1014 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1015 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
1016 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1017 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1018 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1019 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
1020 /* function keys */
1021 VK_F1, VK_F2,
1022 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1023 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
1024 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
1025 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1026 /* modifier keys */
1027 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
1028 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
1029 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
1030 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1031 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1034 static const WORD nonchar_key_scan[256] =
1036 /* unused */
1037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1038 /* special keys */
1039 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1040 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1041 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1042 /* unused */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1047 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1048 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1049 /* cursor keys */
1050 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1052 /* misc keys */
1053 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
1054 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1056 /* keypad keys */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
1058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1059 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1061 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1063 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1064 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1065 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1066 /* function keys */
1067 0x3B, 0x3C,
1068 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1069 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
1070 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1072 /* modifier keys */
1073 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1074 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
1075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1080 /* Returns the Windows virtual key code associated with the X event <e> */
1081 /* x11 lock must be held */
1082 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1084 KeySym keysym = 0;
1085 Status status;
1086 char buf[24];
1088 if (xic)
1089 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1090 else
1091 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1093 if ((e->state & NumLockMask) &&
1094 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1095 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1096 /* Only the Keypad keys 0-9 and . send different keysyms
1097 * depending on the NumLock state */
1098 return nonchar_key_vkey[keysym & 0xFF];
1100 TRACE_(key)("e->keycode = %x\n", e->keycode);
1102 return keyc2vkey[e->keycode];
1105 static BOOL NumState=FALSE, CapsState=FALSE;
1108 /***********************************************************************
1109 * X11DRV_send_keyboard_input
1111 void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time,
1112 DWORD dwExtraInfo, UINT injected_flags )
1114 UINT message;
1115 KEYLP keylp;
1116 KBDLLHOOKSTRUCT hook;
1117 WORD wVkStripped;
1119 wVk = LOBYTE(wVk);
1121 /* strip left/right for menu, control, shift */
1122 if (wVk == VK_LMENU || wVk == VK_RMENU)
1123 wVkStripped = VK_MENU;
1124 else if (wVk == VK_LCONTROL || wVk == VK_RCONTROL)
1125 wVkStripped = VK_CONTROL;
1126 else if (wVk == VK_LSHIFT || wVk == VK_RSHIFT)
1127 wVkStripped = VK_SHIFT;
1128 else
1129 wVkStripped = wVk;
1131 keylp.lp2 = 0;
1132 keylp.lp1.count = 1;
1133 keylp.lp1.code = wScan;
1134 keylp.lp1.extended = (dwFlags & KEYEVENTF_EXTENDEDKEY) != 0;
1135 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
1136 * don't remember where I read it - AK */
1137 /* it's '1' under windows, when a dialog box appears
1138 * and you press one of the underlined keys - DF*/
1140 /* note that there is a test for all this */
1141 if (dwFlags & KEYEVENTF_KEYUP )
1143 message = WM_KEYUP;
1144 if ((key_state_table[VK_MENU] & 0x80) &&
1145 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1146 || !(key_state_table[VK_CONTROL] & 0x80)))
1148 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1149 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1150 message = WM_SYSKEYUP;
1151 TrackSysKey = 0;
1153 key_state_table[wVk] &= ~0x80;
1154 key_state_table[wVkStripped] &= ~0x80;
1155 keylp.lp1.previous = 1;
1156 keylp.lp1.transition = 1;
1158 else
1160 keylp.lp1.previous = (key_state_table[wVk] & 0x80) != 0;
1161 keylp.lp1.transition = 0;
1162 if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1163 key_state_table[wVk] |= 0xc0;
1164 key_state_table[wVkStripped] |= 0xc0;
1166 message = WM_KEYDOWN;
1167 if ((key_state_table[VK_MENU] & 0x80) && !(key_state_table[VK_CONTROL] & 0x80))
1169 message = WM_SYSKEYDOWN;
1170 TrackSysKey = wVkStripped;
1174 keylp.lp1.context = (key_state_table[VK_MENU] & 0x80) != 0; /* 1 if alt */
1176 TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
1177 wVk, keylp.lp2, key_state_table[wVk] );
1179 hook.vkCode = wVk;
1180 hook.scanCode = wScan;
1181 hook.flags = (keylp.lp2 >> 24) | injected_flags;
1182 hook.time = time;
1183 hook.dwExtraInfo = dwExtraInfo;
1184 if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1186 SERVER_START_REQ( send_hardware_message )
1188 req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1189 req->win = 0;
1190 req->msg = message;
1191 req->wparam = wVk;
1192 req->lparam = keylp.lp2;
1193 req->x = cursor_pos.x;
1194 req->y = cursor_pos.y;
1195 req->time = time;
1196 req->info = dwExtraInfo;
1197 wine_server_call( req );
1199 SERVER_END_REQ;
1203 /**********************************************************************
1204 * KEYBOARD_GenerateMsg
1206 * Generate Down+Up messages when NumLock or CapsLock is pressed.
1208 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
1211 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
1213 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
1214 DWORD up, down;
1216 if (*State) {
1217 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
1218 don't treat it. It's from the same key press. Then the state goes to ON.
1219 And from there, a 'release' event will switch off the toggle key. */
1220 *State=FALSE;
1221 TRACE("INTERM : don't treat release of toggle key. key_state_table[%#x] = %#x\n",
1222 vkey,key_state_table[vkey]);
1223 } else
1225 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
1226 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
1227 if ( key_state_table[vkey] & 0x1 ) /* it was ON */
1229 if (Evtype!=KeyPress)
1231 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
1232 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1233 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1234 *State=FALSE;
1235 key_state_table[vkey] &= ~0x01; /* Toggle state to off. */
1238 else /* it was OFF */
1239 if (Evtype==KeyPress)
1241 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
1242 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1243 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1244 *State=TRUE; /* Goes to intermediary state before going to ON */
1245 key_state_table[vkey] |= 0x01; /* Toggle state to on. */
1250 /***********************************************************************
1251 * KEYBOARD_UpdateOneState
1253 * Updates internal state for <vkey>, depending on key <state> under X
1256 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
1258 /* Do something if internal table state != X state for keycode */
1259 if (((key_state_table[vkey] & 0x80)!=0) != state)
1261 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1262 vkey, key_state_table[vkey]);
1264 /* Fake key being pressed inside wine */
1265 X11DRV_send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time, 0, 0 );
1267 TRACE("State after %#.2x\n",key_state_table[vkey]);
1271 /***********************************************************************
1272 * X11DRV_KeymapNotify
1274 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1276 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1277 * from wine to another application and back.
1278 * Toggle keys are handled in HandleEvent.
1280 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1282 int i, j, alt, control, shift;
1283 DWORD time = GetCurrentTime();
1285 alt = control = shift = 0;
1286 for (i = 0; i < 32; i++)
1288 if (!event->xkeymap.key_vector[i]) continue;
1289 for (j = 0; j < 8; j++)
1291 if (!(event->xkeymap.key_vector[i] & (1<<j))) continue;
1292 switch(keyc2vkey[(i * 8) + j] & 0xff)
1294 case VK_MENU: alt = 1; break;
1295 case VK_CONTROL: control = 1; break;
1296 case VK_SHIFT: shift = 1; break;
1300 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
1301 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
1302 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
1305 /***********************************************************************
1306 * X11DRV_KeyEvent
1308 * Handle a X key event
1310 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1312 XKeyEvent *event = &xev->xkey;
1313 char Str[24];
1314 KeySym keysym = 0;
1315 WORD vkey = 0, bScan;
1316 DWORD dwFlags;
1317 int ascii_chars;
1318 XIC xic = X11DRV_get_ic( hwnd );
1319 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1320 Status status = 0;
1322 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1323 event->type, event->window, event->state, event->keycode);
1325 wine_tsx11_lock();
1326 if (xic)
1327 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
1328 else
1329 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1330 wine_tsx11_unlock();
1332 /* Ignore some unwanted events */
1333 if ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1334 keysym == XK_Mode_switch)
1336 wine_tsx11_lock();
1337 TRACE("Ignoring %s keyboard event\n", XKeysymToString(keysym));
1338 wine_tsx11_unlock();
1339 return;
1342 TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status);
1344 if (status == XBufferOverflow)
1345 ERR("Buffer Overflow need %i!\n",ascii_chars);
1347 if (status == XLookupChars)
1349 X11DRV_XIMLookupChars( Str, ascii_chars );
1350 return;
1353 /* If XKB extensions are used, the state mask for AltGr will use the group
1354 index instead of the modifier mask. The group index is set in bits
1355 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1356 pressed, look if the group index is different than 0. From XKB
1357 extension documentation, the group index for AltGr should be 2
1358 (event->state = 0x2000). It's probably better to not assume a
1359 predefined group index and find it dynamically
1361 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1362 /* Save also all possible modifier states. */
1363 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1365 Str[ascii_chars] = '\0';
1366 if (TRACE_ON(key)){
1367 const char *ksname;
1369 wine_tsx11_lock();
1370 ksname = XKeysymToString(keysym);
1371 wine_tsx11_unlock();
1372 if (!ksname)
1373 ksname = "No Name";
1374 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / 0x%02x / '%s'\n",
1375 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1376 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1379 wine_tsx11_lock();
1380 vkey = EVENT_event_to_vkey(xic,event);
1381 /* X returns keycode 0 for composed characters */
1382 if (!vkey && ascii_chars) vkey = VK_NONAME;
1383 wine_tsx11_unlock();
1385 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1386 event->keycode, vkey);
1388 if (vkey)
1390 switch (vkey & 0xff)
1392 case VK_NUMLOCK:
1393 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1394 break;
1395 case VK_CAPITAL:
1396 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,key_state_table[vkey]);
1397 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1398 TRACE("State after : %#.2x\n",key_state_table[vkey]);
1399 break;
1400 default:
1401 /* Adjust the NUMLOCK state if it has been changed outside wine */
1402 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1404 TRACE("Adjusting NumLock state.\n");
1405 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1406 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1408 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1409 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1411 TRACE("Adjusting Caps Lock state.\n");
1412 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1413 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1415 /* Not Num nor Caps : end of intermediary states for both. */
1416 NumState = FALSE;
1417 CapsState = FALSE;
1419 bScan = keyc2scan[event->keycode] & 0xFF;
1420 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1422 dwFlags = 0;
1423 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1424 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1426 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1431 /**********************************************************************
1432 * X11DRV_KEYBOARD_DetectLayout
1434 * Called from X11DRV_InitKeyboard
1435 * This routine walks through the defined keyboard layouts and selects
1436 * whichever matches most closely.
1437 * X11 lock must be held.
1439 static void
1440 X11DRV_KEYBOARD_DetectLayout (void)
1442 Display *display = thread_display();
1443 unsigned current, match, mismatch, seq, i, syms;
1444 int score, keyc, key, pkey, ok;
1445 KeySym keysym = 0;
1446 const char (*lkey)[MAIN_LEN][4];
1447 unsigned max_seq = 0;
1448 int max_score = 0, ismatch = 0;
1449 char ckey[4] =
1450 {0, 0, 0, 0};
1452 syms = keysyms_per_keycode;
1453 if (syms > 4) {
1454 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1455 syms = 4;
1457 for (current = 0; main_key_tab[current].comment; current++) {
1458 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1459 match = 0;
1460 mismatch = 0;
1461 score = 0;
1462 seq = 0;
1463 lkey = main_key_tab[current].key;
1464 pkey = -1;
1465 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1466 /* get data for keycode from X server */
1467 for (i = 0; i < syms; i++) {
1468 keysym = XKeycodeToKeysym (display, keyc, i);
1469 /* Allow both one-byte and two-byte national keysyms */
1470 if ((keysym < 0x8000) && (keysym != ' '))
1472 #ifdef HAVE_XKB
1473 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1474 #endif
1476 TRACE("XKB could not translate keysym %ld\n", keysym);
1477 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1478 * with appropriate ShiftMask and Mode_switch, use XLookupString
1479 * to get character in the local encoding.
1481 ckey[i] = keysym & 0xFF;
1484 else {
1485 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1488 if (ckey[0]) {
1489 /* search for a match in layout table */
1490 /* right now, we just find an absolute match for defined positions */
1491 /* (undefined positions are ignored, so if it's defined as "3#" in */
1492 /* the table, it's okay that the X server has "3#£", for example) */
1493 /* however, the score will be higher for longer matches */
1494 for (key = 0; key < MAIN_LEN; key++) {
1495 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1496 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1497 ok++;
1498 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1499 ok = -1;
1501 if (ok > 0) {
1502 score += ok;
1503 break;
1506 /* count the matches and mismatches */
1507 if (ok > 0) {
1508 match++;
1509 /* and how much the keycode order matches */
1510 if (key > pkey) seq++;
1511 pkey = key;
1512 } else {
1513 /* print spaces instead of \0's */
1514 for (i = 0; i < sizeof(ckey); i++) if (!ckey[i]) ckey[i] = ' ';
1515 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %c%c%c%c\n",
1516 keysym, keyc, ckey[0], ckey[1], ckey[2], ckey[3]);
1517 mismatch++;
1518 score -= syms;
1522 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1523 match, mismatch, seq, score);
1524 if ((score > max_score) ||
1525 ((score == max_score) && (seq > max_seq))) {
1526 /* best match so far */
1527 kbd_layout = current;
1528 max_score = score;
1529 max_seq = seq;
1530 ismatch = !mismatch;
1533 /* we're done, report results if necessary */
1534 if (!ismatch)
1535 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1536 main_key_tab[kbd_layout].comment);
1538 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1541 /**********************************************************************
1542 * X11DRV_InitKeyboard
1544 void X11DRV_InitKeyboard(void)
1546 Display *display = thread_display();
1547 KeySym *ksp;
1548 XModifierKeymap *mmp;
1549 KeySym keysym;
1550 KeyCode *kcp;
1551 XKeyEvent e2;
1552 WORD scan, vkey, OEMvkey;
1553 int keyc, i, keyn, syms;
1554 char ckey[4]={0,0,0,0};
1555 const char (*lkey)[MAIN_LEN][4];
1557 wine_tsx11_lock();
1558 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1559 ksp = XGetKeyboardMapping(display, min_keycode,
1560 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1561 /* We are only interested in keysyms_per_keycode.
1562 There is no need to hold a local copy of the keysyms table */
1563 XFree(ksp);
1565 mmp = XGetModifierMapping(display);
1566 kcp = mmp->modifiermap;
1567 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1569 int j;
1571 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1572 if (*kcp)
1574 int k;
1576 for (k = 0; k < keysyms_per_keycode; k += 1)
1577 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1579 NumLockMask = 1 << i;
1580 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1584 XFreeModifiermap(mmp);
1586 /* Detect the keyboard layout */
1587 X11DRV_KEYBOARD_DetectLayout();
1588 lkey = main_key_tab[kbd_layout].key;
1589 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1591 /* Now build two conversion arrays :
1592 * keycode -> vkey + scancode + extended
1593 * vkey + extended -> keycode */
1595 e2.display = display;
1596 e2.state = 0;
1598 OEMvkey = VK_OEM_8; /* next is available. */
1599 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1601 char buf[30];
1602 int have_chars;
1604 keysym = 0;
1605 e2.keycode = (KeyCode)keyc;
1606 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1607 vkey = 0; scan = 0;
1608 if (keysym) /* otherwise, keycode not used */
1610 if ((keysym >> 8) == 0xFF) /* non-character key */
1612 vkey = nonchar_key_vkey[keysym & 0xff];
1613 scan = nonchar_key_scan[keysym & 0xff];
1614 /* set extended bit when necessary */
1615 if (scan & 0x100) vkey |= 0x100;
1616 } else if (keysym == 0x20) { /* Spacebar */
1617 vkey = VK_SPACE;
1618 scan = 0x39;
1619 } else if (have_chars) {
1620 /* we seem to need to search the layout-dependent scancodes */
1621 int maxlen=0,maxval=-1,ok;
1622 for (i=0; i<syms; i++) {
1623 keysym = XKeycodeToKeysym(display, keyc, i);
1624 if ((keysym<0x8000) && (keysym!=' '))
1626 #ifdef HAVE_XKB
1627 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1628 #endif
1630 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1631 * with appropriate ShiftMask and Mode_switch, use XLookupString
1632 * to get character in the local encoding.
1634 ckey[i] = keysym & 0xFF;
1636 } else {
1637 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1640 /* find key with longest match streak */
1641 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1642 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1643 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1644 if (ok||(i>maxlen)) {
1645 maxlen=i; maxval=keyn;
1647 if (ok) break;
1649 if (maxval>=0) {
1650 /* got it */
1651 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1652 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1653 scan = (*lscan)[maxval];
1654 vkey = (*lvkey)[maxval];
1657 #if 0 /* this breaks VK_OEM_x VKeys in some layout tables by inserting
1658 * a VK code into a not appropriate place.
1660 /* find a suitable layout-dependent VK code */
1661 /* (most Winelib apps ought to be able to work without layout tables!) */
1662 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1664 keysym = XLookupKeysym(&e2, i);
1665 if ((keysym >= VK_0 && keysym <= VK_9)
1666 || (keysym >= VK_A && keysym <= VK_Z)) {
1667 vkey = keysym;
1671 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1673 keysym = XLookupKeysym(&e2, i);
1674 switch (keysym)
1676 case ';': vkey = VK_OEM_1; break;
1677 case '/': vkey = VK_OEM_2; break;
1678 case '`': vkey = VK_OEM_3; break;
1679 case '[': vkey = VK_OEM_4; break;
1680 case '\\': vkey = VK_OEM_5; break;
1681 case ']': vkey = VK_OEM_6; break;
1682 case '\'': vkey = VK_OEM_7; break;
1683 case ',': vkey = VK_OEM_COMMA; break;
1684 case '.': vkey = VK_OEM_PERIOD; break;
1685 case '-': vkey = VK_OEM_MINUS; break;
1686 case '+': vkey = VK_OEM_PLUS; break;
1690 if (!vkey)
1692 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1693 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1694 switch (++OEMvkey)
1696 case 0xc1 : OEMvkey=0xdb; break;
1697 case 0xe5 : OEMvkey=0xe9; break;
1698 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1701 vkey = OEMvkey;
1703 if (TRACE_ON(keyboard))
1705 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1706 OEMvkey, e2.keycode);
1707 TRACE("(");
1708 for (i = 0; i < keysyms_per_keycode; i += 1)
1710 const char *ksname;
1712 keysym = XLookupKeysym(&e2, i);
1713 ksname = XKeysymToString(keysym);
1714 if (!ksname)
1715 ksname = "NoSymbol";
1716 TRACE( "%lX (%s) ", keysym, ksname);
1718 TRACE(")\n");
1721 #endif
1723 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1724 keyc2vkey[e2.keycode] = vkey;
1725 keyc2scan[e2.keycode] = scan;
1726 } /* for */
1728 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1729 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1730 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1731 const char *ksname;
1732 keysym = XKeycodeToKeysym(display, keyc, 0);
1733 ksname = XKeysymToString(keysym);
1734 if (!ksname) ksname = "NoSymbol";
1736 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1738 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1739 keyc2scan[keyc]=scan++;
1742 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1743 kcControl = XKeysymToKeycode(display, XK_Control_L);
1744 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1745 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1746 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1747 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1748 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1749 wine_tsx11_unlock();
1753 /**********************************************************************
1754 * GetAsyncKeyState (X11DRV.@)
1756 SHORT X11DRV_GetAsyncKeyState(INT key)
1758 SHORT retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1759 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1760 key_state_table[key] &= ~0x40;
1761 TRACE_(key)("(%x) -> %x\n", key, retval);
1762 return retval;
1766 /***********************************************************************
1767 * GetKeyboardLayoutList (X11DRV.@)
1769 UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
1771 INT i;
1773 TRACE("%d, %p\n", size, hkl);
1775 if (!size)
1777 size = 4096; /* hope we will never have that many */
1778 hkl = NULL;
1781 for (i = 0; main_key_tab[i].comment && (i < size); i++)
1783 if (hkl)
1785 ULONG_PTR layout = main_key_tab[i].lcid;
1786 LANGID langid;
1788 /* see comment for GetKeyboardLayout */
1789 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1790 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1791 layout |= 0xe001 << 16; /* FIXME */
1792 else
1793 layout |= layout << 16;
1795 hkl[i] = (HKL)layout;
1798 return i;
1802 /***********************************************************************
1803 * GetKeyboardLayout (X11DRV.@)
1805 HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1807 ULONG_PTR layout;
1808 LANGID langid;
1810 if (dwThreadid && dwThreadid != GetCurrentThreadId())
1811 FIXME("couldn't return keyboard layout for thread %04lx\n", dwThreadid);
1813 #if 0
1814 layout = main_key_tab[kbd_layout].lcid;
1815 #else
1816 /* FIXME:
1817 * Winword uses return value of GetKeyboardLayout as a codepage
1818 * to translate ANSI keyboard messages to unicode. But we have
1819 * a problem with it: for instance Polish keyboard layout is
1820 * identical to the US one, and therefore instead of the Polish
1821 * locale id we return the US one.
1823 layout = GetUserDefaultLCID();
1824 #endif
1826 * Microsoft Office expects this value to be something specific
1827 * for Japanese and Korean Windows with an IME the value is 0xe001
1828 * We should probably check to see if an IME exists and if so then
1829 * set this word properly.
1831 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1832 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1833 layout |= 0xe001 << 16; /* FIXME */
1834 else
1835 layout |= layout << 16;
1837 return (HKL)layout;
1841 /***********************************************************************
1842 * GetKeyboardLayoutName (X11DRV.@)
1844 BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1846 static const WCHAR formatW[] = {'%','0','8','l','x',0};
1847 DWORD layout;
1848 LANGID langid;
1850 layout = main_key_tab[kbd_layout].lcid;
1851 /* see comment for GetKeyboardLayout */
1852 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1853 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1854 layout |= 0xe001 << 16; /* FIXME */
1855 else
1856 layout |= layout << 16;
1858 sprintfW(name, formatW, layout);
1859 TRACE("returning %s\n", debugstr_w(name));
1860 return TRUE;
1864 /***********************************************************************
1865 * LoadKeyboardLayout (X11DRV.@)
1867 HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1869 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1870 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1871 return 0;
1875 /***********************************************************************
1876 * UnloadKeyboardLayout (X11DRV.@)
1878 BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
1880 FIXME("%p: stub!\n", hkl);
1881 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1882 return FALSE;
1886 /***********************************************************************
1887 * ActivateKeyboardLayout (X11DRV.@)
1889 HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1891 FIXME("%p, %04x: stub!\n", hkl, flags);
1892 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1893 return 0;
1897 /***********************************************************************
1898 * X11DRV_MappingNotify
1900 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1902 HWND hwnd;
1904 wine_tsx11_lock();
1905 XRefreshKeyboardMapping(&event->xmapping);
1906 wine_tsx11_unlock();
1907 X11DRV_InitKeyboard();
1909 hwnd = GetFocus();
1910 if (!hwnd) hwnd = GetActiveWindow();
1911 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1912 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1916 /***********************************************************************
1917 * VkKeyScanEx (X11DRV.@)
1919 * Note: Windows ignores HKL parameter and uses current active layout instead
1921 SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1923 Display *display = thread_display();
1924 KeyCode keycode;
1925 KeySym keysym;
1926 int i, index;
1927 CHAR cChar;
1928 SHORT ret;
1930 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
1931 * is UTF-8 (multibyte encoding)?
1933 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
1935 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1936 return -1;
1939 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1941 /* char->keysym (same for ANSI chars) */
1942 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1943 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1945 wine_tsx11_lock();
1946 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1947 if (!keycode)
1949 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
1951 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
1952 TRACE(" ... returning ctrl char %#.2x\n", ret);
1953 wine_tsx11_unlock();
1954 return ret;
1956 /* It didn't work ... let's try with deadchar code. */
1957 TRACE("retrying with | 0xFE00\n");
1958 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
1960 wine_tsx11_unlock();
1962 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
1963 cChar, keysym, keysym, keycode, keycode);
1965 /* keycode -> (keyc2vkey) vkey */
1966 ret = keyc2vkey[keycode];
1968 if (!keycode || !ret)
1970 TRACE("keycode for '%c' not found, returning -1\n", cChar);
1971 return -1;
1974 index = -1;
1975 wine_tsx11_lock();
1976 for (i = 0; i < 4; i++) /* find shift state */
1978 if (XKeycodeToKeysym(display, keycode, i) == keysym)
1980 index = i;
1981 break;
1984 wine_tsx11_unlock();
1986 switch (index)
1988 default:
1989 case -1:
1990 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
1991 return -1;
1993 case 0: break;
1994 case 1: ret += 0x0100; break;
1995 case 2: ret += 0x0600; break;
1996 case 3: ret += 0x0700; break;
1999 index : 0 adds 0x0000
2000 index : 1 adds 0x0100 (shift)
2001 index : ? adds 0x0200 (ctrl)
2002 index : 2 adds 0x0600 (ctrl+alt)
2003 index : 3 adds 0x0700 (ctrl+alt+shift)
2006 TRACE(" ... returning %#.2x\n", ret);
2007 return ret;
2010 /***********************************************************************
2011 * MapVirtualKeyEx (X11DRV.@)
2013 UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2015 Display *display = thread_display();
2017 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
2019 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2020 if (hkl != X11DRV_GetKeyboardLayout(0))
2021 FIXME("keyboard layout %p is not supported\n", hkl);
2023 switch(wMapType) {
2024 case 0: { /* vkey-code to scan-code */
2025 /* let's do vkey -> keycode -> scan */
2026 int keyc;
2027 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
2028 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2029 returnMVK (keyc2scan[keyc] & 0xFF);
2030 TRACE("returning no scan-code.\n");
2031 return 0; }
2033 case 1: { /* scan-code to vkey-code */
2034 /* let's do scan -> keycode -> vkey */
2035 int keyc;
2036 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
2037 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2038 returnMVK (keyc2vkey[keyc] & 0xFF);
2039 TRACE("returning no vkey-code.\n");
2040 return 0; }
2042 case 2: { /* vkey-code to unshifted ANSI code */
2043 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2044 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2045 * key.. Looks like something is wrong with the MS docs?
2046 * This is only true for letters, for example VK_0 returns '0' not ')'.
2047 * - hence we use the lock mask to ensure this happens.
2049 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2050 XKeyEvent e;
2051 KeySym keysym;
2052 int keyc;
2053 char s[2];
2054 e.display = display;
2056 e.state = LockMask;
2057 /* LockMask should behave exactly like caps lock - upercase
2058 * the letter keys and thats about it. */
2060 wine_tsx11_lock();
2062 e.keycode = 0;
2063 /* We exit on the first keycode found, to speed up the thing. */
2064 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2065 { /* Find a keycode that could have generated this virtual key */
2066 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2067 { /* We filter the extended bit, we don't know it */
2068 e.keycode = keyc; /* Store it temporarily */
2069 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2070 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2071 state), so set it to 0, we'll find another one */
2076 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2077 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2079 if (wCode==VK_DECIMAL)
2080 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2082 if (!e.keycode)
2084 WARN("Unknown virtual key %X !!!\n", wCode);
2085 wine_tsx11_unlock();
2086 return 0; /* whatever */
2088 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2090 if (XLookupString(&e, s, 2, &keysym, NULL))
2092 wine_tsx11_unlock();
2093 returnMVK (*s);
2096 TRACE("returning no ANSI.\n");
2097 wine_tsx11_unlock();
2098 return 0;
2101 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
2102 /* left and right */
2103 FIXME(" stub for NT\n");
2104 return 0;
2106 default: /* reserved */
2107 WARN("Unknown wMapType %d !\n", wMapType);
2108 return 0;
2110 return 0;
2113 /***********************************************************************
2114 * GetKeyNameText (X11DRV.@)
2116 INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2118 int vkey, ansi, scanCode;
2119 KeyCode keyc;
2120 int keyi;
2121 KeySym keys;
2122 char *name;
2124 scanCode = lParam >> 16;
2125 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2127 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
2128 vkey = X11DRV_MapVirtualKeyEx(scanCode, 1, X11DRV_GetKeyboardLayout(0));
2130 /* handle "don't care" bit (0x02000000) */
2131 if (!(lParam & 0x02000000)) {
2132 switch (vkey) {
2133 case VK_LSHIFT:
2134 case VK_RSHIFT:
2135 vkey = VK_SHIFT;
2136 break;
2137 case VK_LCONTROL:
2138 case VK_RCONTROL:
2139 vkey = VK_CONTROL;
2140 break;
2141 case VK_LMENU:
2142 case VK_RMENU:
2143 vkey = VK_MENU;
2144 break;
2145 default:
2146 break;
2150 ansi = X11DRV_MapVirtualKeyEx(vkey, 2, X11DRV_GetKeyboardLayout(0));
2151 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
2153 /* first get the name of the "regular" keys which is the Upper case
2154 value of the keycap imprint. */
2155 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2156 (scanCode != 0x137) && /* PrtScn */
2157 (scanCode != 0x135) && /* numpad / */
2158 (scanCode != 0x37 ) && /* numpad * */
2159 (scanCode != 0x4a ) && /* numpad - */
2160 (scanCode != 0x4e ) ) /* numpad + */
2162 if ((nSize >= 2) && lpBuffer)
2164 *lpBuffer = toupperW((WCHAR)ansi);
2165 *(lpBuffer+1) = 0;
2166 return 1;
2168 else
2169 return 0;
2172 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2173 without "extended-key" flag. However Wine generates scancode
2174 *with* "extended-key" flag. Seems to occur *only* for the
2175 function keys. Soooo.. We will leave the table alone and
2176 fudge the lookup here till the other part is found and fixed!!! */
2178 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2179 (scanCode == 0x157) || (scanCode == 0x158))
2180 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2182 /* let's do scancode -> keycode -> keysym -> String */
2184 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2185 if ((keyc2scan[keyi]) == scanCode)
2186 break;
2187 if (keyi <= max_keycode)
2189 wine_tsx11_lock();
2190 keyc = (KeyCode) keyi;
2191 keys = XKeycodeToKeysym(thread_display(), keyc, 0);
2192 name = XKeysymToString(keys);
2193 wine_tsx11_unlock();
2194 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2195 scanCode, keyc, (int)keys, name);
2196 if (lpBuffer && nSize && name)
2198 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2199 lpBuffer[nSize - 1] = 0;
2200 return 1;
2204 /* Finally issue FIXME for unknown keys */
2206 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2207 if (lpBuffer && nSize)
2208 *lpBuffer = 0;
2209 return 0;
2212 /***********************************************************************
2213 * X11DRV_KEYBOARD_MapDeadKeysym
2215 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2217 switch (keysym)
2219 /* symbolic ASCII is the same as defined in rfc1345 */
2220 #ifdef XK_dead_tilde
2221 case XK_dead_tilde :
2222 #endif
2223 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2224 return '~'; /* '? */
2225 #ifdef XK_dead_acute
2226 case XK_dead_acute :
2227 #endif
2228 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2229 return 0xb4; /* '' */
2230 #ifdef XK_dead_circumflex
2231 case XK_dead_circumflex:
2232 #endif
2233 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2234 return '^'; /* '> */
2235 #ifdef XK_dead_grave
2236 case XK_dead_grave :
2237 #endif
2238 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2239 return '`'; /* '! */
2240 #ifdef XK_dead_diaeresis
2241 case XK_dead_diaeresis :
2242 #endif
2243 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2244 return 0xa8; /* ': */
2245 #ifdef XK_dead_cedilla
2246 case XK_dead_cedilla :
2247 return 0xb8; /* ', */
2248 #endif
2249 #ifdef XK_dead_macron
2250 case XK_dead_macron :
2251 return '-'; /* 'm isn't defined on iso-8859-x */
2252 #endif
2253 #ifdef XK_dead_breve
2254 case XK_dead_breve :
2255 return 0xa2; /* '( */
2256 #endif
2257 #ifdef XK_dead_abovedot
2258 case XK_dead_abovedot :
2259 return 0xff; /* '. */
2260 #endif
2261 #ifdef XK_dead_abovering
2262 case XK_dead_abovering :
2263 return '0'; /* '0 isn't defined on iso-8859-x */
2264 #endif
2265 #ifdef XK_dead_doubleacute
2266 case XK_dead_doubleacute :
2267 return 0xbd; /* '" */
2268 #endif
2269 #ifdef XK_dead_caron
2270 case XK_dead_caron :
2271 return 0xb7; /* '< */
2272 #endif
2273 #ifdef XK_dead_ogonek
2274 case XK_dead_ogonek :
2275 return 0xb2; /* '; */
2276 #endif
2277 /* FIXME: I don't know this three.
2278 case XK_dead_iota :
2279 return 'i';
2280 case XK_dead_voiced_sound :
2281 return 'v';
2282 case XK_dead_semivoiced_sound :
2283 return 's';
2286 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2287 return 0;
2290 /***********************************************************************
2291 * ToUnicodeEx (X11DRV.@)
2293 * The ToUnicode function translates the specified virtual-key code and keyboard
2294 * state to the corresponding Windows character or characters.
2296 * If the specified key is a dead key, the return value is negative. Otherwise,
2297 * it is one of the following values:
2298 * Value Meaning
2299 * 0 The specified virtual key has no translation for the current state of the keyboard.
2300 * 1 One Windows character was copied to the buffer.
2301 * 2 Two characters were copied to the buffer. This usually happens when a
2302 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2303 * be composed with the specified virtual key to form a single character.
2305 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2308 INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2309 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2311 Display *display = thread_display();
2312 XKeyEvent e;
2313 KeySym keysym = 0;
2314 INT ret;
2315 int keyc;
2316 char lpChar[10];
2317 HWND focus;
2318 XIC xic;
2319 Status status;
2321 if (scanCode & 0x8000)
2323 TRACE("Key UP, doing nothing\n" );
2324 return 0;
2327 if (hkl != X11DRV_GetKeyboardLayout(0))
2328 FIXME("keyboard layout %p is not supported\n", hkl);
2330 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2332 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2333 return 0;
2336 e.display = display;
2337 e.keycode = 0;
2338 e.state = 0;
2339 e.type = KeyPress;
2341 focus = GetFocus();
2342 if (focus) focus = GetAncestor( focus, GA_ROOT );
2343 if (!focus) focus = GetActiveWindow();
2344 e.window = X11DRV_get_whole_window( focus );
2345 xic = X11DRV_get_ic( focus );
2347 if (lpKeyState[VK_SHIFT] & 0x80)
2349 TRACE("ShiftMask = %04x\n", ShiftMask);
2350 e.state |= ShiftMask;
2352 if (lpKeyState[VK_CAPITAL] & 0x01)
2354 TRACE("LockMask = %04x\n", LockMask);
2355 e.state |= LockMask;
2357 if (lpKeyState[VK_CONTROL] & 0x80)
2359 TRACE("ControlMask = %04x\n", ControlMask);
2360 e.state |= ControlMask;
2362 if (lpKeyState[VK_NUMLOCK] & 0x01)
2364 TRACE("NumLockMask = %04x\n", NumLockMask);
2365 e.state |= NumLockMask;
2368 /* Restore saved AltGr state */
2369 TRACE("AltGrMask = %04x\n", AltGrMask);
2370 e.state |= AltGrMask;
2372 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2373 virtKey, scanCode, e.state);
2374 wine_tsx11_lock();
2375 /* We exit on the first keycode found, to speed up the thing. */
2376 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2377 { /* Find a keycode that could have generated this virtual key */
2378 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2379 { /* We filter the extended bit, we don't know it */
2380 e.keycode = keyc; /* Store it temporarily */
2381 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2382 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2383 state), so set it to 0, we'll find another one */
2388 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2389 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2391 if (virtKey==VK_DECIMAL)
2392 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2394 if (virtKey==VK_SEPARATOR)
2395 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2397 if (!e.keycode && virtKey != VK_NONAME)
2399 WARN("Unknown virtual key %X !!!\n", virtKey);
2400 wine_tsx11_unlock();
2401 return virtKey; /* whatever */
2403 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2405 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2406 e.type, e.window, e.state, e.keycode);
2408 if (xic)
2409 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, &status);
2410 else
2411 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
2412 wine_tsx11_unlock();
2414 if (ret == 0)
2416 char dead_char;
2418 #ifdef XK_EuroSign
2419 /* An ugly hack for EuroSign: X can't translate it to a character
2420 for some locales. */
2421 if (keysym == XK_EuroSign)
2423 bufW[0] = 0x20AC;
2424 ret = 1;
2425 goto found;
2427 #endif
2428 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2429 /* Here we change it back. */
2430 if (keysym == XK_ISO_Left_Tab)
2432 bufW[0] = 0x09;
2433 ret = 1;
2434 goto found;
2437 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2438 if (dead_char)
2440 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2441 ret = -1;
2443 else
2445 const char *ksname;
2447 wine_tsx11_lock();
2448 ksname = XKeysymToString(keysym);
2449 wine_tsx11_unlock();
2450 if (!ksname)
2451 ksname = "No Name";
2452 if ((keysym >> 8) != 0xff)
2454 ERR("Please report: no char for keysym %04lX (%s) :\n",
2455 keysym, ksname);
2456 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
2457 virtKey, scanCode, e.keycode, e.state);
2461 else { /* ret != 0 */
2462 /* We have a special case to handle : Shift + arrow, shift + home, ...
2463 X returns a char for it, but Windows doesn't. Let's eat it. */
2464 if (!(e.state & NumLockMask) /* NumLock is off */
2465 && (e.state & ShiftMask) /* Shift is pressed */
2466 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2468 lpChar[0] = 0;
2469 ret = 0;
2472 /* more areas where X returns characters but Windows does not
2473 CTRL + number or CTRL + symbol */
2474 if (e.state & ControlMask)
2476 if (((keysym>=33) && (keysym < 'A')) ||
2477 ((keysym > 'Z') && (keysym < 'a')))
2479 lpChar[0] = 0;
2480 ret = 0;
2484 /* We have another special case for delete key (XK_Delete) on an
2485 extended keyboard. X returns a char for it, but Windows doesn't */
2486 if (keysym == XK_Delete)
2488 lpChar[0] = 0;
2489 ret = 0;
2491 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2492 && (keysym == XK_KP_Decimal))
2494 lpChar[0] = 0;
2495 ret = 0;
2498 /* perform translation to unicode */
2499 if(ret)
2501 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2502 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2506 found:
2507 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
2508 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
2509 return ret;
2512 /***********************************************************************
2513 * Beep (X11DRV.@)
2515 void X11DRV_Beep(void)
2517 wine_tsx11_lock();
2518 XBell(thread_display(), 0);
2519 wine_tsx11_unlock();