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
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
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
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
63 static int min_keycode, max_keycode, keysyms_per_keycode;
64 static WORD keyc2vkey[256], keyc2scan[256];
66 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
68 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
70 /* Keyboard translation tables */
72 static const WORD main_key_scan_qwerty[MAIN_LEN] =
74 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
75 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
76 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
77 /* q w e r t y u i o p [ ] */
78 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
79 /* a s d f g h j k l ; ' \ */
80 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
81 /* z x c v b n m , . / */
82 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
83 0x56 /* the 102nd key (actually to the right of l-shift) */
86 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
88 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
89 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
90 /* q w e r t y u i o p [ ] */
91 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
92 /* a s d f g h j k l ; ' \ */
93 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
94 /* \ z x c v b n m , . / */
95 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
96 0x56, /* the 102nd key (actually to the right of l-shift) */
99 static const WORD main_key_scan_dvorak[MAIN_LEN] =
101 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
102 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
103 /* ' , . p y f g c r l / = */
104 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
105 /* a o e u i d h t n s - \ */
106 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
107 /* ; q j k x b m w v z */
108 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
109 0x56 /* the 102nd key (actually to the right of l-shift) */
112 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
114 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
115 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
116 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
117 /* q w e r t y u i o p @ [ */
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
119 /* a s d f g h j k l ; : ] */
120 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
121 /* z x c v b n m , . / */
122 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
123 0x56 /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
128 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
129 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
130 /* q w e r t y u i o p @ [ */
131 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
132 /* a s d f g h j k l ; : ] */
133 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
134 /* z x c v b n m , . / */
135 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
136 0x73 /* the 102nd key (actually to the right of l-shift) */
140 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
142 /* NOTE: this layout must concur with the scan codes layout above */
143 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
144 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
145 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
146 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
147 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
150 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
154 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
155 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
156 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
157 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
160 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
162 /* NOTE: this layout must concur with the scan codes layout above */
163 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
164 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
166 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
167 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
170 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
176 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
177 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
184 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
185 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
186 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
187 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
192 /* NOTE: this layout must concur with the scan codes layout above */
193 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
194 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
195 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
196 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
197 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
200 static const WORD main_key_vkey_azerty[MAIN_LEN] =
202 /* NOTE: this layout must concur with the scan codes layout above */
203 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
204 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
205 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
206 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
207 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
210 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
212 /* NOTE: this layout must concur with the scan codes layout above */
213 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
214 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
215 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
216 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
217 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
220 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
222 /* the VK mappings for the main keyboard will be auto-assigned as before,
223 so what we have here is just the character tables */
224 /* order: Normal, Shift, AltGr, Shift-AltGr */
225 /* We recommend you write just what is guaranteed to be correct (i.e. what's
226 written on the keycaps), not the bunch of special characters behind AltGr
227 and Shift-AltGr if it can vary among different X servers */
228 /* These tables serve to guess the keyboard type and scancode mapping.
229 Complete modeling is not important, identification/discrimination is. */
230 /* Remember that your 102nd key (to the right of l-shift) should be on a
231 separate line, see existing tables */
232 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
233 /* Remember to also add your new table to the layout index table far below! */
235 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
236 static const char main_key_US[MAIN_LEN][4] =
238 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
239 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
240 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
241 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
244 /*** United States keyboard layout (phantom key version) */
245 /* (XFree86 reports the <> key even if it's not physically there) */
246 static const char main_key_US_phantom[MAIN_LEN][4] =
248 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
249 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
251 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
252 "<>" /* the phantom key */
255 /*** United States keyboard layout (dvorak version) */
256 static const char main_key_US_dvorak[MAIN_LEN][4] =
258 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
259 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
260 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
261 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
264 /*** British keyboard layout */
265 static const char main_key_UK[MAIN_LEN][4] =
267 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
268 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
269 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
270 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
274 /*** French keyboard layout (setxkbmap fr) */
275 static const char main_key_FR[MAIN_LEN][4] =
277 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
278 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
279 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
280 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
284 /*** Icelandic keyboard layout (setxkbmap is) */
285 static const char main_key_IS[MAIN_LEN][4] =
287 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
288 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
290 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
294 /* All german keyb layout tables have the acute/apostrophe symbol next to
295 * the BACKSPACE key removed (replaced with NULL which is ignored by the
297 * This was done because the mapping of the acute (and apostrophe) is done
298 * differently in various xkb-data/xkeyboard-config versions. Some replace
299 * the acute with a normal apostrophe, so that the apostrophe is found twice
300 * on the keyboard (one next to BACKSPACE and one next to ENTER).
301 * Others put the acute and grave accents on the key left of BACKSPACE.
302 * More information on the fd.o bugtracker:
303 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
304 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
305 * among PC and Mac keyboards, so these are not listed.
308 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
309 static const char main_key_DE[MAIN_LEN][4] =
311 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","",
312 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
313 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
314 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
318 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
319 static const char main_key_SG[MAIN_LEN][4] =
321 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
322 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
323 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
324 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
328 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
329 static const char main_key_SF[MAIN_LEN][4] =
331 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
332 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
333 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
334 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
338 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
339 static const char main_key_NO[MAIN_LEN][4] =
341 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
342 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
343 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
344 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
348 /*** Danish keyboard layout (setxkbmap dk) */
349 static const char main_key_DA[MAIN_LEN][4] =
351 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
352 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
353 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
354 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
358 /*** Swedish keyboard layout (setxkbmap se) */
359 static const char main_key_SE[MAIN_LEN][4] =
361 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
362 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
363 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
364 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
368 /*** Estonian keyboard layout (setxkbmap ee) */
369 static const char main_key_ET[MAIN_LEN][4] =
371 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
372 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
373 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
374 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
378 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
379 static const char main_key_CF[MAIN_LEN][4] =
381 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
382 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
383 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
384 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
388 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
389 static const char main_key_CA_fr[MAIN_LEN][4] =
391 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
392 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
393 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
394 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
398 /*** Canadian keyboard layout (setxkbmap ca) */
399 static const char main_key_CA[MAIN_LEN][4] =
401 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
402 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
403 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
404 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
408 /*** Portuguese keyboard layout (setxkbmap pt) */
409 static const char main_key_PT[MAIN_LEN][4] =
411 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
412 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
413 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
414 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
418 /*** Italian keyboard layout (setxkbmap it) */
419 static const char main_key_IT[MAIN_LEN][4] =
421 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
422 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
423 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
424 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
428 /*** Finnish keyboard layout (setxkbmap fi) */
429 static const char main_key_FI[MAIN_LEN][4] =
431 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
432 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
433 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
434 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
438 /*** Bulgarian bds keyboard layout */
439 static const char main_key_BG_bds[MAIN_LEN][4] =
441 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
442 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
443 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
444 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
445 "<>" /* the phantom key */
448 /*** Bulgarian phonetic keyboard layout */
449 static const char main_key_BG_phonetic[MAIN_LEN][4] =
451 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
452 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
453 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
454 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
455 "<>" /* the phantom key */
458 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
459 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
460 static const char main_key_BY[MAIN_LEN][4] =
462 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
463 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
464 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
465 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
469 /*** Russian keyboard layout (contributed by Pavel Roskin) */
470 static const char main_key_RU[MAIN_LEN][4] =
472 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
473 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
474 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
475 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
478 /*** Russian keyboard layout (phantom key version) */
479 static const char main_key_RU_phantom[MAIN_LEN][4] =
481 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
482 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
483 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
484 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
485 "<>" /* the phantom key */
488 /*** Russian keyboard layout KOI8-R */
489 static const char main_key_RU_koi8r[MAIN_LEN][4] =
491 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
492 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
493 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
494 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
495 "<>" /* the phantom key */
498 /*** Russian keyboard layout cp1251 */
499 static const char main_key_RU_cp1251[MAIN_LEN][4] =
501 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
502 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
503 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
504 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
505 "<>" /* the phantom key */
508 /*** Russian phonetic keyboard layout */
509 static const char main_key_RU_phonetic[MAIN_LEN][4] =
511 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
512 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
513 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
514 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
515 "<>" /* the phantom key */
518 /*** Ukrainian keyboard layout KOI8-U */
519 static const char main_key_UA[MAIN_LEN][4] =
521 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
522 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
523 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
524 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
525 "<>" /* the phantom key */
528 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
529 /*** (as it appears on most of keyboards sold today) */
530 static const char main_key_UA_std[MAIN_LEN][4] =
532 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
533 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
534 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
535 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
536 "<>" /* the phantom key */
539 /*** Russian keyboard layout KOI8-R (pair to the previous) */
540 static const char main_key_RU_std[MAIN_LEN][4] =
542 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
543 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
544 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
545 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
546 "<>" /* the phantom key */
549 /*** Spanish keyboard layout (setxkbmap es) */
550 static const char main_key_ES[MAIN_LEN][4] =
552 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
553 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
554 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
555 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
559 /*** Belgian keyboard layout ***/
560 static const char main_key_BE[MAIN_LEN][4] =
562 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
563 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
564 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
565 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
569 /*** Hungarian keyboard layout (setxkbmap hu) */
570 static const char main_key_HU[MAIN_LEN][4] =
572 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
573 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
574 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
575 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
579 /*** Polish (programmer's) keyboard layout ***/
580 static const char main_key_PL[MAIN_LEN][4] =
582 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
583 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
584 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
585 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
589 /*** Slovenian keyboard layout (setxkbmap si) ***/
590 static const char main_key_SI[MAIN_LEN][4] =
592 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
593 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
594 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
595 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
599 /*** Serbian keyboard layout (setxkbmap sr) ***/
600 static const char main_key_SR[MAIN_LEN][4] =
602 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
603 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
604 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
605 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
606 "<>" /* the phantom key */
609 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
610 static const char main_key_US_SR[MAIN_LEN][4] =
612 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
613 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
614 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
615 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
616 "<>" /* the phantom key */
619 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
620 static const char main_key_HR_jelly[MAIN_LEN][4] =
622 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
623 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
624 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
625 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
629 /*** Croatian keyboard layout (setxkbmap hr) ***/
630 static const char main_key_HR[MAIN_LEN][4] =
632 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
633 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
634 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
635 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
639 /*** Japanese 106 keyboard layout ***/
640 static const char main_key_JA_jp106[MAIN_LEN][4] =
642 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
643 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
644 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
645 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
649 static const char main_key_JA_macjp[MAIN_LEN][4] =
651 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
652 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
653 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
654 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
658 /*** Japanese pc98x1 keyboard layout ***/
659 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
661 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
662 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
663 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
664 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
668 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
669 static const char main_key_PT_br[MAIN_LEN][4] =
671 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
672 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
673 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
674 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
677 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
678 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
680 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
681 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
682 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
683 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
686 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
687 static const char main_key_US_intl[MAIN_LEN][4] =
689 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
690 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
691 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
692 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
695 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
696 - dead_abovering replaced with degree - no symbol in iso8859-2
697 - brokenbar replaced with bar */
698 static const char main_key_SK[MAIN_LEN][4] =
700 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
701 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
702 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
703 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
707 /*** Czech keyboard layout (setxkbmap cz) */
708 static const char main_key_CZ[MAIN_LEN][4] =
710 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
711 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
712 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
713 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
717 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
718 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
720 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
721 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
722 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
723 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
727 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
728 static const char main_key_SK_prog[MAIN_LEN][4] =
730 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
731 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
732 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
733 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
737 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
738 static const char main_key_CS[MAIN_LEN][4] =
740 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
741 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
742 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
743 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
747 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
748 static const char main_key_LA[MAIN_LEN][4] =
750 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
751 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
752 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
753 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
757 /*** Lithuanian keyboard layout (setxkbmap lt) */
758 static const char main_key_LT_B[MAIN_LEN][4] =
760 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
761 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
762 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
763 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
767 /*** Turkish keyboard Layout */
768 static const char main_key_TK[MAIN_LEN][4] =
770 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
771 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
772 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
773 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
776 /*** Turkish keyboard layout (setxkbmap tr) */
777 static const char main_key_TR[MAIN_LEN][4] =
779 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
780 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
781 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
782 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
786 /*** Turkish F keyboard layout (setxkbmap trf) */
787 static const char main_key_TR_F[MAIN_LEN][4] =
789 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
790 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
791 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
792 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
796 /*** Israelian keyboard layout (setxkbmap us,il) */
797 static const char main_key_IL[MAIN_LEN][4] =
799 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
800 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
801 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
802 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
806 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
807 static const char main_key_IL_phonetic[MAIN_LEN][4] =
809 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
810 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
811 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
812 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
816 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
817 static const char main_key_IL_saharon[MAIN_LEN][4] =
819 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
820 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
821 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
822 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
826 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
827 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
828 message since they have different characters in gr and el XFree86 layouts. */
829 static const char main_key_EL[MAIN_LEN][4] =
831 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
832 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
833 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
834 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
838 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
839 static const char main_key_th[MAIN_LEN][4] =
841 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
842 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pPÂ","[{º°","]}Å,",
843 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
844 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
847 /*** VNC keyboard layout */
848 static const WORD main_key_scan_vnc[MAIN_LEN] =
850 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
851 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,
855 static const WORD main_key_vkey_vnc[MAIN_LEN] =
857 '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,
858 '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',
862 static const char main_key_vnc[MAIN_LEN][4] =
864 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
865 "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"
868 /*** Dutch keyboard layout (setxkbmap nl) ***/
869 static const char main_key_NL[MAIN_LEN][4] =
871 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
872 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
873 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
874 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
880 /*** Layout table. Add your keyboard mappings to this list */
881 static const struct {
882 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
883 in the appropriate dlls/kernel/nls/.nls file */
885 const char (*key)[MAIN_LEN][4];
886 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
887 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
889 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
892 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
895 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
896 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
897 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
898 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
902 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
906 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
908 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
909 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
913 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
925 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
927 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
928 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
929 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
930 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
932 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
933 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
938 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
948 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0, NULL, NULL, NULL, NULL} /* sentinel */
954 static unsigned kbd_layout=0; /* index into above table of layouts */
956 /* maybe more of these scancodes should be extended? */
957 /* extended must be set for ALT_R, CTRL_R,
958 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
959 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
960 /* FIXME should we set extended bit for NumLock ? My
961 * Windows does ... DF */
962 /* Yes, to distinguish based on scan codes, also
963 for PrtScn key ... GA */
965 static const WORD nonchar_key_vkey[256] =
968 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
970 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
971 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
972 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
974 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
975 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
976 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
977 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
978 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
981 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
982 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
983 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
985 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
986 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
987 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
989 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
990 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
991 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
992 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
993 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
994 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
995 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
996 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
997 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
998 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
999 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1000 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1003 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1004 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1005 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1008 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1009 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1010 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1012 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1015 static const WORD nonchar_key_scan[256] =
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1020 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1021 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1022 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1031 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1034 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1035 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1042 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1044 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1045 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1046 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1049 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1050 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1054 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1055 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1060 static const WORD xfree86_vendor_key_vkey[256] =
1062 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1063 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1064 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1065 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1066 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1067 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1068 0, 0, 0, VK_BROWSER_HOME,
1069 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1070 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1071 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1097 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1100 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1103 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1105 return XKeycodeToKeysym(display, keycode, index);
1108 /* Returns the Windows virtual key code associated with the X event <e> */
1109 /* x11 lock must be held */
1110 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1116 /* Clients should pass only KeyPress events to XmbLookupString */
1117 if (xic && e->type == KeyPress)
1118 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1120 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1122 if ((e->state & NumLockMask) &&
1123 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1124 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1125 /* Only the Keypad keys 0-9 and . send different keysyms
1126 * depending on the NumLock state */
1127 return nonchar_key_vkey[keysym & 0xFF];
1129 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1130 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1131 if ((e->state & ControlMask) && (keysym == XK_Break))
1134 TRACE_(key)("e->keycode = %u\n", e->keycode);
1136 return keyc2vkey[e->keycode];
1140 /***********************************************************************
1141 * X11DRV_send_keyboard_input
1143 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1147 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1149 input.type = INPUT_KEYBOARD;
1150 input.u.ki.wVk = vkey;
1151 input.u.ki.wScan = scan;
1152 input.u.ki.dwFlags = flags;
1153 input.u.ki.time = time;
1154 input.u.ki.dwExtraInfo = 0;
1156 __wine_send_input( hwnd, &input );
1160 /***********************************************************************
1161 * get_async_key_state
1163 static BOOL get_async_key_state( BYTE state[256] )
1167 SERVER_START_REQ( get_key_state )
1171 wine_server_set_reply( req, state, 256 );
1172 ret = !wine_server_call( req );
1178 /***********************************************************************
1179 * X11DRV_KeymapNotify
1181 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1183 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1184 * from wine to another application and back.
1185 * Toggle keys are handled in HandleEvent.
1187 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1190 DWORD time = GetCurrentTime();
1197 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1199 if (!get_async_key_state( keystate )) return;
1201 memset(modifiers, 0, sizeof(modifiers));
1203 /* the minimum keycode is always greater or equal to 8, so we can
1204 * skip the first 8 values, hence start at 1
1206 for (i = 1; i < 32; i++)
1208 for (j = 0; j < 8; j++)
1212 vkey = keyc2vkey[(i * 8) + j];
1222 m = (vkey & 0xff) - VK_LSHIFT;
1223 /* Take the vkey and scan from the first keycode we encounter
1224 for this modifier. */
1225 if (!modifiers[m].vkey)
1227 modifiers[m].vkey = vkey;
1228 modifiers[m].scan = keyc2scan[(i * 8) + j];
1230 if (event->xkeymap.key_vector[i] & (1<<j))
1231 modifiers[m].pressed = TRUE;
1237 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1239 int m = vkey - VK_LSHIFT;
1240 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1242 DWORD flags = modifiers[m].vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1243 if (!modifiers[m].pressed) flags |= KEYEVENTF_KEYUP;
1245 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1246 modifiers[m].vkey, keystate[vkey]);
1248 /* Fake key being pressed inside wine */
1249 X11DRV_send_keyboard_input( hwnd, vkey, modifiers[m].scan & 0xff, flags, time );
1254 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1258 /* Note: X sets the below states on key down and clears them on key up.
1259 Windows triggers them on key down. */
1261 if (!get_async_key_state( keystate )) return;
1263 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1264 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1267 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1268 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1269 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1270 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1273 /* Adjust the NUMLOCK state if it has been changed outside wine */
1274 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1276 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1277 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1278 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1279 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1280 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1283 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1284 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1287 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1288 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1289 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1290 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1294 /***********************************************************************
1297 * Handle a X key event
1299 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1301 XKeyEvent *event = &xev->xkey;
1305 WORD vkey = 0, bScan;
1308 XIC xic = X11DRV_get_ic( hwnd );
1309 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1312 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1313 event->type, event->window, event->state, event->keycode);
1315 if (event->type == KeyPress) update_user_time( event->time );
1318 /* Clients should pass only KeyPress events to XmbLookupString */
1319 if (xic && event->type == KeyPress)
1321 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1322 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1323 if (status == XBufferOverflow)
1325 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1328 ERR_(key)("Failed to allocate memory!\n");
1329 wine_tsx11_unlock();
1332 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1336 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1337 wine_tsx11_unlock();
1339 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1341 if (status == XLookupChars)
1343 X11DRV_XIMLookupChars( Str, ascii_chars );
1345 HeapFree(GetProcessHeap(), 0, Str);
1349 /* If XKB extensions are used, the state mask for AltGr will use the group
1350 index instead of the modifier mask. The group index is set in bits
1351 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1352 pressed, look if the group index is different than 0. From XKB
1353 extension documentation, the group index for AltGr should be 2
1354 (event->state = 0x2000). It's probably better to not assume a
1355 predefined group index and find it dynamically
1357 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1358 /* Save also all possible modifier states. */
1359 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1365 ksname = XKeysymToString(keysym);
1366 wine_tsx11_unlock();
1369 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1370 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1371 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1374 HeapFree(GetProcessHeap(), 0, Str);
1377 vkey = EVENT_event_to_vkey(xic,event);
1378 /* X returns keycode 0 for composed characters */
1379 if (!vkey && ascii_chars) vkey = VK_NONAME;
1380 wine_tsx11_unlock();
1382 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1383 event->keycode, vkey);
1388 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1389 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1391 update_lock_state( hwnd, vkey, event->state, event_time );
1393 bScan = keyc2scan[event->keycode] & 0xFF;
1394 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1396 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1399 /**********************************************************************
1400 * X11DRV_KEYBOARD_DetectLayout
1402 * Called from X11DRV_InitKeyboard
1403 * This routine walks through the defined keyboard layouts and selects
1404 * whichever matches most closely.
1405 * X11 lock must be held.
1408 X11DRV_KEYBOARD_DetectLayout( Display *display )
1410 unsigned current, match, mismatch, seq, i, syms;
1411 int score, keyc, key, pkey, ok;
1413 const char (*lkey)[MAIN_LEN][4];
1414 unsigned max_seq = 0;
1415 int max_score = 0, ismatch = 0;
1418 syms = keysyms_per_keycode;
1420 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1424 memset( ckey, 0, sizeof(ckey) );
1425 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1426 /* get data for keycode from X server */
1427 for (i = 0; i < syms; i++) {
1428 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1429 /* Allow both one-byte and two-byte national keysyms */
1430 if ((keysym < 0x8000) && (keysym != ' '))
1433 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1436 TRACE("XKB could not translate keysym %04lx\n", keysym);
1437 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1438 * with appropriate ShiftMask and Mode_switch, use XLookupString
1439 * to get character in the local encoding.
1441 ckey[keyc][i] = keysym & 0xFF;
1445 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1450 for (current = 0; main_key_tab[current].comment; current++) {
1451 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1456 lkey = main_key_tab[current].key;
1458 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1459 if (ckey[keyc][0]) {
1460 /* search for a match in layout table */
1461 /* right now, we just find an absolute match for defined positions */
1462 /* (undefined positions are ignored, so if it's defined as "3#" in */
1463 /* the table, it's okay that the X server has "3#£", for example) */
1464 /* however, the score will be higher for longer matches */
1465 for (key = 0; key < MAIN_LEN; key++) {
1466 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1467 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1469 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1477 /* count the matches and mismatches */
1480 /* and how much the keycode order matches */
1481 if (key > pkey) seq++;
1484 /* print spaces instead of \0's */
1486 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1488 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1494 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1495 match, mismatch, seq, score);
1496 if ((score > max_score) ||
1497 ((score == max_score) && (seq > max_seq))) {
1498 /* best match so far */
1499 kbd_layout = current;
1502 ismatch = !mismatch;
1505 /* we're done, report results if necessary */
1507 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1508 main_key_tab[kbd_layout].comment);
1510 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1513 static HKL get_locale_kbd_layout(void)
1520 * layout = main_key_tab[kbd_layout].lcid;
1522 * Winword uses return value of GetKeyboardLayout as a codepage
1523 * to translate ANSI keyboard messages to unicode. But we have
1524 * a problem with it: for instance Polish keyboard layout is
1525 * identical to the US one, and therefore instead of the Polish
1526 * locale id we return the US one.
1529 layout = GetUserDefaultLCID();
1532 * Microsoft Office expects this value to be something specific
1533 * for Japanese and Korean Windows with an IME the value is 0xe001
1534 * We should probably check to see if an IME exists and if so then
1535 * set this word properly.
1537 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1538 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1539 layout |= 0xe001 << 16; /* IME */
1541 layout |= layout << 16;
1546 /***********************************************************************
1547 * GetKeyboardLayoutName (X11DRV.@)
1549 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1551 static const WCHAR formatW[] = {'%','0','8','x',0};
1554 layout = HandleToUlong( get_locale_kbd_layout() );
1555 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1556 sprintfW(name, formatW, layout);
1557 TRACE("returning %s\n", debugstr_w(name));
1561 static void set_kbd_layout_preload_key(void)
1563 static const WCHAR preload[] =
1564 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1565 static const WCHAR one[] = {'1',0};
1568 WCHAR layout[KL_NAMELENGTH];
1570 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1573 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1578 if (X11DRV_GetKeyboardLayoutName(layout))
1579 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1584 /**********************************************************************
1585 * X11DRV_InitKeyboard
1587 void X11DRV_InitKeyboard( Display *display )
1590 XModifierKeymap *mmp;
1595 int keyc, i, keyn, syms;
1596 char ckey[4]={0,0,0,0};
1597 const char (*lkey)[MAIN_LEN][4];
1598 char vkey_used[256] = { 0 };
1600 /* Ranges of OEM, function key, and character virtual key codes.
1601 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1602 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1603 static const struct {
1606 { VK_OEM_1, VK_OEM_3 },
1607 { VK_OEM_4, VK_ICO_00 },
1610 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1612 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1613 { 0x41, 0x5a }, /* VK_A - VK_Z */
1618 set_kbd_layout_preload_key();
1621 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1622 ksp = XGetKeyboardMapping(display, min_keycode,
1623 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1624 /* We are only interested in keysyms_per_keycode.
1625 There is no need to hold a local copy of the keysyms table */
1628 mmp = XGetModifierMapping(display);
1629 kcp = mmp->modifiermap;
1630 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1634 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1639 for (k = 0; k < keysyms_per_keycode; k += 1)
1640 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1642 NumLockMask = 1 << i;
1643 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1645 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1647 ScrollLockMask = 1 << i;
1648 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1652 XFreeModifiermap(mmp);
1654 /* Detect the keyboard layout */
1655 X11DRV_KEYBOARD_DetectLayout( display );
1656 lkey = main_key_tab[kbd_layout].key;
1657 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1659 /* Now build two conversion arrays :
1660 * keycode -> vkey + scancode + extended
1661 * vkey + extended -> keycode */
1663 e2.display = display;
1667 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1668 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1674 e2.keycode = (KeyCode)keyc;
1675 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1677 if (keysym) /* otherwise, keycode not used */
1679 if ((keysym >> 8) == 0xFF) /* non-character key */
1681 vkey = nonchar_key_vkey[keysym & 0xff];
1682 scan = nonchar_key_scan[keysym & 0xff];
1683 /* set extended bit when necessary */
1684 if (scan & 0x100) vkey |= 0x100;
1685 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1686 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1687 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1690 } else if (keysym == 0x20) { /* Spacebar */
1693 } else if (have_chars) {
1694 /* we seem to need to search the layout-dependent scancodes */
1695 int maxlen=0,maxval=-1,ok;
1696 for (i=0; i<syms; i++) {
1697 keysym = keycode_to_keysym(display, keyc, i);
1698 if ((keysym<0x8000) && (keysym!=' '))
1701 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1704 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1705 * with appropriate ShiftMask and Mode_switch, use XLookupString
1706 * to get character in the local encoding.
1708 ckey[i] = keysym & 0xFF;
1711 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1714 /* find key with longest match streak */
1715 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1716 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1717 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1718 if (!ok) i--; /* we overshot */
1719 if (ok||(i>maxlen)) {
1720 maxlen=i; maxval=keyn;
1726 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1727 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1728 scan = (*lscan)[maxval];
1729 vkey = (*lvkey)[maxval];
1733 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1734 keyc2vkey[e2.keycode] = vkey;
1735 keyc2scan[e2.keycode] = scan;
1736 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1737 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1738 vkey_used[(vkey & 0xff)] = 1;
1741 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1742 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1744 vkey = keyc2vkey[keyc] & 0xff;
1748 e2.keycode = (KeyCode)keyc;
1749 keysym = XLookupKeysym(&e2, 0);
1753 /* find a suitable layout-dependent VK code */
1754 /* (most Winelib apps ought to be able to work without layout tables!) */
1755 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1757 keysym = XLookupKeysym(&e2, i);
1758 if ((keysym >= XK_0 && keysym <= XK_9)
1759 || (keysym >= XK_A && keysym <= XK_Z)) {
1760 vkey = VKEY_IF_NOT_USED(keysym);
1764 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1766 keysym = XLookupKeysym(&e2, i);
1769 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1770 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1771 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1772 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1773 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1774 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1775 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1776 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1777 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1778 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1779 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1785 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1786 keyc2vkey[e2.keycode] = vkey;
1790 /* For any keycodes which still don't have a vkey, assign any spare
1791 * character, function key, or OEM virtual key code. */
1793 vkey = vkey_ranges[vkey_range].first;
1794 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1796 if (keyc2vkey[keyc] & 0xff)
1799 e2.keycode = (KeyCode)keyc;
1800 keysym = XLookupKeysym(&e2, 0);
1804 while (vkey && vkey_used[vkey])
1806 if (vkey == vkey_ranges[vkey_range].last)
1809 vkey = vkey_ranges[vkey_range].first;
1817 WARN("No more vkeys available!\n");
1821 if (TRACE_ON(keyboard))
1823 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1826 for (i = 0; i < keysyms_per_keycode; i += 1)
1830 keysym = XLookupKeysym(&e2, i);
1831 ksname = XKeysymToString(keysym);
1833 ksname = "NoSymbol";
1834 TRACE( "%lx (%s) ", keysym, ksname);
1839 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1840 keyc2vkey[e2.keycode] = vkey;
1841 vkey_used[vkey] = 1;
1843 #undef VKEY_IF_NOT_USED
1845 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1846 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1847 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1849 keysym = keycode_to_keysym(display, keyc, 0);
1850 ksname = XKeysymToString(keysym);
1851 if (!ksname) ksname = "NoSymbol";
1853 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1855 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1856 keyc2scan[keyc]=scan++;
1859 wine_tsx11_unlock();
1862 static BOOL match_x11_keyboard_layout(HKL hkl)
1864 const DWORD isIME = 0xE0000000;
1865 HKL xHkl = get_locale_kbd_layout();
1867 /* if the layout is an IME, only match the low word (LCID) */
1868 if (((ULONG_PTR)hkl & isIME) == isIME)
1869 return (LOWORD(hkl) == LOWORD(xHkl));
1871 return (hkl == xHkl);
1874 /**********************************************************************
1875 * GetAsyncKeyState (X11DRV.@)
1877 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1879 /* Photoshop livelocks unless mouse events are included here */
1880 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1885 /***********************************************************************
1886 * GetKeyboardLayout (X11DRV.@)
1888 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1890 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1892 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1893 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1896 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1898 return get_locale_kbd_layout();
1902 /***********************************************************************
1903 * LoadKeyboardLayout (X11DRV.@)
1905 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1907 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1908 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1913 /***********************************************************************
1914 * UnloadKeyboardLayout (X11DRV.@)
1916 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1918 FIXME("%p: stub!\n", hkl);
1919 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1924 /***********************************************************************
1925 * ActivateKeyboardLayout (X11DRV.@)
1927 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1930 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1932 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1933 if (flags & KLF_SETFORPROCESS)
1935 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1936 FIXME("KLF_SETFORPROCESS not supported\n");
1941 FIXME("flags %x not supported\n",flags);
1943 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1945 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1946 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1950 if (!match_x11_keyboard_layout(hkl))
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1953 FIXME("setting keyboard of different locales not supported\n");
1957 oldHkl = thread_data->kbd_layout;
1958 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1960 thread_data->kbd_layout = hkl;
1966 /***********************************************************************
1967 * X11DRV_MappingNotify
1969 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1974 XRefreshKeyboardMapping(&event->xmapping);
1975 wine_tsx11_unlock();
1976 X11DRV_InitKeyboard( event->xmapping.display );
1979 if (!hwnd) hwnd = GetActiveWindow();
1980 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1981 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1985 /***********************************************************************
1986 * VkKeyScanEx (X11DRV.@)
1988 * Note: Windows ignores HKL parameter and uses current active layout instead
1990 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1992 Display *display = thread_init_display();
1999 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2000 * is UTF-8 (multibyte encoding)?
2002 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2004 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2008 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2010 /* char->keysym (same for ANSI chars) */
2011 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2012 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2015 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2018 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2020 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2021 TRACE(" ... returning ctrl char %#.2x\n", ret);
2022 wine_tsx11_unlock();
2025 /* It didn't work ... let's try with deadchar code. */
2026 TRACE("retrying with | 0xFE00\n");
2027 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2029 wine_tsx11_unlock();
2031 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2033 /* keycode -> (keyc2vkey) vkey */
2034 ret = keyc2vkey[keycode];
2036 if (!keycode || !ret)
2038 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2044 for (i = 0; i < 4; i++) /* find shift state */
2046 if (keycode_to_keysym(display, keycode, i) == keysym)
2052 wine_tsx11_unlock();
2058 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2062 case 1: ret += 0x0100; break;
2063 case 2: ret += 0x0600; break;
2064 case 3: ret += 0x0700; break;
2067 index : 0 adds 0x0000
2068 index : 1 adds 0x0100 (shift)
2069 index : ? adds 0x0200 (ctrl)
2070 index : 2 adds 0x0600 (ctrl+alt)
2071 index : 3 adds 0x0700 (ctrl+alt+shift)
2074 TRACE(" ... returning %#.2x\n", ret);
2078 /***********************************************************************
2079 * MapVirtualKeyEx (X11DRV.@)
2081 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2083 Display *display = thread_init_display();
2085 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2087 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2088 if (!match_x11_keyboard_layout(hkl))
2089 FIXME("keyboard layout %p is not supported\n", hkl);
2093 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2094 case MAPVK_VK_TO_VSC_EX:
2100 case VK_SHIFT: wCode = VK_LSHIFT; break;
2101 case VK_CONTROL: wCode = VK_LCONTROL; break;
2102 case VK_MENU: wCode = VK_LMENU; break;
2105 /* let's do vkey -> keycode -> scan */
2106 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2107 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2109 if (keyc > max_keycode)
2111 TRACE("returning no scan-code.\n");
2114 returnMVK (keyc2scan[keyc] & 0xFF);
2116 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2117 case MAPVK_VSC_TO_VK_EX:
2122 /* let's do scan -> keycode -> vkey */
2123 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2124 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2126 vkey = keyc2vkey[keyc] & 0xFF;
2127 /* Only stop if it's not a numpad vkey; otherwise keep
2128 looking for a potential better vkey. */
2129 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2135 TRACE("returning no vkey-code.\n");
2139 if (wMapType == MAPVK_VSC_TO_VK)
2144 vkey = VK_SHIFT; break;
2147 vkey = VK_CONTROL; break;
2150 vkey = VK_MENU; break;
2155 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2157 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2158 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2159 * key.. Looks like something is wrong with the MS docs?
2160 * This is only true for letters, for example VK_0 returns '0' not ')'.
2161 * - hence we use the lock mask to ensure this happens.
2163 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2169 e.display = display;
2176 /* We exit on the first keycode found, to speed up the thing. */
2177 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2178 { /* Find a keycode that could have generated this virtual key */
2179 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2180 { /* We filter the extended bit, we don't know it */
2181 e.keycode = keyc; /* Store it temporarily */
2182 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2183 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2184 state), so set it to 0, we'll find another one */
2189 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2190 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2192 if (wCode==VK_DECIMAL)
2193 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2197 WARN("Unknown virtual key %X !!!\n", wCode);
2198 wine_tsx11_unlock();
2199 return 0; /* whatever */
2201 TRACE("Found keycode %u\n",e.keycode);
2203 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2204 wine_tsx11_unlock();
2209 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2210 returnMVK(toupperW(wch));
2212 TRACE("returning no ANSI.\n");
2215 default: /* reserved */
2216 FIXME("Unknown wMapType %d !\n", wMapType);
2222 /***********************************************************************
2223 * GetKeyNameText (X11DRV.@)
2225 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2227 Display *display = thread_init_display();
2228 int vkey, ansi, scanCode;
2234 scanCode = lParam >> 16;
2235 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2237 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2239 /* handle "don't care" bit (0x02000000) */
2240 if (!(lParam & 0x02000000)) {
2243 /* R-Shift is "special" - it is an extended key with separate scan code */
2259 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2260 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2262 /* first get the name of the "regular" keys which is the Upper case
2263 value of the keycap imprint. */
2264 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2265 (scanCode != 0x137) && /* PrtScn */
2266 (scanCode != 0x135) && /* numpad / */
2267 (scanCode != 0x37 ) && /* numpad * */
2268 (scanCode != 0x4a ) && /* numpad - */
2269 (scanCode != 0x4e ) ) /* numpad + */
2271 if ((nSize >= 2) && lpBuffer)
2273 *lpBuffer = toupperW((WCHAR)ansi);
2281 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2282 without "extended-key" flag. However Wine generates scancode
2283 *with* "extended-key" flag. Seems to occur *only* for the
2284 function keys. Soooo.. We will leave the table alone and
2285 fudge the lookup here till the other part is found and fixed!!! */
2287 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2288 (scanCode == 0x157) || (scanCode == 0x158))
2289 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2291 /* let's do scancode -> keycode -> keysym -> String */
2293 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2294 if ((keyc2scan[keyi]) == scanCode)
2296 if (keyi <= max_keycode)
2299 keyc = (KeyCode) keyi;
2300 keys = keycode_to_keysym(display, keyc, 0);
2301 name = XKeysymToString(keys);
2302 wine_tsx11_unlock();
2303 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2304 scanCode, keyc, (int)keys, name);
2305 if (lpBuffer && nSize && name)
2306 return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2309 /* Finally issue WARN for unknown keys */
2311 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2312 if (lpBuffer && nSize)
2317 /***********************************************************************
2318 * X11DRV_KEYBOARD_MapDeadKeysym
2320 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2324 /* symbolic ASCII is the same as defined in rfc1345 */
2325 #ifdef XK_dead_tilde
2326 case XK_dead_tilde :
2328 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2329 return '~'; /* '? */
2330 #ifdef XK_dead_acute
2331 case XK_dead_acute :
2333 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2334 return 0xb4; /* '' */
2335 #ifdef XK_dead_circumflex
2336 case XK_dead_circumflex:
2338 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2339 return '^'; /* '> */
2340 #ifdef XK_dead_grave
2341 case XK_dead_grave :
2343 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2344 return '`'; /* '! */
2345 #ifdef XK_dead_diaeresis
2346 case XK_dead_diaeresis :
2348 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2349 return 0xa8; /* ': */
2350 #ifdef XK_dead_cedilla
2351 case XK_dead_cedilla :
2352 return 0xb8; /* ', */
2354 #ifdef XK_dead_macron
2355 case XK_dead_macron :
2356 return '-'; /* 'm isn't defined on iso-8859-x */
2358 #ifdef XK_dead_breve
2359 case XK_dead_breve :
2360 return 0xa2; /* '( */
2362 #ifdef XK_dead_abovedot
2363 case XK_dead_abovedot :
2364 return 0xff; /* '. */
2366 #ifdef XK_dead_abovering
2367 case XK_dead_abovering :
2368 return '0'; /* '0 isn't defined on iso-8859-x */
2370 #ifdef XK_dead_doubleacute
2371 case XK_dead_doubleacute :
2372 return 0xbd; /* '" */
2374 #ifdef XK_dead_caron
2375 case XK_dead_caron :
2376 return 0xb7; /* '< */
2378 #ifdef XK_dead_ogonek
2379 case XK_dead_ogonek :
2380 return 0xb2; /* '; */
2382 /* FIXME: I don't know this three.
2385 case XK_dead_voiced_sound :
2387 case XK_dead_semivoiced_sound :
2391 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2395 /***********************************************************************
2396 * ToUnicodeEx (X11DRV.@)
2398 * The ToUnicode function translates the specified virtual-key code and keyboard
2399 * state to the corresponding Windows character or characters.
2401 * If the specified key is a dead key, the return value is negative. Otherwise,
2402 * it is one of the following values:
2404 * 0 The specified virtual key has no translation for the current state of the keyboard.
2405 * 1 One Windows character was copied to the buffer.
2406 * 2 Two characters were copied to the buffer. This usually happens when a
2407 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2408 * be composed with the specified virtual key to form a single character.
2410 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2413 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2414 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2416 Display *display = thread_init_display();
2427 if (scanCode & 0x8000)
2429 TRACE_(key)("Key UP, doing nothing\n" );
2433 if (!match_x11_keyboard_layout(hkl))
2434 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2436 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2438 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2442 e.display = display;
2447 focus = x11drv_thread_data()->last_xic_hwnd;
2451 if (focus) focus = GetAncestor( focus, GA_ROOT );
2452 if (!focus) focus = GetActiveWindow();
2454 e.window = X11DRV_get_whole_window( focus );
2455 xic = X11DRV_get_ic( focus );
2457 if (lpKeyState[VK_SHIFT] & 0x80)
2459 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2460 e.state |= ShiftMask;
2462 if (lpKeyState[VK_CAPITAL] & 0x01)
2464 TRACE_(key)("LockMask = %04x\n", LockMask);
2465 e.state |= LockMask;
2467 if (lpKeyState[VK_CONTROL] & 0x80)
2469 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2470 e.state |= ControlMask;
2472 if (lpKeyState[VK_NUMLOCK] & 0x01)
2474 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2475 e.state |= NumLockMask;
2478 /* Restore saved AltGr state */
2479 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2480 e.state |= AltGrMask;
2482 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2483 virtKey, scanCode, e.state);
2485 /* We exit on the first keycode found, to speed up the thing. */
2486 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2487 { /* Find a keycode that could have generated this virtual key */
2488 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2489 { /* We filter the extended bit, we don't know it */
2490 e.keycode = keyc; /* Store it temporarily */
2491 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2492 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2493 state), so set it to 0, we'll find another one */
2498 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2499 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2501 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2502 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2504 if (virtKey==VK_DECIMAL)
2505 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2507 if (virtKey==VK_SEPARATOR)
2508 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2510 if (!e.keycode && virtKey != VK_NONAME)
2512 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2513 wine_tsx11_unlock();
2516 else TRACE_(key)("Found keycode %u\n",e.keycode);
2518 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2519 e.type, e.window, e.state, e.keycode);
2521 /* Clients should pass only KeyPress events to XmbLookupString,
2522 * e.type was set to KeyPress above.
2526 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2527 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2528 if (status == XBufferOverflow)
2530 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2533 ERR_(key)("Failed to allocate memory!\n");
2534 wine_tsx11_unlock();
2537 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2541 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2542 wine_tsx11_unlock();
2544 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2551 ksname = XKeysymToString(keysym);
2552 wine_tsx11_unlock();
2553 if (!ksname) ksname = "No Name";
2554 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2555 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2556 keysym, ksname, ret, debugstr_an(lpChar, ret));
2564 /* An ugly hack for EuroSign: X can't translate it to a character
2565 for some locales. */
2566 if (keysym == XK_EuroSign)
2573 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2574 /* Here we change it back. */
2575 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2582 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2585 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2590 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2592 /* Unicode direct mapping */
2593 bufW[0] = keysym & 0xffff;
2597 else if ((keysym >> 8) == 0x1008FF) {
2607 ksname = XKeysymToString(keysym);
2608 wine_tsx11_unlock();
2611 if ((keysym >> 8) != 0xff)
2613 WARN_(key)("no char for keysym %04lx (%s) :\n",
2615 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2616 virtKey, scanCode, e.keycode, e.state);
2620 else { /* ret != 0 */
2621 /* We have a special case to handle : Shift + arrow, shift + home, ...
2622 X returns a char for it, but Windows doesn't. Let's eat it. */
2623 if (!(e.state & NumLockMask) /* NumLock is off */
2624 && (e.state & ShiftMask) /* Shift is pressed */
2625 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2631 /* more areas where X returns characters but Windows does not
2632 CTRL + number or CTRL + symbol */
2633 if (e.state & ControlMask)
2635 if (((keysym>=33) && (keysym < 'A')) ||
2636 ((keysym > 'Z') && (keysym < 'a')) ||
2644 /* We have another special case for delete key (XK_Delete) on an
2645 extended keyboard. X returns a char for it, but Windows doesn't */
2646 if (keysym == XK_Delete)
2651 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2652 && (keysym == XK_KP_Decimal))
2657 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2658 && (keysym == XK_Return || keysym == XK_KP_Enter))
2664 /* Hack to detect an XLookupString hard-coded to Latin1 */
2665 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2667 bufW[0] = (BYTE)lpChar[0];
2671 /* perform translation to unicode */
2674 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2675 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2681 HeapFree(GetProcessHeap(), 0, lpChar);
2682 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2686 /***********************************************************************
2689 void CDECL X11DRV_Beep(void)
2692 XBell(gdi_display, 0);
2693 wine_tsx11_unlock();