1 /*
2 * X11 keyboard driver
3 *
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
10 *
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.
15 *
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.
20 *
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
24 */
25
26 #include "config.h"
27
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
36
37 #include <ctype.h>
38 #include <stdarg.h>
39 #include <string.h>
40
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"
53
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
59 */
60 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
61 WINE_DECLARE_DEBUG_CHANNEL(key);
62
63 static int min_keycode, max_keycode, keysyms_per_keycode;
64 static WORD keyc2vkey[256], keyc2scan[256];
65
66 static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
67
68 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
69
70 /* Keyboard translation tables */
71 #define MAIN_LEN 49
72 static const WORD main_key_scan_qwerty[MAIN_LEN] =
73 {
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) */
84 };
85
86 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
87 {
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) */
97 };
98
99 static const WORD main_key_scan_dvorak[MAIN_LEN] =
100 {
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) */
110 };
111
112 static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
113 {
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) */
124 };
125
126 static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
127 {
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) */
137 };
138
139
140 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
141 {
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','',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) */
148 };
149
150 static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
151 {
152 /* NOTE: this layout must concur with the scan codes layout above */
153 '1','2','3','4','5','6','7','8','9','',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) */
158 };
159
160 static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
161 {
162 /* NOTE: this layout must concur with the scan codes layout above */
163 '1','2','3','4','5','6','7','8','9','',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) */
168 };
169
170 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
171 {
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','',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) */
178 };
179
180 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
181 {
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','',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) */
188 };
189
190 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
191 {
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','',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) */
198 };
199
200 static const WORD main_key_vkey_azerty[MAIN_LEN] =
201 {
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','',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) */
208 };
209
210 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
211 {
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','',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) */
218 };
219
220 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
221
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! */
234
235 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
236 static const char main_key_US[MAIN_LEN][4] =
237 {
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",",<",".>","/?"
242 };
243
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] =
247 {
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 */
253 };
254
255 /*** United States keyboard layout (dvorak version) */
256 static const char main_key_US_dvorak[MAIN_LEN][4] =
257 {
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"
262 };
263
264 /*** British keyboard layout */
265 static const char main_key_UK[MAIN_LEN][4] =
266 {
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 "\\|"
272 };
273
274 /*** French keyboard layout (setxkbmap fr) */
275 static const char main_key_FR[MAIN_LEN][4] =
276 {
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 "<>"
282 };
283
284 /*** Icelandic keyboard layout (setxkbmap is) */
285 static const char main_key_IS[MAIN_LEN][4] =
286 {
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 "<>"
292 };
293
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.
306 */
307
308 /*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
309 static const char main_key_DE[MAIN_LEN][4] =
310 {
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 "<>"
316 };
317
318 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
319 static const char main_key_SG[MAIN_LEN][4] =
320 {
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 "<>"
326 };
327
328 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
329 static const char main_key_SF[MAIN_LEN][4] =
330 {
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 "<>"
336 };
337
338 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
339 static const char main_key_NO[MAIN_LEN][4] =
340 {
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 "<>"
346 };
347
348 /*** Danish keyboard layout (setxkbmap dk) */
349 static const char main_key_DA[MAIN_LEN][4] =
350 {
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 "<>"
356 };
357
358 /*** Swedish keyboard layout (setxkbmap se) */
359 static const char main_key_SE[MAIN_LEN][4] =
360 {
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 "<>"
366 };
367
368 /*** Estonian keyboard layout (setxkbmap ee) */
369 static const char main_key_ET[MAIN_LEN][4] =
370 {
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 "<>"
376 };
377
378 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
379 static const char main_key_CF[MAIN_LEN][4] =
380 {
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 "«»°"
386 };
387
388 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
389 static const char main_key_CA_fr[MAIN_LEN][4] =
390 {
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 "«»"
396 };
397
398 /*** Canadian keyboard layout (setxkbmap ca) */
399 static const char main_key_CA[MAIN_LEN][4] =
400 {
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 "ùÙ"
406 };
407
408 /*** Portuguese keyboard layout (setxkbmap pt) */
409 static const char main_key_PT[MAIN_LEN][4] =
410 {
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 "<>"
416 };
417
418 /*** Italian keyboard layout (setxkbmap it) */
419 static const char main_key_IT[MAIN_LEN][4] =
420 {
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 "<>"
426 };
427
428 /*** Finnish keyboard layout (setxkbmap fi) */
429 static const char main_key_FI[MAIN_LEN][4] =
430 {
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 "<>"
436 };
437
438 /*** Bulgarian bds keyboard layout */
439 static const char main_key_BG_bds[MAIN_LEN][4] =
440 {
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 */
446 };
447
448 /*** Bulgarian phonetic keyboard layout */
449 static const char main_key_BG_phonetic[MAIN_LEN][4] =
450 {
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 */
456 };
457
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] =
461 {
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Øø",",<Ââ",".>Àà","/?.,", "<>|¦",
466 };
467
468
469 /*** Russian keyboard layout (contributed by Pavel Roskin) */
470 static const char main_key_RU[MAIN_LEN][4] =
471 {
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Øø",",<Ââ",".>Àà","/?"
476 };
477
478 /*** Russian keyboard layout (phantom key version) */
479 static const char main_key_RU_phantom[MAIN_LEN][4] =
480 {
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 */
486 };
487
488 /*** Russian keyboard layout KOI8-R */
489 static const char main_key_RU_koi8r[MAIN_LEN][4] =
490 {
491 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
492 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
493 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
494 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
495 "<>" /* the phantom key */
496 };
497
498 /*** Russian keyboard layout cp1251 */
499 static const char main_key_RU_cp1251[MAIN_LEN][4] =
500 {
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 */
506 };
507
508 /*** Russian phonetic keyboard layout */
509 static const char main_key_RU_phonetic[MAIN_LEN][4] =
510 {
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 */
516 };
517
518 /*** Ukrainian keyboard layout KOI8-U */
519 static const char main_key_UA[MAIN_LEN][4] =
520 {
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 */
526 };
527
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] =
531 {
532 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
533 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
534 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
535 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
536 "<>" /* the phantom key */
537 };
538
539 /*** Russian keyboard layout KOI8-R (pair to the previous) */
540 static const char main_key_RU_std[MAIN_LEN][4] =
541 {
542 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
543 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
544 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
545 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
546 "<>" /* the phantom key */
547 };
548
549 /*** Spanish keyboard layout (setxkbmap es) */
550 static const char main_key_ES[MAIN_LEN][4] =
551 {
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 "<>"
557 };
558
559 /*** Belgian keyboard layout ***/
560 static const char main_key_BE[MAIN_LEN][4] =
561 {
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 "<>\\"
567 };
568
569 /*** Hungarian keyboard layout (setxkbmap hu) */
570 static const char main_key_HU[MAIN_LEN][4] =
571 {
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 "íÍ"
577 };
578
579 /*** Polish (programmer's) keyboard layout ***/
580 static const char main_key_PL[MAIN_LEN][4] =
581 {
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 "<>|"
587 };
588
589 /*** Slovenian keyboard layout (setxkbmap si) ***/
590 static const char main_key_SI[MAIN_LEN][4] =
591 {
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 "<>"
597 };
598
599 /*** Serbian keyboard layout (setxkbmap sr) ***/
600 static const char main_key_SR[MAIN_LEN][4] =
601 {
602 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
603 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
604 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
605 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
606 "<>" /* the phantom key */
607 };
608
609 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
610 static const char main_key_US_SR[MAIN_LEN][4] =
611 {
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 */
617 };
618
619 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
620 static const char main_key_HR_jelly[MAIN_LEN][4] =
621 {
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 "<>|"
627 };
628
629 /*** Croatian keyboard layout (setxkbmap hr) ***/
630 static const char main_key_HR[MAIN_LEN][4] =
631 {
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 "<>"
637 };
638
639 /*** Japanese 106 keyboard layout ***/
640 static const char main_key_JA_jp106[MAIN_LEN][4] =
641 {
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 "\\_",
647 };
648
649 static const char main_key_JA_macjp[MAIN_LEN][4] =
650 {
651 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","","-=","^~","\\|",
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 "__",
656 };
657
658 /*** Japanese pc98x1 keyboard layout ***/
659 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
660 {
661 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","","-=","^`","\\|",
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 "\\_",
666 };
667
668 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
669 static const char main_key_PT_br[MAIN_LEN][4] =
670 {
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",",<",".>",";:","/?",
675 };
676
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] =
679 {
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"
684 };
685
686 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
687 static const char main_key_US_intl[MAIN_LEN][4] =
688 {
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", ",<", ".>", "/?"
693 };
694
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] =
699 {
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 "<>"
705 };
706
707 /*** Czech keyboard layout (setxkbmap cz) */
708 static const char main_key_CZ[MAIN_LEN][4] =
709 {
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 "\\"
715 };
716
717 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
718 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
719 {
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 "\\"
725 };
726
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] =
729 {
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 "<>"
735 };
736
737 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
738 static const char main_key_CS[MAIN_LEN][4] =
739 {
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 "<>\\|"
745 };
746
747 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
748 static const char main_key_LA[MAIN_LEN][4] =
749 {
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 "<>"
755 };
756
757 /*** Lithuanian keyboard layout (setxkbmap lt) */
758 static const char main_key_LT_B[MAIN_LEN][4] =
759 {
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 "ª¬"
765 };
766
767 /*** Turkish keyboard Layout */
768 static const char main_key_TK[MAIN_LEN][4] =
769 {
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","öÖ","çÇ",".:"
774 };
775
776 /*** Turkish keyboard layout (setxkbmap tr) */
777 static const char main_key_TR[MAIN_LEN][4] =
778 {
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 "<>"
784 };
785
786 /*** Turkish F keyboard layout (setxkbmap trf) */
787 static const char main_key_TR_F[MAIN_LEN][4] =
788 {
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 "<>"
794 };
795
796 /*** Israelian keyboard layout (setxkbmap us,il) */
797 static const char main_key_IL[MAIN_LEN][4] =
798 {
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 "<>"
804 };
805
806 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
807 static const char main_key_IL_phonetic[MAIN_LEN][4] =
808 {
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 "<>"
814 };
815
816 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
817 static const char main_key_IL_saharon[MAIN_LEN][4] =
818 {
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 "<>"
824 };
825
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] =
830 {
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 "<>"
836 };
837
838 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
839 static const char main_key_th[MAIN_LEN][4] =
840 {
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·?",",<Á²",".>ãÌ","/?½Æ"
845 };
846
847 /*** VNC keyboard layout */
848 static const WORD main_key_scan_vnc[MAIN_LEN] =
849 {
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
853 };
854
855 static const WORD main_key_vkey_vnc[MAIN_LEN] =
856 {
857 '1','2','3','4','5','6','7','8','9','',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
860 };
861
862 static const char main_key_vnc[MAIN_LEN][4] =
863 {
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"
866 };
867
868 /*** Dutch keyboard layout (setxkbmap nl) ***/
869 static const char main_key_NL[MAIN_LEN][4] =
870 {
871 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","'","/?","°~",
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 "[]"
876 };
877
878
879
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},
951
952 {0, NULL, NULL, NULL, NULL} /* sentinel */
953 };
954 static unsigned kbd_layout=0; /* index into above table of layouts */
955
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 */
964
965 static const WORD nonchar_key_vkey[256] =
966 {
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 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
998 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
999 * in order to produce a locale dependent numeric separator.
1000 */
1001 VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1002 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1003 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1004 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1005 /* function keys */
1006 VK_F1, VK_F2,
1007 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1008 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
1009 VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0, /* FFD0 */
1010 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1011 /* modifier keys */
1012 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */
1013 VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
1014 VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0, /* FFE8 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1016 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1017 };
1018
1019 static const WORD nonchar_key_scan[256] =
1020 {
1021 /* unused */
1022 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1023 /* special keys */
1024 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1025 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1026 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1027 /* unused */
1028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1034 /* cursor keys */
1035 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1037 /* misc keys */
1038 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1039 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1041 /* keypad keys */
1042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1045 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1046 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1047 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1048 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1049 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1050 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1051 /* function keys */
1052 0x3B, 0x3C,
1053 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1054 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1057 /* modifier keys */
1058 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1059 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1062 };
1063
1064 static const WORD xfree86_vendor_key_vkey[256] =
1065 {
1066 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1067 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1068 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1069 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1070 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1071 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1072 0, 0, 0, VK_BROWSER_HOME,
1073 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1074 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1075 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1076 0, 0, 0, 0,
1077 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1078 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1079 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1080 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1081 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1082 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1083 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1084 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1085 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1086 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1087 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1088 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1089 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1092 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1093 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1094 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1095 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1096 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1097 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1098 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1099 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1100 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1101 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1102 };
1103
1104 static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
1105 {
1106 #ifdef HAVE_XKB
1107 if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
1108 #endif
1109 return XKeycodeToKeysym(display, keycode, index);
1110 }
1111
1112 /* Returns the Windows virtual key code associated with the X event <e> */
1113 /* x11 lock must be held */
1114 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1115 {
1116 KeySym keysym = 0;
1117 Status status;
1118 char buf[24];
1119
1120 /* Clients should pass only KeyPress events to XmbLookupString */
1121 if (xic && e->type == KeyPress)
1122 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1123 else
1124 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1125
1126 if ((e->state & NumLockMask) &&
1127 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1128 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1129 /* Only the Keypad keys 0-9 and . send different keysyms
1130 * depending on the NumLock state */
1131 return nonchar_key_vkey[keysym & 0xFF];
1132
1133 /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
1134 * pressing Ctrl+Pause/Break produces VK_CANCEL. */
1135 if ((e->state & ControlMask) && (keysym == XK_Break))
1136 return VK_CANCEL;
1137
1138 TRACE_(key)("e->keycode = %u\n", e->keycode);
1139
1140 return keyc2vkey[e->keycode];
1141 }
1142
1143
1144 /***********************************************************************
1145 * X11DRV_send_keyboard_input
1146 */
1147 static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1148 {
1149 INPUT input;
1150
1151 TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1152
1153 input.type = INPUT_KEYBOARD;
1154 input.u.ki.wVk = vkey;
1155 input.u.ki.wScan = scan;
1156 input.u.ki.dwFlags = flags;
1157 input.u.ki.time = time;
1158 input.u.ki.dwExtraInfo = 0;
1159
1160 __wine_send_input( hwnd, &input );
1161 }
1162
1163
1164 /***********************************************************************
1165 * get_async_key_state
1166 */
1167 static BOOL get_async_key_state( BYTE state[256] )
1168 {
1169 BOOL ret;
1170
1171 SERVER_START_REQ( get_key_state )
1172 {
1173 req->tid = 0;
1174 req->key = -1;
1175 wine_server_set_reply( req, state, 256 );
1176 ret = !wine_server_call( req );
1177 }
1178 SERVER_END_REQ;
1179 return ret;
1180 }
1181
1182 /***********************************************************************
1183 * set_async_key_state
1184 */
1185 static void set_async_key_state( const BYTE state[256] )
1186 {
1187 SERVER_START_REQ( set_key_state )
1188 {
1189 req->tid = GetCurrentThreadId();
1190 req->async = 1;
1191 wine_server_add_data( req, state, 256 );
1192 wine_server_call( req );
1193 }
1194 SERVER_END_REQ;
1195 }
1196
1197 static void update_key_state( BYTE *keystate, BYTE key, int down )
1198 {
1199 if (down)
1200 {
1201 if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
1202 keystate[key] |= 0x80;
1203 }
1204 else keystate[key] &= ~0x80;
1205 }
1206
1207 /***********************************************************************
1208 * X11DRV_KeymapNotify
1209 *
1210 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1211 *
1212 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1213 * from wine to another application and back.
1214 * Toggle keys are handled in HandleEvent.
1215 */
1216 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1217 {
1218 int i, j;
1219 BYTE keystate[256];
1220 WORD vkey;
1221 BOOL changed = FALSE;
1222 struct {
1223 WORD vkey;
1224 BOOL pressed;
1225 } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1226
1227 if (!get_async_key_state( keystate )) return;
1228
1229 memset(modifiers, 0, sizeof(modifiers));
1230
1231 /* the minimum keycode is always greater or equal to 8, so we can
1232 * skip the first 8 values, hence start at 1
1233 */
1234 for (i = 1; i < 32; i++)
1235 {
1236 for (j = 0; j < 8; j++)
1237 {
1238 int m;
1239
1240 vkey = keyc2vkey[(i * 8) + j];
1241
1242 switch(vkey & 0xff)
1243 {
1244 case VK_LMENU:
1245 case VK_RMENU:
1246 case VK_LCONTROL:
1247 case VK_RCONTROL:
1248 case VK_LSHIFT:
1249 case VK_RSHIFT:
1250 m = (vkey & 0xff) - VK_LSHIFT;
1251 /* Take the vkey from the first keycode we encounter for this modifier */
1252 if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
1253 if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1254 break;
1255 }
1256 }
1257 }
1258
1259 for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
1260 {
1261 int m = vkey - VK_LSHIFT;
1262 if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
1263 {
1264 TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
1265 modifiers[m].vkey, keystate[vkey]);
1266
1267 update_key_state( keystate, vkey, modifiers[m].pressed );
1268 changed = TRUE;
1269 }
1270 }
1271
1272 if (!changed) return;
1273
1274 update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
1275 update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
1276 update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1277 set_async_key_state( keystate );
1278 }
1279
1280 static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1281 {
1282 BYTE keystate[256];
1283
1284 /* Note: X sets the below states on key down and clears them on key up.
1285 Windows triggers them on key down. */
1286
1287 if (!get_async_key_state( keystate )) return;
1288
1289 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1290 if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
1291 {
1292 DWORD flags = 0;
1293 if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1294 TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1295 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
1296 X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1297 }
1298
1299 /* Adjust the NUMLOCK state if it has been changed outside wine */
1300 if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
1301 {
1302 DWORD flags = KEYEVENTF_EXTENDEDKEY;
1303 if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
1304 TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1305 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
1306 X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1307 }
1308
1309 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1310 if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
1311 {
1312 DWORD flags = 0;
1313 if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
1314 TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1315 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
1316 X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1317 }
1318 }
1319
1320 /***********************************************************************
1321 * X11DRV_KeyEvent
1322 *
1323 * Handle a X key event
1324 */
1325 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1326 {
1327 XKeyEvent *event = &xev->xkey;
1328 char buf[24];
1329 char *Str = buf;
1330 KeySym keysym = 0;
1331 WORD vkey = 0, bScan;
1332 DWORD dwFlags;
1333 int ascii_chars;
1334 XIC xic = X11DRV_get_ic( hwnd );
1335 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1336 Status status = 0;
1337
1338 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1339 event->type, event->window, event->state, event->keycode);
1340
1341 if (event->type == KeyPress) update_user_time( event->time );
1342
1343 wine_tsx11_lock();
1344 /* Clients should pass only KeyPress events to XmbLookupString */
1345 if (xic && event->type == KeyPress)
1346 {
1347 ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1348 TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1349 if (status == XBufferOverflow)
1350 {
1351 Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
1352 if (Str == NULL)
1353 {
1354 ERR_(key)("Failed to allocate memory!\n");
1355 wine_tsx11_unlock();
1356 return;
1357 }
1358 ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
1359 }
1360 }
1361 else
1362 ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1363 wine_tsx11_unlock();
1364
1365 TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1366
1367 if (status == XLookupChars)
1368 {
1369 X11DRV_XIMLookupChars( Str, ascii_chars );
1370 if (buf != Str)
1371 HeapFree(GetProcessHeap(), 0, Str);
1372 return;
1373 }
1374
1375 /* If XKB extensions are used, the state mask for AltGr will use the group
1376 index instead of the modifier mask. The group index is set in bits
1377 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1378 pressed, look if the group index is different than 0. From XKB
1379 extension documentation, the group index for AltGr should be 2
1380 (event->state = 0x2000). It's probably better to not assume a
1381 predefined group index and find it dynamically
1382
1383 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1384 /* Save also all possible modifier states. */
1385 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1386
1387 if (TRACE_ON(key)){
1388 const char *ksname;
1389
1390 wine_tsx11_lock();
1391 ksname = XKeysymToString(keysym);
1392 wine_tsx11_unlock();
1393 if (!ksname)
1394 ksname = "No Name";
1395 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1396 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1397 keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1398 }
1399 if (buf != Str)
1400 HeapFree(GetProcessHeap(), 0, Str);
1401
1402 wine_tsx11_lock();
1403 vkey = EVENT_event_to_vkey(xic,event);
1404 /* X returns keycode 0 for composed characters */
1405 if (!vkey && ascii_chars) vkey = VK_NONAME;
1406 wine_tsx11_unlock();
1407
1408 TRACE_(key)("keycode %u converted to vkey 0x%X\n",
1409 event->keycode, vkey);
1410
1411 if (!vkey) return;
1412
1413 dwFlags = 0;
1414 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1415 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1416
1417 update_lock_state( hwnd, vkey, event->state, event_time );
1418
1419 bScan = keyc2scan[event->keycode] & 0xFF;
1420 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1421
1422 X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1423 }
1424
1425 /**********************************************************************
1426 * X11DRV_KEYBOARD_DetectLayout
1427 *
1428 * Called from X11DRV_InitKeyboard
1429 * This routine walks through the defined keyboard layouts and selects
1430 * whichever matches most closely.
1431 * X11 lock must be held.
1432 */
1433 static void
1434 X11DRV_KEYBOARD_DetectLayout( Display *display )
1435 {
1436 unsigned current, match, mismatch, seq, i, syms;
1437 int score, keyc, key, pkey, ok;
1438 KeySym keysym = 0;
1439 const char (*lkey)[MAIN_LEN][4];
1440 unsigned max_seq = 0;
1441 int max_score = 0, ismatch = 0;
1442 char ckey[256][4];
1443
1444 syms = keysyms_per_keycode;
1445 if (syms > 4) {
1446 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1447 syms = 4;
1448 }
1449
1450 memset( ckey, 0, sizeof(ckey) );
1451 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1452 /* get data for keycode from X server */
1453 for (i = 0; i < syms; i++) {
1454 if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1455 /* Allow both one-byte and two-byte national keysyms */
1456 if ((keysym < 0x8000) && (keysym != ' '))
1457 {
1458 #ifdef HAVE_XKB
1459 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1460 #endif
1461 {
1462 TRACE("XKB could not translate keysym %04lx\n", keysym);
1463 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1464 * with appropriate ShiftMask and Mode_switch, use XLookupString
1465 * to get character in the local encoding.
1466 */
1467 ckey[keyc][i] = keysym & 0xFF;
1468 }
1469 }
1470 else {
1471 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1472 }
1473 }
1474 }
1475
1476 for (current = 0; main_key_tab[current].comment; current++) {
1477 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1478 match = 0;
1479 mismatch = 0;
1480 score = 0;
1481 seq = 0;
1482 lkey = main_key_tab[current].key;
1483 pkey = -1;
1484 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1485 if (ckey[keyc][0]) {
1486 /* search for a match in layout table */
1487 /* right now, we just find an absolute match for defined positions */
1488 /* (undefined positions are ignored, so if it's defined as "3#" in */
1489 /* the table, it's okay that the X server has "3#£", for example) */
1490 /* however, the score will be higher for longer matches */
1491 for (key = 0; key < MAIN_LEN; key++) {
1492 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1493 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1494 ok++;
1495 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1496 ok = -1;
1497 }
1498 if (ok > 0) {
1499 score += ok;
1500 break;
1501 }
1502 }
1503 /* count the matches and mismatches */
1504 if (ok > 0) {
1505 match++;
1506 /* and how much the keycode order matches */
1507 if (key > pkey) seq++;
1508 pkey = key;
1509 } else {
1510 /* print spaces instead of \0's */
1511 char str[5];
1512 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1513 str[4] = 0;
1514 TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1515 mismatch++;
1516 score -= syms;
1517 }
1518 }
1519 }
1520 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1521 match, mismatch, seq, score);
1522 if ((score > max_score) ||
1523 ((score == max_score) && (seq > max_seq))) {
1524 /* best match so far */
1525 kbd_layout = current;
1526 max_score = score;
1527 max_seq = seq;
1528 ismatch = !mismatch;
1529 }
1530 }
1531 /* we're done, report results if necessary */
1532 if (!ismatch)
1533 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1534 main_key_tab[kbd_layout].comment);
1535
1536 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1537 }
1538
1539 static HKL get_locale_kbd_layout(void)
1540 {
1541 ULONG_PTR layout;
1542 LANGID langid;
1543
1544 /* FIXME:
1545 *
1546 * layout = main_key_tab[kbd_layout].lcid;
1547 *
1548 * Winword uses return value of GetKeyboardLayout as a codepage
1549 * to translate ANSI keyboard messages to unicode. But we have
1550 * a problem with it: for instance Polish keyboard layout is
1551 * identical to the US one, and therefore instead of the Polish
1552 * locale id we return the US one.
1553 */
1554
1555 layout = GetUserDefaultLCID();
1556
1557 /*
1558 * Microsoft Office expects this value to be something specific
1559 * for Japanese and Korean Windows with an IME the value is 0xe001
1560 * We should probably check to see if an IME exists and if so then
1561 * set this word properly.
1562 */
1563 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1564 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1565 layout |= 0xe001 << 16; /* IME */
1566 else
1567 layout |= layout << 16;
1568
1569 return (HKL)layout;
1570 }
1571
1572 /***********************************************************************
1573 * GetKeyboardLayoutName (X11DRV.@)
1574 */
1575 BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1576 {
1577 static const WCHAR formatW[] = {'%','','8','x',0};
1578 DWORD layout;
1579
1580 layout = HandleToUlong( get_locale_kbd_layout() );
1581 if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1582 sprintfW(name, formatW, layout);
1583 TRACE("returning %s\n", debugstr_w(name));
1584 return TRUE;
1585 }
1586
1587 static void set_kbd_layout_preload_key(void)
1588 {
1589 static const WCHAR preload[] =
1590 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
1591 static const WCHAR one[] = {'1',0};
1592
1593 HKEY hkey;
1594 WCHAR layout[KL_NAMELENGTH];
1595
1596 if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
1597 return;
1598
1599 if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
1600 {
1601 RegCloseKey(hkey);
1602 return;
1603 }
1604 if (X11DRV_GetKeyboardLayoutName(layout))
1605 RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));
1606
1607 RegCloseKey(hkey);
1608 }
1609
1610 /**********************************************************************
1611 * X11DRV_InitKeyboard
1612 */
1613 void X11DRV_InitKeyboard( Display *display )
1614 {
1615 KeySym *ksp;
1616 XModifierKeymap *mmp;
1617 KeySym keysym;
1618 KeyCode *kcp;
1619 XKeyEvent e2;
1620 WORD scan, vkey;
1621 int keyc, i, keyn, syms;
1622 char ckey[4]={0,0,0,0};
1623 const char (*lkey)[MAIN_LEN][4];
1624 char vkey_used[256] = { 0 };
1625
1626 /* Ranges of OEM, function key, and character virtual key codes.
1627 * Don't include those handled specially in X11DRV_ToUnicodeEx and
1628 * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1629 static const struct {
1630 WORD first, last;
1631 } vkey_ranges[] = {
1632 { VK_OEM_1, VK_OEM_3 },
1633 { VK_OEM_4, VK_ICO_00 },
1634 { 0xe6, 0xe6 },
1635 { 0xe9, 0xf5 },
1636 { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
1637 { VK_F1, VK_F24 },
1638 { 0x30, 0x39 }, /* VK_0 - VK_9 */
1639 { 0x41, 0x5a }, /* VK_A - VK_Z */
1640 { 0, 0 }
1641 };
1642 int vkey_range;
1643
1644 set_kbd_layout_preload_key();
1645
1646 wine_tsx11_lock();
1647 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1648 ksp = XGetKeyboardMapping(display, min_keycode,
1649 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1650 /* We are only interested in keysyms_per_keycode.
1651 There is no need to hold a local copy of the keysyms table */
1652 XFree(ksp);
1653
1654 mmp = XGetModifierMapping(display);
1655 kcp = mmp->modifiermap;
1656 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1657 {
1658 int j;
1659
1660 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1661 if (*kcp)
1662 {
1663 int k;
1664
1665 for (k = 0; k < keysyms_per_keycode; k += 1)
1666 if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1667 {
1668 NumLockMask = 1 << i;
1669 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1670 }
1671 else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1672 {
1673 ScrollLockMask = 1 << i;
1674 TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
1675 }
1676 }
1677 }
1678 XFreeModifiermap(mmp);
1679
1680 /* Detect the keyboard layout */
1681 X11DRV_KEYBOARD_DetectLayout( display );
1682 lkey = main_key_tab[kbd_layout].key;
1683 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1684
1685 /* Now build two conversion arrays :
1686 * keycode -> vkey + scancode + extended
1687 * vkey + extended -> keycode */
1688
1689 e2.display = display;
1690 e2.state = 0;
1691 e2.type = KeyPress;
1692
1693 memset(keyc2vkey, 0, sizeof(keyc2vkey));
1694 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1695 {
1696 char buf[30];
1697 int have_chars;
1698
1699 keysym = 0;
1700 e2.keycode = (KeyCode)keyc;
1701 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1702 vkey = 0; scan = 0;
1703 if (keysym) /* otherwise, keycode not used */
1704 {
1705 if ((keysym >> 8) == 0xFF) /* non-character key */
1706 {
1707 vkey = nonchar_key_vkey[keysym & 0xff];
1708 scan = nonchar_key_scan[keysym & 0xff];
1709 /* set extended bit when necessary */
1710 if (scan & 0x100) vkey |= 0x100;
1711 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
1712 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
1713 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1714 scan = 0x100;
1715 vkey |= 0x100;
1716 } else if (keysym == 0x20) { /* Spacebar */
1717 vkey = VK_SPACE;
1718 scan = 0x39;
1719 } else if (have_chars) {
1720 /* we seem to need to search the layout-dependent scancodes */
1721 int maxlen=0,maxval=-1,ok;
1722 for (i=0; i<syms; i++) {
1723 keysym = keycode_to_keysym(display, keyc, i);
1724 if ((keysym<0x8000) && (keysym!=' '))
1725 {
1726 #ifdef HAVE_XKB
1727 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1728 #endif
1729 {
1730 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1731 * with appropriate ShiftMask and Mode_switch, use XLookupString
1732 * to get character in the local encoding.
1733 */
1734 ckey[i] = keysym & 0xFF;
1735 }
1736 } else {
1737 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1738 }
1739 }
1740 /* find key with longest match streak */
1741 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1742 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1743 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1744 if (!ok) i--; /* we overshot */
1745 if (ok||(i>maxlen)) {
1746 maxlen=i; maxval=keyn;
1747 }
1748 if (ok) break;
1749 }
1750 if (maxval>=0) {
1751 /* got it */
1752 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1753 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1754 scan = (*lscan)[maxval];
1755 vkey = (*lvkey)[maxval];
1756 }
1757 }
1758 }
1759 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1760 keyc2vkey[e2.keycode] = vkey;
1761 keyc2scan[e2.keycode] = scan;
1762 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1763 WARN("vkey %04X is being used by more than one keycode\n", vkey);
1764 vkey_used[(vkey & 0xff)] = 1;
1765 } /* for */
1766
1767 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1768 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1769 {
1770 vkey = keyc2vkey[keyc] & 0xff;
1771 if (vkey)
1772 continue;
1773
1774 e2.keycode = (KeyCode)keyc;
1775 keysym = XLookupKeysym(&e2, 0);
1776 if (!keysym)
1777 continue;
1778
1779 /* find a suitable layout-dependent VK code */
1780 /* (most Winelib apps ought to be able to work without layout tables!) */
1781 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1782 {
1783 keysym = XLookupKeysym(&e2, i);
1784 if ((keysym >= XK_0 && keysym <= XK_9)
1785 || (keysym >= XK_A && keysym <= XK_Z)) {
1786 vkey = VKEY_IF_NOT_USED(keysym);
1787 }
1788 }
1789
1790 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1791 {
1792 keysym = XLookupKeysym(&e2, i);
1793 switch (keysym)
1794 {
1795 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
1796 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
1797 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
1798 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
1799 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
1800 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
1801 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
1802 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
1803 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
1804 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
1805 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1806 }
1807 }
1808
1809 if (vkey)
1810 {
1811 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1812 keyc2vkey[e2.keycode] = vkey;
1813 }
1814 } /* for */
1815
1816 /* For any keycodes which still don't have a vkey, assign any spare
1817 * character, function key, or OEM virtual key code. */
1818 vkey_range = 0;
1819 vkey = vkey_ranges[vkey_range].first;
1820 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1821 {
1822 if (keyc2vkey[keyc] & 0xff)
1823 continue;
1824
1825 e2.keycode = (KeyCode)keyc;
1826 keysym = XLookupKeysym(&e2, 0);
1827 if (!keysym)
1828 continue;
1829
1830 while (vkey && vkey_used[vkey])
1831 {
1832 if (vkey == vkey_ranges[vkey_range].last)
1833 {
1834 vkey_range++;
1835 vkey = vkey_ranges[vkey_range].first;
1836 }
1837 else
1838 vkey++;
1839 }
1840
1841 if (!vkey)
1842 {
1843 WARN("No more vkeys available!\n");
1844 break;
1845 }
1846
1847 if (TRACE_ON(keyboard))
1848 {
1849 TRACE("spare virtual key %04X assigned to keycode %u:\n",
1850 vkey, e2.keycode);
1851 TRACE("(");
1852 for (i = 0; i < keysyms_per_keycode; i += 1)
1853 {
1854 const char *ksname;
1855
1856 keysym = XLookupKeysym(&e2, i);
1857 ksname = XKeysymToString(keysym);
1858 if (!ksname)
1859 ksname = "NoSymbol";
1860 TRACE( "%lx (%s) ", keysym, ksname);
1861 }
1862 TRACE(")\n");
1863 }
1864
1865 TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1866 keyc2vkey[e2.keycode] = vkey;
1867 vkey_used[vkey] = 1;
1868 } /* for */
1869 #undef VKEY_IF_NOT_USED
1870
1871 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1872 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1873 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1874 const char *ksname;
1875 keysym = keycode_to_keysym(display, keyc, 0);
1876 ksname = XKeysymToString(keysym);
1877 if (!ksname) ksname = "NoSymbol";
1878
1879 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1880
1881 TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1882 keyc2scan[keyc]=scan++;
1883 }
1884
1885 wine_tsx11_unlock();
1886 }
1887
1888 static BOOL match_x11_keyboard_layout(HKL hkl)
1889 {
1890 const DWORD isIME = 0xE0000000;
1891 HKL xHkl = get_locale_kbd_layout();
1892
1893 /* if the layout is an IME, only match the low word (LCID) */
1894 if (((ULONG_PTR)hkl & isIME) == isIME)
1895 return (LOWORD(hkl) == LOWORD(xHkl));
1896 else
1897 return (hkl == xHkl);
1898 }
1899
1900 /**********************************************************************
1901 * GetAsyncKeyState (X11DRV.@)
1902 */
1903 SHORT CDECL X11DRV_GetAsyncKeyState(INT key)
1904 {
1905 /* Photoshop livelocks unless mouse events are included here */
1906 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY | QS_MOUSE, 0 );
1907 return -1;
1908 }
1909
1910
1911 /***********************************************************************
1912 * GetKeyboardLayout (X11DRV.@)
1913 */
1914 HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1915 {
1916 if (!dwThreadid || dwThreadid == GetCurrentThreadId())
1917 {
1918 struct x11drv_thread_data *thread_data = x11drv_thread_data();
1919 if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
1920 }
1921 else
1922 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1923
1924 return get_locale_kbd_layout();
1925 }
1926
1927
1928 /***********************************************************************
1929 * LoadKeyboardLayout (X11DRV.@)
1930 */
1931 HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1932 {
1933 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1934 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1935 return 0;
1936 }
1937
1938
1939 /***********************************************************************
1940 * UnloadKeyboardLayout (X11DRV.@)
1941 */
1942 BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1943 {
1944 FIXME("%p: stub!\n", hkl);
1945 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1946 return FALSE;
1947 }
1948
1949
1950 /***********************************************************************
1951 * ActivateKeyboardLayout (X11DRV.@)
1952 */
1953 HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1954 {
1955 HKL oldHkl = 0;
1956 struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
1957
1958 FIXME("%p, %04x: semi-stub!\n", hkl, flags);
1959 if (flags & KLF_SETFORPROCESS)
1960 {
1961 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1962 FIXME("KLF_SETFORPROCESS not supported\n");
1963 return 0;
1964 }
1965
1966 if (flags)
1967 FIXME("flags %x not supported\n",flags);
1968
1969 if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
1970 {
1971 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1972 FIXME("HKL_NEXT and HKL_PREV not supported\n");
1973 return 0;
1974 }
1975
1976 if (!match_x11_keyboard_layout(hkl))
1977 {
1978 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1979 FIXME("setting keyboard of different locales not supported\n");
1980 return 0;
1981 }
1982
1983 oldHkl = thread_data->kbd_layout;
1984 if (!oldHkl) oldHkl = get_locale_kbd_layout();
1985
1986 thread_data->kbd_layout = hkl;
1987
1988 return oldHkl;
1989 }
1990
1991
1992 /***********************************************************************
1993 * X11DRV_MappingNotify
1994 */
1995 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1996 {
1997 HWND hwnd;
1998
1999 wine_tsx11_lock();
2000 XRefreshKeyboardMapping(&event->xmapping);
2001 wine_tsx11_unlock();
2002 X11DRV_InitKeyboard( event->xmapping.display );
2003
2004 hwnd = GetFocus();
2005 if (!hwnd) hwnd = GetActiveWindow();
2006 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2007 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2008 }
2009
2010
2011 /***********************************************************************
2012 * VkKeyScanEx (X11DRV.@)
2013 *
2014 * Note: Windows ignores HKL parameter and uses current active layout instead
2015 */
2016 SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2017 {
2018 Display *display = thread_init_display();
2019 KeyCode keycode;
2020 KeySym keysym;
2021 int i, index;
2022 CHAR cChar;
2023 SHORT ret;
2024
2025 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2026 * is UTF-8 (multibyte encoding)?
2027 */
2028 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2029 {
2030 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2031 return -1;
2032 }
2033
2034 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2035
2036 /* char->keysym (same for ANSI chars) */
2037 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2038 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2039
2040 wine_tsx11_lock();
2041 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2042 if (!keycode)
2043 {
2044 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2045 {
2046 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2047 TRACE(" ... returning ctrl char %#.2x\n", ret);
2048 wine_tsx11_unlock();
2049 return ret;
2050 }
2051 /* It didn't work ... let's try with deadchar code. */
2052 TRACE("retrying with | 0xFE00\n");
2053 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2054 }
2055 wine_tsx11_unlock();
2056
2057 TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2058
2059 /* keycode -> (keyc2vkey) vkey */
2060 ret = keyc2vkey[keycode];
2061
2062 if (!keycode || !ret)
2063 {
2064 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2065 return -1;
2066 }
2067
2068 index = -1;
2069 wine_tsx11_lock();
2070 for (i = 0; i < 4; i++) /* find shift state */
2071 {
2072 if (keycode_to_keysym(display, keycode, i) == keysym)
2073 {
2074 index = i;
2075 break;
2076 }
2077 }
2078 wine_tsx11_unlock();
2079
2080 switch (index)
2081 {
2082 default:
2083 case -1:
2084 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2085 return -1;
2086
2087 case 0: break;
2088 case 1: ret += 0x0100; break;
2089 case 2: ret += 0x0600; break;
2090 case 3: ret += 0x0700; break;
2091 }
2092 /*
2093 index : 0 adds 0x0000
2094 index : 1 adds 0x0100 (shift)
2095 index : ? adds 0x0200 (ctrl)
2096 index : 2 adds 0x0600 (ctrl+alt)
2097 index : 3 adds 0x0700 (ctrl+alt+shift)
2098 */
2099
2100 TRACE(" ... returning %#.2x\n", ret);
2101 return ret;
2102 }
2103
2104 /***********************************************************************
2105 * MapVirtualKeyEx (X11DRV.@)
2106 */
2107 UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2108 {
2109 Display *display = thread_init_display();
2110
2111 #define returnMVK(value) do { TRACE("returning 0x%x.\n",value); return value; } while(0)
2112
2113 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2114 if (!match_x11_keyboard_layout(hkl))
2115 FIXME("keyboard layout %p is not supported\n", hkl);
2116
2117 switch(wMapType)
2118 {
2119 case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
2120 case MAPVK_VK_TO_VSC_EX:
2121 {
2122 int keyc;
2123
2124 switch (wCode)
2125 {
2126 case VK_SHIFT: wCode = VK_LSHIFT; break;
2127 case VK_CONTROL: wCode = VK_LCONTROL; break;
2128 case VK_MENU: wCode = VK_LMENU; break;
2129 }
2130
2131 /* let's do vkey -> keycode -> scan */
2132 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2133 if ((keyc2vkey[keyc] & 0xFF) == wCode) break;
2134
2135 if (keyc > max_keycode)
2136 {
2137 TRACE("returning no scan-code.\n");
2138 return 0;
2139 }
2140 returnMVK (keyc2scan[keyc] & 0xFF);
2141 }
2142 case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
2143 case MAPVK_VSC_TO_VK_EX:
2144 {
2145 int keyc;
2146 UINT vkey = 0;
2147
2148 /* let's do scan -> keycode -> vkey */
2149 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2150 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2151 {
2152 vkey = keyc2vkey[keyc] & 0xFF;
2153 /* Only stop if it's not a numpad vkey; otherwise keep
2154 looking for a potential better vkey. */
2155 if (vkey && (vkey < VK_NUMPAD0 || VK_DIVIDE < vkey))
2156 break;
2157 }
2158
2159 if (vkey == 0)
2160 {
2161 TRACE("returning no vkey-code.\n");
2162 return 0;
2163 }
2164
2165 if (wMapType == MAPVK_VSC_TO_VK)
2166 switch (vkey)
2167 {
2168 case VK_LSHIFT:
2169 case VK_RSHIFT:
2170 vkey = VK_SHIFT; break;
2171 case VK_LCONTROL:
2172 case VK_RCONTROL:
2173 vkey = VK_CONTROL; break;
2174 case VK_LMENU:
2175 case VK_RMENU:
2176 vkey = VK_MENU; break;
2177 }
2178
2179 returnMVK (vkey);
2180 }
2181 case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
2182 {
2183 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2184 * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
2185 * key.. Looks like something is wrong with the MS docs?
2186 * This is only true for letters, for example VK_0 returns '' not ')'.
2187 * - hence we use the lock mask to ensure this happens.
2188 */
2189 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2190 XKeyEvent e;
2191 KeySym keysym;
2192 int keyc, len;
2193 char s[10];
2194
2195 e.display = display;
2196 e.state = 0;
2197 e.keycode = 0;
2198 e.type = KeyPress;
2199
2200 wine_tsx11_lock();
2201
2202 /* We exit on the first keycode found, to speed up the thing. */
2203 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2204 { /* Find a keycode that could have generated this virtual key */
2205 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2206 { /* We filter the extended bit, we don't know it */
2207 e.keycode = keyc; /* Store it temporarily */
2208 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2209 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2210 state), so set it to 0, we'll find another one */
2211 }
2212 }
2213 }
2214
2215 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2216 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2217
2218 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2219 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2220 * in order to produce a locale dependent numeric separator.
2221 */
2222 if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
2223 {
2224 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2225 if (!e.keycode)
2226 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2227 }
2228
2229 if (!e.keycode)
2230 {
2231 WARN("Unknown virtual key %X !!!\n", wCode);
2232 wine_tsx11_unlock();
2233 return 0; /* whatever */
2234 }
2235 TRACE("Found keycode %u\n",e.keycode);
2236
2237 len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
2238 wine_tsx11_unlock();
2239
2240 if (len)
2241 {
2242 WCHAR wch;
2243 if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1))
2244 returnMVK(toupperW(wch));
2245 }
2246 TRACE("returning no ANSI.\n");
2247 return 0;
2248 }
2249 default: /* reserved */
2250 FIXME("Unknown wMapType %d !\n", wMapType);
2251 return 0;
2252 }
2253 return 0;
2254 }
2255
2256 /***********************************************************************
2257 * GetKeyNameText (X11DRV.@)
2258 */
2259 INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2260 {
2261 Display *display = thread_init_display();
2262 int vkey, ansi, scanCode;
2263 KeyCode keyc;
2264 int keyi;
2265 KeySym keys;
2266 char *name;
2267
2268 scanCode = lParam >> 16;
2269 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2270
2271 vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2272
2273 /* handle "don't care" bit (0x02000000) */
2274 if (!(lParam & 0x02000000)) {
2275 switch (vkey) {
2276 case VK_RSHIFT:
2277 /* R-Shift is "special" - it is an extended key with separate scan code */
2278 scanCode |= 0x100;
2279 /* fall through */
2280 case VK_LSHIFT:
2281 vkey = VK_SHIFT;
2282 break;
2283 case VK_LCONTROL:
2284 case VK_RCONTROL:
2285 vkey = VK_CONTROL;
2286 break;
2287 case VK_LMENU:
2288 case VK_RMENU:
2289 vkey = VK_MENU;
2290 break;
2291 }
2292 }
2293
2294 ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2295 TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2296
2297 /* first get the name of the "regular" keys which is the Upper case
2298 value of the keycap imprint. */
2299 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2300 (scanCode != 0x137) && /* PrtScn */
2301 (scanCode != 0x135) && /* numpad / */
2302 (scanCode != 0x37 ) && /* numpad * */
2303 (scanCode != 0x4a ) && /* numpad - */
2304 (scanCode != 0x4e ) ) /* numpad + */
2305 {
2306 if (nSize >= 2)
2307 {
2308 *lpBuffer = toupperW((WCHAR)ansi);
2309 *(lpBuffer+1) = 0;
2310 return 1;
2311 }
2312 else
2313 return 0;
2314 }
2315
2316 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2317 without "extended-key" flag. However Wine generates scancode
2318 *with* "extended-key" flag. Seems to occur *only* for the
2319 function keys. Soooo.. We will leave the table alone and
2320 fudge the lookup here till the other part is found and fixed!!! */
2321
2322 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2323 (scanCode == 0x157) || (scanCode == 0x158))
2324 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2325
2326 /* let's do scancode -> keycode -> keysym -> String */
2327
2328 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2329 if ((keyc2scan[keyi]) == scanCode)
2330 break;
2331 if (keyi <= max_keycode)
2332 {
2333 INT rc;
2334
2335 wine_tsx11_lock();
2336 keyc = (KeyCode) keyi;
2337 keys = keycode_to_keysym(display, keyc, 0);
2338 name = XKeysymToString(keys);
2339 wine_tsx11_unlock();
2340
2341 if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
2342 {
2343 char* idx = strrchr(name, '_');
2344 if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
2345 {
2346 TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
2347 scanCode, keyc, keys, debugstr_an(name,idx-name));
2348 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
2349 if (!rc) rc = nSize;
2350 lpBuffer[--rc] = 0;
2351 return rc;
2352 }
2353 }
2354
2355 if (name)
2356 {
2357 TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
2358 scanCode, keyc, (int)keys, vkey, debugstr_a(name));
2359 rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2360 if (!rc) rc = nSize;
2361 lpBuffer[--rc] = 0;
2362 return rc;
2363 }
2364 }
2365
2366 /* Finally issue WARN for unknown keys */
2367
2368 WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2369 *lpBuffer = 0;
2370 return 0;
2371 }
2372
2373 /***********************************************************************
2374 * X11DRV_KEYBOARD_MapDeadKeysym
2375 */
2376 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2377 {
2378 switch (keysym)
2379 {
2380 /* symbolic ASCII is the same as defined in rfc1345 */
2381 #ifdef XK_dead_tilde
2382 case XK_dead_tilde :
2383 #endif
2384 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2385 return '~'; /* '? */
2386 #ifdef XK_dead_acute
2387 case XK_dead_acute :
2388 #endif
2389 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2390 return 0xb4; /* '' */
2391 #ifdef XK_dead_circumflex
2392 case XK_dead_circumflex:
2393 #endif
2394 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2395 return '^'; /* '> */
2396 #ifdef XK_dead_grave
2397 case XK_dead_grave :
2398 #endif
2399 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2400 return '`'; /* '! */
2401 #ifdef XK_dead_diaeresis
2402 case XK_dead_diaeresis :
2403 #endif
2404 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2405 return 0xa8; /* ': */
2406 #ifdef XK_dead_cedilla
2407 case XK_dead_cedilla :
2408 return 0xb8; /* ', */
2409 #endif
2410 #ifdef XK_dead_macron
2411 case XK_dead_macron :
2412 return '-'; /* 'm isn't defined on iso-8859-x */
2413 #endif
2414 #ifdef XK_dead_breve
2415 case XK_dead_breve :
2416 return 0xa2; /* '( */
2417 #endif
2418 #ifdef XK_dead_abovedot
2419 case XK_dead_abovedot :
2420 return 0xff; /* '. */
2421 #endif
2422 #ifdef XK_dead_abovering
2423 case XK_dead_abovering :
2424 return ''; /* '0 isn't defined on iso-8859-x */
2425 #endif
2426 #ifdef XK_dead_doubleacute
2427 case XK_dead_doubleacute :
2428 return 0xbd; /* '" */
2429 #endif
2430 #ifdef XK_dead_caron
2431 case XK_dead_caron :
2432 return 0xb7; /* '< */
2433 #endif
2434 #ifdef XK_dead_ogonek
2435 case XK_dead_ogonek :
2436 return 0xb2; /* '; */
2437 #endif
2438 /* FIXME: I don't know this three.
2439 case XK_dead_iota :
2440 return 'i';
2441 case XK_dead_voiced_sound :
2442 return 'v';
2443 case XK_dead_semivoiced_sound :
2444 return 's';
2445 */
2446 }
2447 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2448 return 0;
2449 }
2450
2451 /***********************************************************************
2452 * ToUnicodeEx (X11DRV.@)
2453 *
2454 * The ToUnicode function translates the specified virtual-key code and keyboard
2455 * state to the corresponding Windows character or characters.
2456 *
2457 * If the specified key is a dead key, the return value is negative. Otherwise,
2458 * it is one of the following values:
2459 * Value Meaning
2460 * 0 The specified virtual key has no translation for the current state of the keyboard.
2461 * 1 One Windows character was copied to the buffer.
2462 * 2 Two characters were copied to the buffer. This usually happens when a
2463 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2464 * be composed with the specified virtual key to form a single character.
2465 *
2466 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2467 *
2468 */
2469 INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
2470 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2471 {
2472 Display *display = thread_init_display();
2473 XKeyEvent e;
2474 KeySym keysym = 0;
2475 INT ret;
2476 int keyc;
2477 char buf[10];
2478 char *lpChar = buf;
2479 HWND focus;
2480 XIC xic;
2481 Status status = 0;
2482
2483 if (scanCode & 0x8000)
2484 {
2485 TRACE_(key)("Key UP, doing nothing\n" );
2486 return 0;
2487 }
2488
2489 if (!match_x11_keyboard_layout(hkl))
2490 FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2491
2492 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2493 {
2494 TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2495 return 0;
2496 }
2497
2498 e.display = display;
2499 e.keycode = 0;
2500 e.state = 0;
2501 e.type = KeyPress;
2502
2503 focus = x11drv_thread_data()->last_xic_hwnd;
2504 if (!focus)
2505 {
2506 focus = GetFocus();
2507 if (focus) focus = GetAncestor( focus, GA_ROOT );
2508 if (!focus) focus = GetActiveWindow();
2509 }
2510 e.window = X11DRV_get_whole_window( focus );
2511 xic = X11DRV_get_ic( focus );
2512
2513 if (lpKeyState[VK_SHIFT] & 0x80)
2514 {
2515 TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2516 e.state |= ShiftMask;
2517 }
2518 if (lpKeyState[VK_CAPITAL] & 0x01)
2519 {
2520 TRACE_(key)("LockMask = %04x\n", LockMask);
2521 e.state |= LockMask;
2522 }
2523 if (lpKeyState[VK_CONTROL] & 0x80)
2524 {
2525 TRACE_(key)("ControlMask = %04x\n", ControlMask);
2526 e.state |= ControlMask;
2527 }
2528 if (lpKeyState[VK_NUMLOCK] & 0x01)
2529 {
2530 TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2531 e.state |= NumLockMask;
2532 }
2533
2534 /* Restore saved AltGr state */
2535 TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2536 e.state |= AltGrMask;
2537
2538 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2539 virtKey, scanCode, e.state);
2540 wine_tsx11_lock();
2541 /* We exit on the first keycode found, to speed up the thing. */
2542 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2543 { /* Find a keycode that could have generated this virtual key */
2544 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2545 { /* We filter the extended bit, we don't know it */
2546 e.keycode = keyc; /* Store it temporarily */
2547 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2548 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2549 state), so set it to 0, we'll find another one */
2550 }
2551 }
2552 }
2553
2554 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2555 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2556
2557 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2558 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2559
2560 /* Windows always generates VK_DECIMAL for Del/. on keypad while some
2561 * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
2562 * in order to produce a locale dependent numeric separator.
2563 */
2564 if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2565 {
2566 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2567 if (!e.keycode)
2568 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2569 }
2570
2571 if (!e.keycode && virtKey != VK_NONAME)
2572 {
2573 WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2574 wine_tsx11_unlock();
2575 return 0;
2576 }
2577 else TRACE_(key)("Found keycode %u\n",e.keycode);
2578
2579 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2580 e.type, e.window, e.state, e.keycode);
2581
2582 /* Clients should pass only KeyPress events to XmbLookupString,
2583 * e.type was set to KeyPress above.
2584 */
2585 if (xic)
2586 {
2587 ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2588 TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2589 if (status == XBufferOverflow)
2590 {
2591 lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
2592 if (lpChar == NULL)
2593 {
2594 ERR_(key)("Failed to allocate memory!\n");
2595 wine_tsx11_unlock();
2596 return 0;
2597 }
2598 ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
2599 }
2600 }
2601 else
2602 ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2603 wine_tsx11_unlock();
2604
2605 TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);
2606
2607 if (TRACE_ON(key))
2608 {
2609 const char *ksname;
2610
2611 wine_tsx11_lock();
2612 ksname = XKeysymToString(keysym);
2613 wine_tsx11_unlock();
2614 if (!ksname) ksname = "No Name";
2615 TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2616 (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
2617 keysym, ksname, ret, debugstr_an(lpChar, ret));
2618 }
2619
2620 if (ret == 0)
2621 {
2622 char dead_char;
2623
2624 #ifdef XK_EuroSign
2625 /* An ugly hack for EuroSign: X can't translate it to a character
2626 for some locales. */
2627 if (keysym == XK_EuroSign)
2628 {
2629 bufW[0] = 0x20AC;
2630 ret = 1;
2631 goto found;
2632 }
2633 #endif
2634 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2635 /* Here we change it back. */
2636 if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2637 {
2638 bufW[0] = 0x09;
2639 ret = 1;
2640 goto found;
2641 }
2642
2643 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2644 if (dead_char)
2645 {
2646 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2647 ret = -1;
2648 goto found;
2649 }
2650
2651 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2652 {
2653 /* Unicode direct mapping */
2654 bufW[0] = keysym & 0xffff;
2655 ret = 1;
2656 goto found;
2657 }
2658 else if ((keysym >> 8) == 0x1008FF) {
2659 bufW[0] = 0;
2660 ret = 0;
2661 goto found;
2662 }
2663 else
2664 {
2665 const char *ksname;
2666
2667 wine_tsx11_lock();
2668 ksname = XKeysymToString(keysym);
2669 wine_tsx11_unlock();
2670 if (!ksname)
2671 ksname = "No Name";
2672 if ((keysym >> 8) != 0xff)
2673 {
2674 WARN_(key)("no char for keysym %04lx (%s) :\n",
2675 keysym, ksname);
2676 WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2677 virtKey, scanCode, e.keycode, e.state);
2678 }
2679 }
2680 }
2681 else { /* ret != 0 */
2682 /* We have a special case to handle : Shift + arrow, shift + home, ...
2683 X returns a char for it, but Windows doesn't. Let's eat it. */
2684 if (!(e.state & NumLockMask) /* NumLock is off */
2685 && (e.state & ShiftMask) /* Shift is pressed */
2686 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2687 {
2688 lpChar[0] = 0;
2689 ret = 0;
2690 }
2691
2692 /* more areas where X returns characters but Windows does not
2693 CTRL + number or CTRL + symbol */
2694 if (e.state & ControlMask)
2695 {
2696 if (((keysym>=33) && (keysym < 'A')) ||
2697 ((keysym > 'Z') && (keysym < 'a')) ||
2698 (keysym == XK_Tab))
2699 {
2700 lpChar[0] = 0;
2701 ret = 0;
2702 }
2703 }
2704
2705 /* We have another special case for delete key (XK_Delete) on an
2706 extended keyboard. X returns a char for it, but Windows doesn't */
2707 if (keysym == XK_Delete)
2708 {
2709 lpChar[0] = 0;
2710 ret = 0;
2711 }
2712 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2713 && (keysym == XK_KP_Decimal))
2714 {
2715 lpChar[0] = 0;
2716 ret = 0;
2717 }
2718 else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
2719 && (keysym == XK_Return || keysym == XK_KP_Enter))
2720 {
2721 lpChar[0] = '\n';
2722 ret = 1;
2723 }
2724
2725 /* Hack to detect an XLookupString hard-coded to Latin1 */
2726 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
2727 {
2728 bufW[0] = (BYTE)lpChar[0];
2729 goto found;
2730 }
2731
2732 /* perform translation to unicode */
2733 if(ret)
2734 {
2735 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2736 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2737 }
2738 }
2739
2740 found:
2741 if (buf != lpChar)
2742 HeapFree(GetProcessHeap(), 0, lpChar);
2743
2744 /* Null-terminate the buffer, if there's room. MSDN clearly states that the
2745 caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
2746 if (1 <= ret && ret < bufW_size)
2747 bufW[ret] = 0;
2748
2749 TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2750 return ret;
2751 }
2752
2753 /***********************************************************************
2754 * Beep (X11DRV.@)
2755 */
2756 void CDECL X11DRV_Beep(void)
2757 {
2758 wine_tsx11_lock();
2759 XBell(gdi_display, 0);
2760 wine_tsx11_unlock();
2761 }
2762
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.