4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
50 #include "wine/server.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
54 /* log format (add 0-padding as appropriate):
55 keycode %u as in output from xev
56 keysym %lx as in X11/keysymdef.h
57 vkey %X as in winuser.h
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard
);
61 WINE_DECLARE_DEBUG_CHANNEL(key
);
63 /* key state table bits:
64 0x80 -> key is pressed
65 0x40 -> key got pressed since last time
66 0x01 -> key is toggled
68 BYTE key_state_table
[256];
70 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
71 or a WM_KEYUP message */
73 static int min_keycode
, max_keycode
, keysyms_per_keycode
;
74 static WORD keyc2vkey
[256], keyc2scan
[256];
76 static int NumLockMask
, ScrollLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
78 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
80 /* Keyboard translation tables */
82 static const WORD main_key_scan_qwerty
[MAIN_LEN
] =
84 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
85 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
86 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
87 /* q w e r t y u i o p [ ] */
88 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
89 /* a s d f g h j k l ; ' \ */
90 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
91 /* z x c v b n m , . / */
92 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
93 0x56 /* the 102nd key (actually to the right of l-shift) */
96 static const WORD main_key_scan_abnt_qwerty
[MAIN_LEN
] =
98 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
99 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
100 /* q w e r t y u i o p [ ] */
101 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
102 /* a s d f g h j k l ; ' \ */
103 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
104 /* \ z x c v b n m , . / */
105 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
106 0x56, /* the 102nd key (actually to the right of l-shift) */
109 static const WORD main_key_scan_dvorak
[MAIN_LEN
] =
111 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
112 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
113 /* ' , . p y f g c r l / = */
114 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
115 /* a o e u i d h t n s - \ */
116 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
117 /* ; q j k x b m w v z */
118 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
119 0x56 /* the 102nd key (actually to the right of l-shift) */
122 static const WORD main_key_scan_qwerty_jp106
[MAIN_LEN
] =
124 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
125 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
126 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
127 /* q w e r t y u i o p @ [ */
128 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
129 /* a s d f g h j k l ; : ] */
130 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
131 /* z x c v b n m , . / */
132 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
133 0x56 /* the 102nd key (actually to the right of l-shift) */
136 static const WORD main_key_scan_qwerty_macjp
[MAIN_LEN
] =
138 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
139 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
140 /* q w e r t y u i o p @ [ */
141 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
142 /* a s d f g h j k l ; : ] */
143 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
144 /* z x c v b n m , . / */
145 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
146 0x73 /* the 102nd key (actually to the right of l-shift) */
150 static const WORD main_key_vkey_qwerty
[MAIN_LEN
] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
154 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
155 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
156 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
157 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
160 static const WORD main_key_vkey_qwerty_jp106
[MAIN_LEN
] =
162 /* NOTE: this layout must concur with the scan codes layout above */
163 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,VK_OEM_3
,
164 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
166 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
167 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
170 static const WORD main_key_vkey_qwerty_macjp
[MAIN_LEN
] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_7
,VK_OEM_5
,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3
,VK_OEM_4
,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS
,VK_OEM_1
,VK_OEM_6
,
176 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
177 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_qwerty_v2
[MAIN_LEN
] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_5
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS
,VK_OEM_4
,
184 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
185 'A','S','D','F','G','H','J','K','L',VK_OEM_3
,VK_OEM_7
,VK_OEM_2
,
186 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_MINUS
,
187 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_qwertz
[MAIN_LEN
] =
192 /* NOTE: this layout must concur with the scan codes layout above */
193 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
194 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
195 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
196 'Y','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
197 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
200 static const WORD main_key_vkey_abnt_qwerty
[MAIN_LEN
] =
202 /* NOTE: this layout must concur with the scan codes layout above */
203 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
204 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
205 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_8
,VK_OEM_5
,
206 VK_OEM_7
,'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
207 VK_OEM_102
, /* the 102nd key (actually to the right of l-shift) */
210 static const WORD main_key_vkey_azerty
[MAIN_LEN
] =
212 /* NOTE: this layout must concur with the scan codes layout above */
213 VK_OEM_7
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_PLUS
,
214 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
215 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3
,VK_OEM_5
,
216 'W','X','C','V','B','N',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,VK_OEM_8
,
217 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
220 static const WORD main_key_vkey_dvorak
[MAIN_LEN
] =
222 /* NOTE: this layout must concur with the scan codes layout above */
223 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_6
,
224 VK_OEM_7
,VK_OEM_COMMA
,VK_OEM_PERIOD
,'P','Y','F','G','C','R','L',VK_OEM_2
,VK_OEM_PLUS
,
225 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS
,VK_OEM_5
,
226 VK_OEM_1
,'Q','J','K','X','B','M','W','V','Z',
227 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
230 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
232 /* the VK mappings for the main keyboard will be auto-assigned as before,
233 so what we have here is just the character tables */
234 /* order: Normal, Shift, AltGr, Shift-AltGr */
235 /* We recommend you write just what is guaranteed to be correct (i.e. what's
236 written on the keycaps), not the bunch of special characters behind AltGr
237 and Shift-AltGr if it can vary among different X servers */
238 /* Remember that your 102nd key (to the right of l-shift) should be on a
239 separate line, see existing tables */
240 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
241 /* Remember to also add your new table to the layout index table far below! */
243 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
244 static const char main_key_US
[MAIN_LEN
][4] =
246 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
247 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
248 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
249 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
252 /*** United States keyboard layout (phantom key version) */
253 /* (XFree86 reports the <> key even if it's not physically there) */
254 static const char main_key_US_phantom
[MAIN_LEN
][4] =
256 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
257 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
258 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
259 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
260 "<>" /* the phantom key */
263 /*** United States keyboard layout (dvorak version) */
264 static const char main_key_US_dvorak
[MAIN_LEN
][4] =
266 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
267 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
268 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
269 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
272 /*** British keyboard layout */
273 static const char main_key_UK
[MAIN_LEN
][4] =
275 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
276 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
277 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
278 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
282 /*** French keyboard layout (setxkbmap fr) */
283 static const char main_key_FR
[MAIN_LEN
][4] =
285 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
286 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
287 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
288 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
292 /*** Icelandic keyboard layout (setxkbmap is) */
293 static const char main_key_IS
[MAIN_LEN
][4] =
295 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
296 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
297 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
298 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
302 /* All german keyb layout tables have the acute/apostrophe symbol next to
303 * the BACKSPACE key removed (replaced with NULL which is ignored by the
305 * This was done because the mapping of the acute (and apostrophe) is done
306 * differently in various xkb-data/xkeyboard-config versions. Some replace
307 * the acute with a normal apostrophe, so that the apostrophe is found twice
308 * on the keyboard (one next to BACKSPACE and one next to ENTER).
309 * Others put the acute and grave accents on the key left of BACKSPACE.
310 * More information on the fd.o bugtracker:
311 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
314 /*** German Logitech Desktop Pro keyboard layout */
315 static const char main_key_DE_logitech
[MAIN_LEN
][4] =
317 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","\0`",
318 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
319 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
320 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
324 /*** German keyboard layout (setxkbmap de) */
325 static const char main_key_DE
[MAIN_LEN
][4] =
327 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","\0`",
328 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
330 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
334 /*** German keyboard layout without dead keys */
335 static const char main_key_DE_nodead
[MAIN_LEN
][4] =
337 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","",
338 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
339 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
340 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
344 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
345 static const char main_key_SG
[MAIN_LEN
][4] =
347 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
348 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
349 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
350 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
354 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
355 static const char main_key_SF
[MAIN_LEN
][4] =
357 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
358 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
359 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
360 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
364 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
365 static const char main_key_NO
[MAIN_LEN
][4] =
367 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
368 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
369 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
370 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
374 /*** Danish keyboard layout (setxkbmap dk) */
375 static const char main_key_DA
[MAIN_LEN
][4] =
377 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
378 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
379 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
380 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
384 /*** Swedish keyboard layout (setxkbmap se) */
385 static const char main_key_SE
[MAIN_LEN
][4] =
387 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
388 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
389 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
390 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
394 /*** Estonian keyboard layout (setxkbmap ee) */
395 static const char main_key_ET
[MAIN_LEN
][4] =
397 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
398 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
399 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
400 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
404 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
405 static const char main_key_CF
[MAIN_LEN
][4] =
407 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
408 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
409 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
410 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
414 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
415 static const char main_key_CA_fr
[MAIN_LEN
][4] =
417 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
418 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
419 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
420 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
424 /*** Canadian keyboard layout (setxkbmap ca) */
425 static const char main_key_CA
[MAIN_LEN
][4] =
427 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
428 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
429 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
430 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
434 /*** Portuguese keyboard layout (setxkbmap pt) */
435 static const char main_key_PT
[MAIN_LEN
][4] =
437 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
438 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
439 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
440 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
444 /*** Italian keyboard layout (setxkbmap it) */
445 static const char main_key_IT
[MAIN_LEN
][4] =
447 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
448 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
449 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
450 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
454 /*** Finnish keyboard layout (setxkbmap fi) */
455 static const char main_key_FI
[MAIN_LEN
][4] =
457 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
458 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
459 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
460 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
464 /*** Bulgarian bds keyboard layout */
465 static const char main_key_BG_bds
[MAIN_LEN
][4] =
467 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
468 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
469 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
470 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
471 "<>" /* the phantom key */
474 /*** Bulgarian phonetic keyboard layout */
475 static const char main_key_BG_phonetic
[MAIN_LEN
][4] =
477 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
478 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
479 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
480 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
481 "<>" /* the phantom key */
484 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
485 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
486 static const char main_key_BY
[MAIN_LEN
][4] =
488 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
489 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
490 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
491 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
495 /*** Russian keyboard layout (contributed by Pavel Roskin) */
496 static const char main_key_RU
[MAIN_LEN
][4] =
498 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
499 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
500 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
501 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
504 /*** Russian keyboard layout (phantom key version) */
505 static const char main_key_RU_phantom
[MAIN_LEN
][4] =
507 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
508 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
509 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
510 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
511 "<>" /* the phantom key */
514 /*** Russian keyboard layout KOI8-R */
515 static const char main_key_RU_koi8r
[MAIN_LEN
][4] =
517 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
518 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
519 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
520 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
521 "<>" /* the phantom key */
524 /*** Russian keyboard layout cp1251 */
525 static const char main_key_RU_cp1251
[MAIN_LEN
][4] =
527 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
528 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
529 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
530 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
531 "<>" /* the phantom key */
534 /*** Russian phonetic keyboard layout */
535 static const char main_key_RU_phonetic
[MAIN_LEN
][4] =
537 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
538 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
539 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
540 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
541 "<>" /* the phantom key */
544 /*** Ukrainian keyboard layout KOI8-U */
545 static const char main_key_UA
[MAIN_LEN
][4] =
547 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
548 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
549 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
550 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
551 "<>" /* the phantom key */
554 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
555 /*** (as it appears on most of keyboards sold today) */
556 static const char main_key_UA_std
[MAIN_LEN
][4] =
558 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
559 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
560 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
561 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
562 "<>" /* the phantom key */
565 /*** Russian keyboard layout KOI8-R (pair to the previous) */
566 static const char main_key_RU_std
[MAIN_LEN
][4] =
568 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
569 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
570 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
571 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
572 "<>" /* the phantom key */
575 /*** Spanish keyboard layout (setxkbmap es) */
576 static const char main_key_ES
[MAIN_LEN
][4] =
578 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
579 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
580 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
581 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
585 /*** Belgian keyboard layout ***/
586 static const char main_key_BE
[MAIN_LEN
][4] =
588 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
589 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
590 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
591 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
595 /*** Hungarian keyboard layout (setxkbmap hu) */
596 static const char main_key_HU
[MAIN_LEN
][4] =
598 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
599 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
600 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
601 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
605 /*** Polish (programmer's) keyboard layout ***/
606 static const char main_key_PL
[MAIN_LEN
][4] =
608 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
609 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
610 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
611 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
615 /*** Slovenian keyboard layout (setxkbmap si) ***/
616 static const char main_key_SI
[MAIN_LEN
][4] =
618 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
619 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
620 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
621 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
625 /*** Serbian keyboard layout (setxkbmap sr) ***/
626 static const char main_key_SR
[MAIN_LEN
][4] =
628 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
629 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
630 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
631 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
632 "<>" /* the phantom key */
635 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
636 static const char main_key_US_SR
[MAIN_LEN
][4] =
638 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
639 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
640 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
641 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
642 "<>" /* the phantom key */
645 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
646 static const char main_key_HR_jelly
[MAIN_LEN
][4] =
648 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
649 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
650 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
651 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
655 /*** Croatian keyboard layout (setxkbmap hr) ***/
656 static const char main_key_HR
[MAIN_LEN
][4] =
658 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
659 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
660 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
661 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
665 /*** Japanese 106 keyboard layout ***/
666 static const char main_key_JA_jp106
[MAIN_LEN
][4] =
668 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
669 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
670 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
671 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
675 static const char main_key_JA_macjp
[MAIN_LEN
][4] =
677 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
678 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
679 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
680 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
684 /*** Japanese pc98x1 keyboard layout ***/
685 static const char main_key_JA_pc98x1
[MAIN_LEN
][4] =
687 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
688 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
689 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
690 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
694 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
695 static const char main_key_PT_br
[MAIN_LEN
][4] =
697 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
698 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
699 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
700 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
703 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
704 static const char main_key_PT_br_alt_gr
[MAIN_LEN
][4] =
706 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
707 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
708 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
709 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
712 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
713 static const char main_key_US_intl
[MAIN_LEN
][4] =
715 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
716 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
717 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
718 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
721 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
722 - dead_abovering replaced with degree - no symbol in iso8859-2
723 - brokenbar replaced with bar */
724 static const char main_key_SK
[MAIN_LEN
][4] =
726 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
727 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
728 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
729 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
733 /*** Czech keyboard layout (setxkbmap cz) */
734 static const char main_key_CZ
[MAIN_LEN
][4] =
736 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
737 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
738 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
739 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
743 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
744 static const char main_key_CZ_qwerty
[MAIN_LEN
][4] =
746 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
747 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
748 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
749 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
753 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
754 static const char main_key_SK_prog
[MAIN_LEN
][4] =
756 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
757 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
758 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
759 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
763 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
764 static const char main_key_CS
[MAIN_LEN
][4] =
766 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
767 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
768 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
769 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
773 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
774 static const char main_key_LA
[MAIN_LEN
][4] =
776 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
777 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
778 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
779 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
783 /*** Lithuanian keyboard layout (setxkbmap lt) */
784 static const char main_key_LT_B
[MAIN_LEN
][4] =
786 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
787 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
788 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
789 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
793 /*** Turkish keyboard Layout */
794 static const char main_key_TK
[MAIN_LEN
][4] =
796 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
797 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
798 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
799 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
802 /*** Turkish keyboard layout (setxkbmap tr) */
803 static const char main_key_TR
[MAIN_LEN
][4] =
805 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
806 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
807 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
808 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
812 /*** Turkish F keyboard layout (setxkbmap trf) */
813 static const char main_key_TR_F
[MAIN_LEN
][4] =
815 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
816 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
817 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
818 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
822 /*** Israelian keyboard layout (setxkbmap us,il) */
823 static const char main_key_IL
[MAIN_LEN
][4] =
825 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
826 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
827 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
828 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
832 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
833 static const char main_key_IL_phonetic
[MAIN_LEN
][4] =
835 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
836 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
837 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
838 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
842 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
843 static const char main_key_IL_saharon
[MAIN_LEN
][4] =
845 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
846 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
847 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
848 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
852 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
853 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
854 message since they have different characters in gr and el XFree86 layouts. */
855 static const char main_key_EL
[MAIN_LEN
][4] =
857 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
858 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
859 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
860 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
864 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
865 static const char main_key_th
[MAIN_LEN
][4] =
867 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
868 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pPÂ","[{º°","]}Å,",
869 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
870 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
873 /*** VNC keyboard layout */
874 static const WORD main_key_scan_vnc
[MAIN_LEN
] =
876 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
877 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,
881 static const WORD main_key_vkey_vnc
[MAIN_LEN
] =
883 '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
,
884 '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',
888 static const char main_key_vnc
[MAIN_LEN
][4] =
890 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
891 "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"
894 /*** Dutch keyboard layout (setxkbmap nl) ***/
895 static const char main_key_NL
[MAIN_LEN
][4] =
897 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
898 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
899 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
900 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
906 /*** Layout table. Add your keyboard mappings to this list */
907 static const struct {
908 LCID lcid
; /* input locale identifier, look for LOCALE_ILANGUAGE
909 in the appropriate dlls/kernel/nls/.nls file */
911 const char (*key
)[MAIN_LEN
][4];
912 const WORD (*scan
)[MAIN_LEN
]; /* scan codes mapping */
913 const WORD (*vkey
)[MAIN_LEN
]; /* virtual key codes mapping */
915 {0x0409, "United States keyboard layout", &main_key_US
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
916 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
917 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak
, &main_key_scan_dvorak
, &main_key_vkey_dvorak
},
918 {0x0409, "United States International keyboard layout", &main_key_US_intl
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
919 {0x0809, "British keyboard layout", &main_key_UK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
920 {0x0407, "German keyboard layout", &main_key_DE
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
921 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
922 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
923 {0x0807, "Swiss German keyboard layout", &main_key_SG
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
924 {0x100c, "Swiss French keyboard layout", &main_key_SF
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
925 {0x041d, "Swedish keyboard layout", &main_key_SE
, &main_key_scan_qwerty
, &main_key_vkey_qwerty_v2
},
926 {0x0425, "Estonian keyboard layout", &main_key_ET
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
927 {0x0414, "Norwegian keyboard layout", &main_key_NO
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
928 {0x0406, "Danish keyboard layout", &main_key_DA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
929 {0x040c, "French keyboard layout", &main_key_FR
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
930 {0x0c0c, "Canadian French keyboard layout", &main_key_CF
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
931 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
932 {0x0c0c, "Canadian keyboard layout", &main_key_CA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
933 {0x080c, "Belgian keyboard layout", &main_key_BE
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
934 {0x0816, "Portuguese keyboard layout", &main_key_PT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
935 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br
, &main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
936 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr
,&main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
937 {0x040b, "Finnish keyboard layout", &main_key_FI
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
938 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
939 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
940 {0x0423, "Belarusian keyboard layout", &main_key_BY
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
941 {0x0419, "Russian keyboard layout", &main_key_RU
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
942 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
943 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
944 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
945 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
946 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
947 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
948 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
949 {0x040a, "Spanish keyboard layout", &main_key_ES
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
950 {0x0410, "Italian keyboard layout", &main_key_IT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
951 {0x040f, "Icelandic keyboard layout", &main_key_IS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
952 {0x040e, "Hungarian keyboard layout", &main_key_HU
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
953 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
954 {0x0424, "Slovenian keyboard layout", &main_key_SI
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
955 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
956 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
957 {0x041a, "Croatian keyboard layout", &main_key_HR
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
958 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
959 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106
, &main_key_scan_qwerty_jp106
, &main_key_vkey_qwerty_jp106
},
960 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp
, &main_key_scan_qwerty_macjp
, &main_key_vkey_qwerty_macjp
},
961 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
962 {0x041b, "Slovak keyboard layout", &main_key_SK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
963 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
964 {0x0405, "Czech keyboard layout", &main_key_CS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
965 {0x0405, "Czech keyboard layout cz", &main_key_CZ
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
966 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
967 {0x040a, "Latin American keyboard layout", &main_key_LA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
968 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
969 {0x041f, "Turkish keyboard layout", &main_key_TK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
970 {0x041f, "Turkish keyboard layout tr", &main_key_TR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
971 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
972 {0x040d, "Israelian keyboard layout", &main_key_IL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
973 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
974 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
975 {0x0409, "VNC keyboard layout", &main_key_vnc
, &main_key_scan_vnc
, &main_key_vkey_vnc
},
976 {0x0408, "Greek keyboard layout", &main_key_EL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
977 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
978 {0x0413, "Dutch keyboard layout", &main_key_NL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
980 {0, NULL
, NULL
, NULL
, NULL
} /* sentinel */
982 static unsigned kbd_layout
=0; /* index into above table of layouts */
984 /* maybe more of these scancodes should be extended? */
985 /* extended must be set for ALT_R, CTRL_R,
986 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
987 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
988 /* FIXME should we set extended bit for NumLock ? My
989 * Windows does ... DF */
990 /* Yes, to distinguish based on scan codes, also
991 for PrtScn key ... GA */
993 static const WORD nonchar_key_vkey
[256] =
996 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
998 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
999 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
1000 0, 0, 0, VK_ESCAPE
, 0, 0, 0, 0, /* FF18 */
1002 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
1003 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
1004 0, VK_HANGUL
, 0, 0, VK_HANJA
, 0, 0, 0, /* FF30 */
1005 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
1007 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
1009 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, /* FF50 */
1010 VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
,
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1013 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0,0,0, VK_APPS
, /* FF60 */
1014 0, VK_CANCEL
, VK_HELP
, VK_CANCEL
, 0, 0, 0, 0, /* FF68 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1017 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK
, /* FF78 */
1018 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1019 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
1020 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
1021 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, /* FF98 */
1022 VK_END
, VK_CLEAR
, VK_INSERT
, VK_DELETE
,
1023 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1024 0, 0, VK_MULTIPLY
, VK_ADD
, /* FFA8 */
1025 VK_SEPARATOR
, VK_SUBTRACT
, VK_DECIMAL
, VK_DIVIDE
,
1026 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, /* FFB0 */
1027 VK_NUMPAD4
, VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
,
1028 VK_NUMPAD8
, VK_NUMPAD9
, 0, 0, 0, VK_OEM_NEC_EQUAL
, /* FFB8 */
1031 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
1032 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
, VK_F17
, VK_F18
, /* FFC8 */
1033 VK_F19
, VK_F20
, VK_F21
, VK_F22
, VK_F23
, VK_F24
, 0, 0, /* FFD0 */
1034 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1036 0, VK_LSHIFT
, VK_RSHIFT
, VK_LCONTROL
, /* FFE0 */
1037 VK_RCONTROL
, VK_CAPITAL
, 0, VK_MENU
,
1038 VK_MENU
, VK_LMENU
, VK_RMENU
, VK_LWIN
, VK_RWIN
, 0, 0, 0, /* FFE8 */
1039 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1040 0, 0, 0, 0, 0, 0, 0, VK_DELETE
/* FFF8 */
1043 static const WORD nonchar_key_scan
[256] =
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1048 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1049 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1050 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1059 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1062 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1063 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1068 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1070 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1072 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1073 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1074 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1077 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1078 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1082 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1083 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1088 static const WORD xfree86_vendor_key_vkey
[256] =
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1092 0, VK_VOLUME_DOWN
, VK_VOLUME_MUTE
, VK_VOLUME_UP
, /* 1008FF10 */
1093 VK_MEDIA_PLAY_PAUSE
, VK_MEDIA_STOP
,
1094 VK_MEDIA_PREV_TRACK
, VK_MEDIA_NEXT_TRACK
,
1095 0, VK_LAUNCH_MAIL
, 0, VK_BROWSER_SEARCH
, /* 1008FF18 */
1096 0, 0, 0, VK_BROWSER_HOME
,
1097 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK
, VK_BROWSER_FORWARD
, /* 1008FF20 */
1098 VK_BROWSER_STOP
, VK_BROWSER_REFRESH
, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1099 VK_BROWSER_FAVORITES
, 0, VK_LAUNCH_MEDIA_SELECT
, 0, /* 1008FF30 */
1101 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1102 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1103 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1104 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1105 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1106 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1107 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1108 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1109 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1110 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1111 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1112 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1113 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1114 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1115 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1116 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1117 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1118 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1119 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1120 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1121 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1122 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1123 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1124 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1125 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1128 /* Returns the Windows virtual key code associated with the X event <e> */
1129 /* x11 lock must be held */
1130 static WORD
EVENT_event_to_vkey( XIC xic
, XKeyEvent
*e
)
1136 /* Clients should pass only KeyPress events to XmbLookupString */
1137 if (xic
&& e
->type
== KeyPress
)
1138 XmbLookupString(xic
, e
, buf
, sizeof(buf
), &keysym
, &status
);
1140 XLookupString(e
, buf
, sizeof(buf
), &keysym
, NULL
);
1142 if ((e
->state
& NumLockMask
) &&
1143 (keysym
== XK_KP_Separator
|| keysym
== XK_KP_Decimal
||
1144 (keysym
>= XK_KP_0
&& keysym
<= XK_KP_9
)))
1145 /* Only the Keypad keys 0-9 and . send different keysyms
1146 * depending on the NumLock state */
1147 return nonchar_key_vkey
[keysym
& 0xFF];
1149 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1150 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1151 if ((e
->state
& ControlMask
) && (keysym
== XK_Break
))
1154 TRACE_(key
)("e->keycode = %u\n", e
->keycode
);
1156 return keyc2vkey
[e
->keycode
];
1160 /***********************************************************************
1161 * X11DRV_send_keyboard_input
1163 void X11DRV_send_keyboard_input( WORD wVk
, WORD wScan
, DWORD event_flags
, DWORD time
,
1164 DWORD dwExtraInfo
, UINT injected_flags
)
1167 KBDLLHOOKSTRUCT hook
;
1168 WORD flags
, wVkStripped
, wVkL
, wVkR
, vk_hook
= wVk
;
1172 flags
= LOBYTE(wScan
);
1174 if (event_flags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1175 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1177 /* strip left/right for menu, control, shift */
1183 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1184 wVkStripped
= VK_MENU
;
1191 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1192 wVkStripped
= VK_CONTROL
;
1199 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1200 wVkStripped
= VK_SHIFT
;
1205 wVkStripped
= wVkL
= wVkR
= wVk
;
1208 if (event_flags
& KEYEVENTF_KEYUP
)
1211 if (((key_state_table
[VK_MENU
] & 0x80) &&
1212 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1213 || !(key_state_table
[VK_CONTROL
] & 0x80)))
1214 || (wVkStripped
== VK_F10
))
1216 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1217 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1218 message
= WM_SYSKEYUP
;
1221 flags
|= KF_REPEAT
| KF_UP
;
1225 message
= WM_KEYDOWN
;
1226 if (((key_state_table
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1227 !(key_state_table
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
)) ||
1228 (wVkStripped
== VK_F10
))
1230 message
= WM_SYSKEYDOWN
;
1231 TrackSysKey
= wVkStripped
;
1233 if (!(event_flags
& KEYEVENTF_UNICODE
) && key_state_table
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1236 if (event_flags
& KEYEVENTF_UNICODE
)
1238 vk_hook
= wVk
= VK_PACKET
;
1239 lParam
= MAKELPARAM(1 /* repeat count */, wScan
);
1240 TRACE_(key
)("message=0x%04x wParam=0x%04X lParam=0x%08lx\n",
1241 message
, wVk
, lParam
);
1244 /* Hook gets whatever key was sent. */
1245 hook
.vkCode
= vk_hook
;
1246 hook
.scanCode
= wScan
;
1247 hook
.flags
= (flags
>> 8) | injected_flags
;
1249 hook
.dwExtraInfo
= dwExtraInfo
;
1250 if (HOOK_CallHooks( WH_KEYBOARD_LL
, HC_ACTION
, message
, (LPARAM
)&hook
, TRUE
)) return;
1252 if (!(event_flags
& KEYEVENTF_UNICODE
))
1254 if (event_flags
& KEYEVENTF_KEYUP
)
1256 key_state_table
[wVk
] &= ~0x80;
1257 key_state_table
[wVkStripped
] = key_state_table
[wVkL
] | key_state_table
[wVkR
];
1261 if (!(key_state_table
[wVk
] & 0x80)) key_state_table
[wVk
] ^= 0x01;
1262 key_state_table
[wVk
] |= 0xc0;
1263 key_state_table
[wVkStripped
] = key_state_table
[wVkL
] | key_state_table
[wVkR
];
1266 if (key_state_table
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1268 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1270 lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1272 TRACE_(key
)(" message=0x%04x wParam=0x%04X, lParam=0x%08lx, InputKeyState=0x%x\n",
1273 message
, wVk
, lParam
, key_state_table
[wVk
]);
1276 SERVER_START_REQ( send_hardware_message
)
1278 req
->id
= (injected_flags
& LLKHF_INJECTED
) ? 0 : GetCurrentThreadId();
1282 req
->lparam
= lParam
;
1283 req
->x
= cursor_pos
.x
;
1284 req
->y
= cursor_pos
.y
;
1286 req
->info
= dwExtraInfo
;
1287 wine_server_call( req
);
1293 /***********************************************************************
1294 * KEYBOARD_UpdateOneState
1296 * Updates internal state for <vkey>, depending on key <state> under X
1299 static inline void KEYBOARD_UpdateOneState ( WORD vkey
, WORD scan
, int state
, DWORD time
)
1301 /* Do something if internal table state != X state for keycode */
1302 if (((key_state_table
[vkey
& 0xff] & 0x80)!=0) != state
)
1304 DWORD flags
= vkey
& 0x100 ? KEYEVENTF_EXTENDEDKEY
: 0;
1306 if (!state
) flags
|= KEYEVENTF_KEYUP
;
1308 TRACE("Adjusting state for vkey %#.2X. State before %#.2x\n",
1309 vkey
, key_state_table
[vkey
& 0xff]);
1311 /* Fake key being pressed inside wine */
1312 X11DRV_send_keyboard_input( vkey
& 0xff, scan
& 0xff, flags
, time
, 0, 0 );
1314 TRACE("State after %#.2x\n", key_state_table
[vkey
& 0xff]);
1318 /***********************************************************************
1319 * X11DRV_KeymapNotify
1321 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1323 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1324 * from wine to another application and back.
1325 * Toggle keys are handled in HandleEvent.
1327 void X11DRV_KeymapNotify( HWND hwnd
, XEvent
*event
)
1330 DWORD time
= GetCurrentTime();
1332 /* the minimum keycode is always greater or equal to 8, so we can
1333 * skip the first 8 values, hence start at 1
1335 for (i
= 1; i
< 32; i
++)
1337 for (j
= 0; j
< 8; j
++)
1339 WORD vkey
= keyc2vkey
[(i
* 8) + j
];
1340 WORD scan
= keyc2scan
[(i
* 8) + j
];
1341 int state
= (event
->xkeymap
.key_vector
[i
] & (1<<j
)) != 0;
1351 KEYBOARD_UpdateOneState( vkey
, scan
, state
, time
);
1358 static void update_lock_state(BYTE vkey
, WORD scan
, DWORD time
)
1360 DWORD flags
= vkey
== VK_NUMLOCK
? KEYEVENTF_EXTENDEDKEY
: 0;
1362 if (key_state_table
[vkey
] & 0x80) flags
^= KEYEVENTF_KEYUP
;
1364 X11DRV_send_keyboard_input( vkey
, scan
, flags
, time
, 0, 0 );
1365 X11DRV_send_keyboard_input( vkey
, scan
, flags
^ KEYEVENTF_KEYUP
, time
, 0, 0 );
1368 /***********************************************************************
1371 * Handle a X key event
1373 void X11DRV_KeyEvent( HWND hwnd
, XEvent
*xev
)
1375 XKeyEvent
*event
= &xev
->xkey
;
1379 WORD vkey
= 0, bScan
;
1382 XIC xic
= X11DRV_get_ic( hwnd
);
1383 DWORD event_time
= EVENT_x11_time_to_win32_time(event
->time
);
1386 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode %u\n",
1387 event
->type
, event
->window
, event
->state
, event
->keycode
);
1390 /* Clients should pass only KeyPress events to XmbLookupString */
1391 if (xic
&& event
->type
== KeyPress
)
1393 ascii_chars
= XmbLookupString(xic
, event
, buf
, sizeof(buf
), &keysym
, &status
);
1394 TRACE("XmbLookupString needs %i byte(s)\n", ascii_chars
);
1395 if (status
== XBufferOverflow
)
1397 Str
= HeapAlloc(GetProcessHeap(), 0, ascii_chars
);
1400 ERR("Failed to allocate memory!\n");
1401 wine_tsx11_unlock();
1404 ascii_chars
= XmbLookupString(xic
, event
, Str
, ascii_chars
, &keysym
, &status
);
1408 ascii_chars
= XLookupString(event
, buf
, sizeof(buf
), &keysym
, NULL
);
1409 wine_tsx11_unlock();
1411 TRACE_(key
)("nbyte = %d, status %d\n", ascii_chars
, status
);
1413 if (status
== XLookupChars
)
1415 X11DRV_XIMLookupChars( Str
, ascii_chars
);
1417 HeapFree(GetProcessHeap(), 0, Str
);
1421 /* If XKB extensions are used, the state mask for AltGr will use the group
1422 index instead of the modifier mask. The group index is set in bits
1423 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1424 pressed, look if the group index is different than 0. From XKB
1425 extension documentation, the group index for AltGr should be 2
1426 (event->state = 0x2000). It's probably better to not assume a
1427 predefined group index and find it dynamically
1429 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1430 /* Save also all possible modifier states. */
1431 AltGrMask
= event
->state
& (0x6000 | Mod1Mask
| Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
);
1437 ksname
= XKeysymToString(keysym
);
1438 wine_tsx11_unlock();
1441 TRACE_(key
)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1442 (event
->type
== KeyPress
) ? "KeyPress" : "KeyRelease",
1443 keysym
, ksname
, ascii_chars
, debugstr_an(Str
, ascii_chars
));
1446 HeapFree(GetProcessHeap(), 0, Str
);
1449 vkey
= EVENT_event_to_vkey(xic
,event
);
1450 /* X returns keycode 0 for composed characters */
1451 if (!vkey
&& ascii_chars
) vkey
= VK_NONAME
;
1452 wine_tsx11_unlock();
1454 TRACE_(key
)("keycode %u converted to vkey 0x%X\n",
1455 event
->keycode
, vkey
);
1460 if ( event
->type
== KeyRelease
) dwFlags
|= KEYEVENTF_KEYUP
;
1461 if ( vkey
& 0x100 ) dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
1464 /* Note: X sets the below states on key down and clears them on key up.
1465 Windows triggers them on key down. */
1467 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1468 if (!(key_state_table
[VK_CAPITAL
] & 0x01) != !(event
->state
& LockMask
) &&
1471 TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table
[VK_CAPITAL
]);
1472 update_lock_state(VK_CAPITAL
, 0x3A, event_time
);
1475 /* Adjust the NUMLOCK state if it has been changed outside wine */
1476 if (!(key_state_table
[VK_NUMLOCK
] & 0x01) != !(event
->state
& NumLockMask
) &&
1477 (vkey
& 0xff) != VK_NUMLOCK
)
1479 TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table
[VK_NUMLOCK
]);
1480 update_lock_state(VK_NUMLOCK
, 0x45, event_time
);
1483 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1484 if (!(key_state_table
[VK_SCROLL
] & 0x01) != !(event
->state
& ScrollLockMask
) &&
1487 TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table
[VK_SCROLL
]);
1488 update_lock_state(VK_SCROLL
, 0x46, event_time
);
1491 /* we get this event repeatedly if we hold down the key (keyboard repeat) */
1492 if ((VK_F12
== vkey
) && (event
->type
== KeyPress
) && getenv("WINEDELAY")) {
1493 __wine_dbg_toggle_block();
1496 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
1497 TRACE_(key
)("bScan = 0x%02x.\n", bScan
);
1499 X11DRV_send_keyboard_input( vkey
& 0xff, bScan
, dwFlags
, event_time
, 0, 0 );
1502 /**********************************************************************
1503 * X11DRV_KEYBOARD_DetectLayout
1505 * Called from X11DRV_InitKeyboard
1506 * This routine walks through the defined keyboard layouts and selects
1507 * whichever matches most closely.
1508 * X11 lock must be held.
1511 X11DRV_KEYBOARD_DetectLayout( Display
*display
)
1513 unsigned current
, match
, mismatch
, seq
, i
, syms
;
1514 int score
, keyc
, key
, pkey
, ok
;
1516 const char (*lkey
)[MAIN_LEN
][4];
1517 unsigned max_seq
= 0;
1518 int max_score
= 0, ismatch
= 0;
1521 syms
= keysyms_per_keycode
;
1523 WARN("%d keysyms per keycode not supported, set to 4\n", syms
);
1527 memset( ckey
, 0, sizeof(ckey
) );
1528 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1529 /* get data for keycode from X server */
1530 for (i
= 0; i
< syms
; i
++) {
1531 if (!(keysym
= XKeycodeToKeysym (display
, keyc
, i
))) continue;
1532 /* Allow both one-byte and two-byte national keysyms */
1533 if ((keysym
< 0x8000) && (keysym
!= ' '))
1536 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[keyc
][i
], 1, NULL
))
1539 TRACE("XKB could not translate keysym %04lx\n", keysym
);
1540 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1541 * with appropriate ShiftMask and Mode_switch, use XLookupString
1542 * to get character in the local encoding.
1544 ckey
[keyc
][i
] = keysym
& 0xFF;
1548 ckey
[keyc
][i
] = KEYBOARD_MapDeadKeysym(keysym
);
1553 for (current
= 0; main_key_tab
[current
].comment
; current
++) {
1554 TRACE("Attempting to match against \"%s\"\n", main_key_tab
[current
].comment
);
1559 lkey
= main_key_tab
[current
].key
;
1561 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1562 if (ckey
[keyc
][0]) {
1563 /* search for a match in layout table */
1564 /* right now, we just find an absolute match for defined positions */
1565 /* (undefined positions are ignored, so if it's defined as "3#" in */
1566 /* the table, it's okay that the X server has "3#£", for example) */
1567 /* however, the score will be higher for longer matches */
1568 for (key
= 0; key
< MAIN_LEN
; key
++) {
1569 for (ok
= 0, i
= 0; (ok
>= 0) && (i
< syms
); i
++) {
1570 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] == ckey
[keyc
][i
]))
1572 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[keyc
][i
]))
1580 /* count the matches and mismatches */
1583 /* and how much the keycode order matches */
1584 if (key
> pkey
) seq
++;
1587 /* print spaces instead of \0's */
1589 for (i
= 0; i
< 4; i
++) str
[i
] = ckey
[keyc
][i
] ? ckey
[keyc
][i
] : ' ';
1591 TRACE_(key
)("mismatch for keycode %u, got %s\n", keyc
, str
);
1597 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1598 match
, mismatch
, seq
, score
);
1599 if ((score
> max_score
) ||
1600 ((score
== max_score
) && (seq
> max_seq
))) {
1601 /* best match so far */
1602 kbd_layout
= current
;
1605 ismatch
= !mismatch
;
1608 /* we're done, report results if necessary */
1610 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1611 main_key_tab
[kbd_layout
].comment
);
1613 TRACE("detected layout is \"%s\"\n", main_key_tab
[kbd_layout
].comment
);
1616 static HKL
get_locale_kbd_layout(void)
1623 * layout = main_key_tab[kbd_layout].lcid;
1625 * Winword uses return value of GetKeyboardLayout as a codepage
1626 * to translate ANSI keyboard messages to unicode. But we have
1627 * a problem with it: for instance Polish keyboard layout is
1628 * identical to the US one, and therefore instead of the Polish
1629 * locale id we return the US one.
1632 layout
= GetUserDefaultLCID();
1635 * Microsoft Office expects this value to be something specific
1636 * for Japanese and Korean Windows with an IME the value is 0xe001
1637 * We should probably check to see if an IME exists and if so then
1638 * set this word properly.
1640 langid
= PRIMARYLANGID(LANGIDFROMLCID(layout
));
1641 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
1642 layout
|= 0xe001 << 16; /* IME */
1644 layout
|= layout
<< 16;
1649 /***********************************************************************
1650 * GetKeyboardLayoutName (X11DRV.@)
1652 BOOL CDECL
X11DRV_GetKeyboardLayoutName(LPWSTR name
)
1654 static const WCHAR formatW
[] = {'%','0','8','x',0};
1657 layout
= HandleToUlong( get_locale_kbd_layout() );
1658 if (HIWORD(layout
) == LOWORD(layout
)) layout
= LOWORD(layout
);
1659 sprintfW(name
, formatW
, layout
);
1660 TRACE("returning %s\n", debugstr_w(name
));
1664 static void set_kbd_layout_preload_key(void)
1666 static const WCHAR preload
[] =
1667 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1668 static const WCHAR one
[] = {'1',0};
1671 WCHAR layout
[KL_NAMELENGTH
];
1673 if (RegCreateKeyExW(HKEY_CURRENT_USER
, preload
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
1676 if (!RegQueryValueExW(hkey
, one
, NULL
, NULL
, NULL
, NULL
))
1681 if (X11DRV_GetKeyboardLayoutName(layout
))
1682 RegSetValueExW(hkey
, one
, 0, REG_SZ
, (const BYTE
*)layout
, sizeof(layout
));
1687 /**********************************************************************
1688 * X11DRV_InitKeyboard
1690 void X11DRV_InitKeyboard( Display
*display
)
1693 XModifierKeymap
*mmp
;
1698 int keyc
, i
, keyn
, syms
;
1699 char ckey
[4]={0,0,0,0};
1700 const char (*lkey
)[MAIN_LEN
][4];
1701 char vkey_used
[256] = { 0 };
1703 /* Ranges of OEM, function key, and character virtual key codes.
1704 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1705 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1706 static const struct {
1709 { VK_OEM_1
, VK_OEM_3
},
1710 { VK_OEM_4
, VK_ICO_00
},
1713 { VK_OEM_NEC_EQUAL
, VK_OEM_NEC_EQUAL
},
1715 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1716 { 0x41, 0x5a }, /* VK_A - VK_Z */
1721 set_kbd_layout_preload_key();
1724 XDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
1725 ksp
= XGetKeyboardMapping(display
, min_keycode
,
1726 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
1727 /* We are only interested in keysyms_per_keycode.
1728 There is no need to hold a local copy of the keysyms table */
1731 mmp
= XGetModifierMapping(display
);
1732 kcp
= mmp
->modifiermap
;
1733 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
1737 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
1742 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
1743 if (XKeycodeToKeysym(display
, *kcp
, k
) == XK_Num_Lock
)
1745 NumLockMask
= 1 << i
;
1746 TRACE_(key
)("NumLockMask is %x\n", NumLockMask
);
1748 else if (XKeycodeToKeysym(display
, *kcp
, k
) == XK_Scroll_Lock
)
1750 ScrollLockMask
= 1 << i
;
1751 TRACE_(key
)("ScrollLockMask is %x\n", ScrollLockMask
);
1755 XFreeModifiermap(mmp
);
1757 /* Detect the keyboard layout */
1758 X11DRV_KEYBOARD_DetectLayout( display
);
1759 lkey
= main_key_tab
[kbd_layout
].key
;
1760 syms
= (keysyms_per_keycode
> 4) ? 4 : keysyms_per_keycode
;
1762 /* Now build two conversion arrays :
1763 * keycode -> vkey + scancode + extended
1764 * vkey + extended -> keycode */
1766 e2
.display
= display
;
1770 memset(keyc2vkey
, 0, sizeof(keyc2vkey
));
1771 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1777 e2
.keycode
= (KeyCode
)keyc
;
1778 have_chars
= XLookupString(&e2
, buf
, sizeof(buf
), &keysym
, NULL
);
1780 if (keysym
) /* otherwise, keycode not used */
1782 if ((keysym
>> 8) == 0xFF) /* non-character key */
1784 vkey
= nonchar_key_vkey
[keysym
& 0xff];
1785 scan
= nonchar_key_scan
[keysym
& 0xff];
1786 /* set extended bit when necessary */
1787 if (scan
& 0x100) vkey
|= 0x100;
1788 } else if ((keysym
>> 8) == 0x1008FF) { /* XFree86 vendor keys */
1789 vkey
= xfree86_vendor_key_vkey
[keysym
& 0xff];
1790 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1793 } else if (keysym
== 0x20) { /* Spacebar */
1796 } else if (have_chars
) {
1797 /* we seem to need to search the layout-dependent scancodes */
1798 int maxlen
=0,maxval
=-1,ok
;
1799 for (i
=0; i
<syms
; i
++) {
1800 keysym
= XKeycodeToKeysym(display
, keyc
, i
);
1801 if ((keysym
<0x8000) && (keysym
!=' '))
1804 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[i
], 1, NULL
))
1807 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1808 * with appropriate ShiftMask and Mode_switch, use XLookupString
1809 * to get character in the local encoding.
1811 ckey
[i
] = keysym
& 0xFF;
1814 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
1817 /* find key with longest match streak */
1818 for (keyn
=0; keyn
<MAIN_LEN
; keyn
++) {
1819 for (ok
=(*lkey
)[keyn
][i
=0]; ok
&&(i
<4); i
++)
1820 if ((*lkey
)[keyn
][i
] && (*lkey
)[keyn
][i
]!=ckey
[i
]) ok
=0;
1821 if (!ok
) i
--; /* we overshot */
1822 if (ok
||(i
>maxlen
)) {
1823 maxlen
=i
; maxval
=keyn
;
1829 const WORD (*lscan
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].scan
;
1830 const WORD (*lvkey
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].vkey
;
1831 scan
= (*lscan
)[maxval
];
1832 vkey
= (*lvkey
)[maxval
];
1836 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1837 keyc2vkey
[e2
.keycode
] = vkey
;
1838 keyc2scan
[e2
.keycode
] = scan
;
1839 if ((vkey
& 0xff) && vkey_used
[(vkey
& 0xff)])
1840 WARN("vkey %04X is being used by more than one keycode\n", vkey
);
1841 vkey_used
[(vkey
& 0xff)] = 1;
1844 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1845 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1847 vkey
= keyc2vkey
[keyc
] & 0xff;
1851 e2
.keycode
= (KeyCode
)keyc
;
1852 keysym
= XLookupKeysym(&e2
, 0);
1856 /* find a suitable layout-dependent VK code */
1857 /* (most Winelib apps ought to be able to work without layout tables!) */
1858 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1860 keysym
= XLookupKeysym(&e2
, i
);
1861 if ((keysym
>= XK_0
&& keysym
<= XK_9
)
1862 || (keysym
>= XK_A
&& keysym
<= XK_Z
)) {
1863 vkey
= VKEY_IF_NOT_USED(keysym
);
1867 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1869 keysym
= XLookupKeysym(&e2
, i
);
1872 case ';': vkey
= VKEY_IF_NOT_USED(VK_OEM_1
); break;
1873 case '/': vkey
= VKEY_IF_NOT_USED(VK_OEM_2
); break;
1874 case '`': vkey
= VKEY_IF_NOT_USED(VK_OEM_3
); break;
1875 case '[': vkey
= VKEY_IF_NOT_USED(VK_OEM_4
); break;
1876 case '\\': vkey
= VKEY_IF_NOT_USED(VK_OEM_5
); break;
1877 case ']': vkey
= VKEY_IF_NOT_USED(VK_OEM_6
); break;
1878 case '\'': vkey
= VKEY_IF_NOT_USED(VK_OEM_7
); break;
1879 case ',': vkey
= VKEY_IF_NOT_USED(VK_OEM_COMMA
); break;
1880 case '.': vkey
= VKEY_IF_NOT_USED(VK_OEM_PERIOD
); break;
1881 case '-': vkey
= VKEY_IF_NOT_USED(VK_OEM_MINUS
); break;
1882 case '+': vkey
= VKEY_IF_NOT_USED(VK_OEM_PLUS
); break;
1888 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1889 keyc2vkey
[e2
.keycode
] = vkey
;
1893 /* For any keycodes which still don't have a vkey, assign any spare
1894 * character, function key, or OEM virtual key code. */
1896 vkey
= vkey_ranges
[vkey_range
].first
;
1897 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1899 if (keyc2vkey
[keyc
] & 0xff)
1902 e2
.keycode
= (KeyCode
)keyc
;
1903 keysym
= XLookupKeysym(&e2
, 0);
1907 while (vkey
&& vkey_used
[vkey
])
1909 if (vkey
== vkey_ranges
[vkey_range
].last
)
1912 vkey
= vkey_ranges
[vkey_range
].first
;
1920 WARN("No more vkeys available!\n");
1924 if (TRACE_ON(keyboard
))
1926 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1929 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
1933 keysym
= XLookupKeysym(&e2
, i
);
1934 ksname
= XKeysymToString(keysym
);
1936 ksname
= "NoSymbol";
1937 TRACE( "%lx (%s) ", keysym
, ksname
);
1942 TRACE("keycode %u => vkey %04X\n", e2
.keycode
, vkey
);
1943 keyc2vkey
[e2
.keycode
] = vkey
;
1944 vkey_used
[vkey
] = 1;
1946 #undef VKEY_IF_NOT_USED
1948 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1949 for (scan
= 0x60, keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1950 if (keyc2vkey
[keyc
]&&!keyc2scan
[keyc
]) {
1952 keysym
= XKeycodeToKeysym(display
, keyc
, 0);
1953 ksname
= XKeysymToString(keysym
);
1954 if (!ksname
) ksname
= "NoSymbol";
1956 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1958 TRACE_(key
)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan
,keyc
,ksname
);
1959 keyc2scan
[keyc
]=scan
++;
1962 wine_tsx11_unlock();
1965 static BOOL
match_x11_keyboard_layout(HKL hkl
)
1967 const DWORD isIME
= 0xE0000000;
1968 HKL xHkl
= get_locale_kbd_layout();
1970 /* if the layout is an IME, only match the low word (LCID) */
1971 if (((ULONG_PTR
)hkl
& isIME
) == isIME
)
1972 return (LOWORD(hkl
) == LOWORD(xHkl
));
1974 return (hkl
== xHkl
);
1977 /**********************************************************************
1978 * GetAsyncKeyState (X11DRV.@)
1980 SHORT CDECL
X11DRV_GetAsyncKeyState(INT key
)
1984 /* Photoshop livelocks unless mouse events are included here */
1985 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL
, 0, QS_KEY
| QS_MOUSE
, 0 );
1987 retval
= ((key_state_table
[key
] & 0x40) ? 0x0001 : 0) |
1988 ((key_state_table
[key
] & 0x80) ? 0x8000 : 0);
1989 key_state_table
[key
] &= ~0x40;
1990 TRACE_(key
)("(%X) -> %x\n", key
, retval
);
1995 /***********************************************************************
1996 * GetKeyboardLayout (X11DRV.@)
1998 HKL CDECL
X11DRV_GetKeyboardLayout(DWORD dwThreadid
)
2000 if (!dwThreadid
|| dwThreadid
== GetCurrentThreadId())
2002 struct x11drv_thread_data
*thread_data
= x11drv_thread_data();
2003 if (thread_data
&& thread_data
->kbd_layout
) return thread_data
->kbd_layout
;
2006 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid
);
2008 return get_locale_kbd_layout();
2012 /***********************************************************************
2013 * LoadKeyboardLayout (X11DRV.@)
2015 HKL CDECL
X11DRV_LoadKeyboardLayout(LPCWSTR name
, UINT flags
)
2017 FIXME("%s, %04x: stub!\n", debugstr_w(name
), flags
);
2018 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2023 /***********************************************************************
2024 * UnloadKeyboardLayout (X11DRV.@)
2026 BOOL CDECL
X11DRV_UnloadKeyboardLayout(HKL hkl
)
2028 FIXME("%p: stub!\n", hkl
);
2029 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2034 /***********************************************************************
2035 * ActivateKeyboardLayout (X11DRV.@)
2037 HKL CDECL
X11DRV_ActivateKeyboardLayout(HKL hkl
, UINT flags
)
2040 struct x11drv_thread_data
*thread_data
= x11drv_init_thread_data();
2042 FIXME("%p, %04x: semi-stub!\n", hkl
, flags
);
2043 if (flags
& KLF_SETFORPROCESS
)
2045 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2046 FIXME("KLF_SETFORPROCESS not supported\n");
2051 FIXME("flags %x not supported\n",flags
);
2053 if (hkl
== (HKL
)HKL_NEXT
|| hkl
== (HKL
)HKL_PREV
)
2055 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2056 FIXME("HKL_NEXT and HKL_PREV not supported\n");
2060 if (!match_x11_keyboard_layout(hkl
))
2062 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2063 FIXME("setting keyboard of different locales not supported\n");
2067 oldHkl
= thread_data
->kbd_layout
;
2068 if (!oldHkl
) oldHkl
= get_locale_kbd_layout();
2070 thread_data
->kbd_layout
= hkl
;
2076 /***********************************************************************
2077 * X11DRV_MappingNotify
2079 void X11DRV_MappingNotify( HWND dummy
, XEvent
*event
)
2084 XRefreshKeyboardMapping(&event
->xmapping
);
2085 wine_tsx11_unlock();
2086 X11DRV_InitKeyboard( event
->xmapping
.display
);
2089 if (!hwnd
) hwnd
= GetActiveWindow();
2090 PostMessageW(hwnd
, WM_INPUTLANGCHANGEREQUEST
,
2091 0 /*FIXME*/, (LPARAM
)X11DRV_GetKeyboardLayout(0));
2095 /***********************************************************************
2096 * VkKeyScanEx (X11DRV.@)
2098 * Note: Windows ignores HKL parameter and uses current active layout instead
2100 SHORT CDECL
X11DRV_VkKeyScanEx(WCHAR wChar
, HKL hkl
)
2102 Display
*display
= thread_init_display();
2109 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2110 * is UTF-8 (multibyte encoding)?
2112 if (!WideCharToMultiByte(CP_UNIXCP
, 0, &wChar
, 1, &cChar
, 1, NULL
, NULL
))
2114 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar
);
2118 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar
, cChar
);
2120 /* char->keysym (same for ANSI chars) */
2121 keysym
= (unsigned char)cChar
; /* (!) cChar is signed */
2122 if (keysym
<= 27) keysym
+= 0xFF00; /* special chars : return, backspace... */
2125 keycode
= XKeysymToKeycode(display
, keysym
); /* keysym -> keycode */
2128 if (keysym
>= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2130 ret
= 0x0240 + cChar
; /* 0x0200 indicates a control character */
2131 TRACE(" ... returning ctrl char %#.2x\n", ret
);
2132 wine_tsx11_unlock();
2135 /* It didn't work ... let's try with deadchar code. */
2136 TRACE("retrying with | 0xFE00\n");
2137 keycode
= XKeysymToKeycode(display
, keysym
| 0xFE00);
2139 wine_tsx11_unlock();
2141 TRACE("'%c'(%lx): got keycode %u\n", cChar
, keysym
, keycode
);
2143 /* keycode -> (keyc2vkey) vkey */
2144 ret
= keyc2vkey
[keycode
];
2146 if (!keycode
|| !ret
)
2148 TRACE("keycode for '%c' not found, returning -1\n", cChar
);
2154 for (i
= 0; i
< 4; i
++) /* find shift state */
2156 if (XKeycodeToKeysym(display
, keycode
, i
) == keysym
)
2162 wine_tsx11_unlock();
2168 WARN("Keysym %lx not found while parsing the keycode table\n", keysym
);
2172 case 1: ret
+= 0x0100; break;
2173 case 2: ret
+= 0x0600; break;
2174 case 3: ret
+= 0x0700; break;
2177 index : 0 adds 0x0000
2178 index : 1 adds 0x0100 (shift)
2179 index : ? adds 0x0200 (ctrl)
2180 index : 2 adds 0x0600 (ctrl+alt)
2181 index : 3 adds 0x0700 (ctrl+alt+shift)
2184 TRACE(" ... returning %#.2x\n", ret
);
2188 /***********************************************************************
2189 * MapVirtualKeyEx (X11DRV.@)
2191 UINT CDECL
X11DRV_MapVirtualKeyEx(UINT wCode
, UINT wMapType
, HKL hkl
)
2193 Display
*display
= thread_init_display();
2195 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2197 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode
, wMapType
, hkl
);
2198 if (!match_x11_keyboard_layout(hkl
))
2199 FIXME("keyboard layout %p is not supported\n", hkl
);
2203 case MAPVK_VK_TO_VSC
: /* vkey-code to scan-code */
2204 case MAPVK_VK_TO_VSC_EX
:
2210 case VK_SHIFT
: wCode
= VK_LSHIFT
; break;
2211 case VK_CONTROL
: wCode
= VK_LCONTROL
; break;
2212 case VK_MENU
: wCode
= VK_LMENU
; break;
2215 /* let's do vkey -> keycode -> scan */
2216 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2217 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
) break;
2219 if (keyc
> max_keycode
)
2221 TRACE("returning no scan-code.\n");
2224 returnMVK (keyc2scan
[keyc
] & 0xFF);
2226 case MAPVK_VSC_TO_VK
: /* scan-code to vkey-code */
2227 case MAPVK_VSC_TO_VK_EX
:
2232 /* let's do scan -> keycode -> vkey */
2233 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2234 if ((keyc2scan
[keyc
] & 0xFF) == (wCode
& 0xFF))
2236 vkey
= keyc2vkey
[keyc
] & 0xFF;
2237 /* Only stop if it's not a numpad vkey; otherwise keep
2238 looking for a potential better vkey. */
2239 if (vkey
&& (vkey
< VK_NUMPAD0
|| VK_DIVIDE
< vkey
))
2245 TRACE("returning no vkey-code.\n");
2249 if (wMapType
== MAPVK_VSC_TO_VK
)
2254 vkey
= VK_SHIFT
; break;
2257 vkey
= VK_CONTROL
; break;
2260 vkey
= VK_MENU
; break;
2265 case MAPVK_VK_TO_CHAR
: /* vkey-code to unshifted ANSI code */
2267 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2268 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2269 * key.. Looks like something is wrong with the MS docs?
2270 * This is only true for letters, for example VK_0 returns '0' not ')'.
2271 * - hence we use the lock mask to ensure this happens.
2273 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2279 e
.display
= display
;
2286 /* We exit on the first keycode found, to speed up the thing. */
2287 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2288 { /* Find a keycode that could have generated this virtual key */
2289 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
2290 { /* We filter the extended bit, we don't know it */
2291 e
.keycode
= keyc
; /* Store it temporarily */
2292 if ((EVENT_event_to_vkey(0,&e
) & 0xFF) != wCode
) {
2293 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2294 state), so set it to 0, we'll find another one */
2299 if ((wCode
>=VK_NUMPAD0
) && (wCode
<=VK_NUMPAD9
))
2300 e
.keycode
= XKeysymToKeycode(e
.display
, wCode
-VK_NUMPAD0
+XK_KP_0
);
2302 if (wCode
==VK_DECIMAL
)
2303 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2307 WARN("Unknown virtual key %X !!!\n", wCode
);
2308 wine_tsx11_unlock();
2309 return 0; /* whatever */
2311 TRACE("Found keycode %u\n",e
.keycode
);
2313 len
= XLookupString(&e
, s
, sizeof(s
), &keysym
, NULL
);
2314 wine_tsx11_unlock();
2319 if (MultiByteToWideChar(CP_UNIXCP
, 0, s
, len
, &wch
, 1))
2320 returnMVK(toupperW(wch
));
2322 TRACE("returning no ANSI.\n");
2325 default: /* reserved */
2326 FIXME("Unknown wMapType %d !\n", wMapType
);
2332 /***********************************************************************
2333 * GetKeyNameText (X11DRV.@)
2335 INT CDECL
X11DRV_GetKeyNameText(LONG lParam
, LPWSTR lpBuffer
, INT nSize
)
2337 Display
*display
= thread_init_display();
2338 int vkey
, ansi
, scanCode
;
2344 scanCode
= lParam
>> 16;
2345 scanCode
&= 0x1ff; /* keep "extended-key" flag with code */
2347 vkey
= X11DRV_MapVirtualKeyEx(scanCode
, MAPVK_VSC_TO_VK_EX
, X11DRV_GetKeyboardLayout(0));
2349 /* handle "don't care" bit (0x02000000) */
2350 if (!(lParam
& 0x02000000)) {
2353 /* R-Shift is "special" - it is an extended key with separate scan code */
2369 ansi
= X11DRV_MapVirtualKeyEx(vkey
, MAPVK_VK_TO_CHAR
, X11DRV_GetKeyboardLayout(0));
2370 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode
, vkey
, ansi
);
2372 /* first get the name of the "regular" keys which is the Upper case
2373 value of the keycap imprint. */
2374 if ( ((ansi
>= 0x21) && (ansi
<= 0x7e)) &&
2375 (scanCode
!= 0x137) && /* PrtScn */
2376 (scanCode
!= 0x135) && /* numpad / */
2377 (scanCode
!= 0x37 ) && /* numpad * */
2378 (scanCode
!= 0x4a ) && /* numpad - */
2379 (scanCode
!= 0x4e ) ) /* numpad + */
2381 if ((nSize
>= 2) && lpBuffer
)
2383 *lpBuffer
= toupperW((WCHAR
)ansi
);
2391 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2392 without "extended-key" flag. However Wine generates scancode
2393 *with* "extended-key" flag. Seems to occur *only* for the
2394 function keys. Soooo.. We will leave the table alone and
2395 fudge the lookup here till the other part is found and fixed!!! */
2397 if ( ((scanCode
>= 0x13b) && (scanCode
<= 0x144)) ||
2398 (scanCode
== 0x157) || (scanCode
== 0x158))
2399 scanCode
&= 0xff; /* remove "extended-key" flag for Fx keys */
2401 /* let's do scancode -> keycode -> keysym -> String */
2403 for (keyi
=min_keycode
; keyi
<=max_keycode
; keyi
++)
2404 if ((keyc2scan
[keyi
]) == scanCode
)
2406 if (keyi
<= max_keycode
)
2409 keyc
= (KeyCode
) keyi
;
2410 keys
= XKeycodeToKeysym(display
, keyc
, 0);
2411 name
= XKeysymToString(keys
);
2412 wine_tsx11_unlock();
2413 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2414 scanCode
, keyc
, (int)keys
, name
);
2415 if (lpBuffer
&& nSize
&& name
)
2416 return MultiByteToWideChar(CP_UNIXCP
, 0, name
, -1, lpBuffer
, nSize
);
2419 /* Finally issue WARN for unknown keys */
2421 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam
,lpBuffer
,nSize
,vkey
,ansi
);
2422 if (lpBuffer
&& nSize
)
2427 /***********************************************************************
2428 * X11DRV_KEYBOARD_MapDeadKeysym
2430 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
2434 /* symbolic ASCII is the same as defined in rfc1345 */
2435 #ifdef XK_dead_tilde
2436 case XK_dead_tilde
:
2438 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2439 return '~'; /* '? */
2440 #ifdef XK_dead_acute
2441 case XK_dead_acute
:
2443 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2444 return 0xb4; /* '' */
2445 #ifdef XK_dead_circumflex
2446 case XK_dead_circumflex
:
2448 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2449 return '^'; /* '> */
2450 #ifdef XK_dead_grave
2451 case XK_dead_grave
:
2453 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2454 return '`'; /* '! */
2455 #ifdef XK_dead_diaeresis
2456 case XK_dead_diaeresis
:
2458 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2459 return 0xa8; /* ': */
2460 #ifdef XK_dead_cedilla
2461 case XK_dead_cedilla
:
2462 return 0xb8; /* ', */
2464 #ifdef XK_dead_macron
2465 case XK_dead_macron
:
2466 return '-'; /* 'm isn't defined on iso-8859-x */
2468 #ifdef XK_dead_breve
2469 case XK_dead_breve
:
2470 return 0xa2; /* '( */
2472 #ifdef XK_dead_abovedot
2473 case XK_dead_abovedot
:
2474 return 0xff; /* '. */
2476 #ifdef XK_dead_abovering
2477 case XK_dead_abovering
:
2478 return '0'; /* '0 isn't defined on iso-8859-x */
2480 #ifdef XK_dead_doubleacute
2481 case XK_dead_doubleacute
:
2482 return 0xbd; /* '" */
2484 #ifdef XK_dead_caron
2485 case XK_dead_caron
:
2486 return 0xb7; /* '< */
2488 #ifdef XK_dead_ogonek
2489 case XK_dead_ogonek
:
2490 return 0xb2; /* '; */
2492 /* FIXME: I don't know this three.
2495 case XK_dead_voiced_sound :
2497 case XK_dead_semivoiced_sound :
2501 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
2505 /***********************************************************************
2506 * ToUnicodeEx (X11DRV.@)
2508 * The ToUnicode function translates the specified virtual-key code and keyboard
2509 * state to the corresponding Windows character or characters.
2511 * If the specified key is a dead key, the return value is negative. Otherwise,
2512 * it is one of the following values:
2514 * 0 The specified virtual key has no translation for the current state of the keyboard.
2515 * 1 One Windows character was copied to the buffer.
2516 * 2 Two characters were copied to the buffer. This usually happens when a
2517 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2518 * be composed with the specified virtual key to form a single character.
2520 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2523 INT CDECL
X11DRV_ToUnicodeEx(UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
2524 LPWSTR bufW
, int bufW_size
, UINT flags
, HKL hkl
)
2526 Display
*display
= thread_init_display();
2537 if (scanCode
& 0x8000)
2539 TRACE("Key UP, doing nothing\n" );
2543 if (!match_x11_keyboard_layout(hkl
))
2544 FIXME("keyboard layout %p is not supported\n", hkl
);
2546 if ((lpKeyState
[VK_MENU
] & 0x80) && (lpKeyState
[VK_CONTROL
] & 0x80))
2548 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2552 e
.display
= display
;
2558 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
2559 if (!focus
) focus
= GetActiveWindow();
2560 e
.window
= X11DRV_get_whole_window( focus
);
2561 xic
= X11DRV_get_ic( focus
);
2563 if (lpKeyState
[VK_SHIFT
] & 0x80)
2565 TRACE("ShiftMask = %04x\n", ShiftMask
);
2566 e
.state
|= ShiftMask
;
2568 if (lpKeyState
[VK_CAPITAL
] & 0x01)
2570 TRACE("LockMask = %04x\n", LockMask
);
2571 e
.state
|= LockMask
;
2573 if (lpKeyState
[VK_CONTROL
] & 0x80)
2575 TRACE("ControlMask = %04x\n", ControlMask
);
2576 e
.state
|= ControlMask
;
2578 if (lpKeyState
[VK_NUMLOCK
] & 0x01)
2580 TRACE("NumLockMask = %04x\n", NumLockMask
);
2581 e
.state
|= NumLockMask
;
2584 /* Restore saved AltGr state */
2585 TRACE("AltGrMask = %04x\n", AltGrMask
);
2586 e
.state
|= AltGrMask
;
2588 TRACE_(key
)("(%04X, %04X) : faked state = 0x%04x\n",
2589 virtKey
, scanCode
, e
.state
);
2591 /* We exit on the first keycode found, to speed up the thing. */
2592 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2593 { /* Find a keycode that could have generated this virtual key */
2594 if ((keyc2vkey
[keyc
] & 0xFF) == virtKey
)
2595 { /* We filter the extended bit, we don't know it */
2596 e
.keycode
= keyc
; /* Store it temporarily */
2597 if ((EVENT_event_to_vkey(xic
,&e
) & 0xFF) != virtKey
) {
2598 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2599 state), so set it to 0, we'll find another one */
2604 if (virtKey
>= VK_LEFT
&& virtKey
<= VK_DOWN
)
2605 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
- VK_LEFT
+ XK_Left
);
2607 if ((virtKey
>=VK_NUMPAD0
) && (virtKey
<=VK_NUMPAD9
))
2608 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
-VK_NUMPAD0
+XK_KP_0
);
2610 if (virtKey
==VK_DECIMAL
)
2611 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2613 if (virtKey
==VK_SEPARATOR
)
2614 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Separator
);
2616 if (!e
.keycode
&& virtKey
!= VK_NONAME
)
2618 WARN("Unknown virtual key %X !!!\n", virtKey
);
2619 wine_tsx11_unlock();
2622 else TRACE("Found keycode %u\n",e
.keycode
);
2624 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode %u\n",
2625 e
.type
, e
.window
, e
.state
, e
.keycode
);
2627 /* Clients should pass only KeyPress events to XmbLookupString,
2628 * e.type was set to KeyPress above.
2632 ret
= XmbLookupString(xic
, &e
, buf
, sizeof(buf
), &keysym
, &status
);
2633 TRACE("XmbLookupString needs %d byte(s)\n", ret
);
2634 if (status
== XBufferOverflow
)
2636 lpChar
= HeapAlloc(GetProcessHeap(), 0, ret
);
2639 ERR("Failed to allocate memory!\n");
2640 wine_tsx11_unlock();
2643 ret
= XmbLookupString(xic
, &e
, lpChar
, ret
, &keysym
, &status
);
2647 ret
= XLookupString(&e
, buf
, sizeof(buf
), &keysym
, NULL
);
2648 wine_tsx11_unlock();
2650 TRACE_(key
)("nbyte = %d, status 0x%x\n", ret
, status
);
2657 ksname
= XKeysymToString(keysym
);
2658 wine_tsx11_unlock();
2659 if (!ksname
) ksname
= "No Name";
2660 TRACE_(key
)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2661 (e
.type
== KeyPress
) ? "KeyPress" : "KeyRelease",
2662 keysym
, ksname
, ret
, debugstr_an(lpChar
, ret
));
2670 /* An ugly hack for EuroSign: X can't translate it to a character
2671 for some locales. */
2672 if (keysym
== XK_EuroSign
)
2679 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2680 /* Here we change it back. */
2681 if (keysym
== XK_ISO_Left_Tab
&& !(e
.state
& ControlMask
))
2688 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
2691 MultiByteToWideChar(CP_UNIXCP
, 0, &dead_char
, 1, bufW
, bufW_size
);
2696 if (keysym
>= 0x01000100 && keysym
<= 0x0100ffff)
2698 /* Unicode direct mapping */
2699 bufW
[0] = keysym
& 0xffff;
2703 else if ((keysym
>> 8) == 0x1008FF) {
2713 ksname
= XKeysymToString(keysym
);
2714 wine_tsx11_unlock();
2717 if ((keysym
>> 8) != 0xff)
2719 WARN("no char for keysym %04lx (%s) :\n",
2721 WARN("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2722 virtKey
, scanCode
, e
.keycode
, e
.state
);
2726 else { /* ret != 0 */
2727 /* We have a special case to handle : Shift + arrow, shift + home, ...
2728 X returns a char for it, but Windows doesn't. Let's eat it. */
2729 if (!(e
.state
& NumLockMask
) /* NumLock is off */
2730 && (e
.state
& ShiftMask
) /* Shift is pressed */
2731 && (keysym
>=XK_KP_0
) && (keysym
<=XK_KP_9
))
2737 /* more areas where X returns characters but Windows does not
2738 CTRL + number or CTRL + symbol */
2739 if (e
.state
& ControlMask
)
2741 if (((keysym
>=33) && (keysym
< 'A')) ||
2742 ((keysym
> 'Z') && (keysym
< 'a')) ||
2750 /* We have another special case for delete key (XK_Delete) on an
2751 extended keyboard. X returns a char for it, but Windows doesn't */
2752 if (keysym
== XK_Delete
)
2757 else if((lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
2758 && (keysym
== XK_KP_Decimal
))
2763 else if((lpKeyState
[VK_CONTROL
] & 0x80) /* Control is pressed */
2764 && (keysym
== XK_Return
|| keysym
== XK_KP_Enter
))
2770 /* Hack to detect an XLookupString hard-coded to Latin1 */
2771 if (ret
== 1 && keysym
>= 0x00a0 && keysym
<= 0x00ff && (BYTE
)lpChar
[0] == keysym
)
2773 bufW
[0] = (BYTE
)lpChar
[0];
2777 /* perform translation to unicode */
2780 TRACE_(key
)("Translating char 0x%02x to unicode\n", *(BYTE
*)lpChar
);
2781 ret
= MultiByteToWideChar(CP_UNIXCP
, 0, lpChar
, ret
, bufW
, bufW_size
);
2787 HeapFree(GetProcessHeap(), 0, lpChar
);
2788 TRACE_(key
)("returning %d with %s\n", ret
, debugstr_wn(bufW
, ret
));
2792 /***********************************************************************
2795 void CDECL
X11DRV_Beep(void)
2798 XBell(gdi_display
, 0);
2799 wine_tsx11_unlock();