wininet: Support the Cache-Control max-age directive for setting url cache entry...
[wine/testsucceed.git] / dlls / winex11.drv / keyboard.c
blob4185025f343ddb918843e881484b6ab08742144b
1 /*
2 * X11 keyboard driver
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
35 #endif
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wingdi.h"
46 #include "winuser.h"
47 #include "winreg.h"
48 #include "winnls.h"
49 #include "x11drv.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
54 /* log format (add 0-padding as appropriate):
55 keycode %u as in output from xev
56 keysym %lx as in X11/keysymdef.h
57 vkey %X as in winuser.h
58 scancode %x
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
63 static int min_keycode, max_keycode, keysyms_per_keycode;
64 static WORD keyc2vkey[256], keyc2scan[256];
66 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
68 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
70 /* Keyboard translation tables */
71 #define MAIN_LEN 49
72 static const WORD main_key_scan_qwerty[MAIN_LEN] =
74 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
75 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
76 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
77 /* q w e r t y u i o p [ ] */
78 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
79 /* a s d f g h j k l ; ' \ */
80 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
81 /* z x c v b n m , . / */
82 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
83 0x56 /* the 102nd key (actually to the right of l-shift) */
86 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
88 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
89 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
90 /* q w e r t y u i o p [ ] */
91 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
92 /* a s d f g h j k l ; ' \ */
93 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
94 /* \ z x c v b n m , . / */
95 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
96 0x56, /* the 102nd key (actually to the right of l-shift) */
99 static const WORD main_key_scan_dvorak[MAIN_LEN] =
101 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
102 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
103 /* ' , . p y f g c r l / = */
104 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
105 /* a o e u i d h t n s - \ */
106 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
107 /* ; q j k x b m w v z */
108 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
109 0x56 /* the 102nd key (actually to the right of l-shift) */
112 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
114 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
115 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
116 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
117 /* q w e r t y u i o p @ [ */
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
119 /* a s d f g h j k l ; : ] */
120 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
121 /* z x c v b n m , . / */
122 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
123 0x56 /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
128 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
129 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
130 /* q w e r t y u i o p @ [ */
131 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
132 /* a s d f g h j k l ; : ] */
133 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
134 /* z x c v b n m , . / */
135 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
136 0x73 /* the 102nd key (actually to the right of l-shift) */
140 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
142 /* NOTE: this layout must concur with the scan codes layout above */
143 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
144 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
145 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
146 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
147 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
150 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
152 /* NOTE: this layout must concur with the scan codes layout above */
153 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
154 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
155 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
156 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
157 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
160 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
162 /* NOTE: this layout must concur with the scan codes layout above */
163 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
164 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
165 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
166 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
167 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
170 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
172 /* NOTE: this layout must concur with the scan codes layout above */
173 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
174 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
175 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
176 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
177 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
180 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
182 /* NOTE: this layout must concur with the scan codes layout above */
183 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
184 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
185 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
186 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
187 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
190 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
192 /* NOTE: this layout must concur with the scan codes layout above */
193 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
194 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
195 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
196 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
197 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
200 static const WORD main_key_vkey_azerty[MAIN_LEN] =
202 /* NOTE: this layout must concur with the scan codes layout above */
203 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
204 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
205 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
206 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
207 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
210 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
212 /* NOTE: this layout must concur with the scan codes layout above */
213 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
214 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
215 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
216 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
217 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
220 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
222 /* the VK mappings for the main keyboard will be auto-assigned as before,
223 so what we have here is just the character tables */
224 /* order: Normal, Shift, AltGr, Shift-AltGr */
225 /* We recommend you write just what is guaranteed to be correct (i.e. what's
226 written on the keycaps), not the bunch of special characters behind AltGr
227 and Shift-AltGr if it can vary among different X servers */
228 /* These tables serve to guess the keyboard type and scancode mapping.
229 Complete modeling is not important, identification/discrimination is. */
230 /* Remember that your 102nd key (to the right of l-shift) should be on a
231 separate line, see existing tables */
232 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
233 /* Remember to also add your new table to the layout index table far below! */
235 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
236 static const char main_key_US[MAIN_LEN][4] =
238 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
239 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
240 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
241 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
244 /*** United States keyboard layout (phantom key version) */
245 /* (XFree86 reports the <> key even if it's not physically there) */
246 static const char main_key_US_phantom[MAIN_LEN][4] =
248 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
249 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
251 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
252 "<>" /* the phantom key */
255 /*** United States keyboard layout (dvorak version) */
256 static const char main_key_US_dvorak[MAIN_LEN][4] =
258 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
259 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
260 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
261 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
264 /*** British keyboard layout */
265 static const char main_key_UK[MAIN_LEN][4] =
267 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
268 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
269 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
270 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
271 "\\|"
274 /*** French keyboard layout (setxkbmap fr) */
275 static const char main_key_FR[MAIN_LEN][4] =
277 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
278 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
279 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
280 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
281 "<>"
284 /*** Icelandic keyboard layout (setxkbmap is) */
285 static const char main_key_IS[MAIN_LEN][4] =
287 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
288 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
290 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
291 "<>"
294 /* All german keyb layout tables have the acute/apostrophe symbol next to
295 * the BACKSPACE key removed (replaced with NULL which is ignored by the
296 * detection code).
297 * This was done because the mapping of the acute (and apostrophe) is done
298 * differently in various xkb-data/xkeyboard-config versions. Some replace
299 * the acute with a normal apostrophe, so that the apostrophe is found twice
300 * on the keyboard (one next to BACKSPACE and one next to ENTER).
301 * Others put the acute and grave accents on the key left of BACKSPACE.
302 * More information on the fd.o bugtracker:
303 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
304 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
305 * among PC and Mac keyboards, so these are not listed.
308 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
309 static const char main_key_DE[MAIN_LEN][4] =
311 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","",
312 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
313 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
314 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
315 "<>"
318 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
319 static const char main_key_SG[MAIN_LEN][4] =
321 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
322 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
323 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
324 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
325 "<>"
328 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
329 static const char main_key_SF[MAIN_LEN][4] =
331 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
332 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
333 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
334 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
335 "<>"
338 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
339 static const char main_key_NO[MAIN_LEN][4] =
341 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
342 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
343 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
344 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
345 "<>"
348 /*** Danish keyboard layout (setxkbmap dk) */
349 static const char main_key_DA[MAIN_LEN][4] =
351 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
352 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
353 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
354 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
355 "<>"
358 /*** Swedish keyboard layout (setxkbmap se) */
359 static const char main_key_SE[MAIN_LEN][4] =
361 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
362 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
363 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
364 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
365 "<>"
368 /*** Estonian keyboard layout (setxkbmap ee) */
369 static const char main_key_ET[MAIN_LEN][4] =
371 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
372 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
373 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
374 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
375 "<>"
378 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
379 static const char main_key_CF[MAIN_LEN][4] =
381 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
382 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
383 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
384 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
385 "«»°"
388 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
389 static const char main_key_CA_fr[MAIN_LEN][4] =
391 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
392 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
393 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
394 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
395 "«»"
398 /*** Canadian keyboard layout (setxkbmap ca) */
399 static const char main_key_CA[MAIN_LEN][4] =
401 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
402 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
403 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
404 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
405 "ùÙ"
408 /*** Portuguese keyboard layout (setxkbmap pt) */
409 static const char main_key_PT[MAIN_LEN][4] =
411 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
412 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
413 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
414 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
415 "<>"
418 /*** Italian keyboard layout (setxkbmap it) */
419 static const char main_key_IT[MAIN_LEN][4] =
421 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
422 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
423 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
424 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
425 "<>"
428 /*** Finnish keyboard layout (setxkbmap fi) */
429 static const char main_key_FI[MAIN_LEN][4] =
431 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
432 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
433 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
434 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
435 "<>"
438 /*** Bulgarian bds keyboard layout */
439 static const char main_key_BG_bds[MAIN_LEN][4] =
441 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
442 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
443 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
444 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
445 "<>" /* the phantom key */
448 /*** Bulgarian phonetic keyboard layout */
449 static const char main_key_BG_phonetic[MAIN_LEN][4] =
451 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
452 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
453 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
454 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
455 "<>" /* the phantom key */
458 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
459 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
460 static const char main_key_BY[MAIN_LEN][4] =
462 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
463 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
464 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
465 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
469 /*** Russian keyboard layout (contributed by Pavel Roskin) */
470 static const char main_key_RU[MAIN_LEN][4] =
472 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
473 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
474 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
475 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
478 /*** Russian keyboard layout (phantom key version) */
479 static const char main_key_RU_phantom[MAIN_LEN][4] =
481 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
482 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
483 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
484 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
485 "<>" /* the phantom key */
488 /*** Russian keyboard layout KOI8-R */
489 static const char main_key_RU_koi8r[MAIN_LEN][4] =
491 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
492 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
493 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
494 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
495 "<>" /* the phantom key */
498 /*** Russian keyboard layout cp1251 */
499 static const char main_key_RU_cp1251[MAIN_LEN][4] =
501 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
502 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
503 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
504 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
505 "<>" /* the phantom key */
508 /*** Russian phonetic keyboard layout */
509 static const char main_key_RU_phonetic[MAIN_LEN][4] =
511 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
512 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
513 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
514 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
515 "<>" /* the phantom key */
518 /*** Ukrainian keyboard layout KOI8-U */
519 static const char main_key_UA[MAIN_LEN][4] =
521 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
522 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
523 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
524 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
525 "<>" /* the phantom key */
528 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
529 /*** (as it appears on most of keyboards sold today) */
530 static const char main_key_UA_std[MAIN_LEN][4] =
532 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
533 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
534 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
535 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
536 "<>" /* the phantom key */
539 /*** Russian keyboard layout KOI8-R (pair to the previous) */
540 static const char main_key_RU_std[MAIN_LEN][4] =
542 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
543 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
544 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
545 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
546 "<>" /* the phantom key */
549 /*** Spanish keyboard layout (setxkbmap es) */
550 static const char main_key_ES[MAIN_LEN][4] =
552 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
553 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
554 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
555 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
556 "<>"
559 /*** Belgian keyboard layout ***/
560 static const char main_key_BE[MAIN_LEN][4] =
562 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
563 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
564 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
565 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
566 "<>\\"
569 /*** Hungarian keyboard layout (setxkbmap hu) */
570 static const char main_key_HU[MAIN_LEN][4] =
572 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
573 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
574 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
575 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
576 "íÍ"
579 /*** Polish (programmer's) keyboard layout ***/
580 static const char main_key_PL[MAIN_LEN][4] =
582 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
583 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
584 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
585 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
586 "<>|"
589 /*** Slovenian keyboard layout (setxkbmap si) ***/
590 static const char main_key_SI[MAIN_LEN][4] =
592 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
593 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
594 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
595 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
596 "<>"
599 /*** Serbian keyboard layout (setxkbmap sr) ***/
600 static const char main_key_SR[MAIN_LEN][4] =
602 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
603 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
604 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
605 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
606 "<>" /* the phantom key */
609 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
610 static const char main_key_US_SR[MAIN_LEN][4] =
612 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
613 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
614 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
615 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
616 "<>" /* the phantom key */
619 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
620 static const char main_key_HR_jelly[MAIN_LEN][4] =
622 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
623 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
624 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
625 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
626 "<>|"
629 /*** Croatian keyboard layout (setxkbmap hr) ***/
630 static const char main_key_HR[MAIN_LEN][4] =
632 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
633 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
634 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
635 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
636 "<>"
639 /*** Japanese 106 keyboard layout ***/
640 static const char main_key_JA_jp106[MAIN_LEN][4] =
642 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
643 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
644 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
645 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
646 "\\_",
649 static const char main_key_JA_macjp[MAIN_LEN][4] =
651 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
652 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
653 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
654 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
655 "__",
658 /*** Japanese pc98x1 keyboard layout ***/
659 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
661 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
662 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
663 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
664 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
665 "\\_",
668 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
669 static const char main_key_PT_br[MAIN_LEN][4] =
671 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
672 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
673 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
674 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
677 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
678 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
680 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
681 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
682 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
683 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
686 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
687 static const char main_key_US_intl[MAIN_LEN][4] =
689 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
690 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
691 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
692 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
695 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
696 - dead_abovering replaced with degree - no symbol in iso8859-2
697 - brokenbar replaced with bar */
698 static const char main_key_SK[MAIN_LEN][4] =
700 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
701 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
702 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
703 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
704 "<>"
707 /*** Czech keyboard layout (setxkbmap cz) */
708 static const char main_key_CZ[MAIN_LEN][4] =
710 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
711 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
712 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
713 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
714 "\\"
717 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
718 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
720 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
721 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
722 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
723 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
724 "\\"
727 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
728 static const char main_key_SK_prog[MAIN_LEN][4] =
730 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
731 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
732 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
733 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
734 "<>"
737 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
738 static const char main_key_CS[MAIN_LEN][4] =
740 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
741 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
742 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
743 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
744 "<>\\|"
747 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
748 static const char main_key_LA[MAIN_LEN][4] =
750 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
751 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
752 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
753 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
754 "<>"
757 /*** Lithuanian keyboard layout (setxkbmap lt) */
758 static const char main_key_LT_B[MAIN_LEN][4] =
760 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
761 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
762 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
763 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
764 "ª¬"
767 /*** Turkish keyboard Layout */
768 static const char main_key_TK[MAIN_LEN][4] =
770 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
771 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
772 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
773 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
776 /*** Turkish keyboard layout (setxkbmap tr) */
777 static const char main_key_TR[MAIN_LEN][4] =
779 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
780 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
781 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
782 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
783 "<>"
786 /*** Turkish F keyboard layout (setxkbmap trf) */
787 static const char main_key_TR_F[MAIN_LEN][4] =
789 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
790 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
791 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
792 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
793 "<>"
796 /*** Israelian keyboard layout (setxkbmap us,il) */
797 static const char main_key_IL[MAIN_LEN][4] =
799 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
800 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
801 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
802 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
803 "<>"
806 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
807 static const char main_key_IL_phonetic[MAIN_LEN][4] =
809 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
810 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
811 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
812 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
813 "<>"
816 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
817 static const char main_key_IL_saharon[MAIN_LEN][4] =
819 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
820 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
821 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
822 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
823 "<>"
826 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
827 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
828 message since they have different characters in gr and el XFree86 layouts. */
829 static const char main_key_EL[MAIN_LEN][4] =
831 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
832 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
833 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
834 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
835 "<>"
838 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
839 static const char main_key_th[MAIN_LEN][4] =
841 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
842 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
843 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
844 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
847 /*** VNC keyboard layout */
848 static const WORD main_key_scan_vnc[MAIN_LEN] =
850 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
851 0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C,
852 0x56
855 static const WORD main_key_vkey_vnc[MAIN_LEN] =
857 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_4,VK_OEM_6,VK_OEM_1,VK_OEM_7,VK_OEM_3,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_5,
858 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
859 VK_OEM_102
862 static const char main_key_vnc[MAIN_LEN][4] =
864 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
865 "aA","bB","cC","dD","eE","fF","gG","hH","iI","jJ","kK","lL","mM","nN","oO","pP","qQ","rR","sS","tT","uU","vV","wW","xX","yY","zZ"
868 /*** Dutch keyboard layout (setxkbmap nl) ***/
869 static const char main_key_NL[MAIN_LEN][4] =
871 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
872 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
873 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
874 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
875 "[]"
880 /*** Layout table. Add your keyboard mappings to this list */
881 static const struct {
882 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
883 in the appropriate dlls/kernel/nls/.nls file */
884 const char *comment;
885 const char (*key)[MAIN_LEN][4];
886 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
887 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
888 } main_key_tab[]={
889 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
890 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
892 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
895 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
896 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
897 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
898 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
899 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
902 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
904 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
905 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
906 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
907 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
908 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
909 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
910 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
911 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
912 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
913 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
917 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
918 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
919 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
920 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
921 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
922 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
923 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
924 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
925 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
926 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
927 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
928 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
929 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
930 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
931 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
932 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
933 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
934 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
935 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
936 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
937 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
938 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
939 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
940 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
941 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
942 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
943 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
944 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
946 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
947 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
948 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
949 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
950 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
952 {0, NULL, NULL, NULL, NULL} /* sentinel */
954 static unsigned kbd_layout=0; /* index into above table of layouts */
956 /* maybe more of these scancodes should be extended? */
957 /* extended must be set for ALT_R, CTRL_R,
958 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
959 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
960 /* FIXME should we set extended bit for NumLock ? My
961 * Windows does ... DF */
962 /* Yes, to distinguish based on scan codes, also
963 for PrtScn key ... GA */
965 static const WORD nonchar_key_vkey[256] =
967 /* unused */
968 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
969 /* special keys */
970 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
971 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
972 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
973 /* unused */
974 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
975 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
976 0, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0, /* FF30 */
977 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
978 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
979 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
980 /* cursor keys */
981 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
982 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
983 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
984 /* misc keys */
985 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
986 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
987 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
988 /* keypad keys */
989 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
990 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
991 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
992 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
993 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
994 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
995 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
996 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
997 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
998 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
999 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1000 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1001 /* function keys */
1002 VK_F1, VK_F2,
1003 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1004 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1005 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1007 /* modifier keys */
1008 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1009 VK_RCONTROL, VK_CAPITAL, 0, VK_MENU,
1010 VK_MENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1012 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1015 static const WORD nonchar_key_scan[256] =
1017 /* unused */
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1019 /* special keys */
1020 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1021 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1022 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1023 /* unused */
1024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1030 /* cursor keys */
1031 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1033 /* misc keys */
1034 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1035 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1037 /* keypad keys */
1038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1042 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1044 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1045 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1046 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1047 /* function keys */
1048 0x3B, 0x3C,
1049 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1050 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1053 /* modifier keys */
1054 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1055 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1060 static const WORD xfree86_vendor_key_vkey[256] =
1062 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1063 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1064 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1065 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1066 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1067 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1068 0, 0, 0, VK_BROWSER_HOME,
1069 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1070 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1071 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1072 0, 0, 0, 0,
1073 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1074 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1075 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1076 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1097 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1100 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1102 #ifdef HAVE_XKB
1103 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1104 #endif
1105 return XKeycodeToKeysym(display, keycode, index);
1108 /* Returns the Windows virtual key code associated with the X event <e> */
1109 /* x11 lock must be held */
1110 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1112 KeySym keysym = 0;
1113 Status status;
1114 char buf[24];
1116 /* Clients should pass only KeyPress events to XmbLookupString */
1117 if (xic && e->type == KeyPress)
1118 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1119 else
1120 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1122 if ((e->state & NumLockMask) &&
1123 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1124 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1125 /* Only the Keypad keys 0-9 and . send different keysyms
1126 * depending on the NumLock state */
1127 return nonchar_key_vkey[keysym & 0xFF];
1129 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1130 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1131 if ((e->state & ControlMask) && (keysym == XK_Break))
1132 return VK_CANCEL;
1134 TRACE_(key)("e->keycode = %u\n", e->keycode);
1136 return keyc2vkey[e->keycode];
1140 /***********************************************************************
1141 * X11DRV_send_keyboard_input
1143 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1145 INPUT input;
1147 TRACE_(key)( "vkey=%04x scan=%04x flags=%04x\n", vkey, scan, flags );
1149 input.type = INPUT_KEYBOARD;
1150 input.u.ki.wVk = vkey;
1151 input.u.ki.wScan = scan;
1152 input.u.ki.dwFlags = flags;
1153 input.u.ki.time = time;
1154 input.u.ki.dwExtraInfo = 0;
1156 __wine_send_input( hwnd, &input );
1160 /***********************************************************************
1161 * get_async_key_state
1163 static BOOL get_async_key_state( BYTE state[256] )
1165 BOOL ret;
1167 SERVER_START_REQ( get_key_state )
1169 req->tid = 0;
1170 req->key = -1;
1171 wine_server_set_reply( req, state, 256 );
1172 ret = !wine_server_call( req );
1174 SERVER_END_REQ;
1175 return ret;
1178 /***********************************************************************
1179 * X11DRV_KeymapNotify
1181 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1183 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1184 * from wine to another application and back.
1185 * Toggle keys are handled in HandleEvent.
1187 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1189 int i, j;
1190 DWORD time = GetCurrentTime();
1191 BYTE keystate[256];
1193 if (!get_async_key_state( keystate )) return;
1195 /* the minimum keycode is always greater or equal to 8, so we can
1196 * skip the first 8 values, hence start at 1
1198 for (i = 1; i < 32; i++)
1200 for (j = 0; j < 8; j++)
1202 WORD vkey = keyc2vkey[(i * 8) + j];
1204 switch(vkey & 0xff)
1206 case VK_LMENU:
1207 case VK_RMENU:
1208 case VK_LCONTROL:
1209 case VK_RCONTROL:
1210 case VK_LSHIFT:
1211 case VK_RSHIFT:
1212 if (!(keystate[vkey & 0xff] & 0x80) != !(event->xkeymap.key_vector[i] & (1<<j)))
1214 WORD scan = keyc2scan[(i * 8) + j];
1215 DWORD flags = vkey & 0x100 ? KEYEVENTF_EXTENDEDKEY : 0;
1216 if (!(event->xkeymap.key_vector[i] & (1<<j))) flags |= KEYEVENTF_KEYUP;
1218 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1219 vkey, keystate[vkey & 0xff]);
1221 /* Fake key being pressed inside wine */
1222 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, scan & 0xff, flags, time );
1224 break;
1230 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1232 BYTE keystate[256];
1234 /* Note: X sets the below states on key down and clears them on key up.
1235 Windows triggers them on key down. */
1237 if (!get_async_key_state( keystate )) return;
1239 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1240 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1242 DWORD flags = 0;
1243 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1244 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1245 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1246 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1249 /* Adjust the NUMLOCK state if it has been changed outside wine */
1250 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1252 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1253 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1254 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1255 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1256 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1259 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1260 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1262 DWORD flags = 0;
1263 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1264 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1265 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1266 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1270 /***********************************************************************
1271 * X11DRV_KeyEvent
1273 * Handle a X key event
1275 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1277 XKeyEvent *event = &xev->xkey;
1278 char buf[24];
1279 char *Str = buf;
1280 KeySym keysym = 0;
1281 WORD vkey = 0, bScan;
1282 DWORD dwFlags;
1283 int ascii_chars;
1284 XIC xic = X11DRV_get_ic( hwnd );
1285 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1286 Status status = 0;
1288 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1289 event->type, event->window, event->state, event->keycode);
1291 if (event->type == KeyPress) update_user_time( event->time );
1293 wine_tsx11_lock();
1294 /* Clients should pass only KeyPress events to XmbLookupString */
1295 if (xic && event->type == KeyPress)
1297 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1298 TRACE("XmbLookupString needs %i byte(s)\n", ascii_chars);
1299 if (status == XBufferOverflow)
1301 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1302 if (Str == NULL)
1304 ERR("Failed to allocate memory!\n");
1305 wine_tsx11_unlock();
1306 return;
1308 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1311 else
1312 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1313 wine_tsx11_unlock();
1315 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1317 if (status == XLookupChars)
1319 X11DRV_XIMLookupChars( Str, ascii_chars );
1320 if (buf != Str)
1321 HeapFree(GetProcessHeap(), 0, Str);
1322 return;
1325 /* If XKB extensions are used, the state mask for AltGr will use the group
1326 index instead of the modifier mask. The group index is set in bits
1327 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1328 pressed, look if the group index is different than 0. From XKB
1329 extension documentation, the group index for AltGr should be 2
1330 (event->state = 0x2000). It's probably better to not assume a
1331 predefined group index and find it dynamically
1333 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1334 /* Save also all possible modifier states. */
1335 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1337 if (TRACE_ON(key)){
1338 const char *ksname;
1340 wine_tsx11_lock();
1341 ksname = XKeysymToString(keysym);
1342 wine_tsx11_unlock();
1343 if (!ksname)
1344 ksname = "No Name";
1345 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1346 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1347 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1349 if (buf != Str)
1350 HeapFree(GetProcessHeap(), 0, Str);
1352 wine_tsx11_lock();
1353 vkey = EVENT_event_to_vkey(xic,event);
1354 /* X returns keycode 0 for composed characters */
1355 if (!vkey && ascii_chars) vkey = VK_NONAME;
1356 wine_tsx11_unlock();
1358 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1359 event->keycode, vkey);
1361 if (!vkey) return;
1363 dwFlags = 0;
1364 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1365 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1367 update_lock_state( hwnd, vkey, event->state, event_time );
1369 bScan = keyc2scan[event->keycode] & 0xFF;
1370 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1372 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1375 /**********************************************************************
1376 * X11DRV_KEYBOARD_DetectLayout
1378 * Called from X11DRV_InitKeyboard
1379 * This routine walks through the defined keyboard layouts and selects
1380 * whichever matches most closely.
1381 * X11 lock must be held.
1383 static void
1384 X11DRV_KEYBOARD_DetectLayout( Display *display )
1386 unsigned current, match, mismatch, seq, i, syms;
1387 int score, keyc, key, pkey, ok;
1388 KeySym keysym = 0;
1389 const char (*lkey)[MAIN_LEN][4];
1390 unsigned max_seq = 0;
1391 int max_score = 0, ismatch = 0;
1392 char ckey[256][4];
1394 syms = keysyms_per_keycode;
1395 if (syms > 4) {
1396 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1397 syms = 4;
1400 memset( ckey, 0, sizeof(ckey) );
1401 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1402 /* get data for keycode from X server */
1403 for (i = 0; i < syms; i++) {
1404 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1405 /* Allow both one-byte and two-byte national keysyms */
1406 if ((keysym < 0x8000) && (keysym != ' '))
1408 #ifdef HAVE_XKB
1409 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1410 #endif
1412 TRACE("XKB could not translate keysym %04lx\n", keysym);
1413 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1414 * with appropriate ShiftMask and Mode_switch, use XLookupString
1415 * to get character in the local encoding.
1417 ckey[keyc][i] = keysym & 0xFF;
1420 else {
1421 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1426 for (current = 0; main_key_tab[current].comment; current++) {
1427 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1428 match = 0;
1429 mismatch = 0;
1430 score = 0;
1431 seq = 0;
1432 lkey = main_key_tab[current].key;
1433 pkey = -1;
1434 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1435 if (ckey[keyc][0]) {
1436 /* search for a match in layout table */
1437 /* right now, we just find an absolute match for defined positions */
1438 /* (undefined positions are ignored, so if it's defined as "3#" in */
1439 /* the table, it's okay that the X server has "3#£", for example) */
1440 /* however, the score will be higher for longer matches */
1441 for (key = 0; key < MAIN_LEN; key++) {
1442 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1443 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1444 ok++;
1445 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1446 ok = -1;
1448 if (ok > 0) {
1449 score += ok;
1450 break;
1453 /* count the matches and mismatches */
1454 if (ok > 0) {
1455 match++;
1456 /* and how much the keycode order matches */
1457 if (key > pkey) seq++;
1458 pkey = key;
1459 } else {
1460 /* print spaces instead of \0's */
1461 char str[5];
1462 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1463 str[4] = 0;
1464 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1465 mismatch++;
1466 score -= syms;
1470 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1471 match, mismatch, seq, score);
1472 if ((score > max_score) ||
1473 ((score == max_score) && (seq > max_seq))) {
1474 /* best match so far */
1475 kbd_layout = current;
1476 max_score = score;
1477 max_seq = seq;
1478 ismatch = !mismatch;
1481 /* we're done, report results if necessary */
1482 if (!ismatch)
1483 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1484 main_key_tab[kbd_layout].comment);
1486 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1489 static HKL get_locale_kbd_layout(void)
1491 ULONG_PTR layout;
1492 LANGID langid;
1494 /* FIXME:
1496 * layout = main_key_tab[kbd_layout].lcid;
1498 * Winword uses return value of GetKeyboardLayout as a codepage
1499 * to translate ANSI keyboard messages to unicode. But we have
1500 * a problem with it: for instance Polish keyboard layout is
1501 * identical to the US one, and therefore instead of the Polish
1502 * locale id we return the US one.
1505 layout = GetUserDefaultLCID();
1508 * Microsoft Office expects this value to be something specific
1509 * for Japanese and Korean Windows with an IME the value is 0xe001
1510 * We should probably check to see if an IME exists and if so then
1511 * set this word properly.
1513 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1514 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1515 layout |= 0xe001 << 16; /* IME */
1516 else
1517 layout |= layout << 16;
1519 return (HKL)layout;
1522 /***********************************************************************
1523 * GetKeyboardLayoutName (X11DRV.@)
1525 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1527 static const WCHAR formatW[] = {'%','0','8','x',0};
1528 DWORD layout;
1530 layout = HandleToUlong( get_locale_kbd_layout() );
1531 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1532 sprintfW(name, formatW, layout);
1533 TRACE("returning %s\n", debugstr_w(name));
1534 return TRUE;
1537 static void set_kbd_layout_preload_key(void)
1539 static const WCHAR preload[] =
1540 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1541 static const WCHAR one[] = {'1',0};
1543 HKEY hkey;
1544 WCHAR layout[KL_NAMELENGTH];
1546 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1547 return;
1549 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1551 RegCloseKey(hkey);
1552 return;
1554 if (X11DRV_GetKeyboardLayoutName(layout))
1555 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1557 RegCloseKey(hkey);
1560 /**********************************************************************
1561 * X11DRV_InitKeyboard
1563 void X11DRV_InitKeyboard( Display *display )
1565 KeySym *ksp;
1566 XModifierKeymap *mmp;
1567 KeySym keysym;
1568 KeyCode *kcp;
1569 XKeyEvent e2;
1570 WORD scan, vkey;
1571 int keyc, i, keyn, syms;
1572 char ckey[4]={0,0,0,0};
1573 const char (*lkey)[MAIN_LEN][4];
1574 char vkey_used[256] = { 0 };
1576 /* Ranges of OEM, function key, and character virtual key codes.
1577 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1578 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1579 static const struct {
1580 WORD first, last;
1581 } vkey_ranges[] = {
1582 { VK_OEM_1, VK_OEM_3 },
1583 { VK_OEM_4, VK_ICO_00 },
1584 { 0xe6, 0xe6 },
1585 { 0xe9, 0xf5 },
1586 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1587 { VK_F1, VK_F24 },
1588 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1589 { 0x41, 0x5a }, /* VK_A - VK_Z */
1590 { 0, 0 }
1592 int vkey_range;
1594 set_kbd_layout_preload_key();
1596 wine_tsx11_lock();
1597 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1598 ksp = XGetKeyboardMapping(display, min_keycode,
1599 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1600 /* We are only interested in keysyms_per_keycode.
1601 There is no need to hold a local copy of the keysyms table */
1602 XFree(ksp);
1604 mmp = XGetModifierMapping(display);
1605 kcp = mmp->modifiermap;
1606 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1608 int j;
1610 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1611 if (*kcp)
1613 int k;
1615 for (k = 0; k < keysyms_per_keycode; k += 1)
1616 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1618 NumLockMask = 1 << i;
1619 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1621 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1623 ScrollLockMask = 1 << i;
1624 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1628 XFreeModifiermap(mmp);
1630 /* Detect the keyboard layout */
1631 X11DRV_KEYBOARD_DetectLayout( display );
1632 lkey = main_key_tab[kbd_layout].key;
1633 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1635 /* Now build two conversion arrays :
1636 * keycode -> vkey + scancode + extended
1637 * vkey + extended -> keycode */
1639 e2.display = display;
1640 e2.state = 0;
1641 e2.type = KeyPress;
1643 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1644 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1646 char buf[30];
1647 int have_chars;
1649 keysym = 0;
1650 e2.keycode = (KeyCode)keyc;
1651 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1652 vkey = 0; scan = 0;
1653 if (keysym) /* otherwise, keycode not used */
1655 if ((keysym >> 8) == 0xFF) /* non-character key */
1657 vkey = nonchar_key_vkey[keysym & 0xff];
1658 scan = nonchar_key_scan[keysym & 0xff];
1659 /* set extended bit when necessary */
1660 if (scan & 0x100) vkey |= 0x100;
1661 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1662 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1663 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1664 scan = 0x100;
1665 vkey |= 0x100;
1666 } else if (keysym == 0x20) { /* Spacebar */
1667 vkey = VK_SPACE;
1668 scan = 0x39;
1669 } else if (have_chars) {
1670 /* we seem to need to search the layout-dependent scancodes */
1671 int maxlen=0,maxval=-1,ok;
1672 for (i=0; i<syms; i++) {
1673 keysym = keycode_to_keysym(display, keyc, i);
1674 if ((keysym<0x8000) && (keysym!=' '))
1676 #ifdef HAVE_XKB
1677 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1678 #endif
1680 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1681 * with appropriate ShiftMask and Mode_switch, use XLookupString
1682 * to get character in the local encoding.
1684 ckey[i] = keysym & 0xFF;
1686 } else {
1687 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1690 /* find key with longest match streak */
1691 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1692 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1693 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1694 if (!ok) i--; /* we overshot */
1695 if (ok||(i>maxlen)) {
1696 maxlen=i; maxval=keyn;
1698 if (ok) break;
1700 if (maxval>=0) {
1701 /* got it */
1702 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1703 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1704 scan = (*lscan)[maxval];
1705 vkey = (*lvkey)[maxval];
1709 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1710 keyc2vkey[e2.keycode] = vkey;
1711 keyc2scan[e2.keycode] = scan;
1712 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1713 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1714 vkey_used[(vkey & 0xff)] = 1;
1715 } /* for */
1717 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1718 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1720 vkey = keyc2vkey[keyc] & 0xff;
1721 if (vkey)
1722 continue;
1724 e2.keycode = (KeyCode)keyc;
1725 keysym = XLookupKeysym(&e2, 0);
1726 if (!keysym)
1727 continue;
1729 /* find a suitable layout-dependent VK code */
1730 /* (most Winelib apps ought to be able to work without layout tables!) */
1731 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1733 keysym = XLookupKeysym(&e2, i);
1734 if ((keysym >= XK_0 && keysym <= XK_9)
1735 || (keysym >= XK_A && keysym <= XK_Z)) {
1736 vkey = VKEY_IF_NOT_USED(keysym);
1740 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1742 keysym = XLookupKeysym(&e2, i);
1743 switch (keysym)
1745 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1746 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1747 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1748 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1749 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1750 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1751 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1752 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1753 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1754 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1755 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1759 if (vkey)
1761 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1762 keyc2vkey[e2.keycode] = vkey;
1764 } /* for */
1766 /* For any keycodes which still don't have a vkey, assign any spare
1767 * character, function key, or OEM virtual key code. */
1768 vkey_range = 0;
1769 vkey = vkey_ranges[vkey_range].first;
1770 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1772 if (keyc2vkey[keyc] & 0xff)
1773 continue;
1775 e2.keycode = (KeyCode)keyc;
1776 keysym = XLookupKeysym(&e2, 0);
1777 if (!keysym)
1778 continue;
1780 while (vkey && vkey_used[vkey])
1782 if (vkey == vkey_ranges[vkey_range].last)
1784 vkey_range++;
1785 vkey = vkey_ranges[vkey_range].first;
1787 else
1788 vkey++;
1791 if (!vkey)
1793 WARN("No more vkeys available!\n");
1794 break;
1797 if (TRACE_ON(keyboard))
1799 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1800 vkey, e2.keycode);
1801 TRACE("(");
1802 for (i = 0; i < keysyms_per_keycode; i += 1)
1804 const char *ksname;
1806 keysym = XLookupKeysym(&e2, i);
1807 ksname = XKeysymToString(keysym);
1808 if (!ksname)
1809 ksname = "NoSymbol";
1810 TRACE( "%lx (%s) ", keysym, ksname);
1812 TRACE(")\n");
1815 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1816 keyc2vkey[e2.keycode] = vkey;
1817 vkey_used[vkey] = 1;
1818 } /* for */
1819 #undef VKEY_IF_NOT_USED
1821 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1822 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1823 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1824 const char *ksname;
1825 keysym = keycode_to_keysym(display, keyc, 0);
1826 ksname = XKeysymToString(keysym);
1827 if (!ksname) ksname = "NoSymbol";
1829 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1831 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1832 keyc2scan[keyc]=scan++;
1835 wine_tsx11_unlock();
1838 static BOOL match_x11_keyboard_layout(HKL hkl)
1840 const DWORD isIME = 0xE0000000;
1841 HKL xHkl = get_locale_kbd_layout();
1843 /* if the layout is an IME, only match the low word (LCID) */
1844 if (((ULONG_PTR)hkl & isIME) == isIME)
1845 return (LOWORD(hkl) == LOWORD(xHkl));
1846 else
1847 return (hkl == xHkl);
1850 /**********************************************************************
1851 * GetAsyncKeyState (X11DRV.@)
1853 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1855 /* Photoshop livelocks unless mouse events are included here */
1856 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1857 return -1;
1861 /***********************************************************************
1862 * GetKeyboardLayout (X11DRV.@)
1864 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1866 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1868 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1869 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1871 else
1872 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1874 return get_locale_kbd_layout();
1878 /***********************************************************************
1879 * LoadKeyboardLayout (X11DRV.@)
1881 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1883 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1884 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1885 return 0;
1889 /***********************************************************************
1890 * UnloadKeyboardLayout (X11DRV.@)
1892 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1894 FIXME("%p: stub!\n", hkl);
1895 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1896 return FALSE;
1900 /***********************************************************************
1901 * ActivateKeyboardLayout (X11DRV.@)
1903 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1905 HKL oldHkl = 0;
1906 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1908 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1909 if (flags & KLF_SETFORPROCESS)
1911 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1912 FIXME("KLF_SETFORPROCESS not supported\n");
1913 return 0;
1916 if (flags)
1917 FIXME("flags %x not supported\n",flags);
1919 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1921 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1922 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1923 return 0;
1926 if (!match_x11_keyboard_layout(hkl))
1928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1929 FIXME("setting keyboard of different locales not supported\n");
1930 return 0;
1933 oldHkl = thread_data->kbd_layout;
1934 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1936 thread_data->kbd_layout = hkl;
1938 return oldHkl;
1942 /***********************************************************************
1943 * X11DRV_MappingNotify
1945 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1947 HWND hwnd;
1949 wine_tsx11_lock();
1950 XRefreshKeyboardMapping(&event->xmapping);
1951 wine_tsx11_unlock();
1952 X11DRV_InitKeyboard( event->xmapping.display );
1954 hwnd = GetFocus();
1955 if (!hwnd) hwnd = GetActiveWindow();
1956 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1957 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1961 /***********************************************************************
1962 * VkKeyScanEx (X11DRV.@)
1964 * Note: Windows ignores HKL parameter and uses current active layout instead
1966 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1968 Display *display = thread_init_display();
1969 KeyCode keycode;
1970 KeySym keysym;
1971 int i, index;
1972 CHAR cChar;
1973 SHORT ret;
1975 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
1976 * is UTF-8 (multibyte encoding)?
1978 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
1980 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1981 return -1;
1984 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1986 /* char->keysym (same for ANSI chars) */
1987 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1988 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1990 wine_tsx11_lock();
1991 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1992 if (!keycode)
1994 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
1996 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
1997 TRACE(" ... returning ctrl char %#.2x\n", ret);
1998 wine_tsx11_unlock();
1999 return ret;
2001 /* It didn't work ... let's try with deadchar code. */
2002 TRACE("retrying with | 0xFE00\n");
2003 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2005 wine_tsx11_unlock();
2007 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2009 /* keycode -> (keyc2vkey) vkey */
2010 ret = keyc2vkey[keycode];
2012 if (!keycode || !ret)
2014 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2015 return -1;
2018 index = -1;
2019 wine_tsx11_lock();
2020 for (i = 0; i < 4; i++) /* find shift state */
2022 if (keycode_to_keysym(display, keycode, i) == keysym)
2024 index = i;
2025 break;
2028 wine_tsx11_unlock();
2030 switch (index)
2032 default:
2033 case -1:
2034 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2035 return -1;
2037 case 0: break;
2038 case 1: ret += 0x0100; break;
2039 case 2: ret += 0x0600; break;
2040 case 3: ret += 0x0700; break;
2043 index : 0 adds 0x0000
2044 index : 1 adds 0x0100 (shift)
2045 index : ? adds 0x0200 (ctrl)
2046 index : 2 adds 0x0600 (ctrl+alt)
2047 index : 3 adds 0x0700 (ctrl+alt+shift)
2050 TRACE(" ... returning %#.2x\n", ret);
2051 return ret;
2054 /***********************************************************************
2055 * MapVirtualKeyEx (X11DRV.@)
2057 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2059 Display *display = thread_init_display();
2061 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2063 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2064 if (!match_x11_keyboard_layout(hkl))
2065 FIXME("keyboard layout %p is not supported\n", hkl);
2067 switch(wMapType)
2069 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2070 case MAPVK_VK_TO_VSC_EX:
2072 int keyc;
2074 switch (wCode)
2076 case VK_SHIFT: wCode = VK_LSHIFT; break;
2077 case VK_CONTROL: wCode = VK_LCONTROL; break;
2078 case VK_MENU: wCode = VK_LMENU; break;
2081 /* let's do vkey -> keycode -> scan */
2082 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2083 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2085 if (keyc > max_keycode)
2087 TRACE("returning no scan-code.\n");
2088 return 0;
2090 returnMVK (keyc2scan[keyc] & 0xFF);
2092 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2093 case MAPVK_VSC_TO_VK_EX:
2095 int keyc;
2096 UINT vkey = 0;
2098 /* let's do scan -> keycode -> vkey */
2099 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2100 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2102 vkey = keyc2vkey[keyc] & 0xFF;
2103 /* Only stop if it's not a numpad vkey; otherwise keep
2104 looking for a potential better vkey. */
2105 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2106 break;
2109 if (vkey == 0)
2111 TRACE("returning no vkey-code.\n");
2112 return 0;
2115 if (wMapType == MAPVK_VSC_TO_VK)
2116 switch (vkey)
2118 case VK_LSHIFT:
2119 case VK_RSHIFT:
2120 vkey = VK_SHIFT; break;
2121 case VK_LCONTROL:
2122 case VK_RCONTROL:
2123 vkey = VK_CONTROL; break;
2124 case VK_LMENU:
2125 case VK_RMENU:
2126 vkey = VK_MENU; break;
2129 returnMVK (vkey);
2131 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2133 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2134 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2135 * key.. Looks like something is wrong with the MS docs?
2136 * This is only true for letters, for example VK_0 returns '0' not ')'.
2137 * - hence we use the lock mask to ensure this happens.
2139 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2140 XKeyEvent e;
2141 KeySym keysym;
2142 int keyc, len;
2143 char s[10];
2145 e.display = display;
2146 e.state = 0;
2147 e.keycode = 0;
2148 e.type = KeyPress;
2150 wine_tsx11_lock();
2152 /* We exit on the first keycode found, to speed up the thing. */
2153 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2154 { /* Find a keycode that could have generated this virtual key */
2155 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2156 { /* We filter the extended bit, we don't know it */
2157 e.keycode = keyc; /* Store it temporarily */
2158 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2159 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2160 state), so set it to 0, we'll find another one */
2165 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2166 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2168 if (wCode==VK_DECIMAL)
2169 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2171 if (!e.keycode)
2173 WARN("Unknown virtual key %X !!!\n", wCode);
2174 wine_tsx11_unlock();
2175 return 0; /* whatever */
2177 TRACE("Found keycode %u\n",e.keycode);
2179 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2180 wine_tsx11_unlock();
2182 if (len)
2184 WCHAR wch;
2185 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2186 returnMVK(toupperW(wch));
2188 TRACE("returning no ANSI.\n");
2189 return 0;
2191 default: /* reserved */
2192 FIXME("Unknown wMapType %d !\n", wMapType);
2193 return 0;
2195 return 0;
2198 /***********************************************************************
2199 * GetKeyNameText (X11DRV.@)
2201 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2203 Display *display = thread_init_display();
2204 int vkey, ansi, scanCode;
2205 KeyCode keyc;
2206 int keyi;
2207 KeySym keys;
2208 char *name;
2210 scanCode = lParam >> 16;
2211 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2213 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2215 /* handle "don't care" bit (0x02000000) */
2216 if (!(lParam & 0x02000000)) {
2217 switch (vkey) {
2218 case VK_RSHIFT:
2219 /* R-Shift is "special" - it is an extended key with separate scan code */
2220 scanCode |= 0x100;
2221 case VK_LSHIFT:
2222 vkey = VK_SHIFT;
2223 break;
2224 case VK_LCONTROL:
2225 case VK_RCONTROL:
2226 vkey = VK_CONTROL;
2227 break;
2228 case VK_LMENU:
2229 case VK_RMENU:
2230 vkey = VK_MENU;
2231 break;
2235 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2236 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2238 /* first get the name of the "regular" keys which is the Upper case
2239 value of the keycap imprint. */
2240 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2241 (scanCode != 0x137) && /* PrtScn */
2242 (scanCode != 0x135) && /* numpad / */
2243 (scanCode != 0x37 ) && /* numpad * */
2244 (scanCode != 0x4a ) && /* numpad - */
2245 (scanCode != 0x4e ) ) /* numpad + */
2247 if ((nSize >= 2) && lpBuffer)
2249 *lpBuffer = toupperW((WCHAR)ansi);
2250 *(lpBuffer+1) = 0;
2251 return 1;
2253 else
2254 return 0;
2257 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2258 without "extended-key" flag. However Wine generates scancode
2259 *with* "extended-key" flag. Seems to occur *only* for the
2260 function keys. Soooo.. We will leave the table alone and
2261 fudge the lookup here till the other part is found and fixed!!! */
2263 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2264 (scanCode == 0x157) || (scanCode == 0x158))
2265 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2267 /* let's do scancode -> keycode -> keysym -> String */
2269 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2270 if ((keyc2scan[keyi]) == scanCode)
2271 break;
2272 if (keyi <= max_keycode)
2274 wine_tsx11_lock();
2275 keyc = (KeyCode) keyi;
2276 keys = keycode_to_keysym(display, keyc, 0);
2277 name = XKeysymToString(keys);
2278 wine_tsx11_unlock();
2279 TRACE("found scan=%04x keyc=%u keysym=%04x string=%s\n",
2280 scanCode, keyc, (int)keys, name);
2281 if (lpBuffer && nSize && name)
2282 return MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2285 /* Finally issue WARN for unknown keys */
2287 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2288 if (lpBuffer && nSize)
2289 *lpBuffer = 0;
2290 return 0;
2293 /***********************************************************************
2294 * X11DRV_KEYBOARD_MapDeadKeysym
2296 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2298 switch (keysym)
2300 /* symbolic ASCII is the same as defined in rfc1345 */
2301 #ifdef XK_dead_tilde
2302 case XK_dead_tilde :
2303 #endif
2304 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2305 return '~'; /* '? */
2306 #ifdef XK_dead_acute
2307 case XK_dead_acute :
2308 #endif
2309 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2310 return 0xb4; /* '' */
2311 #ifdef XK_dead_circumflex
2312 case XK_dead_circumflex:
2313 #endif
2314 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2315 return '^'; /* '> */
2316 #ifdef XK_dead_grave
2317 case XK_dead_grave :
2318 #endif
2319 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2320 return '`'; /* '! */
2321 #ifdef XK_dead_diaeresis
2322 case XK_dead_diaeresis :
2323 #endif
2324 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2325 return 0xa8; /* ': */
2326 #ifdef XK_dead_cedilla
2327 case XK_dead_cedilla :
2328 return 0xb8; /* ', */
2329 #endif
2330 #ifdef XK_dead_macron
2331 case XK_dead_macron :
2332 return '-'; /* 'm isn't defined on iso-8859-x */
2333 #endif
2334 #ifdef XK_dead_breve
2335 case XK_dead_breve :
2336 return 0xa2; /* '( */
2337 #endif
2338 #ifdef XK_dead_abovedot
2339 case XK_dead_abovedot :
2340 return 0xff; /* '. */
2341 #endif
2342 #ifdef XK_dead_abovering
2343 case XK_dead_abovering :
2344 return '0'; /* '0 isn't defined on iso-8859-x */
2345 #endif
2346 #ifdef XK_dead_doubleacute
2347 case XK_dead_doubleacute :
2348 return 0xbd; /* '" */
2349 #endif
2350 #ifdef XK_dead_caron
2351 case XK_dead_caron :
2352 return 0xb7; /* '< */
2353 #endif
2354 #ifdef XK_dead_ogonek
2355 case XK_dead_ogonek :
2356 return 0xb2; /* '; */
2357 #endif
2358 /* FIXME: I don't know this three.
2359 case XK_dead_iota :
2360 return 'i';
2361 case XK_dead_voiced_sound :
2362 return 'v';
2363 case XK_dead_semivoiced_sound :
2364 return 's';
2367 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2368 return 0;
2371 /***********************************************************************
2372 * ToUnicodeEx (X11DRV.@)
2374 * The ToUnicode function translates the specified virtual-key code and keyboard
2375 * state to the corresponding Windows character or characters.
2377 * If the specified key is a dead key, the return value is negative. Otherwise,
2378 * it is one of the following values:
2379 * Value Meaning
2380 * 0 The specified virtual key has no translation for the current state of the keyboard.
2381 * 1 One Windows character was copied to the buffer.
2382 * 2 Two characters were copied to the buffer. This usually happens when a
2383 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2384 * be composed with the specified virtual key to form a single character.
2386 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2389 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2390 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2392 Display *display = thread_init_display();
2393 XKeyEvent e;
2394 KeySym keysym = 0;
2395 INT ret;
2396 int keyc;
2397 char buf[10];
2398 char *lpChar = buf;
2399 HWND focus;
2400 XIC xic;
2401 Status status = 0;
2403 if (scanCode & 0x8000)
2405 TRACE("Key UP, doing nothing\n" );
2406 return 0;
2409 if (!match_x11_keyboard_layout(hkl))
2410 FIXME("keyboard layout %p is not supported\n", hkl);
2412 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2414 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2415 return 0;
2418 e.display = display;
2419 e.keycode = 0;
2420 e.state = 0;
2421 e.type = KeyPress;
2423 focus = x11drv_thread_data()->last_xic_hwnd;
2424 if (!focus)
2426 focus = GetFocus();
2427 if (focus) focus = GetAncestor( focus, GA_ROOT );
2428 if (!focus) focus = GetActiveWindow();
2430 e.window = X11DRV_get_whole_window( focus );
2431 xic = X11DRV_get_ic( focus );
2433 if (lpKeyState[VK_SHIFT] & 0x80)
2435 TRACE("ShiftMask = %04x\n", ShiftMask);
2436 e.state |= ShiftMask;
2438 if (lpKeyState[VK_CAPITAL] & 0x01)
2440 TRACE("LockMask = %04x\n", LockMask);
2441 e.state |= LockMask;
2443 if (lpKeyState[VK_CONTROL] & 0x80)
2445 TRACE("ControlMask = %04x\n", ControlMask);
2446 e.state |= ControlMask;
2448 if (lpKeyState[VK_NUMLOCK] & 0x01)
2450 TRACE("NumLockMask = %04x\n", NumLockMask);
2451 e.state |= NumLockMask;
2454 /* Restore saved AltGr state */
2455 TRACE("AltGrMask = %04x\n", AltGrMask);
2456 e.state |= AltGrMask;
2458 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2459 virtKey, scanCode, e.state);
2460 wine_tsx11_lock();
2461 /* We exit on the first keycode found, to speed up the thing. */
2462 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2463 { /* Find a keycode that could have generated this virtual key */
2464 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2465 { /* We filter the extended bit, we don't know it */
2466 e.keycode = keyc; /* Store it temporarily */
2467 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2468 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2469 state), so set it to 0, we'll find another one */
2474 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2475 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2477 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2478 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2480 if (virtKey==VK_DECIMAL)
2481 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2483 if (virtKey==VK_SEPARATOR)
2484 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2486 if (!e.keycode && virtKey != VK_NONAME)
2488 WARN("Unknown virtual key %X !!!\n", virtKey);
2489 wine_tsx11_unlock();
2490 return 0;
2492 else TRACE("Found keycode %u\n",e.keycode);
2494 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2495 e.type, e.window, e.state, e.keycode);
2497 /* Clients should pass only KeyPress events to XmbLookupString,
2498 * e.type was set to KeyPress above.
2500 if (xic)
2502 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2503 TRACE("XmbLookupString needs %d byte(s)\n", ret);
2504 if (status == XBufferOverflow)
2506 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2507 if (lpChar == NULL)
2509 ERR("Failed to allocate memory!\n");
2510 wine_tsx11_unlock();
2511 return 0;
2513 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2516 else
2517 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2518 wine_tsx11_unlock();
2520 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2522 if (TRACE_ON(key))
2524 const char *ksname;
2526 wine_tsx11_lock();
2527 ksname = XKeysymToString(keysym);
2528 wine_tsx11_unlock();
2529 if (!ksname) ksname = "No Name";
2530 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2531 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2532 keysym, ksname, ret, debugstr_an(lpChar, ret));
2535 if (ret == 0)
2537 char dead_char;
2539 #ifdef XK_EuroSign
2540 /* An ugly hack for EuroSign: X can't translate it to a character
2541 for some locales. */
2542 if (keysym == XK_EuroSign)
2544 bufW[0] = 0x20AC;
2545 ret = 1;
2546 goto found;
2548 #endif
2549 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2550 /* Here we change it back. */
2551 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2553 bufW[0] = 0x09;
2554 ret = 1;
2555 goto found;
2558 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2559 if (dead_char)
2561 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2562 ret = -1;
2563 goto found;
2566 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2568 /* Unicode direct mapping */
2569 bufW[0] = keysym & 0xffff;
2570 ret = 1;
2571 goto found;
2573 else if ((keysym >> 8) == 0x1008FF) {
2574 bufW[0] = 0;
2575 ret = 0;
2576 goto found;
2578 else
2580 const char *ksname;
2582 wine_tsx11_lock();
2583 ksname = XKeysymToString(keysym);
2584 wine_tsx11_unlock();
2585 if (!ksname)
2586 ksname = "No Name";
2587 if ((keysym >> 8) != 0xff)
2589 WARN("no char for keysym %04lx (%s) :\n",
2590 keysym, ksname);
2591 WARN("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2592 virtKey, scanCode, e.keycode, e.state);
2596 else { /* ret != 0 */
2597 /* We have a special case to handle : Shift + arrow, shift + home, ...
2598 X returns a char for it, but Windows doesn't. Let's eat it. */
2599 if (!(e.state & NumLockMask) /* NumLock is off */
2600 && (e.state & ShiftMask) /* Shift is pressed */
2601 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2603 lpChar[0] = 0;
2604 ret = 0;
2607 /* more areas where X returns characters but Windows does not
2608 CTRL + number or CTRL + symbol */
2609 if (e.state & ControlMask)
2611 if (((keysym>=33) && (keysym < 'A')) ||
2612 ((keysym > 'Z') && (keysym < 'a')) ||
2613 (keysym == XK_Tab))
2615 lpChar[0] = 0;
2616 ret = 0;
2620 /* We have another special case for delete key (XK_Delete) on an
2621 extended keyboard. X returns a char for it, but Windows doesn't */
2622 if (keysym == XK_Delete)
2624 lpChar[0] = 0;
2625 ret = 0;
2627 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2628 && (keysym == XK_KP_Decimal))
2630 lpChar[0] = 0;
2631 ret = 0;
2633 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2634 && (keysym == XK_Return || keysym == XK_KP_Enter))
2636 lpChar[0] = '\n';
2637 ret = 1;
2640 /* Hack to detect an XLookupString hard-coded to Latin1 */
2641 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2643 bufW[0] = (BYTE)lpChar[0];
2644 goto found;
2647 /* perform translation to unicode */
2648 if(ret)
2650 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2651 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2655 found:
2656 if (buf != lpChar)
2657 HeapFree(GetProcessHeap(), 0, lpChar);
2658 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2659 return ret;
2662 /***********************************************************************
2663 * Beep (X11DRV.@)
2665 void CDECL X11DRV_Beep(void)
2667 wine_tsx11_lock();
2668 XBell(gdi_display, 0);
2669 wine_tsx11_unlock();