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