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
32 #include <X11/Xatom.h>
33 #include <X11/keysym.h>
35 #include <X11/Xresource.h>
36 #include <X11/Xutil.h>
37 #ifdef HAVE_X11_XKBLIB_H
38 #include <X11/XKBlib.h>
45 #define NONAMELESSUNION
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 /* log format (add 0-padding as appropriate):
58 keycode %u as in output from xev
59 keysym %lx as in X11/keysymdef.h
60 vkey %X as in winuser.h
63 WINE_DEFAULT_DEBUG_CHANNEL(keyboard
);
64 WINE_DECLARE_DEBUG_CHANNEL(key
);
66 static const unsigned int ControlMask
= 1 << 2;
68 static int min_keycode
, max_keycode
, keysyms_per_keycode
;
69 static KeySym
*key_mapping
;
70 static WORD keyc2vkey
[256], keyc2scan
[256];
72 static int NumLockMask
, ScrollLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
74 static pthread_mutex_t kbd_mutex
= PTHREAD_MUTEX_INITIALIZER
;
76 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
78 /* Keyboard translation tables */
80 static const WORD main_key_scan_qwerty
[MAIN_LEN
] =
82 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
83 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
84 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
85 /* q w e r t y u i o p [ ] */
86 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
87 /* a s d f g h j k l ; ' \ */
88 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
89 /* z x c v b n m , . / */
90 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
91 0x56 /* the 102nd key (actually to the right of l-shift) */
94 static const WORD main_key_scan_abnt_qwerty
[MAIN_LEN
] =
96 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
97 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
98 /* q w e r t y u i o p [ ] */
99 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
100 /* a s d f g h j k l ; ' \ */
101 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
102 /* \ z x c v b n m , . / */
103 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
104 0x56, /* the 102nd key (actually to the right of l-shift) */
107 static const WORD main_key_scan_dvorak
[MAIN_LEN
] =
109 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
110 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
111 /* ' , . p y f g c r l / = */
112 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
113 /* a o e u i d h t n s - \ */
114 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
115 /* ; q j k x b m w v z */
116 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
117 0x56 /* the 102nd key (actually to the right of l-shift) */
120 static const WORD main_key_scan_qwerty_jp106
[MAIN_LEN
] =
122 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ (Yen) */
123 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7D,
124 /* q w e r t y u i o p @ [ */
125 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
126 /* a s d f g h j k l ; : ] */
127 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
128 /* z x c v b n m , . / \ (Underscore) */
129 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x73
133 static const WORD main_key_vkey_qwerty
[MAIN_LEN
] =
135 /* NOTE: this layout must concur with the scan codes layout above */
136 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
137 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
138 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
139 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
140 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
143 static const WORD main_key_vkey_qwerty_jp106
[MAIN_LEN
] =
145 /* NOTE: this layout must concur with the scan codes layout above */
146 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_7
,VK_OEM_5
,
147 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3
,VK_OEM_4
,
148 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS
,VK_OEM_1
,VK_OEM_6
,
149 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
150 VK_OEM_102
/* the 102nd key (actually to the left of r-shift) */
153 static const WORD main_key_vkey_qwerty_v2
[MAIN_LEN
] =
155 /* NOTE: this layout must concur with the scan codes layout above */
156 VK_OEM_5
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS
,VK_OEM_4
,
157 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
158 'A','S','D','F','G','H','J','K','L',VK_OEM_3
,VK_OEM_7
,VK_OEM_2
,
159 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_MINUS
,
160 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
163 static const WORD main_key_vkey_qwertz
[MAIN_LEN
] =
165 /* NOTE: this layout must concur with the scan codes layout above */
166 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
167 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
168 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
169 'Y','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
170 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
173 static const WORD main_key_vkey_abnt_qwerty
[MAIN_LEN
] =
175 /* NOTE: this layout must concur with the scan codes layout above */
176 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
177 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
178 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_8
,VK_OEM_5
,
179 VK_OEM_7
,'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
180 VK_OEM_102
, /* the 102nd key (actually to the right of l-shift) */
183 static const WORD main_key_vkey_azerty
[MAIN_LEN
] =
185 /* NOTE: this layout must concur with the scan codes layout above */
186 VK_OEM_7
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_PLUS
,
187 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
188 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3
,VK_OEM_5
,
189 'W','X','C','V','B','N',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,VK_OEM_8
,
190 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
193 static const WORD main_key_vkey_dvorak
[MAIN_LEN
] =
195 /* NOTE: this layout must concur with the scan codes layout above */
196 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_6
,
197 VK_OEM_7
,VK_OEM_COMMA
,VK_OEM_PERIOD
,'P','Y','F','G','C','R','L',VK_OEM_2
,VK_OEM_PLUS
,
198 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS
,VK_OEM_5
,
199 VK_OEM_1
,'Q','J','K','X','B','M','W','V','Z',
200 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
203 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
205 /* the VK mappings for the main keyboard will be auto-assigned as before,
206 so what we have here is just the character tables */
207 /* order: Normal, Shift, AltGr, Shift-AltGr */
208 /* We recommend you write just what is guaranteed to be correct (i.e. what's
209 written on the keycaps), not the bunch of special characters behind AltGr
210 and Shift-AltGr if it can vary among different X servers */
211 /* These tables serve to guess the keyboard type and scancode mapping.
212 Complete modeling is not important, identification/discrimination is. */
213 /* Remember that your 102nd key (to the right of l-shift) should be on a
214 separate line, see existing tables */
215 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
216 /* Remember to also add your new table to the layout index table far below! */
218 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
219 static const char main_key_US
[MAIN_LEN
][4] =
221 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
222 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
223 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
224 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
227 /*** United States keyboard layout (phantom key version) */
228 /* (XFree86 reports the <> key even if it's not physically there) */
229 static const char main_key_US_phantom
[MAIN_LEN
][4] =
231 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
232 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
233 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
234 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
235 "<>" /* the phantom key */
238 /*** United States keyboard layout (dvorak version) */
239 static const char main_key_US_dvorak
[MAIN_LEN
][4] =
241 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
242 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
243 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
244 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
247 /*** British keyboard layout */
248 static const char main_key_UK
[MAIN_LEN
][4] =
250 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
251 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
252 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
253 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
257 /*** French keyboard layout (setxkbmap fr) */
258 static const char main_key_FR
[MAIN_LEN
][4] =
260 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
261 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
262 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
263 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
267 /*** Icelandic keyboard layout (setxkbmap is) */
268 static const char main_key_IS
[MAIN_LEN
][4] =
270 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
271 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
272 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
273 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
277 /* All german keyb layout tables have the acute/apostrophe symbol next to
278 * the BACKSPACE key removed (replaced with NULL which is ignored by the
280 * This was done because the mapping of the acute (and apostrophe) is done
281 * differently in various xkb-data/xkeyboard-config versions. Some replace
282 * the acute with a normal apostrophe, so that the apostrophe is found twice
283 * on the keyboard (one next to BACKSPACE and one next to ENTER).
284 * Others put the acute and grave accents on the key left of BACKSPACE.
285 * More information on the fd.o bugtracker:
286 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
287 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
288 * among PC and Mac keyboards, so these are not listed.
291 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
292 static const char main_key_DE
[MAIN_LEN
][4] =
294 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
295 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
296 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
297 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
301 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
302 static const char main_key_SG
[MAIN_LEN
][4] =
304 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
305 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
306 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
307 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
311 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
312 static const char main_key_SF
[MAIN_LEN
][4] =
314 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
315 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
316 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
317 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
321 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
322 static const char main_key_NO
[MAIN_LEN
][4] =
324 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
325 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
326 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
327 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
331 /*** Danish keyboard layout (setxkbmap dk) */
332 static const char main_key_DA
[MAIN_LEN
][4] =
334 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
335 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
336 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
337 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
341 /*** Swedish keyboard layout (setxkbmap se) */
342 static const char main_key_SE
[MAIN_LEN
][4] =
344 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
345 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
346 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
347 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
351 /*** Estonian keyboard layout (setxkbmap ee) */
352 static const char main_key_ET
[MAIN_LEN
][4] =
354 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
355 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
356 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
357 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
361 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
362 static const char main_key_CF
[MAIN_LEN
][4] =
364 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
365 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
366 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
367 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
371 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
372 static const char main_key_CA_fr
[MAIN_LEN
][4] =
374 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
375 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
376 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
377 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
381 /*** Canadian keyboard layout (setxkbmap ca) */
382 static const char main_key_CA
[MAIN_LEN
][4] =
384 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
385 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
386 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
387 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
391 /*** Portuguese keyboard layout (setxkbmap pt) */
392 static const char main_key_PT
[MAIN_LEN
][4] =
394 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
395 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
396 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
397 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
401 /*** Italian keyboard layout (setxkbmap it) */
402 static const char main_key_IT
[MAIN_LEN
][4] =
404 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
405 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
406 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
407 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
411 /*** Finnish keyboard layout (setxkbmap fi) */
412 static const char main_key_FI
[MAIN_LEN
][4] =
414 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
415 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
416 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
417 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
421 /*** Bulgarian bds keyboard layout */
422 static const char main_key_BG_bds
[MAIN_LEN
][4] =
424 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
425 "qQ,\xfb","wW\xf3\xd3","eE\xe5\xc5","rR\xe8\xc8","tT\xf8\xd8","yY\xf9\xd9","uU\xea\xca","iI\xf1\xd1","oO\xe4\xc4","pP\xe7\xc7","[{\xf6\xd6","]};",
426 "aA\xfc\xdc","sS\xff\xdf","dD\xe0\xc0","fF\xee\xce","gG\xe6\xc6","hH\xe3\xc3","jJ\xf2\xd2","kK\xed\xcd","lL\xe2\xc2",";:\xec\xcc","'\"\xf7\xd7","\\|'\xdb",
427 "zZ\xfe\xde","xX\xe9\xc9","cC\xfa\xda","vV\xfd\xdd","bB\xf4\xd4","nN\xf5\xd5","mM\xef\xcf",",<\xf0\xd0",".>\xeb\xcb","/?\xe1\xc1",
428 "<>" /* the phantom key */
431 /*** Bulgarian phonetic keyboard layout */
432 static const char main_key_BG_phonetic
[MAIN_LEN
][4] =
434 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
435 "qQ\xff\xdf","wW\xe2\xc2","eE\xe5\xc5","rR\xf0\xd0","tT\xf2\xd2","yY\xfa\xda","uU\xf3\xd3","iI\xe8\xc8","oO\xee\xce","pP\xef\xcf","[{\xf8\xd8","]}\xf9\xd9",
436 "aA\xe0\xc0","sS\xf1\xd1","dD\xe4\xc4","fF\xf4\xd4","gG\xe3\xc3","hH\xf5\xd5","jJ\xe9\xc9","kK\xea\xca","lL\xeb\xcb",";:","'\"","\\|\xfe\xde",
437 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
438 "<>" /* the phantom key */
441 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
442 /*** It matches Belarusian layout for XKB from Alexander Mikhailian */
443 static const char main_key_BY
[MAIN_LEN
][4] =
445 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
446 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xae\xbe","pP\xda\xfa","[{\xc8\xe8","]}''",
447 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|/|",
448 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xa6\xb6","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?.,", "<>|\xa6",
452 /*** Russian keyboard layout (contributed by Pavel Roskin) */
453 static const char main_key_RU
[MAIN_LEN
][4] =
455 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
456 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
457 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
458 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?"
461 /*** Russian keyboard layout (phantom key version) */
462 static const char main_key_RU_phantom
[MAIN_LEN
][4] =
464 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
465 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
466 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
467 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?",
468 "<>" /* the phantom key */
471 /*** Russian keyboard layout KOI8-R */
472 static const char main_key_RU_koi8r
[MAIN_LEN
][4] =
474 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
475 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
476 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
477 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
478 "<>" /* the phantom key */
481 /*** Russian keyboard layout cp1251 */
482 static const char main_key_RU_cp1251
[MAIN_LEN
][4] =
484 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
485 "qQ\xe9\xc9","wW\xf6\xd6","eE\xf3\xd3","rR\xea\xca","tT\xe5\xc5","yY\xed\xcd","uU\xe3\xc3","iI\xf8\xd8","oO\xf9\xd9","pP\xe7\xc7","[{\xf5\xd5","]}\xfa\xda",
486 "aA\xf4\xd4","sS\xfb\xdb","dD\xe2\xc2","fF\xe0\xc0","gG\xef\xcf","hH\xf0\xd0","jJ\xee\xce","kK\xeb\xcb","lL\xe4\xc4",";:\xe6\xc6","'\"\xfd\xdd","\\|",
487 "zZ\xff\xdf","xX\xf7\xd7","cC\xf1\xd1","vV\xec\xcc","bB\xe8\xc8","nN\xf2\xd2","mM\xfc\xdc",",<\xe1\xc1",".>\xfe\xde","/?",
488 "<>" /* the phantom key */
491 /*** Russian phonetic keyboard layout */
492 static const char main_key_RU_phonetic
[MAIN_LEN
][4] =
494 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
495 "qQ\xd1\xf1","wW\xd7\xf7","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xd9\xf9","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}\xdd\xfd",
496 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xca\xea","kK\xcb\xeb","lL\xcc\xec",";:","'\"","\\|",
497 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
498 "<>" /* the phantom key */
501 /*** Ukrainian keyboard layout KOI8-U */
502 static const char main_key_UA
[MAIN_LEN
][4] =
504 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
505 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xa7\xb7",
506 "aA\xc6\xe6","sS\xa6\xb6","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xa4\xb4","\\|\\|",
507 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?/?",
508 "<>" /* the phantom key */
511 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
512 /*** (as it appears on most of keyboards sold today) */
513 static const char main_key_UA_std
[MAIN_LEN
][4] =
515 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
516 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
517 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
518 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
519 "<>" /* the phantom key */
522 /*** Russian keyboard layout KOI8-R (pair to the previous) */
523 static const char main_key_RU_std
[MAIN_LEN
][4] =
525 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
526 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
527 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
528 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
529 "<>" /* the phantom key */
532 /*** Spanish keyboard layout (setxkbmap es) */
533 static const char main_key_ES
[MAIN_LEN
][4] =
535 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
536 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
537 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
538 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
542 /*** Belgian keyboard layout ***/
543 static const char main_key_BE
[MAIN_LEN
][4] =
545 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
546 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
547 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
548 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
552 /*** Hungarian keyboard layout (setxkbmap hu) */
553 static const char main_key_HU
[MAIN_LEN
][4] =
555 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
556 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
557 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
558 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
562 /*** Polish (programmer's) keyboard layout ***/
563 static const char main_key_PL
[MAIN_LEN
][4] =
565 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
566 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
567 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
568 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
572 /*** Slovenian keyboard layout (setxkbmap si) ***/
573 static const char main_key_SI
[MAIN_LEN
][4] =
575 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
576 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
577 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
578 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
582 /*** Serbian keyboard layout (setxkbmap sr) ***/
583 static const char main_key_SR
[MAIN_LEN
][4] =
585 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
586 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
587 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
588 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
589 "<>" /* the phantom key */
592 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
593 static const char main_key_US_SR
[MAIN_LEN
][4] =
595 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
596 "qQ\xa9\xb9","wW\xaa\xba","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xda\xfa","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}[]",
597 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xa8\xb8","kK\xcb\xeb","lL\xcc\xec",";:\xde\xfe","'\"\xab\xbb","\\|-_",
598 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
599 "<>" /* the phantom key */
602 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
603 static const char main_key_HR_jelly
[MAIN_LEN
][4] =
605 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
606 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
607 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
608 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
612 /*** Croatian keyboard layout (setxkbmap hr) ***/
613 static const char main_key_HR
[MAIN_LEN
][4] =
615 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
616 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
617 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
618 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
622 /*** Japanese 106 keyboard layout ***/
623 static const char main_key_JA_jp106
[MAIN_LEN
][4] =
625 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
626 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
627 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
628 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
632 static const char main_key_JA_macjp
[MAIN_LEN
][4] =
634 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
635 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
636 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
637 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
641 /*** Japanese pc98x1 keyboard layout ***/
642 static const char main_key_JA_pc98x1
[MAIN_LEN
][4] =
644 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
645 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
646 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
647 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
651 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
652 static const char main_key_PT_br
[MAIN_LEN
][4] =
654 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
655 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
656 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
657 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
660 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
661 static const char main_key_PT_br_alt_gr
[MAIN_LEN
][4] =
663 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
664 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
665 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
666 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
669 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
670 static const char main_key_US_intl
[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 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
679 - dead_abovering replaced with degree - no symbol in iso8859-2
680 - brokenbar replaced with bar */
681 static const char main_key_SK
[MAIN_LEN
][4] =
683 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
684 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
685 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
686 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
690 /*** Czech keyboard layout (setxkbmap cz) */
691 static const char main_key_CZ
[MAIN_LEN
][4] =
693 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
694 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
695 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
696 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
700 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
701 static const char main_key_CZ_qwerty
[MAIN_LEN
][4] =
703 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
704 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
705 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
706 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
710 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
711 static const char main_key_SK_prog
[MAIN_LEN
][4] =
713 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
714 "qQ\xe4\xc4","wW\xec\xcc","eE\xe9\xc9","rR\xf8\xd8","tT\xbb\xab","yY\xfd\xdd","uU\xf9\xd9","iI\xed\xcd","oO\xf3\xd3","pP\xf6\xd6","[{","]}",
715 "aA\xe1\xc1","sS\xb9\xa9","dD\xef\xcf","fF\xeb\xcb","gG\xe0\xc0","hH\xfa\xda","jJ\xfc\xdc","kK\xf4\xd4","lL\xb5\xa5",";:","'\"","\\|",
716 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
720 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
721 static const char main_key_CS
[MAIN_LEN
][4] =
723 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
724 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
725 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
726 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
730 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
731 static const char main_key_LA
[MAIN_LEN
][4] =
733 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
734 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
735 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
736 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
740 /*** Lithuanian keyboard layout (setxkbmap lt) */
741 static const char main_key_LT_B
[MAIN_LEN
][4] =
743 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
744 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
745 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
746 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
750 /*** Turkish keyboard Layout */
751 static const char main_key_TK
[MAIN_LEN
][4] =
753 "\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
754 "qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
755 "aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
756 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
759 /*** Turkish keyboard layout (setxkbmap tr) */
760 static const char main_key_TR
[MAIN_LEN
][4] =
762 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
763 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
764 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
765 "zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
769 /*** Turkish F keyboard layout (setxkbmap trf) */
770 static const char main_key_TR_F
[MAIN_LEN
][4] =
772 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
773 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
774 "uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
775 "jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
779 /*** Israelian keyboard layout (setxkbmap us,il) */
780 static const char main_key_IL
[MAIN_LEN
][4] =
782 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
783 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
784 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
785 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
789 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
790 static const char main_key_IL_phonetic
[MAIN_LEN
][4] =
792 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
793 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
794 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
795 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
799 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
800 static const char main_key_IL_saharon
[MAIN_LEN
][4] =
802 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
803 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
804 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
805 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
809 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
810 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
811 message since they have different characters in gr and el XFree86 layouts. */
812 static const char main_key_EL
[MAIN_LEN
][4] =
814 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
815 "qQ;:","wW","eE\xe5\xc5","rR\xf1\xd1","tT\xf4\xd4","yY\xf5\xd5","uU\xe8\xc8","iI\xe9\xc9","oO\xef\xcf","pP\xf0\xd0","[{","]}",
816 "aA\xe1\xc1","sS","dD\xe4\xc4","fF\xf6\xd6","gG\xe3\xc3","hH\xe7\xc7","jJ\xee\xce","kK\xea\xca","lL\xeb\xcb",";:\xb4\xa8","'\"","\\|",
817 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
821 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
822 static const char main_key_th
[MAIN_LEN
][4] =
824 "`~_%","1!\xe5+","2@/\xf1","3#-\xf2","4$\xc0\xf3","5%\xb6\xf4","6^\xd8\xd9","7&\xd6\xdf","8*\xa4\xf5","9(\xb5\xf6","0)\xa8\xf7","-_\xa2\xf8","=+\xaa\xf9",
825 "qQ\xe6\xf0","wW\xe4\"","eE\xd3\xae","rR\xbe\xb1","tT\xd0\xb8","yY\xd1\xed","uU\xd5\xea","iI\xc3\xb3","oO\xb9\xcf","pP\xc2\xad","[{\xba\xb0","]}\xc5,",
826 "aA\xbf\xc4","sS\xcb\xa6","dD\xa1\xaf","fF\xb4\xe2","gG\xe0\xac","hH\xe9\xe7","jJ\xe8\xeb","kK\xd2\xc9","lL\xca\xc8",";:\xc7\xab","\'\"\xa7.","\\|\xa3\xa5",
827 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
830 /*** VNC keyboard layout */
831 static const WORD main_key_scan_vnc
[MAIN_LEN
] =
833 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
834 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,
838 static const WORD main_key_vkey_vnc
[MAIN_LEN
] =
840 '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
,
841 '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',
845 static const char main_key_vnc
[MAIN_LEN
][4] =
847 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
848 "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"
851 /*** Dutch keyboard layout (setxkbmap nl) ***/
852 static const char main_key_NL
[MAIN_LEN
][4] =
854 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
855 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
856 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
857 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
863 /*** Layout table. Add your keyboard mappings to this list */
864 static const struct {
865 LCID lcid
; /* input locale identifier, look for LOCALE_ILANGUAGE
866 in the appropriate dlls/kernel/nls/.nls file */
868 const char (*key
)[MAIN_LEN
][4];
869 const WORD (*scan
)[MAIN_LEN
]; /* scan codes mapping */
870 const WORD (*vkey
)[MAIN_LEN
]; /* virtual key codes mapping */
872 {0x0409, "United States keyboard layout", &main_key_US
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
873 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
874 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak
, &main_key_scan_dvorak
, &main_key_vkey_dvorak
},
875 {0x0409, "United States International keyboard layout", &main_key_US_intl
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
876 {0x0809, "British keyboard layout", &main_key_UK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
877 {0x0407, "German keyboard layout", &main_key_DE
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
878 {0x0807, "Swiss German keyboard layout", &main_key_SG
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
879 {0x100c, "Swiss French keyboard layout", &main_key_SF
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
880 {0x041d, "Swedish keyboard layout", &main_key_SE
, &main_key_scan_qwerty
, &main_key_vkey_qwerty_v2
},
881 {0x0425, "Estonian keyboard layout", &main_key_ET
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
882 {0x0414, "Norwegian keyboard layout", &main_key_NO
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
883 {0x0406, "Danish keyboard layout", &main_key_DA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
884 {0x040c, "French keyboard layout", &main_key_FR
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
885 {0x0c0c, "Canadian French keyboard layout", &main_key_CF
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
886 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
887 {0x0c0c, "Canadian keyboard layout", &main_key_CA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
888 {0x080c, "Belgian keyboard layout", &main_key_BE
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
889 {0x0816, "Portuguese keyboard layout", &main_key_PT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
890 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br
, &main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
891 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr
,&main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
892 {0x040b, "Finnish keyboard layout", &main_key_FI
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
893 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
894 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
895 {0x0423, "Belarusian keyboard layout", &main_key_BY
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
896 {0x0419, "Russian keyboard layout", &main_key_RU
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
897 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
898 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
899 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
900 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
901 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
902 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
903 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
904 {0x040a, "Spanish keyboard layout", &main_key_ES
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
905 {0x0410, "Italian keyboard layout", &main_key_IT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
906 {0x040f, "Icelandic keyboard layout", &main_key_IS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
907 {0x040e, "Hungarian keyboard layout", &main_key_HU
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
908 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
909 {0x0424, "Slovenian keyboard layout", &main_key_SI
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
910 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
911 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
912 {0x041a, "Croatian keyboard layout", &main_key_HR
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
913 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
914 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106
, &main_key_scan_qwerty_jp106
, &main_key_vkey_qwerty_jp106
},
915 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp
, &main_key_scan_qwerty_jp106
, &main_key_vkey_qwerty_jp106
},
916 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
917 {0x041b, "Slovak keyboard layout", &main_key_SK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
918 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
919 {0x0405, "Czech keyboard layout", &main_key_CS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
920 {0x0405, "Czech keyboard layout cz", &main_key_CZ
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
921 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
922 {0x040a, "Latin American keyboard layout", &main_key_LA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
923 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
924 {0x041f, "Turkish keyboard layout", &main_key_TK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
925 {0x041f, "Turkish keyboard layout tr", &main_key_TR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
926 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
927 {0x040d, "Israelian keyboard layout", &main_key_IL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
928 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
929 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
930 {0x0409, "VNC keyboard layout", &main_key_vnc
, &main_key_scan_vnc
, &main_key_vkey_vnc
},
931 {0x0408, "Greek keyboard layout", &main_key_EL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
932 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
933 {0x0413, "Dutch keyboard layout", &main_key_NL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
935 {0, NULL
, NULL
, NULL
, NULL
} /* sentinel */
937 static unsigned kbd_layout
=0; /* index into above table of layouts */
939 /* maybe more of these scancodes should be extended? */
940 /* extended must be set for ALT_R, CTRL_R,
941 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
942 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
943 /* FIXME should we set extended bit for NumLock ? My
944 * Windows does ... DF */
945 /* Yes, to distinguish based on scan codes, also
946 for PrtScn key ... GA */
948 static const WORD nonchar_key_vkey
[256] =
951 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
953 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
954 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
955 0, 0, 0, VK_ESCAPE
, 0, 0, 0, 0, /* FF18 */
956 /* Japanese special keys */
957 0, VK_KANJI
, VK_NONCONVERT
, VK_CONVERT
, /* FF20 */
958 VK_DBE_ROMAN
, 0, 0, VK_DBE_HIRAGANA
,
959 0, 0, VK_DBE_SBCSCHAR
, 0, 0, 0, 0, 0, /* FF28 */
960 /* Korean special keys (FF31-) */
961 VK_DBE_ALPHANUMERIC
, VK_HANGUL
, 0, 0, VK_HANJA
, 0, 0, 0, /* FF30 */
962 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
964 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
965 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
967 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, /* FF50 */
968 VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
,
969 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
971 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0,0,0, VK_APPS
, /* FF60 */
972 0, VK_CANCEL
, VK_HELP
, VK_CANCEL
, 0, 0, 0, 0, /* FF68 */
973 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
975 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK
, /* FF78 */
976 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
977 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
978 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
979 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, /* FF98 */
980 VK_END
, VK_CLEAR
, VK_INSERT
, VK_DELETE
,
981 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
982 0, 0, VK_MULTIPLY
, VK_ADD
, /* FFA8 */
983 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
984 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
985 * in order to produce a locale dependent numeric separator.
987 VK_DECIMAL
, VK_SUBTRACT
, VK_DECIMAL
, VK_DIVIDE
,
988 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, /* FFB0 */
989 VK_NUMPAD4
, VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
,
990 VK_NUMPAD8
, VK_NUMPAD9
, 0, 0, 0, VK_OEM_NEC_EQUAL
, /* FFB8 */
993 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
994 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
, VK_F17
, VK_F18
, /* FFC8 */
995 VK_F19
, VK_F20
, VK_F21
, VK_F22
, VK_F23
, VK_F24
, 0, 0, /* FFD0 */
996 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
998 0, VK_LSHIFT
, VK_RSHIFT
, VK_LCONTROL
, /* FFE0 */
999 VK_RCONTROL
, VK_CAPITAL
, 0, VK_LMENU
,
1000 VK_RMENU
, VK_LMENU
, VK_RMENU
, VK_LWIN
, VK_RWIN
, 0, 0, 0, /* FFE8 */
1001 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1002 0, 0, 0, 0, 0, 0, 0, VK_DELETE
/* FFF8 */
1005 static const WORD nonchar_key_scan
[256] =
1008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1010 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1011 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1012 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1013 /* Japanese special keys */
1014 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */
1015 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1016 /* Korean special keys (FF31-) */
1017 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1020 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1023 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1026 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1027 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1034 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1036 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1037 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1038 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1041 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1042 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1046 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1047 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1048 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1049 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1052 static const WORD xfree86_vendor_key_vkey
[256] =
1054 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1055 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1056 0, VK_VOLUME_DOWN
, VK_VOLUME_MUTE
, VK_VOLUME_UP
, /* 1008FF10 */
1057 VK_MEDIA_PLAY_PAUSE
, VK_MEDIA_STOP
,
1058 VK_MEDIA_PREV_TRACK
, VK_MEDIA_NEXT_TRACK
,
1059 0, VK_LAUNCH_MAIL
, 0, VK_BROWSER_SEARCH
, /* 1008FF18 */
1060 0, 0, 0, VK_BROWSER_HOME
,
1061 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK
, VK_BROWSER_FORWARD
, /* 1008FF20 */
1062 VK_BROWSER_STOP
, VK_BROWSER_REFRESH
, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1063 VK_BROWSER_FAVORITES
, 0, VK_LAUNCH_MEDIA_SELECT
, 0, /* 1008FF30 */
1065 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1066 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1067 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1068 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1069 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1070 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1071 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1072 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1089 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1092 static inline KeySym
keycode_to_keysym( Display
*display
, KeyCode keycode
, int index
)
1095 if (use_xkb
) return XkbKeycodeToKeysym(display
, keycode
, 0, index
);
1097 return key_mapping
[(keycode
- min_keycode
) * keysyms_per_keycode
+ index
];
1100 /* Returns the Windows virtual key code associated with the X event <e> */
1101 /* kbd_section must be held */
1102 static WORD
EVENT_event_to_vkey( XIC xic
, XKeyEvent
*e
)
1108 /* Clients should pass only KeyPress events to XmbLookupString */
1109 if (xic
&& e
->type
== KeyPress
)
1110 XmbLookupString(xic
, e
, buf
, sizeof(buf
), &keysym
, &status
);
1112 XLookupString(e
, buf
, sizeof(buf
), &keysym
, NULL
);
1114 if ((e
->state
& NumLockMask
) &&
1115 (keysym
== XK_KP_Separator
|| keysym
== XK_KP_Decimal
||
1116 (keysym
>= XK_KP_0
&& keysym
<= XK_KP_9
)))
1117 /* Only the Keypad keys 0-9 and . send different keysyms
1118 * depending on the NumLock state */
1119 return nonchar_key_vkey
[keysym
& 0xFF];
1121 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1122 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1123 if ((e
->state
& ControlMask
) && (keysym
== XK_Break
))
1126 TRACE_(key
)("e->keycode = %u\n", e
->keycode
);
1128 return keyc2vkey
[e
->keycode
];
1132 /***********************************************************************
1133 * X11DRV_send_keyboard_input
1135 static void X11DRV_send_keyboard_input( HWND hwnd
, WORD vkey
, WORD scan
, UINT flags
, UINT time
)
1139 TRACE_(key
)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd
, vkey
, scan
, flags
);
1141 input
.type
= INPUT_KEYBOARD
;
1142 input
.u
.ki
.wVk
= vkey
;
1143 input
.u
.ki
.wScan
= scan
;
1144 input
.u
.ki
.dwFlags
= flags
;
1145 input
.u
.ki
.time
= time
;
1146 input
.u
.ki
.dwExtraInfo
= 0;
1148 __wine_send_input( hwnd
, &input
, NULL
);
1152 /***********************************************************************
1153 * get_async_key_state
1155 static BOOL
get_async_key_state( BYTE state
[256] )
1159 SERVER_START_REQ( get_key_state
)
1163 wine_server_set_reply( req
, state
, 256 );
1164 ret
= !wine_server_call( req
);
1170 /***********************************************************************
1171 * set_async_key_state
1173 static void set_async_key_state( const BYTE state
[256] )
1175 SERVER_START_REQ( set_key_state
)
1178 wine_server_add_data( req
, state
, 256 );
1179 wine_server_call( req
);
1184 static void update_key_state( BYTE
*keystate
, BYTE key
, int down
)
1188 if (!(keystate
[key
] & 0x80)) keystate
[key
] ^= 0x01;
1189 keystate
[key
] |= 0x80;
1191 else keystate
[key
] &= ~0x80;
1194 /***********************************************************************
1195 * X11DRV_KeymapNotify
1197 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1199 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1200 * from wine to another application and back.
1201 * Toggle keys are handled in HandleEvent.
1203 BOOL
X11DRV_KeymapNotify( HWND hwnd
, XEvent
*event
)
1208 BOOL changed
= FALSE
;
1214 if (!get_async_key_state( keystate
)) return FALSE
;
1216 memset(keys
, 0, sizeof(keys
));
1218 pthread_mutex_lock( &kbd_mutex
);
1220 /* the minimum keycode is always greater or equal to 8, so we can
1221 * skip the first 8 values, hence start at 1
1223 for (i
= 1; i
< 32; i
++)
1225 for (j
= 0; j
< 8; j
++)
1227 vkey
= keyc2vkey
[(i
* 8) + j
];
1229 /* If multiple keys map to the same vkey, we want to report it as
1230 * pressed iff any of them are pressed. */
1231 if (!keys
[vkey
& 0xff].vkey
) keys
[vkey
& 0xff].vkey
= vkey
;
1232 if (event
->xkeymap
.key_vector
[i
] & (1<<j
)) keys
[vkey
& 0xff].pressed
= TRUE
;
1236 for (vkey
= 1; vkey
<= 0xff; vkey
++)
1238 if (keys
[vkey
].vkey
&& !(keystate
[vkey
] & 0x80) != !keys
[vkey
].pressed
)
1240 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1241 keys
[vkey
].vkey
, keystate
[vkey
]);
1243 update_key_state( keystate
, vkey
, keys
[vkey
].pressed
);
1248 pthread_mutex_unlock( &kbd_mutex
);
1249 if (!changed
) return FALSE
;
1251 update_key_state( keystate
, VK_CONTROL
, (keystate
[VK_LCONTROL
] | keystate
[VK_RCONTROL
]) & 0x80 );
1252 update_key_state( keystate
, VK_MENU
, (keystate
[VK_LMENU
] | keystate
[VK_RMENU
]) & 0x80 );
1253 update_key_state( keystate
, VK_SHIFT
, (keystate
[VK_LSHIFT
] | keystate
[VK_RSHIFT
]) & 0x80 );
1254 set_async_key_state( keystate
);
1258 static void adjust_lock_state( BYTE
*keystate
, HWND hwnd
, WORD vkey
, WORD scan
, DWORD flags
, DWORD time
)
1260 BYTE prev_state
= keystate
[vkey
] & 0x01;
1262 X11DRV_send_keyboard_input( hwnd
, vkey
, scan
, flags
, time
);
1263 X11DRV_send_keyboard_input( hwnd
, vkey
, scan
, flags
^ KEYEVENTF_KEYUP
, time
);
1265 /* Keyboard hooks may have blocked processing lock keys causing our state
1266 * to be different than state on X server side. Although Windows allows hooks
1267 * to block changing state, we can't prevent it on X server side. Having
1268 * different states would cause us to try to adjust it again on the next
1269 * key event. We prevent that by overriding hooks and setting key states here. */
1270 if (get_async_key_state( keystate
) && (keystate
[vkey
] & 0x01) == prev_state
)
1272 WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey
, keystate
[vkey
]);
1273 keystate
[vkey
] ^= 0x01;
1274 set_async_key_state( keystate
);
1278 static void update_lock_state( HWND hwnd
, WORD vkey
, UINT state
, UINT time
)
1282 /* Note: X sets the below states on key down and clears them on key up.
1283 Windows triggers them on key down. */
1285 if (!get_async_key_state( keystate
)) return;
1287 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1288 if (!(keystate
[VK_CAPITAL
] & 0x01) != !(state
& LockMask
) && vkey
!= VK_CAPITAL
)
1291 if (keystate
[VK_CAPITAL
] & 0x80) flags
^= KEYEVENTF_KEYUP
;
1292 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate
[VK_CAPITAL
]);
1293 adjust_lock_state( keystate
, hwnd
, VK_CAPITAL
, 0x3a, flags
, 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 adjust_lock_state( keystate
, hwnd
, VK_NUMLOCK
, 0x45, flags
, time
);
1305 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1306 if (!(keystate
[VK_SCROLL
] & 0x01) != !(state
& ScrollLockMask
) && vkey
!= VK_SCROLL
)
1309 if (keystate
[VK_SCROLL
] & 0x80) flags
^= KEYEVENTF_KEYUP
;
1310 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate
[VK_SCROLL
]);
1311 adjust_lock_state( keystate
, hwnd
, VK_SCROLL
, 0x46, flags
, time
);
1315 /***********************************************************************
1318 * Handle a X key event
1320 BOOL
X11DRV_KeyEvent( HWND hwnd
, XEvent
*xev
)
1322 XKeyEvent
*event
= &xev
->xkey
;
1326 WORD vkey
= 0, bScan
;
1329 XIC xic
= X11DRV_get_ic( hwnd
);
1330 DWORD event_time
= EVENT_x11_time_to_win32_time(event
->time
);
1333 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode %u\n",
1334 event
->type
, event
->window
, event
->state
, event
->keycode
);
1336 if (event
->type
== KeyPress
) update_user_time( event
->time
);
1338 /* Clients should pass only KeyPress events to XmbLookupString */
1339 if (xic
&& event
->type
== KeyPress
)
1341 ascii_chars
= XmbLookupString(xic
, event
, buf
, sizeof(buf
), &keysym
, &status
);
1342 TRACE_(key
)("XmbLookupString needs %i byte(s)\n", ascii_chars
);
1343 if (status
== XBufferOverflow
)
1345 Str
= malloc( ascii_chars
);
1348 ERR_(key
)("Failed to allocate memory!\n");
1351 ascii_chars
= XmbLookupString(xic
, event
, Str
, ascii_chars
, &keysym
, &status
);
1355 ascii_chars
= XLookupString(event
, buf
, sizeof(buf
), &keysym
, NULL
);
1357 TRACE_(key
)("nbyte = %d, status %d\n", ascii_chars
, status
);
1359 if (status
== XLookupChars
)
1361 X11DRV_XIMLookupChars( Str
, ascii_chars
);
1367 pthread_mutex_lock( &kbd_mutex
);
1369 /* If XKB extensions are used, the state mask for AltGr will use the group
1370 index instead of the modifier mask. The group index is set in bits
1371 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1372 pressed, look if the group index is different than 0. From XKB
1373 extension documentation, the group index for AltGr should be 2
1374 (event->state = 0x2000). It's probably better to not assume a
1375 predefined group index and find it dynamically
1377 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1378 /* Save also all possible modifier states. */
1379 AltGrMask
= event
->state
& (0x6000 | Mod1Mask
| Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
);
1384 ksname
= XKeysymToString(keysym
);
1387 TRACE_(key
)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1388 (event
->type
== KeyPress
) ? "KeyPress" : "KeyRelease",
1389 keysym
, ksname
, ascii_chars
, debugstr_an(Str
, ascii_chars
));
1394 vkey
= EVENT_event_to_vkey(xic
,event
);
1395 /* X returns keycode 0 for composed characters */
1396 if (!vkey
&& ascii_chars
) vkey
= VK_NONAME
;
1397 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
1399 TRACE_(key
)("keycode %u converted to vkey 0x%X scan %02x\n",
1400 event
->keycode
, vkey
, bScan
);
1402 pthread_mutex_unlock( &kbd_mutex
);
1404 if (!vkey
) return FALSE
;
1407 if ( event
->type
== KeyRelease
) dwFlags
|= KEYEVENTF_KEYUP
;
1408 if ( vkey
& 0x100 ) dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
1410 update_lock_state( hwnd
, vkey
, event
->state
, event_time
);
1412 X11DRV_send_keyboard_input( hwnd
, vkey
& 0xff, bScan
, dwFlags
, event_time
);
1416 /**********************************************************************
1417 * X11DRV_KEYBOARD_DetectLayout
1419 * Called from X11DRV_InitKeyboard
1420 * This routine walks through the defined keyboard layouts and selects
1421 * whichever matches most closely.
1422 * kbd_section must be held.
1425 X11DRV_KEYBOARD_DetectLayout( Display
*display
)
1427 unsigned current
, match
, mismatch
, seq
, i
, syms
;
1428 int score
, keyc
, key
, pkey
, ok
;
1430 const char (*lkey
)[MAIN_LEN
][4];
1431 unsigned max_seq
= 0;
1432 int max_score
= INT_MIN
, ismatch
= 0;
1435 syms
= keysyms_per_keycode
;
1437 WARN("%d keysyms per keycode not supported, set to 4\n", syms
);
1441 memset( ckey
, 0, sizeof(ckey
) );
1442 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1443 /* get data for keycode from X server */
1444 for (i
= 0; i
< syms
; i
++) {
1445 if (!(keysym
= keycode_to_keysym (display
, keyc
, i
))) continue;
1446 /* Allow both one-byte and two-byte national keysyms */
1447 if ((keysym
< 0x8000) && (keysym
!= ' '))
1450 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[keyc
][i
], 1, NULL
))
1453 TRACE("XKB could not translate keysym %04lx\n", keysym
);
1454 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1455 * with appropriate ShiftMask and Mode_switch, use XLookupString
1456 * to get character in the local encoding.
1458 ckey
[keyc
][i
] = keysym
& 0xFF;
1462 ckey
[keyc
][i
] = KEYBOARD_MapDeadKeysym(keysym
);
1467 for (current
= 0; main_key_tab
[current
].comment
; current
++) {
1468 TRACE("Attempting to match against \"%s\"\n", main_key_tab
[current
].comment
);
1473 lkey
= main_key_tab
[current
].key
;
1475 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1476 if (ckey
[keyc
][0]) {
1477 /* search for a match in layout table */
1478 /* right now, we just find an absolute match for defined positions */
1479 /* (undefined positions are ignored, so if it's defined as "3#" in */
1480 /* the table, it's okay that the X server has "3#£", for example) */
1481 /* however, the score will be higher for longer matches */
1482 for (key
= 0; key
< MAIN_LEN
; key
++) {
1483 for (ok
= 0, i
= 0; (ok
>= 0) && (i
< syms
); i
++) {
1484 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] == ckey
[keyc
][i
]))
1486 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[keyc
][i
]))
1494 /* count the matches and mismatches */
1497 /* and how much the keycode order matches */
1498 if (key
> pkey
) seq
++;
1501 /* print spaces instead of \0's */
1503 for (i
= 0; i
< 4; i
++) str
[i
] = ckey
[keyc
][i
] ? ckey
[keyc
][i
] : ' ';
1505 TRACE_(key
)("mismatch for keycode %u, got %s\n", keyc
, debugstr_a(str
));
1511 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1512 match
, mismatch
, seq
, score
);
1513 if ((score
> max_score
) ||
1514 ((score
== max_score
) && (seq
> max_seq
))) {
1515 /* best match so far */
1516 kbd_layout
= current
;
1519 ismatch
= !mismatch
;
1522 /* we're done, report results if necessary */
1524 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1525 main_key_tab
[kbd_layout
].comment
);
1527 TRACE("detected layout is \"%s\"\n", main_key_tab
[kbd_layout
].comment
);
1530 static HKL
get_locale_kbd_layout(void)
1537 * layout = main_key_tab[kbd_layout].lcid;
1539 * Winword uses return value of GetKeyboardLayout as a codepage
1540 * to translate ANSI keyboard messages to unicode. But we have
1541 * a problem with it: for instance Polish keyboard layout is
1542 * identical to the US one, and therefore instead of the Polish
1543 * locale id we return the US one.
1546 NtQueryDefaultLocale( TRUE
, &layout
);
1549 * Microsoft Office expects this value to be something specific
1550 * for Japanese and Korean Windows with an IME the value is 0xe001
1551 * We should probably check to see if an IME exists and if so then
1552 * set this word properly.
1554 langid
= PRIMARYLANGID(LANGIDFROMLCID(layout
));
1555 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
1556 layout
= MAKELONG( layout
, 0xe001 ); /* IME */
1558 layout
|= layout
<< 16;
1560 return (HKL
)(UINT_PTR
)layout
;
1564 /**********************************************************************
1565 * X11DRV_InitKeyboard
1567 void X11DRV_InitKeyboard( Display
*display
)
1569 XModifierKeymap
*mmp
;
1574 int keyc
, i
, keyn
, syms
;
1575 char ckey
[4]={0,0,0,0};
1576 const char (*lkey
)[MAIN_LEN
][4];
1577 char vkey_used
[256] = { 0 };
1579 /* Ranges of OEM, function key, and character virtual key codes.
1580 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1581 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1582 static const struct {
1585 { VK_OEM_1
, VK_OEM_3
},
1586 { VK_OEM_4
, VK_OEM_8
},
1587 { VK_OEM_AX
, VK_ICO_00
},
1590 { VK_OEM_NEC_EQUAL
, VK_OEM_NEC_EQUAL
},
1592 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1593 { 0x41, 0x5a }, /* VK_A - VK_Z */
1598 pthread_mutex_lock( &kbd_mutex
);
1599 XDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
1600 if (key_mapping
) XFree( key_mapping
);
1601 key_mapping
= XGetKeyboardMapping(display
, min_keycode
,
1602 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
1604 mmp
= XGetModifierMapping(display
);
1605 kcp
= mmp
->modifiermap
;
1606 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
1610 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
1615 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
1616 if (keycode_to_keysym(display
, *kcp
, k
) == XK_Num_Lock
)
1618 NumLockMask
= 1 << i
;
1619 TRACE_(key
)("NumLockMask is %x\n", NumLockMask
);
1621 else if (keycode_to_keysym(display
, *kcp
, k
) == XK_Scroll_Lock
)
1623 ScrollLockMask
= 1 << i
;
1624 TRACE_(key
)("ScrollLockMask is %x\n", ScrollLockMask
);
1628 XFreeModifiermap(mmp
);
1630 /* Detect the keyboard layout */
1631 X11DRV_KEYBOARD_DetectLayout( display
);
1632 lkey
= main_key_tab
[kbd_layout
].key
;
1633 syms
= (keysyms_per_keycode
> 4) ? 4 : keysyms_per_keycode
;
1635 /* Now build two conversion arrays :
1636 * keycode -> vkey + scancode + extended
1637 * vkey + extended -> keycode */
1639 e2
.display
= display
;
1643 memset(keyc2vkey
, 0, sizeof(keyc2vkey
));
1644 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1650 e2
.keycode
= (KeyCode
)keyc
;
1651 have_chars
= XLookupString(&e2
, buf
, sizeof(buf
), &keysym
, NULL
);
1653 if (keysym
) /* otherwise, keycode not used */
1655 if ((keysym
>> 8) == 0xFF) /* non-character key */
1657 vkey
= nonchar_key_vkey
[keysym
& 0xff];
1658 scan
= nonchar_key_scan
[keysym
& 0xff];
1659 /* set extended bit when necessary */
1660 if (scan
& 0x100) vkey
|= 0x100;
1661 } else if ((keysym
>> 8) == 0x1008FF) { /* XFree86 vendor keys */
1662 vkey
= xfree86_vendor_key_vkey
[keysym
& 0xff];
1663 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1666 } else if (keysym
== 0x20) { /* Spacebar */
1669 } else if (have_chars
) {
1670 /* we seem to need to search the layout-dependent scancodes */
1671 int maxlen
=0,maxval
=-1,ok
;
1672 for (i
=0; i
<syms
; i
++) {
1673 keysym
= keycode_to_keysym(display
, keyc
, i
);
1674 if ((keysym
<0x8000) && (keysym
!=' '))
1677 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[i
], 1, NULL
))
1680 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1681 * with appropriate ShiftMask and Mode_switch, use XLookupString
1682 * to get character in the local encoding.
1684 ckey
[i
] = (keysym
<= 0x7F) ? keysym
: 0;
1687 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
1690 /* find key with longest match streak */
1691 for (keyn
=0; keyn
<MAIN_LEN
; keyn
++) {
1692 for (ok
=(*lkey
)[keyn
][i
=0]; ok
&&(i
<4); i
++)
1693 if ((*lkey
)[keyn
][i
] && (*lkey
)[keyn
][i
]!=ckey
[i
]) ok
=0;
1694 if (!ok
) i
--; /* we overshot */
1695 if (ok
||(i
>maxlen
)) {
1696 maxlen
=i
; maxval
=keyn
;
1702 const WORD (*lscan
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].scan
;
1703 const WORD (*lvkey
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].vkey
;
1704 scan
= (*lscan
)[maxval
];
1705 vkey
= (*lvkey
)[maxval
];
1709 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1710 keyc2vkey
[e2
.keycode
] = vkey
;
1711 keyc2scan
[e2
.keycode
] = scan
;
1712 if ((vkey
& 0xff) && vkey_used
[(vkey
& 0xff)])
1713 WARN("vkey %04X is being used by more than one keycode\n", vkey
);
1714 vkey_used
[(vkey
& 0xff)] = 1;
1717 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1718 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1720 vkey
= keyc2vkey
[keyc
] & 0xff;
1724 e2
.keycode
= (KeyCode
)keyc
;
1725 keysym
= XLookupKeysym(&e2
, 0);
1729 /* find a suitable layout-dependent VK code */
1730 /* (most Winelib apps ought to be able to work without layout tables!) */
1731 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1733 keysym
= XLookupKeysym(&e2
, i
);
1734 if ((keysym
>= XK_0
&& keysym
<= XK_9
)
1735 || (keysym
>= XK_A
&& keysym
<= XK_Z
)) {
1736 vkey
= VKEY_IF_NOT_USED(keysym
);
1740 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1742 keysym
= XLookupKeysym(&e2
, i
);
1745 case ';': vkey
= VKEY_IF_NOT_USED(VK_OEM_1
); break;
1746 case '/': vkey
= VKEY_IF_NOT_USED(VK_OEM_2
); break;
1747 case '`': vkey
= VKEY_IF_NOT_USED(VK_OEM_3
); break;
1748 case '[': vkey
= VKEY_IF_NOT_USED(VK_OEM_4
); break;
1749 case '\\': vkey
= VKEY_IF_NOT_USED(VK_OEM_5
); break;
1750 case ']': vkey
= VKEY_IF_NOT_USED(VK_OEM_6
); break;
1751 case '\'': vkey
= VKEY_IF_NOT_USED(VK_OEM_7
); break;
1752 case ',': vkey
= VKEY_IF_NOT_USED(VK_OEM_COMMA
); break;
1753 case '.': vkey
= VKEY_IF_NOT_USED(VK_OEM_PERIOD
); break;
1754 case '-': vkey
= VKEY_IF_NOT_USED(VK_OEM_MINUS
); break;
1755 case '+': vkey
= VKEY_IF_NOT_USED(VK_OEM_PLUS
); break;
1761 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1762 keyc2vkey
[e2
.keycode
] = vkey
;
1766 /* For any keycodes which still don't have a vkey, assign any spare
1767 * character, function key, or OEM virtual key code. */
1769 vkey
= vkey_ranges
[vkey_range
].first
;
1770 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1772 if (keyc2vkey
[keyc
] & 0xff)
1775 e2
.keycode
= (KeyCode
)keyc
;
1776 keysym
= XLookupKeysym(&e2
, 0);
1780 while (vkey
&& vkey_used
[vkey
])
1782 if (vkey
== vkey_ranges
[vkey_range
].last
)
1785 vkey
= vkey_ranges
[vkey_range
].first
;
1793 WARN("No more vkeys available!\n");
1797 if (TRACE_ON(keyboard
))
1799 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1802 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
1806 keysym
= XLookupKeysym(&e2
, i
);
1807 ksname
= XKeysymToString(keysym
);
1809 ksname
= "NoSymbol";
1810 TRACE( "%lx (%s) ", keysym
, ksname
);
1815 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1816 keyc2vkey
[e2
.keycode
] = vkey
;
1817 vkey_used
[vkey
] = 1;
1819 #undef VKEY_IF_NOT_USED
1821 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1822 for (scan
= 0x60, keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1823 if (keyc2vkey
[keyc
]&&!keyc2scan
[keyc
]) {
1825 keysym
= keycode_to_keysym(display
, keyc
, 0);
1826 ksname
= XKeysymToString(keysym
);
1827 if (!ksname
) ksname
= "NoSymbol";
1829 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1831 TRACE_(key
)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan
,keyc
,ksname
);
1832 keyc2scan
[keyc
]=scan
++;
1835 pthread_mutex_unlock( &kbd_mutex
);
1838 static BOOL
match_x11_keyboard_layout(HKL hkl
)
1840 const DWORD isIME
= 0xE0000000;
1841 HKL xHkl
= get_locale_kbd_layout();
1843 /* if the layout is an IME, only match the low word (LCID) */
1844 if (((ULONG_PTR
)hkl
& isIME
) == isIME
)
1845 return (LOWORD(hkl
) == LOWORD(xHkl
));
1847 return (hkl
== xHkl
);
1851 /***********************************************************************
1852 * ActivateKeyboardLayout (X11DRV.@)
1854 BOOL
X11DRV_ActivateKeyboardLayout(HKL hkl
, UINT flags
)
1856 FIXME("%p, %04x: semi-stub!\n", hkl
, flags
);
1858 if (flags
& KLF_SETFORPROCESS
)
1860 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1861 FIXME("KLF_SETFORPROCESS not supported\n");
1865 if (!match_x11_keyboard_layout(hkl
))
1867 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1868 FIXME("setting keyboard of different locales not supported\n");
1876 /***********************************************************************
1877 * X11DRV_MappingNotify
1879 BOOL
X11DRV_MappingNotify( HWND dummy
, XEvent
*event
)
1883 XRefreshKeyboardMapping(&event
->xmapping
);
1884 X11DRV_InitKeyboard( event
->xmapping
.display
);
1887 if (!hwnd
) hwnd
= get_active_window();
1888 NtUserPostMessage( hwnd
, WM_INPUTLANGCHANGEREQUEST
,
1889 0 /*FIXME*/, (LPARAM
)NtUserGetKeyboardLayout(0) );
1894 /***********************************************************************
1895 * VkKeyScanEx (X11DRV.@)
1897 * Note: Windows ignores HKL parameter and uses current active layout instead
1899 SHORT
X11DRV_VkKeyScanEx( WCHAR wChar
, HKL hkl
)
1901 Display
*display
= thread_init_display();
1908 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
1909 * is UTF-8 (multibyte encoding)?
1911 if (!ntdll_wcstoumbs( &wChar
, 1, &cChar
, 1, FALSE
))
1913 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar
);
1917 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar
, cChar
);
1919 /* char->keysym (same for ANSI chars) */
1920 keysym
= (unsigned char)cChar
; /* (!) cChar is signed */
1921 if (keysym
<= 27) keysym
+= 0xFF00; /* special chars : return, backspace... */
1923 keycode
= XKeysymToKeycode(display
, keysym
); /* keysym -> keycode */
1926 if (keysym
>= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
1928 ret
= 0x0240 + cChar
; /* 0x0200 indicates a control character */
1929 TRACE(" ... returning ctrl char %#.2x\n", ret
);
1932 /* It didn't work ... let's try with deadchar code. */
1933 TRACE("retrying with | 0xFE00\n");
1934 keycode
= XKeysymToKeycode(display
, keysym
| 0xFE00);
1937 TRACE("'%c'(%lx): got keycode %u\n", cChar
, keysym
, keycode
);
1938 if (!keycode
) return -1;
1940 pthread_mutex_lock( &kbd_mutex
);
1942 /* keycode -> (keyc2vkey) vkey */
1943 ret
= keyc2vkey
[keycode
];
1946 pthread_mutex_unlock( &kbd_mutex
);
1947 TRACE("keycode for '%c' not found, returning -1\n", cChar
);
1951 for (index
= 0; index
< 4; index
++) /* find shift state */
1952 if (keycode_to_keysym(display
, keycode
, index
) == keysym
) break;
1954 pthread_mutex_unlock( &kbd_mutex
);
1959 case 1: ret
+= 0x0100; break;
1960 case 2: ret
+= 0x0600; break;
1961 case 3: ret
+= 0x0700; break;
1963 WARN("Keysym %lx not found while parsing the keycode table\n", keysym
);
1967 index : 0 adds 0x0000
1968 index : 1 adds 0x0100 (shift)
1969 index : ? adds 0x0200 (ctrl)
1970 index : 2 adds 0x0600 (ctrl+alt)
1971 index : 3 adds 0x0700 (ctrl+alt+shift)
1974 TRACE(" ... returning %#.2x\n", ret
);
1978 /***********************************************************************
1979 * MapVirtualKeyEx (X11DRV.@)
1981 UINT
X11DRV_MapVirtualKeyEx( UINT wCode
, UINT wMapType
, HKL hkl
)
1985 Display
*display
= thread_init_display();
1987 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode
, wMapType
, hkl
);
1988 if (!match_x11_keyboard_layout(hkl
))
1989 FIXME("keyboard layout %p is not supported\n", hkl
);
1991 pthread_mutex_lock( &kbd_mutex
);
1995 case MAPVK_VK_TO_VSC
: /* vkey-code to scan-code */
1996 case MAPVK_VK_TO_VSC_EX
:
1999 case VK_SHIFT
: wCode
= VK_LSHIFT
; break;
2000 case VK_CONTROL
: wCode
= VK_LCONTROL
; break;
2001 case VK_MENU
: wCode
= VK_LMENU
; break;
2004 /* let's do vkey -> keycode -> scan */
2005 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2007 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
2009 ret
= keyc2scan
[keyc
] & 0xFF;
2014 /* set scan code prefix */
2015 if (wMapType
== MAPVK_VK_TO_VSC_EX
&&
2016 (wCode
== VK_RCONTROL
|| wCode
== VK_RMENU
))
2020 case MAPVK_VSC_TO_VK
: /* scan-code to vkey-code */
2021 case MAPVK_VSC_TO_VK_EX
:
2023 /* let's do scan -> keycode -> vkey */
2024 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2025 if ((keyc2scan
[keyc
] & 0xFF) == (wCode
& 0xFF))
2027 ret
= keyc2vkey
[keyc
] & 0xFF;
2028 /* Only stop if it's not a numpad vkey; otherwise keep
2029 looking for a potential better vkey. */
2030 if (ret
&& (ret
< VK_NUMPAD0
|| VK_DIVIDE
< ret
))
2034 if (wMapType
== MAPVK_VSC_TO_VK
)
2039 ret
= VK_SHIFT
; break;
2042 ret
= VK_CONTROL
; break;
2045 ret
= VK_MENU
; break;
2050 case MAPVK_VK_TO_CHAR
: /* vkey-code to unshifted ANSI code */
2052 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2053 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2054 * key.. Looks like something is wrong with the MS docs?
2055 * This is only true for letters, for example VK_0 returns '0' not ')'.
2056 * - hence we use the lock mask to ensure this happens.
2058 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2064 e
.display
= display
;
2069 /* We exit on the first keycode found, to speed up the thing. */
2070 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2071 { /* Find a keycode that could have generated this virtual key */
2072 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
2073 { /* We filter the extended bit, we don't know it */
2074 e
.keycode
= keyc
; /* Store it temporarily */
2075 if ((EVENT_event_to_vkey(0,&e
) & 0xFF) != wCode
) {
2076 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2077 state), so set it to 0, we'll find another one */
2082 if ((wCode
>=VK_NUMPAD0
) && (wCode
<=VK_NUMPAD9
))
2083 e
.keycode
= XKeysymToKeycode(e
.display
, wCode
-VK_NUMPAD0
+XK_KP_0
);
2085 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2086 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2087 * in order to produce a locale dependent numeric separator.
2089 if (wCode
== VK_DECIMAL
|| wCode
== VK_SEPARATOR
)
2091 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Separator
);
2093 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2098 WARN("Unknown virtual key %X !!!\n", wCode
);
2101 TRACE("Found keycode %u\n",e
.keycode
);
2103 len
= XLookupString(&e
, s
, sizeof(s
), &keysym
, NULL
);
2107 if (ntdll_umbstowcs( s
, len
, &wch
, 1 )) ret
= RtlUpcaseUnicodeChar( wch
);
2112 default: /* reserved */
2113 FIXME("Unknown wMapType %d !\n", wMapType
);
2117 pthread_mutex_unlock( &kbd_mutex
);
2118 TRACE( "returning 0x%x.\n", ret
);
2122 /***********************************************************************
2123 * GetKeyNameText (X11DRV.@)
2125 INT
X11DRV_GetKeyNameText( LONG lParam
, LPWSTR lpBuffer
, INT nSize
)
2127 Display
*display
= thread_init_display();
2128 int vkey
, ansi
, scanCode
;
2134 scanCode
= lParam
>> 16;
2135 scanCode
&= 0x1ff; /* keep "extended-key" flag with code */
2137 vkey
= X11DRV_MapVirtualKeyEx( scanCode
, MAPVK_VSC_TO_VK_EX
, NtUserGetKeyboardLayout(0) );
2139 /* handle "don't care" bit (0x02000000) */
2140 if (!(lParam
& 0x02000000)) {
2143 /* R-Shift is "special" - it is an extended key with separate scan code */
2160 ansi
= X11DRV_MapVirtualKeyEx( vkey
, MAPVK_VK_TO_CHAR
, NtUserGetKeyboardLayout(0) );
2161 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode
, vkey
, ansi
);
2163 /* first get the name of the "regular" keys which is the Upper case
2164 value of the keycap imprint. */
2165 if ( ((ansi
>= 0x21) && (ansi
<= 0x7e)) &&
2166 (scanCode
!= 0x137) && /* PrtScn */
2167 (scanCode
!= 0x135) && /* numpad / */
2168 (scanCode
!= 0x37 ) && /* numpad * */
2169 (scanCode
!= 0x4a ) && /* numpad - */
2170 (scanCode
!= 0x4e ) ) /* numpad + */
2174 *lpBuffer
= RtlUpcaseUnicodeChar( ansi
);
2182 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2183 without "extended-key" flag. However Wine generates scancode
2184 *with* "extended-key" flag. Seems to occur *only* for the
2185 function keys. Soooo.. We will leave the table alone and
2186 fudge the lookup here till the other part is found and fixed!!! */
2188 if ( ((scanCode
>= 0x13b) && (scanCode
<= 0x144)) ||
2189 (scanCode
== 0x157) || (scanCode
== 0x158))
2190 scanCode
&= 0xff; /* remove "extended-key" flag for Fx keys */
2192 /* let's do scancode -> keycode -> keysym -> String */
2194 pthread_mutex_lock( &kbd_mutex
);
2196 for (keyi
=min_keycode
; keyi
<=max_keycode
; keyi
++)
2197 if ((keyc2scan
[keyi
]) == scanCode
)
2199 if (keyi
<= max_keycode
)
2203 keyc
= (KeyCode
) keyi
;
2204 keys
= keycode_to_keysym(display
, keyc
, 0);
2205 name
= XKeysymToString(keys
);
2207 if (name
&& (vkey
== VK_SHIFT
|| vkey
== VK_CONTROL
|| vkey
== VK_MENU
))
2209 char* idx
= strrchr(name
, '_');
2210 if (idx
&& (idx
[1] == 'r' || idx
[1] == 'R' || idx
[1] == 'l' || idx
[1] == 'L') && !idx
[2])
2212 pthread_mutex_unlock( &kbd_mutex
);
2213 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2214 scanCode
, keyc
, keys
, debugstr_an(name
,idx
-name
));
2215 rc
= ntdll_umbstowcs( name
, idx
- name
+ 1, lpBuffer
, nSize
);
2216 if (!rc
) rc
= nSize
;
2224 pthread_mutex_unlock( &kbd_mutex
);
2225 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2226 scanCode
, keyc
, (int)keys
, vkey
, debugstr_a(name
));
2227 rc
= ntdll_umbstowcs( name
, strlen(name
) + 1, lpBuffer
, nSize
);
2228 if (!rc
) rc
= nSize
;
2234 /* Finally issue WARN for unknown keys */
2236 pthread_mutex_unlock( &kbd_mutex
);
2237 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",(int)lParam
,lpBuffer
,nSize
,vkey
,ansi
);
2242 /***********************************************************************
2243 * X11DRV_KEYBOARD_MapDeadKeysym
2245 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
2249 /* symbolic ASCII is the same as defined in rfc1345 */
2250 #ifdef XK_dead_tilde
2251 case XK_dead_tilde
:
2253 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2254 return '~'; /* '? */
2255 #ifdef XK_dead_acute
2256 case XK_dead_acute
:
2258 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2259 return 0xb4; /* '' */
2260 #ifdef XK_dead_circumflex
2261 case XK_dead_circumflex
:
2263 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2264 return '^'; /* '> */
2265 #ifdef XK_dead_grave
2266 case XK_dead_grave
:
2268 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2269 return '`'; /* '! */
2270 #ifdef XK_dead_diaeresis
2271 case XK_dead_diaeresis
:
2273 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2274 return 0xa8; /* ': */
2275 #ifdef XK_dead_cedilla
2276 case XK_dead_cedilla
:
2277 return 0xb8; /* ', */
2279 #ifdef XK_dead_macron
2280 case XK_dead_macron
:
2281 return '-'; /* 'm isn't defined on iso-8859-x */
2283 #ifdef XK_dead_breve
2284 case XK_dead_breve
:
2285 return 0xa2; /* '( */
2287 #ifdef XK_dead_abovedot
2288 case XK_dead_abovedot
:
2289 return 0xff; /* '. */
2291 #ifdef XK_dead_abovering
2292 case XK_dead_abovering
:
2293 return '0'; /* '0 isn't defined on iso-8859-x */
2295 #ifdef XK_dead_doubleacute
2296 case XK_dead_doubleacute
:
2297 return 0xbd; /* '" */
2299 #ifdef XK_dead_caron
2300 case XK_dead_caron
:
2301 return 0xb7; /* '< */
2303 #ifdef XK_dead_ogonek
2304 case XK_dead_ogonek
:
2305 return 0xb2; /* '; */
2307 /* FIXME: I don't know this three.
2310 case XK_dead_voiced_sound :
2312 case XK_dead_semivoiced_sound :
2316 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
2320 /***********************************************************************
2321 * ToUnicodeEx (X11DRV.@)
2323 * The ToUnicode function translates the specified virtual-key code and keyboard
2324 * state to the corresponding Windows character or characters.
2326 * If the specified key is a dead key, the return value is negative. Otherwise,
2327 * it is one of the following values:
2329 * 0 The specified virtual key has no translation for the current state of the keyboard.
2330 * 1 One Windows character was copied to the buffer.
2331 * 2 Two characters were copied to the buffer. This usually happens when a
2332 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2333 * be composed with the specified virtual key to form a single character.
2335 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2338 INT
X11DRV_ToUnicodeEx( UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
2339 LPWSTR bufW
, int bufW_size
, UINT flags
, HKL hkl
)
2341 Display
*display
= thread_init_display();
2352 if (scanCode
& 0x8000)
2354 TRACE_(key
)("Key UP, doing nothing\n" );
2358 if (!match_x11_keyboard_layout(hkl
))
2359 FIXME_(key
)("keyboard layout %p is not supported\n", hkl
);
2361 if ((lpKeyState
[VK_MENU
] & 0x80) && (lpKeyState
[VK_CONTROL
] & 0x80))
2363 TRACE_(key
)("Ctrl+Alt+[key] won't generate a character\n");
2367 e
.display
= display
;
2372 focus
= x11drv_thread_data()->last_xic_hwnd
;
2375 focus
= get_focus();
2376 if (focus
) focus
= NtUserGetAncestor( focus
, GA_ROOT
);
2377 if (!focus
) focus
= get_active_window();
2379 e
.window
= X11DRV_get_whole_window( focus
);
2380 xic
= X11DRV_get_ic( focus
);
2382 pthread_mutex_lock( &kbd_mutex
);
2384 if (lpKeyState
[VK_SHIFT
] & 0x80)
2386 TRACE_(key
)("ShiftMask = %04x\n", ShiftMask
);
2387 e
.state
|= ShiftMask
;
2389 if (lpKeyState
[VK_CAPITAL
] & 0x01)
2391 TRACE_(key
)("LockMask = %04x\n", LockMask
);
2392 e
.state
|= LockMask
;
2394 if (lpKeyState
[VK_CONTROL
] & 0x80)
2396 TRACE_(key
)("ControlMask = %04x\n", ControlMask
);
2397 e
.state
|= ControlMask
;
2399 if (lpKeyState
[VK_NUMLOCK
] & 0x01)
2401 TRACE_(key
)("NumLockMask = %04x\n", NumLockMask
);
2402 e
.state
|= NumLockMask
;
2405 /* Restore saved AltGr state */
2406 TRACE_(key
)("AltGrMask = %04x\n", AltGrMask
);
2407 e
.state
|= AltGrMask
;
2409 TRACE_(key
)("(%04X, %04X) : faked state = 0x%04x\n",
2410 virtKey
, scanCode
, e
.state
);
2412 /* We exit on the first keycode found, to speed up the thing. */
2413 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2414 { /* Find a keycode that could have generated this virtual key */
2415 if ((keyc2vkey
[keyc
] & 0xFF) == virtKey
)
2416 { /* We filter the extended bit, we don't know it */
2417 e
.keycode
= keyc
; /* Store it temporarily */
2418 if ((EVENT_event_to_vkey(xic
,&e
) & 0xFF) != virtKey
) {
2419 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2420 state), so set it to 0, we'll find another one */
2425 if (virtKey
>= VK_LEFT
&& virtKey
<= VK_DOWN
)
2426 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
- VK_LEFT
+ XK_Left
);
2428 if ((virtKey
>=VK_NUMPAD0
) && (virtKey
<=VK_NUMPAD9
))
2429 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
-VK_NUMPAD0
+XK_KP_0
);
2431 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2432 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2433 * in order to produce a locale dependent numeric separator.
2435 if (virtKey
== VK_DECIMAL
|| virtKey
== VK_SEPARATOR
)
2437 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Separator
);
2439 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2442 /* Ctrl-Space generates space on Windows */
2443 if (e
.state
== ControlMask
&& virtKey
== VK_SPACE
)
2450 if (!e
.keycode
&& virtKey
!= VK_NONAME
)
2452 WARN_(key
)("Unknown virtual key %X !!!\n", virtKey
);
2453 pthread_mutex_unlock( &kbd_mutex
);
2456 else TRACE_(key
)("Found keycode %u\n",e
.keycode
);
2458 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode %u\n",
2459 e
.type
, e
.window
, e
.state
, e
.keycode
);
2461 /* Clients should pass only KeyPress events to XmbLookupString,
2462 * e.type was set to KeyPress above.
2466 ret
= XmbLookupString(xic
, &e
, buf
, sizeof(buf
), &keysym
, &status
);
2467 TRACE_(key
)("XmbLookupString needs %d byte(s)\n", ret
);
2468 if (status
== XBufferOverflow
)
2470 lpChar
= malloc( ret
);
2473 ERR_(key
)("Failed to allocate memory!\n");
2474 pthread_mutex_unlock( &kbd_mutex
);
2477 ret
= XmbLookupString(xic
, &e
, lpChar
, ret
, &keysym
, &status
);
2481 ret
= XLookupString(&e
, buf
, sizeof(buf
), &keysym
, NULL
);
2483 TRACE_(key
)("nbyte = %d, status 0x%x\n", ret
, status
);
2489 ksname
= XKeysymToString(keysym
);
2490 if (!ksname
) ksname
= "No Name";
2491 TRACE_(key
)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2492 (e
.type
== KeyPress
) ? "KeyPress" : "KeyRelease",
2493 keysym
, ksname
, ret
, debugstr_an(lpChar
, ret
));
2501 /* An ugly hack for EuroSign: X can't translate it to a character
2502 for some locales. */
2503 if (keysym
== XK_EuroSign
)
2510 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2511 /* Here we change it back. */
2512 if (keysym
== XK_ISO_Left_Tab
&& !(e
.state
& ControlMask
))
2519 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
2522 ntdll_umbstowcs( &dead_char
, 1, bufW
, bufW_size
);
2527 if (keysym
>= 0x01000100 && keysym
<= 0x0100ffff)
2529 /* Unicode direct mapping */
2530 bufW
[0] = keysym
& 0xffff;
2534 else if ((keysym
>> 8) == 0x1008FF) {
2543 ksname
= XKeysymToString(keysym
);
2546 if ((keysym
>> 8) != 0xff)
2548 WARN_(key
)("no char for keysym %04lx (%s) :\n",
2550 WARN_(key
)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2551 virtKey
, scanCode
, e
.keycode
, e
.state
);
2555 else { /* ret != 0 */
2556 /* We have a special case to handle : Shift + arrow, shift + home, ...
2557 X returns a char for it, but Windows doesn't. Let's eat it. */
2558 if (!(e
.state
& NumLockMask
) /* NumLock is off */
2559 && (e
.state
& ShiftMask
) /* Shift is pressed */
2560 && (keysym
>=XK_KP_0
) && (keysym
<=XK_KP_9
))
2566 /* more areas where X returns characters but Windows does not
2567 CTRL + number or CTRL + symbol */
2568 if (e
.state
& ControlMask
)
2570 if (((keysym
>=33) && (keysym
< '@')) ||
2579 /* We have another special case for delete key (XK_Delete) on an
2580 extended keyboard. X returns a char for it, but Windows doesn't */
2581 if (keysym
== XK_Delete
)
2586 else if((lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
2587 && (keysym
== XK_KP_Decimal
))
2592 else if((lpKeyState
[VK_CONTROL
] & 0x80) /* Control is pressed */
2593 && (keysym
== XK_Return
|| keysym
== XK_KP_Enter
))
2595 if (lpKeyState
[VK_SHIFT
] & 0x80)
2607 /* Hack to detect an XLookupString hard-coded to Latin1 */
2608 if (ret
== 1 && keysym
>= 0x00a0 && keysym
<= 0x00ff && (BYTE
)lpChar
[0] == keysym
)
2610 bufW
[0] = (BYTE
)lpChar
[0];
2614 /* perform translation to unicode */
2617 TRACE_(key
)("Translating char 0x%02x to unicode\n", *(BYTE
*)lpChar
);
2618 ret
= ntdll_umbstowcs( lpChar
, ret
, bufW
, bufW_size
);
2626 pthread_mutex_unlock( &kbd_mutex
);
2628 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2629 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2630 if (1 <= ret
&& ret
< bufW_size
)
2633 TRACE_(key
)("returning %d with %s\n", ret
, debugstr_wn(bufW
, ret
));
2637 /***********************************************************************
2640 void X11DRV_Beep(void)
2642 XBell(gdi_display
, 0);