po: Update simplified Chinese translation.
[wine/multimedia.git] / dlls / winex11.drv / keyboard.c
blob360c13ed207cef8234209ebcaf890edcd328c97e
1 /*
2 * X11 keyboard driver
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
35 #endif
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wingdi.h"
46 #include "winuser.h"
47 #include "winreg.h"
48 #include "winnls.h"
49 #include "x11drv.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
54 /* log format (add 0-padding as appropriate):
55 keycode %u as in output from xev
56 keysym %lx as in X11/keysymdef.h
57 vkey %X as in winuser.h
58 scancode %x
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
63 static int min_keycode, max_keycode, keysyms_per_keycode;
64 static KeySym *key_mapping;
65 static WORD keyc2vkey[256], keyc2scan[256];
67 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
69 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
71 /* Keyboard translation tables */
72 #define MAIN_LEN 49
73 static const WORD main_key_scan_qwerty[MAIN_LEN] =
75 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
76 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
77 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
78 /* q w e r t y u i o p [ ] */
79 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
80 /* a s d f g h j k l ; ' \ */
81 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
82 /* z x c v b n m , . / */
83 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
84 0x56 /* the 102nd key (actually to the right of l-shift) */
87 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
89 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
90 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
91 /* q w e r t y u i o p [ ] */
92 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
93 /* a s d f g h j k l ; ' \ */
94 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
95 /* \ z x c v b n m , . / */
96 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
97 0x56, /* the 102nd key (actually to the right of l-shift) */
100 static const WORD main_key_scan_dvorak[MAIN_LEN] =
102 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
103 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
104 /* ' , . p y f g c r l / = */
105 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
106 /* a o e u i d h t n s - \ */
107 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
108 /* ; q j k x b m w v z */
109 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
110 0x56 /* the 102nd key (actually to the right of l-shift) */
113 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
115 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
116 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
117 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
118 /* q w e r t y u i o p @ [ */
119 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
120 /* a s d f g h j k l ; : ] */
121 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
122 /* z x c v b n m , . / */
123 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
124 0x56 /* the 102nd key (actually to the right of l-shift) */
127 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
129 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
130 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
131 /* q w e r t y u i o p @ [ */
132 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
133 /* a s d f g h j k l ; : ] */
134 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
135 /* z x c v b n m , . / */
136 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
137 0x73 /* the 102nd key (actually to the right of l-shift) */
141 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
143 /* NOTE: this layout must concur with the scan codes layout above */
144 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
145 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
146 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
147 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
148 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
151 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
153 /* NOTE: this layout must concur with the scan codes layout above */
154 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
155 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
156 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
157 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
158 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
161 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
163 /* NOTE: this layout must concur with the scan codes layout above */
164 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
165 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
166 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
167 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
168 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
171 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
173 /* NOTE: this layout must concur with the scan codes layout above */
174 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
175 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
176 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
177 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
178 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
181 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
183 /* NOTE: this layout must concur with the scan codes layout above */
184 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
185 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
186 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
187 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
188 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
191 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
193 /* NOTE: this layout must concur with the scan codes layout above */
194 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
195 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
196 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
197 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
198 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
201 static const WORD main_key_vkey_azerty[MAIN_LEN] =
203 /* NOTE: this layout must concur with the scan codes layout above */
204 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
205 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
206 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
207 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
208 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
211 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
213 /* NOTE: this layout must concur with the scan codes layout above */
214 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
215 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
216 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
217 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
218 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
221 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
223 /* the VK mappings for the main keyboard will be auto-assigned as before,
224 so what we have here is just the character tables */
225 /* order: Normal, Shift, AltGr, Shift-AltGr */
226 /* We recommend you write just what is guaranteed to be correct (i.e. what's
227 written on the keycaps), not the bunch of special characters behind AltGr
228 and Shift-AltGr if it can vary among different X servers */
229 /* These tables serve to guess the keyboard type and scancode mapping.
230 Complete modeling is not important, identification/discrimination is. */
231 /* Remember that your 102nd key (to the right of l-shift) should be on a
232 separate line, see existing tables */
233 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
234 /* Remember to also add your new table to the layout index table far below! */
236 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
237 static const char main_key_US[MAIN_LEN][4] =
239 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
240 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
241 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
242 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
245 /*** United States keyboard layout (phantom key version) */
246 /* (XFree86 reports the <> key even if it's not physically there) */
247 static const char main_key_US_phantom[MAIN_LEN][4] =
249 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
250 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
251 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
252 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
253 "<>" /* the phantom key */
256 /*** United States keyboard layout (dvorak version) */
257 static const char main_key_US_dvorak[MAIN_LEN][4] =
259 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
260 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
261 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
262 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
265 /*** British keyboard layout */
266 static const char main_key_UK[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 "\\|"
275 /*** French keyboard layout (setxkbmap fr) */
276 static const char main_key_FR[MAIN_LEN][4] =
278 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
279 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
280 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
281 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
282 "<>"
285 /*** Icelandic keyboard layout (setxkbmap is) */
286 static const char main_key_IS[MAIN_LEN][4] =
288 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
289 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
290 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
291 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
292 "<>"
295 /* All german keyb layout tables have the acute/apostrophe symbol next to
296 * the BACKSPACE key removed (replaced with NULL which is ignored by the
297 * detection code).
298 * This was done because the mapping of the acute (and apostrophe) is done
299 * differently in various xkb-data/xkeyboard-config versions. Some replace
300 * the acute with a normal apostrophe, so that the apostrophe is found twice
301 * on the keyboard (one next to BACKSPACE and one next to ENTER).
302 * Others put the acute and grave accents on the key left of BACKSPACE.
303 * More information on the fd.o bugtracker:
304 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
305 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
306 * among PC and Mac keyboards, so these are not listed.
309 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
310 static const char main_key_DE[MAIN_LEN][4] =
312 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","",
313 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
314 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
315 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
316 "<>"
319 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
320 static const char main_key_SG[MAIN_LEN][4] =
322 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
323 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
325 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
326 "<>"
329 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
330 static const char main_key_SF[MAIN_LEN][4] =
332 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
333 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
334 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
335 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
336 "<>"
339 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
340 static const char main_key_NO[MAIN_LEN][4] =
342 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
343 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
344 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
345 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
346 "<>"
349 /*** Danish keyboard layout (setxkbmap dk) */
350 static const char main_key_DA[MAIN_LEN][4] =
352 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
353 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
354 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
355 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
356 "<>"
359 /*** Swedish keyboard layout (setxkbmap se) */
360 static const char main_key_SE[MAIN_LEN][4] =
362 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
363 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
364 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
365 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
366 "<>"
369 /*** Estonian keyboard layout (setxkbmap ee) */
370 static const char main_key_ET[MAIN_LEN][4] =
372 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
373 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
374 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
375 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
376 "<>"
379 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
380 static const char main_key_CF[MAIN_LEN][4] =
382 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
383 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
384 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
385 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
386 "«»°"
389 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
390 static const char main_key_CA_fr[MAIN_LEN][4] =
392 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
393 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
394 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
395 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
396 "«»"
399 /*** Canadian keyboard layout (setxkbmap ca) */
400 static const char main_key_CA[MAIN_LEN][4] =
402 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
403 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
404 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
405 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
406 "ùÙ"
409 /*** Portuguese keyboard layout (setxkbmap pt) */
410 static const char main_key_PT[MAIN_LEN][4] =
412 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
413 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
414 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
415 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
416 "<>"
419 /*** Italian keyboard layout (setxkbmap it) */
420 static const char main_key_IT[MAIN_LEN][4] =
422 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
423 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
424 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
425 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
426 "<>"
429 /*** Finnish keyboard layout (setxkbmap fi) */
430 static const char main_key_FI[MAIN_LEN][4] =
432 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
433 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
434 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
435 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
436 "<>"
439 /*** Bulgarian bds keyboard layout */
440 static const char main_key_BG_bds[MAIN_LEN][4] =
442 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
443 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
444 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
445 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
446 "<>" /* the phantom key */
449 /*** Bulgarian phonetic keyboard layout */
450 static const char main_key_BG_phonetic[MAIN_LEN][4] =
452 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
453 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
454 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
455 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
456 "<>" /* the phantom key */
459 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
460 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
461 static const char main_key_BY[MAIN_LEN][4] =
463 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
464 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
465 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
466 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
470 /*** Russian keyboard layout (contributed by Pavel Roskin) */
471 static const char main_key_RU[MAIN_LEN][4] =
473 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
474 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
475 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
476 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
479 /*** Russian keyboard layout (phantom key version) */
480 static const char main_key_RU_phantom[MAIN_LEN][4] =
482 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
483 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
484 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
485 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
486 "<>" /* the phantom key */
489 /*** Russian keyboard layout KOI8-R */
490 static const char main_key_RU_koi8r[MAIN_LEN][4] =
492 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
493 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
494 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
495 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
496 "<>" /* the phantom key */
499 /*** Russian keyboard layout cp1251 */
500 static const char main_key_RU_cp1251[MAIN_LEN][4] =
502 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
503 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
504 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
505 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
506 "<>" /* the phantom key */
509 /*** Russian phonetic keyboard layout */
510 static const char main_key_RU_phonetic[MAIN_LEN][4] =
512 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
513 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
514 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
515 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
516 "<>" /* the phantom key */
519 /*** Ukrainian keyboard layout KOI8-U */
520 static const char main_key_UA[MAIN_LEN][4] =
522 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
523 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
524 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
525 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
526 "<>" /* the phantom key */
529 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
530 /*** (as it appears on most of keyboards sold today) */
531 static const char main_key_UA_std[MAIN_LEN][4] =
533 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
534 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
535 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
536 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
537 "<>" /* the phantom key */
540 /*** Russian keyboard layout KOI8-R (pair to the previous) */
541 static const char main_key_RU_std[MAIN_LEN][4] =
543 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
544 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
545 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
546 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
547 "<>" /* the phantom key */
550 /*** Spanish keyboard layout (setxkbmap es) */
551 static const char main_key_ES[MAIN_LEN][4] =
553 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
554 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
555 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
556 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
557 "<>"
560 /*** Belgian keyboard layout ***/
561 static const char main_key_BE[MAIN_LEN][4] =
563 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
564 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
565 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
566 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
567 "<>\\"
570 /*** Hungarian keyboard layout (setxkbmap hu) */
571 static const char main_key_HU[MAIN_LEN][4] =
573 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
574 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
575 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
576 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
577 "íÍ"
580 /*** Polish (programmer's) keyboard layout ***/
581 static const char main_key_PL[MAIN_LEN][4] =
583 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
584 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
585 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
586 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
587 "<>|"
590 /*** Slovenian keyboard layout (setxkbmap si) ***/
591 static const char main_key_SI[MAIN_LEN][4] =
593 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
594 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
595 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
596 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
597 "<>"
600 /*** Serbian keyboard layout (setxkbmap sr) ***/
601 static const char main_key_SR[MAIN_LEN][4] =
603 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
604 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
605 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
606 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
607 "<>" /* the phantom key */
610 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
611 static const char main_key_US_SR[MAIN_LEN][4] =
613 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
614 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
615 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
616 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
617 "<>" /* the phantom key */
620 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
621 static const char main_key_HR_jelly[MAIN_LEN][4] =
623 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
624 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
625 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
626 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
627 "<>|"
630 /*** Croatian keyboard layout (setxkbmap hr) ***/
631 static const char main_key_HR[MAIN_LEN][4] =
633 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
634 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
635 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
636 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
637 "<>"
640 /*** Japanese 106 keyboard layout ***/
641 static const char main_key_JA_jp106[MAIN_LEN][4] =
643 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
644 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
645 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
646 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
647 "\\_",
650 static const char main_key_JA_macjp[MAIN_LEN][4] =
652 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
653 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
654 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
655 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
656 "__",
659 /*** Japanese pc98x1 keyboard layout ***/
660 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
662 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
663 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
664 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
665 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
666 "\\_",
669 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
670 static const char main_key_PT_br[MAIN_LEN][4] =
672 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
673 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
674 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
675 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
678 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
679 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
681 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
682 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
683 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
684 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
687 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
688 static const char main_key_US_intl[MAIN_LEN][4] =
690 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
691 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
692 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
693 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
696 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
697 - dead_abovering replaced with degree - no symbol in iso8859-2
698 - brokenbar replaced with bar */
699 static const char main_key_SK[MAIN_LEN][4] =
701 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
702 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
703 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
704 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
705 "<>"
708 /*** Czech keyboard layout (setxkbmap cz) */
709 static const char main_key_CZ[MAIN_LEN][4] =
711 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
712 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
713 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
714 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
715 "\\"
718 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
719 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
721 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
722 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
723 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
724 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
725 "\\"
728 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
729 static const char main_key_SK_prog[MAIN_LEN][4] =
731 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
732 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
733 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
734 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
735 "<>"
738 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
739 static const char main_key_CS[MAIN_LEN][4] =
741 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
742 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
743 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
744 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
745 "<>\\|"
748 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
749 static const char main_key_LA[MAIN_LEN][4] =
751 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
752 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
753 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
754 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
755 "<>"
758 /*** Lithuanian keyboard layout (setxkbmap lt) */
759 static const char main_key_LT_B[MAIN_LEN][4] =
761 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
762 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
763 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
764 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
765 "ª¬"
768 /*** Turkish keyboard Layout */
769 static const char main_key_TK[MAIN_LEN][4] =
771 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
772 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
773 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
774 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
777 /*** Turkish keyboard layout (setxkbmap tr) */
778 static const char main_key_TR[MAIN_LEN][4] =
780 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
781 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
782 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
783 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
784 "<>"
787 /*** Turkish F keyboard layout (setxkbmap trf) */
788 static const char main_key_TR_F[MAIN_LEN][4] =
790 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
791 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
792 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
793 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
794 "<>"
797 /*** Israelian keyboard layout (setxkbmap us,il) */
798 static const char main_key_IL[MAIN_LEN][4] =
800 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
801 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
802 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
803 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
804 "<>"
807 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
808 static const char main_key_IL_phonetic[MAIN_LEN][4] =
810 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
811 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
812 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
813 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
814 "<>"
817 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
818 static const char main_key_IL_saharon[MAIN_LEN][4] =
820 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
821 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
822 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
823 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
824 "<>"
827 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
828 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
829 message since they have different characters in gr and el XFree86 layouts. */
830 static const char main_key_EL[MAIN_LEN][4] =
832 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
833 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
834 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
835 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
836 "<>"
839 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
840 static const char main_key_th[MAIN_LEN][4] =
842 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
843 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
844 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
845 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
848 /*** VNC keyboard layout */
849 static const WORD main_key_scan_vnc[MAIN_LEN] =
851 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
852 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,
853 0x56
856 static const WORD main_key_vkey_vnc[MAIN_LEN] =
858 '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,
859 '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',
860 VK_OEM_102
863 static const char main_key_vnc[MAIN_LEN][4] =
865 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
866 "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"
869 /*** Dutch keyboard layout (setxkbmap nl) ***/
870 static const char main_key_NL[MAIN_LEN][4] =
872 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
873 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
874 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
875 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
876 "[]"
881 /*** Layout table. Add your keyboard mappings to this list */
882 static const struct {
883 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
884 in the appropriate dlls/kernel/nls/.nls file */
885 const char *comment;
886 const char (*key)[MAIN_LEN][4];
887 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
888 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
889 } main_key_tab[]={
890 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
892 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
893 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
895 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
896 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
897 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
898 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
899 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
902 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
903 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
906 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
907 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
908 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
909 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
910 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
913 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
925 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
926 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
927 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
928 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
929 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
930 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
931 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
933 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
934 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
938 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
939 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
948 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
949 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
951 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
953 {0, NULL, NULL, NULL, NULL} /* sentinel */
955 static unsigned kbd_layout=0; /* index into above table of layouts */
957 /* maybe more of these scancodes should be extended? */
958 /* extended must be set for ALT_R, CTRL_R,
959 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
960 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
961 /* FIXME should we set extended bit for NumLock ? My
962 * Windows does ... DF */
963 /* Yes, to distinguish based on scan codes, also
964 for PrtScn key ... GA */
966 static const WORD nonchar_key_vkey[256] =
968 /* unused */
969 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
970 /* special keys */
971 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
972 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
973 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
974 /* unused */
975 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
976 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
977 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
978 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
980 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
981 /* cursor keys */
982 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
983 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
984 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
985 /* misc keys */
986 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
987 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
988 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
989 /* keypad keys */
990 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
991 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
992 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
993 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
994 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
995 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
996 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
997 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
998 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
999 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1000 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1001 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1002 /* function keys */
1003 VK_F1, VK_F2,
1004 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1005 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1006 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1007 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1008 /* modifier keys */
1009 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1010 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1011 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1012 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1013 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1016 static const WORD nonchar_key_scan[256] =
1018 /* unused */
1019 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1020 /* special keys */
1021 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1022 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1023 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1024 /* unused */
1025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1031 /* cursor keys */
1032 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1034 /* misc keys */
1035 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1036 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1038 /* keypad keys */
1039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1042 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1043 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1045 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1046 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1047 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1048 /* function keys */
1049 0x3B, 0x3C,
1050 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1051 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1054 /* modifier keys */
1055 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1056 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1061 static const WORD xfree86_vendor_key_vkey[256] =
1063 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1064 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1065 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1066 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1067 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1068 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1069 0, 0, 0, VK_BROWSER_HOME,
1070 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1071 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1072 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1073 0, 0, 0, 0,
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1097 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1098 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1101 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1103 #ifdef HAVE_XKB
1104 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1105 #endif
1106 return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index];
1109 /* Returns the Windows virtual key code associated with the X event <e> */
1110 /* x11 lock must be held */
1111 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1113 KeySym keysym = 0;
1114 Status status;
1115 char buf[24];
1117 /* Clients should pass only KeyPress events to XmbLookupString */
1118 if (xic && e->type == KeyPress)
1119 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1120 else
1121 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1123 if ((e->state & NumLockMask) &&
1124 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1125 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1126 /* Only the Keypad keys 0-9 and . send different keysyms
1127 * depending on the NumLock state */
1128 return nonchar_key_vkey[keysym & 0xFF];
1130 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1131 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1132 if ((e->state & ControlMask) && (keysym == XK_Break))
1133 return VK_CANCEL;
1135 TRACE_(key)("e->keycode = %u\n", e->keycode);
1137 return keyc2vkey[e->keycode];
1141 /***********************************************************************
1142 * X11DRV_send_keyboard_input
1144 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1146 INPUT input;
1148 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1150 input.type = INPUT_KEYBOARD;
1151 input.u.ki.wVk = vkey;
1152 input.u.ki.wScan = scan;
1153 input.u.ki.dwFlags = flags;
1154 input.u.ki.time = time;
1155 input.u.ki.dwExtraInfo = 0;
1157 __wine_send_input( hwnd, &input );
1161 /***********************************************************************
1162 * get_async_key_state
1164 static BOOL get_async_key_state( BYTE state[256] )
1166 BOOL ret;
1168 SERVER_START_REQ( get_key_state )
1170 req->tid = 0;
1171 req->key = -1;
1172 wine_server_set_reply( req, state, 256 );
1173 ret = !wine_server_call( req );
1175 SERVER_END_REQ;
1176 return ret;
1179 /***********************************************************************
1180 * set_async_key_state
1182 static void set_async_key_state( const BYTE state[256] )
1184 SERVER_START_REQ( set_key_state )
1186 req->tid = GetCurrentThreadId();
1187 req->async = 1;
1188 wine_server_add_data( req, state, 256 );
1189 wine_server_call( req );
1191 SERVER_END_REQ;
1194 static void update_key_state( BYTE *keystate, BYTE key, int down )
1196 if (down)
1198 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1199 keystate[key] |= 0x80;
1201 else keystate[key] &= ~0x80;
1204 /***********************************************************************
1205 * X11DRV_KeymapNotify
1207 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1209 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1210 * from wine to another application and back.
1211 * Toggle keys are handled in HandleEvent.
1213 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1215 int i, j;
1216 BYTE keystate[256];
1217 WORD vkey;
1218 BOOL changed = FALSE;
1219 struct {
1220 WORD vkey;
1221 BOOL pressed;
1222 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1224 if (!get_async_key_state( keystate )) return;
1226 memset(modifiers, 0, sizeof(modifiers));
1228 /* the minimum keycode is always greater or equal to 8, so we can
1229 * skip the first 8 values, hence start at 1
1231 for (i = 1; i < 32; i++)
1233 for (j = 0; j < 8; j++)
1235 int m;
1237 vkey = keyc2vkey[(i * 8) + j];
1239 switch(vkey & 0xff)
1241 case VK_LMENU:
1242 case VK_RMENU:
1243 case VK_LCONTROL:
1244 case VK_RCONTROL:
1245 case VK_LSHIFT:
1246 case VK_RSHIFT:
1247 m = (vkey & 0xff) - VK_LSHIFT;
1248 /* Take the vkey from the first keycode we encounter for this modifier */
1249 if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
1250 if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1251 break;
1256 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1258 int m = vkey - VK_LSHIFT;
1259 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1261 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1262 modifiers[m].vkey, keystate[vkey]);
1264 update_key_state( keystate, vkey, modifiers[m].pressed );
1265 changed = TRUE;
1269 if (!changed) return;
1271 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1272 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1273 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1274 set_async_key_state( keystate );
1277 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1279 BYTE keystate[256];
1281 /* Note: X sets the below states on key down and clears them on key up.
1282 Windows triggers them on key down. */
1284 if (!get_async_key_state( keystate )) return;
1286 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1287 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1289 DWORD flags = 0;
1290 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1291 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1292 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1293 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1296 /* Adjust the NUMLOCK state if it has been changed outside wine */
1297 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1299 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1300 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1301 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1302 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1303 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1306 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1307 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1309 DWORD flags = 0;
1310 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1311 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1312 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1313 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1317 /***********************************************************************
1318 * X11DRV_KeyEvent
1320 * Handle a X key event
1322 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1324 XKeyEvent *event = &xev->xkey;
1325 char buf[24];
1326 char *Str = buf;
1327 KeySym keysym = 0;
1328 WORD vkey = 0, bScan;
1329 DWORD dwFlags;
1330 int ascii_chars;
1331 XIC xic = X11DRV_get_ic( hwnd );
1332 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1333 Status status = 0;
1335 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1336 event->type, event->window, event->state, event->keycode);
1338 if (event->type == KeyPress) update_user_time( event->time );
1340 wine_tsx11_lock();
1341 /* Clients should pass only KeyPress events to XmbLookupString */
1342 if (xic && event->type == KeyPress)
1344 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1345 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1346 if (status == XBufferOverflow)
1348 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1349 if (Str == NULL)
1351 ERR_(key)("Failed to allocate memory!\n");
1352 wine_tsx11_unlock();
1353 return;
1355 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1358 else
1359 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1360 wine_tsx11_unlock();
1362 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1364 if (status == XLookupChars)
1366 X11DRV_XIMLookupChars( Str, ascii_chars );
1367 if (buf != Str)
1368 HeapFree(GetProcessHeap(), 0, Str);
1369 return;
1372 /* If XKB extensions are used, the state mask for AltGr will use the group
1373 index instead of the modifier mask. The group index is set in bits
1374 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1375 pressed, look if the group index is different than 0. From XKB
1376 extension documentation, the group index for AltGr should be 2
1377 (event->state = 0x2000). It's probably better to not assume a
1378 predefined group index and find it dynamically
1380 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1381 /* Save also all possible modifier states. */
1382 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1384 if (TRACE_ON(key)){
1385 const char *ksname;
1387 wine_tsx11_lock();
1388 ksname = XKeysymToString(keysym);
1389 wine_tsx11_unlock();
1390 if (!ksname)
1391 ksname = "No Name";
1392 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1393 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1394 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1396 if (buf != Str)
1397 HeapFree(GetProcessHeap(), 0, Str);
1399 wine_tsx11_lock();
1400 vkey = EVENT_event_to_vkey(xic,event);
1401 /* X returns keycode 0 for composed characters */
1402 if (!vkey && ascii_chars) vkey = VK_NONAME;
1403 wine_tsx11_unlock();
1405 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1406 event->keycode, vkey);
1408 if (!vkey) return;
1410 dwFlags = 0;
1411 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1412 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1414 update_lock_state( hwnd, vkey, event->state, event_time );
1416 bScan = keyc2scan[event->keycode] & 0xFF;
1417 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1419 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1422 /**********************************************************************
1423 * X11DRV_KEYBOARD_DetectLayout
1425 * Called from X11DRV_InitKeyboard
1426 * This routine walks through the defined keyboard layouts and selects
1427 * whichever matches most closely.
1428 * X11 lock must be held.
1430 static void
1431 X11DRV_KEYBOARD_DetectLayout( Display *display )
1433 unsigned current, match, mismatch, seq, i, syms;
1434 int score, keyc, key, pkey, ok;
1435 KeySym keysym = 0;
1436 const char (*lkey)[MAIN_LEN][4];
1437 unsigned max_seq = 0;
1438 int max_score = 0, ismatch = 0;
1439 char ckey[256][4];
1441 syms = keysyms_per_keycode;
1442 if (syms > 4) {
1443 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1444 syms = 4;
1447 memset( ckey, 0, sizeof(ckey) );
1448 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1449 /* get data for keycode from X server */
1450 for (i = 0; i < syms; i++) {
1451 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1452 /* Allow both one-byte and two-byte national keysyms */
1453 if ((keysym < 0x8000) && (keysym != ' '))
1455 #ifdef HAVE_XKB
1456 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1457 #endif
1459 TRACE("XKB could not translate keysym %04lx\n", keysym);
1460 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1461 * with appropriate ShiftMask and Mode_switch, use XLookupString
1462 * to get character in the local encoding.
1464 ckey[keyc][i] = keysym & 0xFF;
1467 else {
1468 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1473 for (current = 0; main_key_tab[current].comment; current++) {
1474 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1475 match = 0;
1476 mismatch = 0;
1477 score = 0;
1478 seq = 0;
1479 lkey = main_key_tab[current].key;
1480 pkey = -1;
1481 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1482 if (ckey[keyc][0]) {
1483 /* search for a match in layout table */
1484 /* right now, we just find an absolute match for defined positions */
1485 /* (undefined positions are ignored, so if it's defined as "3#" in */
1486 /* the table, it's okay that the X server has "3#£", for example) */
1487 /* however, the score will be higher for longer matches */
1488 for (key = 0; key < MAIN_LEN; key++) {
1489 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1490 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1491 ok++;
1492 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1493 ok = -1;
1495 if (ok > 0) {
1496 score += ok;
1497 break;
1500 /* count the matches and mismatches */
1501 if (ok > 0) {
1502 match++;
1503 /* and how much the keycode order matches */
1504 if (key > pkey) seq++;
1505 pkey = key;
1506 } else {
1507 /* print spaces instead of \0's */
1508 char str[5];
1509 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1510 str[4] = 0;
1511 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1512 mismatch++;
1513 score -= syms;
1517 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1518 match, mismatch, seq, score);
1519 if ((score > max_score) ||
1520 ((score == max_score) && (seq > max_seq))) {
1521 /* best match so far */
1522 kbd_layout = current;
1523 max_score = score;
1524 max_seq = seq;
1525 ismatch = !mismatch;
1528 /* we're done, report results if necessary */
1529 if (!ismatch)
1530 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1531 main_key_tab[kbd_layout].comment);
1533 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1536 static HKL get_locale_kbd_layout(void)
1538 ULONG_PTR layout;
1539 LANGID langid;
1541 /* FIXME:
1543 * layout = main_key_tab[kbd_layout].lcid;
1545 * Winword uses return value of GetKeyboardLayout as a codepage
1546 * to translate ANSI keyboard messages to unicode. But we have
1547 * a problem with it: for instance Polish keyboard layout is
1548 * identical to the US one, and therefore instead of the Polish
1549 * locale id we return the US one.
1552 layout = GetUserDefaultLCID();
1555 * Microsoft Office expects this value to be something specific
1556 * for Japanese and Korean Windows with an IME the value is 0xe001
1557 * We should probably check to see if an IME exists and if so then
1558 * set this word properly.
1560 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1561 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1562 layout |= 0xe001 << 16; /* IME */
1563 else
1564 layout |= layout << 16;
1566 return (HKL)layout;
1569 /***********************************************************************
1570 * GetKeyboardLayoutName (X11DRV.@)
1572 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1574 static const WCHAR formatW[] = {'%','0','8','x',0};
1575 DWORD layout;
1577 layout = HandleToUlong( get_locale_kbd_layout() );
1578 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1579 sprintfW(name, formatW, layout);
1580 TRACE("returning %s\n", debugstr_w(name));
1581 return TRUE;
1584 static void set_kbd_layout_preload_key(void)
1586 static const WCHAR preload[] =
1587 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1588 static const WCHAR one[] = {'1',0};
1590 HKEY hkey;
1591 WCHAR layout[KL_NAMELENGTH];
1593 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1594 return;
1596 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1598 RegCloseKey(hkey);
1599 return;
1601 if (X11DRV_GetKeyboardLayoutName(layout))
1602 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1604 RegCloseKey(hkey);
1607 /**********************************************************************
1608 * X11DRV_InitKeyboard
1610 void X11DRV_InitKeyboard( Display *display )
1612 XModifierKeymap *mmp;
1613 KeySym keysym;
1614 KeyCode *kcp;
1615 XKeyEvent e2;
1616 WORD scan, vkey;
1617 int keyc, i, keyn, syms;
1618 char ckey[4]={0,0,0,0};
1619 const char (*lkey)[MAIN_LEN][4];
1620 char vkey_used[256] = { 0 };
1622 /* Ranges of OEM, function key, and character virtual key codes.
1623 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1624 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1625 static const struct {
1626 WORD first, last;
1627 } vkey_ranges[] = {
1628 { VK_OEM_1, VK_OEM_3 },
1629 { VK_OEM_4, VK_ICO_00 },
1630 { 0xe6, 0xe6 },
1631 { 0xe9, 0xf5 },
1632 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1633 { VK_F1, VK_F24 },
1634 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1635 { 0x41, 0x5a }, /* VK_A - VK_Z */
1636 { 0, 0 }
1638 int vkey_range;
1640 set_kbd_layout_preload_key();
1642 wine_tsx11_lock();
1643 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1644 if (key_mapping) XFree( key_mapping );
1645 key_mapping = XGetKeyboardMapping(display, min_keycode,
1646 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1648 mmp = XGetModifierMapping(display);
1649 kcp = mmp->modifiermap;
1650 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1652 int j;
1654 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1655 if (*kcp)
1657 int k;
1659 for (k = 0; k < keysyms_per_keycode; k += 1)
1660 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1662 NumLockMask = 1 << i;
1663 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1665 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1667 ScrollLockMask = 1 << i;
1668 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1672 XFreeModifiermap(mmp);
1674 /* Detect the keyboard layout */
1675 X11DRV_KEYBOARD_DetectLayout( display );
1676 lkey = main_key_tab[kbd_layout].key;
1677 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1679 /* Now build two conversion arrays :
1680 * keycode -> vkey + scancode + extended
1681 * vkey + extended -> keycode */
1683 e2.display = display;
1684 e2.state = 0;
1685 e2.type = KeyPress;
1687 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1688 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1690 char buf[30];
1691 int have_chars;
1693 keysym = 0;
1694 e2.keycode = (KeyCode)keyc;
1695 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1696 vkey = 0; scan = 0;
1697 if (keysym) /* otherwise, keycode not used */
1699 if ((keysym >> 8) == 0xFF) /* non-character key */
1701 vkey = nonchar_key_vkey[keysym & 0xff];
1702 scan = nonchar_key_scan[keysym & 0xff];
1703 /* set extended bit when necessary */
1704 if (scan & 0x100) vkey |= 0x100;
1705 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1706 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1707 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1708 scan = 0x100;
1709 vkey |= 0x100;
1710 } else if (keysym == 0x20) { /* Spacebar */
1711 vkey = VK_SPACE;
1712 scan = 0x39;
1713 } else if (have_chars) {
1714 /* we seem to need to search the layout-dependent scancodes */
1715 int maxlen=0,maxval=-1,ok;
1716 for (i=0; i<syms; i++) {
1717 keysym = keycode_to_keysym(display, keyc, i);
1718 if ((keysym<0x8000) && (keysym!=' '))
1720 #ifdef HAVE_XKB
1721 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1722 #endif
1724 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1725 * with appropriate ShiftMask and Mode_switch, use XLookupString
1726 * to get character in the local encoding.
1728 ckey[i] = keysym & 0xFF;
1730 } else {
1731 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1734 /* find key with longest match streak */
1735 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1736 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1737 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1738 if (!ok) i--; /* we overshot */
1739 if (ok||(i>maxlen)) {
1740 maxlen=i; maxval=keyn;
1742 if (ok) break;
1744 if (maxval>=0) {
1745 /* got it */
1746 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1747 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1748 scan = (*lscan)[maxval];
1749 vkey = (*lvkey)[maxval];
1753 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1754 keyc2vkey[e2.keycode] = vkey;
1755 keyc2scan[e2.keycode] = scan;
1756 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1757 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1758 vkey_used[(vkey & 0xff)] = 1;
1759 } /* for */
1761 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1762 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1764 vkey = keyc2vkey[keyc] & 0xff;
1765 if (vkey)
1766 continue;
1768 e2.keycode = (KeyCode)keyc;
1769 keysym = XLookupKeysym(&e2, 0);
1770 if (!keysym)
1771 continue;
1773 /* find a suitable layout-dependent VK code */
1774 /* (most Winelib apps ought to be able to work without layout tables!) */
1775 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1777 keysym = XLookupKeysym(&e2, i);
1778 if ((keysym >= XK_0 && keysym <= XK_9)
1779 || (keysym >= XK_A && keysym <= XK_Z)) {
1780 vkey = VKEY_IF_NOT_USED(keysym);
1784 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1786 keysym = XLookupKeysym(&e2, i);
1787 switch (keysym)
1789 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1790 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1791 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1792 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1793 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1794 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1795 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1796 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1797 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1798 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1799 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1803 if (vkey)
1805 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1806 keyc2vkey[e2.keycode] = vkey;
1808 } /* for */
1810 /* For any keycodes which still don't have a vkey, assign any spare
1811 * character, function key, or OEM virtual key code. */
1812 vkey_range = 0;
1813 vkey = vkey_ranges[vkey_range].first;
1814 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1816 if (keyc2vkey[keyc] & 0xff)
1817 continue;
1819 e2.keycode = (KeyCode)keyc;
1820 keysym = XLookupKeysym(&e2, 0);
1821 if (!keysym)
1822 continue;
1824 while (vkey && vkey_used[vkey])
1826 if (vkey == vkey_ranges[vkey_range].last)
1828 vkey_range++;
1829 vkey = vkey_ranges[vkey_range].first;
1831 else
1832 vkey++;
1835 if (!vkey)
1837 WARN("No more vkeys available!\n");
1838 break;
1841 if (TRACE_ON(keyboard))
1843 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1844 vkey, e2.keycode);
1845 TRACE("(");
1846 for (i = 0; i < keysyms_per_keycode; i += 1)
1848 const char *ksname;
1850 keysym = XLookupKeysym(&e2, i);
1851 ksname = XKeysymToString(keysym);
1852 if (!ksname)
1853 ksname = "NoSymbol";
1854 TRACE( "%lx (%s) ", keysym, ksname);
1856 TRACE(")\n");
1859 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1860 keyc2vkey[e2.keycode] = vkey;
1861 vkey_used[vkey] = 1;
1862 } /* for */
1863 #undef VKEY_IF_NOT_USED
1865 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1866 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1867 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1868 const char *ksname;
1869 keysym = keycode_to_keysym(display, keyc, 0);
1870 ksname = XKeysymToString(keysym);
1871 if (!ksname) ksname = "NoSymbol";
1873 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1875 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1876 keyc2scan[keyc]=scan++;
1879 wine_tsx11_unlock();
1882 static BOOL match_x11_keyboard_layout(HKL hkl)
1884 const DWORD isIME = 0xE0000000;
1885 HKL xHkl = get_locale_kbd_layout();
1887 /* if the layout is an IME, only match the low word (LCID) */
1888 if (((ULONG_PTR)hkl & isIME) == isIME)
1889 return (LOWORD(hkl) == LOWORD(xHkl));
1890 else
1891 return (hkl == xHkl);
1894 /**********************************************************************
1895 * GetAsyncKeyState (X11DRV.@)
1897 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1899 /* Photoshop livelocks unless mouse events are included here */
1900 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1901 return -1;
1905 /***********************************************************************
1906 * GetKeyboardLayout (X11DRV.@)
1908 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1910 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1912 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1913 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1915 else
1916 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1918 return get_locale_kbd_layout();
1922 /***********************************************************************
1923 * LoadKeyboardLayout (X11DRV.@)
1925 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1927 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1929 return 0;
1933 /***********************************************************************
1934 * UnloadKeyboardLayout (X11DRV.@)
1936 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1938 FIXME("%p: stub!\n", hkl);
1939 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1940 return FALSE;
1944 /***********************************************************************
1945 * ActivateKeyboardLayout (X11DRV.@)
1947 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1949 HKL oldHkl = 0;
1950 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1952 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1953 if (flags & KLF_SETFORPROCESS)
1955 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1956 FIXME("KLF_SETFORPROCESS not supported\n");
1957 return 0;
1960 if (flags)
1961 FIXME("flags %x not supported\n",flags);
1963 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1965 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1966 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1967 return 0;
1970 if (!match_x11_keyboard_layout(hkl))
1972 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1973 FIXME("setting keyboard of different locales not supported\n");
1974 return 0;
1977 oldHkl = thread_data->kbd_layout;
1978 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1980 thread_data->kbd_layout = hkl;
1982 return oldHkl;
1986 /***********************************************************************
1987 * X11DRV_MappingNotify
1989 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1991 HWND hwnd;
1993 wine_tsx11_lock();
1994 XRefreshKeyboardMapping(&event->xmapping);
1995 wine_tsx11_unlock();
1996 X11DRV_InitKeyboard( event->xmapping.display );
1998 hwnd = GetFocus();
1999 if (!hwnd) hwnd = GetActiveWindow();
2000 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2001 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2005 /***********************************************************************
2006 * VkKeyScanEx (X11DRV.@)
2008 * Note: Windows ignores HKL parameter and uses current active layout instead
2010 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2012 Display *display = thread_init_display();
2013 KeyCode keycode;
2014 KeySym keysym;
2015 int i, index;
2016 CHAR cChar;
2017 SHORT ret;
2019 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2020 * is UTF-8 (multibyte encoding)?
2022 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2024 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2025 return -1;
2028 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2030 /* char->keysym (same for ANSI chars) */
2031 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2032 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2034 wine_tsx11_lock();
2035 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2036 if (!keycode)
2038 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2040 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2041 TRACE(" ... returning ctrl char %#.2x\n", ret);
2042 wine_tsx11_unlock();
2043 return ret;
2045 /* It didn't work ... let's try with deadchar code. */
2046 TRACE("retrying with | 0xFE00\n");
2047 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2049 wine_tsx11_unlock();
2051 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2053 /* keycode -> (keyc2vkey) vkey */
2054 ret = keyc2vkey[keycode];
2056 if (!keycode || !ret)
2058 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2059 return -1;
2062 index = -1;
2063 wine_tsx11_lock();
2064 for (i = 0; i < 4; i++) /* find shift state */
2066 if (keycode_to_keysym(display, keycode, i) == keysym)
2068 index = i;
2069 break;
2072 wine_tsx11_unlock();
2074 switch (index)
2076 default:
2077 case -1:
2078 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2079 return -1;
2081 case 0: break;
2082 case 1: ret += 0x0100; break;
2083 case 2: ret += 0x0600; break;
2084 case 3: ret += 0x0700; break;
2087 index : 0 adds 0x0000
2088 index : 1 adds 0x0100 (shift)
2089 index : ? adds 0x0200 (ctrl)
2090 index : 2 adds 0x0600 (ctrl+alt)
2091 index : 3 adds 0x0700 (ctrl+alt+shift)
2094 TRACE(" ... returning %#.2x\n", ret);
2095 return ret;
2098 /***********************************************************************
2099 * MapVirtualKeyEx (X11DRV.@)
2101 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2103 Display *display = thread_init_display();
2105 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2107 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2108 if (!match_x11_keyboard_layout(hkl))
2109 FIXME("keyboard layout %p is not supported\n", hkl);
2111 switch(wMapType)
2113 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2114 case MAPVK_VK_TO_VSC_EX:
2116 int keyc;
2118 switch (wCode)
2120 case VK_SHIFT: wCode = VK_LSHIFT; break;
2121 case VK_CONTROL: wCode = VK_LCONTROL; break;
2122 case VK_MENU: wCode = VK_LMENU; break;
2125 /* let's do vkey -> keycode -> scan */
2126 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2127 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2129 if (keyc > max_keycode)
2131 TRACE("returning no scan-code.\n");
2132 return 0;
2134 returnMVK (keyc2scan[keyc] & 0xFF);
2136 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2137 case MAPVK_VSC_TO_VK_EX:
2139 int keyc;
2140 UINT vkey = 0;
2142 /* let's do scan -> keycode -> vkey */
2143 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2144 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2146 vkey = keyc2vkey[keyc] & 0xFF;
2147 /* Only stop if it's not a numpad vkey; otherwise keep
2148 looking for a potential better vkey. */
2149 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2150 break;
2153 if (vkey == 0)
2155 TRACE("returning no vkey-code.\n");
2156 return 0;
2159 if (wMapType == MAPVK_VSC_TO_VK)
2160 switch (vkey)
2162 case VK_LSHIFT:
2163 case VK_RSHIFT:
2164 vkey = VK_SHIFT; break;
2165 case VK_LCONTROL:
2166 case VK_RCONTROL:
2167 vkey = VK_CONTROL; break;
2168 case VK_LMENU:
2169 case VK_RMENU:
2170 vkey = VK_MENU; break;
2173 returnMVK (vkey);
2175 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2177 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2178 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2179 * key.. Looks like something is wrong with the MS docs?
2180 * This is only true for letters, for example VK_0 returns '0' not ')'.
2181 * - hence we use the lock mask to ensure this happens.
2183 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2184 XKeyEvent e;
2185 KeySym keysym;
2186 int keyc, len;
2187 char s[10];
2189 e.display = display;
2190 e.state = 0;
2191 e.keycode = 0;
2192 e.type = KeyPress;
2194 wine_tsx11_lock();
2196 /* We exit on the first keycode found, to speed up the thing. */
2197 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2198 { /* Find a keycode that could have generated this virtual key */
2199 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2200 { /* We filter the extended bit, we don't know it */
2201 e.keycode = keyc; /* Store it temporarily */
2202 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2203 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2204 state), so set it to 0, we'll find another one */
2209 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2210 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2212 if (wCode==VK_DECIMAL)
2213 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2215 if (!e.keycode)
2217 WARN("Unknown virtual key %X !!!\n", wCode);
2218 wine_tsx11_unlock();
2219 return 0; /* whatever */
2221 TRACE("Found keycode %u\n",e.keycode);
2223 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2224 wine_tsx11_unlock();
2226 if (len)
2228 WCHAR wch;
2229 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2230 returnMVK(toupperW(wch));
2232 TRACE("returning no ANSI.\n");
2233 return 0;
2235 default: /* reserved */
2236 FIXME("Unknown wMapType %d !\n", wMapType);
2237 return 0;
2239 return 0;
2242 /***********************************************************************
2243 * GetKeyNameText (X11DRV.@)
2245 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2247 Display *display = thread_init_display();
2248 int vkey, ansi, scanCode;
2249 KeyCode keyc;
2250 int keyi;
2251 KeySym keys;
2252 char *name;
2254 scanCode = lParam >> 16;
2255 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2257 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2259 /* handle "don't care" bit (0x02000000) */
2260 if (!(lParam & 0x02000000)) {
2261 switch (vkey) {
2262 case VK_RSHIFT:
2263 /* R-Shift is "special" - it is an extended key with separate scan code */
2264 scanCode |= 0x100;
2265 /* fall through */
2266 case VK_LSHIFT:
2267 vkey = VK_SHIFT;
2268 break;
2269 case VK_LCONTROL:
2270 case VK_RCONTROL:
2271 vkey = VK_CONTROL;
2272 break;
2273 case VK_LMENU:
2274 case VK_RMENU:
2275 vkey = VK_MENU;
2276 break;
2280 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2281 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2283 /* first get the name of the "regular" keys which is the Upper case
2284 value of the keycap imprint. */
2285 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2286 (scanCode != 0x137) && /* PrtScn */
2287 (scanCode != 0x135) && /* numpad / */
2288 (scanCode != 0x37 ) && /* numpad * */
2289 (scanCode != 0x4a ) && /* numpad - */
2290 (scanCode != 0x4e ) ) /* numpad + */
2292 if (nSize >= 2)
2294 *lpBuffer = toupperW((WCHAR)ansi);
2295 *(lpBuffer+1) = 0;
2296 return 1;
2298 else
2299 return 0;
2302 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2303 without "extended-key" flag. However Wine generates scancode
2304 *with* "extended-key" flag. Seems to occur *only* for the
2305 function keys. Soooo.. We will leave the table alone and
2306 fudge the lookup here till the other part is found and fixed!!! */
2308 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2309 (scanCode == 0x157) || (scanCode == 0x158))
2310 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2312 /* let's do scancode -> keycode -> keysym -> String */
2314 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2315 if ((keyc2scan[keyi]) == scanCode)
2316 break;
2317 if (keyi <= max_keycode)
2319 INT rc;
2321 wine_tsx11_lock();
2322 keyc = (KeyCode) keyi;
2323 keys = keycode_to_keysym(display, keyc, 0);
2324 name = XKeysymToString(keys);
2325 wine_tsx11_unlock();
2327 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2329 char* idx = strrchr(name, '_');
2330 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2332 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2333 scanCode, keyc, keys, debugstr_an(name,idx-name));
2334 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2335 if (!rc) rc = nSize;
2336 lpBuffer[--rc] = 0;
2337 return rc;
2341 if (name)
2343 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2344 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2345 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2346 if (!rc) rc = nSize;
2347 lpBuffer[--rc] = 0;
2348 return rc;
2352 /* Finally issue WARN for unknown keys */
2354 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2355 *lpBuffer = 0;
2356 return 0;
2359 /***********************************************************************
2360 * X11DRV_KEYBOARD_MapDeadKeysym
2362 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2364 switch (keysym)
2366 /* symbolic ASCII is the same as defined in rfc1345 */
2367 #ifdef XK_dead_tilde
2368 case XK_dead_tilde :
2369 #endif
2370 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2371 return '~'; /* '? */
2372 #ifdef XK_dead_acute
2373 case XK_dead_acute :
2374 #endif
2375 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2376 return 0xb4; /* '' */
2377 #ifdef XK_dead_circumflex
2378 case XK_dead_circumflex:
2379 #endif
2380 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2381 return '^'; /* '> */
2382 #ifdef XK_dead_grave
2383 case XK_dead_grave :
2384 #endif
2385 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2386 return '`'; /* '! */
2387 #ifdef XK_dead_diaeresis
2388 case XK_dead_diaeresis :
2389 #endif
2390 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2391 return 0xa8; /* ': */
2392 #ifdef XK_dead_cedilla
2393 case XK_dead_cedilla :
2394 return 0xb8; /* ', */
2395 #endif
2396 #ifdef XK_dead_macron
2397 case XK_dead_macron :
2398 return '-'; /* 'm isn't defined on iso-8859-x */
2399 #endif
2400 #ifdef XK_dead_breve
2401 case XK_dead_breve :
2402 return 0xa2; /* '( */
2403 #endif
2404 #ifdef XK_dead_abovedot
2405 case XK_dead_abovedot :
2406 return 0xff; /* '. */
2407 #endif
2408 #ifdef XK_dead_abovering
2409 case XK_dead_abovering :
2410 return '0'; /* '0 isn't defined on iso-8859-x */
2411 #endif
2412 #ifdef XK_dead_doubleacute
2413 case XK_dead_doubleacute :
2414 return 0xbd; /* '" */
2415 #endif
2416 #ifdef XK_dead_caron
2417 case XK_dead_caron :
2418 return 0xb7; /* '< */
2419 #endif
2420 #ifdef XK_dead_ogonek
2421 case XK_dead_ogonek :
2422 return 0xb2; /* '; */
2423 #endif
2424 /* FIXME: I don't know this three.
2425 case XK_dead_iota :
2426 return 'i';
2427 case XK_dead_voiced_sound :
2428 return 'v';
2429 case XK_dead_semivoiced_sound :
2430 return 's';
2433 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2434 return 0;
2437 /***********************************************************************
2438 * ToUnicodeEx (X11DRV.@)
2440 * The ToUnicode function translates the specified virtual-key code and keyboard
2441 * state to the corresponding Windows character or characters.
2443 * If the specified key is a dead key, the return value is negative. Otherwise,
2444 * it is one of the following values:
2445 * Value Meaning
2446 * 0 The specified virtual key has no translation for the current state of the keyboard.
2447 * 1 One Windows character was copied to the buffer.
2448 * 2 Two characters were copied to the buffer. This usually happens when a
2449 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2450 * be composed with the specified virtual key to form a single character.
2452 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2455 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2456 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2458 Display *display = thread_init_display();
2459 XKeyEvent e;
2460 KeySym keysym = 0;
2461 INT ret;
2462 int keyc;
2463 char buf[10];
2464 char *lpChar = buf;
2465 HWND focus;
2466 XIC xic;
2467 Status status = 0;
2469 if (scanCode & 0x8000)
2471 TRACE_(key)("Key UP, doing nothing\n" );
2472 return 0;
2475 if (!match_x11_keyboard_layout(hkl))
2476 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2478 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2480 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2481 return 0;
2484 e.display = display;
2485 e.keycode = 0;
2486 e.state = 0;
2487 e.type = KeyPress;
2489 focus = x11drv_thread_data()->last_xic_hwnd;
2490 if (!focus)
2492 focus = GetFocus();
2493 if (focus) focus = GetAncestor( focus, GA_ROOT );
2494 if (!focus) focus = GetActiveWindow();
2496 e.window = X11DRV_get_whole_window( focus );
2497 xic = X11DRV_get_ic( focus );
2499 if (lpKeyState[VK_SHIFT] & 0x80)
2501 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2502 e.state |= ShiftMask;
2504 if (lpKeyState[VK_CAPITAL] & 0x01)
2506 TRACE_(key)("LockMask = %04x\n", LockMask);
2507 e.state |= LockMask;
2509 if (lpKeyState[VK_CONTROL] & 0x80)
2511 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2512 e.state |= ControlMask;
2514 if (lpKeyState[VK_NUMLOCK] & 0x01)
2516 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2517 e.state |= NumLockMask;
2520 /* Restore saved AltGr state */
2521 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2522 e.state |= AltGrMask;
2524 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2525 virtKey, scanCode, e.state);
2526 wine_tsx11_lock();
2527 /* We exit on the first keycode found, to speed up the thing. */
2528 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2529 { /* Find a keycode that could have generated this virtual key */
2530 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2531 { /* We filter the extended bit, we don't know it */
2532 e.keycode = keyc; /* Store it temporarily */
2533 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2534 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2535 state), so set it to 0, we'll find another one */
2540 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2541 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2543 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2544 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2546 if (virtKey==VK_DECIMAL)
2547 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2549 if (virtKey==VK_SEPARATOR)
2550 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2552 if (!e.keycode && virtKey != VK_NONAME)
2554 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2555 wine_tsx11_unlock();
2556 return 0;
2558 else TRACE_(key)("Found keycode %u\n",e.keycode);
2560 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2561 e.type, e.window, e.state, e.keycode);
2563 /* Clients should pass only KeyPress events to XmbLookupString,
2564 * e.type was set to KeyPress above.
2566 if (xic)
2568 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2569 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2570 if (status == XBufferOverflow)
2572 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2573 if (lpChar == NULL)
2575 ERR_(key)("Failed to allocate memory!\n");
2576 wine_tsx11_unlock();
2577 return 0;
2579 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2582 else
2583 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2584 wine_tsx11_unlock();
2586 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2588 if (TRACE_ON(key))
2590 const char *ksname;
2592 wine_tsx11_lock();
2593 ksname = XKeysymToString(keysym);
2594 wine_tsx11_unlock();
2595 if (!ksname) ksname = "No Name";
2596 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2597 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2598 keysym, ksname, ret, debugstr_an(lpChar, ret));
2601 if (ret == 0)
2603 char dead_char;
2605 #ifdef XK_EuroSign
2606 /* An ugly hack for EuroSign: X can't translate it to a character
2607 for some locales. */
2608 if (keysym == XK_EuroSign)
2610 bufW[0] = 0x20AC;
2611 ret = 1;
2612 goto found;
2614 #endif
2615 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2616 /* Here we change it back. */
2617 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2619 bufW[0] = 0x09;
2620 ret = 1;
2621 goto found;
2624 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2625 if (dead_char)
2627 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2628 ret = -1;
2629 goto found;
2632 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2634 /* Unicode direct mapping */
2635 bufW[0] = keysym & 0xffff;
2636 ret = 1;
2637 goto found;
2639 else if ((keysym >> 8) == 0x1008FF) {
2640 bufW[0] = 0;
2641 ret = 0;
2642 goto found;
2644 else
2646 const char *ksname;
2648 wine_tsx11_lock();
2649 ksname = XKeysymToString(keysym);
2650 wine_tsx11_unlock();
2651 if (!ksname)
2652 ksname = "No Name";
2653 if ((keysym >> 8) != 0xff)
2655 WARN_(key)("no char for keysym %04lx (%s) :\n",
2656 keysym, ksname);
2657 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2658 virtKey, scanCode, e.keycode, e.state);
2662 else { /* ret != 0 */
2663 /* We have a special case to handle : Shift + arrow, shift + home, ...
2664 X returns a char for it, but Windows doesn't. Let's eat it. */
2665 if (!(e.state & NumLockMask) /* NumLock is off */
2666 && (e.state & ShiftMask) /* Shift is pressed */
2667 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2669 lpChar[0] = 0;
2670 ret = 0;
2673 /* more areas where X returns characters but Windows does not
2674 CTRL + number or CTRL + symbol */
2675 if (e.state & ControlMask)
2677 if (((keysym>=33) && (keysym < 'A')) ||
2678 ((keysym > 'Z') && (keysym < 'a')) ||
2679 (keysym == XK_Tab))
2681 lpChar[0] = 0;
2682 ret = 0;
2686 /* We have another special case for delete key (XK_Delete) on an
2687 extended keyboard. X returns a char for it, but Windows doesn't */
2688 if (keysym == XK_Delete)
2690 lpChar[0] = 0;
2691 ret = 0;
2693 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2694 && (keysym == XK_KP_Decimal))
2696 lpChar[0] = 0;
2697 ret = 0;
2699 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2700 && (keysym == XK_Return || keysym == XK_KP_Enter))
2702 lpChar[0] = '\n';
2703 ret = 1;
2706 /* Hack to detect an XLookupString hard-coded to Latin1 */
2707 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2709 bufW[0] = (BYTE)lpChar[0];
2710 goto found;
2713 /* perform translation to unicode */
2714 if(ret)
2716 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2717 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2721 found:
2722 if (buf != lpChar)
2723 HeapFree(GetProcessHeap(), 0, lpChar);
2725 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2726 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2727 if (1 <= ret && ret < bufW_size)
2728 bufW[ret] = 0;
2730 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2731 return ret;
2734 /***********************************************************************
2735 * Beep (X11DRV.@)
2737 void CDECL X11DRV_Beep(void)
2739 wine_tsx11_lock();
2740 XBell(gdi_display, 0);
2741 wine_tsx11_unlock();