4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
33 #ifdef HAVE_X11_XKBLIB_H
34 #include <X11/XKBlib.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
49 #include "wine/server.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(keyboard
);
54 WINE_DECLARE_DEBUG_CHANNEL(key
);
56 /* key state table bits:
57 0x80 -> key is pressed
58 0x40 -> key got pressed since last time
59 0x01 -> key is toggled
61 BYTE key_state_table
[256];
63 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
64 or a WM_KEYUP message */
66 static int min_keycode
, max_keycode
, keysyms_per_keycode
;
67 static WORD keyc2vkey
[256], keyc2scan
[256];
69 static int NumLockMask
, ScrollLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
71 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
73 /* Keyboard translation tables */
75 static const WORD main_key_scan_qwerty
[MAIN_LEN
] =
77 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
78 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
79 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
80 /* q w e r t y u i o p [ ] */
81 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
82 /* a s d f g h j k l ; ' \ */
83 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
84 /* z x c v b n m , . / */
85 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
86 0x56 /* the 102nd key (actually to the right of l-shift) */
89 static const WORD main_key_scan_abnt_qwerty
[MAIN_LEN
] =
91 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
92 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
93 /* q w e r t y u i o p [ ] */
94 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
95 /* a s d f g h j k l ; ' \ */
96 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
97 /* \ z x c v b n m , . / */
98 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
99 0x56, /* the 102nd key (actually to the right of l-shift) */
102 static const WORD main_key_scan_dvorak
[MAIN_LEN
] =
104 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
105 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
106 /* ' , . p y f g c r l / = */
107 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
108 /* a o e u i d h t n s - \ */
109 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
110 /* ; q j k x b m w v z */
111 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
112 0x56 /* the 102nd key (actually to the right of l-shift) */
115 static const WORD main_key_scan_qwerty_jp106
[MAIN_LEN
] =
117 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
118 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
119 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
120 /* q w e r t y u i o p @ [ */
121 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
122 /* a s d f g h j k l ; : ] */
123 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
124 /* z x c v b n m , . / */
125 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
126 0x56 /* the 102nd key (actually to the right of l-shift) */
129 static const WORD main_key_scan_qwerty_macjp
[MAIN_LEN
] =
131 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
132 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
133 /* q w e r t y u i o p @ [ */
134 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
135 /* a s d f g h j k l ; : ] */
136 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
137 /* z x c v b n m , . / */
138 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
139 0x73 /* the 102nd key (actually to the right of l-shift) */
143 static const WORD main_key_vkey_qwerty
[MAIN_LEN
] =
145 /* NOTE: this layout must concur with the scan codes layout above */
146 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
147 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
148 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
149 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
150 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
153 static const WORD main_key_vkey_qwerty_jp106
[MAIN_LEN
] =
155 /* NOTE: this layout must concur with the scan codes layout above */
156 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,VK_OEM_3
,
157 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
158 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
159 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
160 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
163 static const WORD main_key_vkey_qwerty_macjp
[MAIN_LEN
] =
165 /* NOTE: this layout must concur with the scan codes layout above */
166 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_7
,VK_OEM_5
,
167 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3
,VK_OEM_4
,
168 'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS
,VK_OEM_1
,VK_OEM_6
,
169 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
170 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
173 static const WORD main_key_vkey_qwerty_v2
[MAIN_LEN
] =
175 /* NOTE: this layout must concur with the scan codes layout above */
176 VK_OEM_5
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS
,VK_OEM_4
,
177 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
178 'A','S','D','F','G','H','J','K','L',VK_OEM_3
,VK_OEM_7
,VK_OEM_2
,
179 'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_MINUS
,
180 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
183 static const WORD main_key_vkey_qwertz
[MAIN_LEN
] =
185 /* NOTE: this layout must concur with the scan codes layout above */
186 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
187 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
188 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
189 'Y','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
190 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
193 static const WORD main_key_vkey_qwertz_105
[MAIN_LEN
] =
195 /* NOTE: this layout must concur with the scan codes layout above */
196 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
197 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
198 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_7
,VK_OEM_5
,
199 VK_OEM_102
,'Y','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
202 static const WORD main_key_vkey_abnt_qwerty
[MAIN_LEN
] =
204 /* NOTE: this layout must concur with the scan codes layout above */
205 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,
206 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4
,VK_OEM_6
,
207 'A','S','D','F','G','H','J','K','L',VK_OEM_1
,VK_OEM_8
,VK_OEM_5
,
208 VK_OEM_7
,'Z','X','C','V','B','N','M',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
209 VK_OEM_102
, /* the 102nd key (actually to the right of l-shift) */
212 static const WORD main_key_vkey_azerty
[MAIN_LEN
] =
214 /* NOTE: this layout must concur with the scan codes layout above */
215 VK_OEM_7
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_PLUS
,
216 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6
,VK_OEM_1
,
217 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3
,VK_OEM_5
,
218 'W','X','C','V','B','N',VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,VK_OEM_8
,
219 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
222 static const WORD main_key_vkey_dvorak
[MAIN_LEN
] =
224 /* NOTE: this layout must concur with the scan codes layout above */
225 VK_OEM_3
,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4
,VK_OEM_6
,
226 VK_OEM_7
,VK_OEM_COMMA
,VK_OEM_PERIOD
,'P','Y','F','G','C','R','L',VK_OEM_2
,VK_OEM_PLUS
,
227 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS
,VK_OEM_5
,
228 VK_OEM_1
,'Q','J','K','X','B','M','W','V','Z',
229 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
232 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
234 /* the VK mappings for the main keyboard will be auto-assigned as before,
235 so what we have here is just the character tables */
236 /* order: Normal, Shift, AltGr, Shift-AltGr */
237 /* We recommend you write just what is guaranteed to be correct (i.e. what's
238 written on the keycaps), not the bunch of special characters behind AltGr
239 and Shift-AltGr if it can vary among different X servers */
240 /* Remember that your 102nd key (to the right of l-shift) should be on a
241 separate line, see existing tables */
242 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
243 /* Remember to also add your new table to the layout index table far below! */
245 /*** German Logitech Desktop Pro keyboard layout */
246 static const char main_key_DE_logitech
[MAIN_LEN
][4] =
248 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
249 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
251 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
255 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
256 static const char main_key_US
[MAIN_LEN
][4] =
258 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
259 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
260 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
261 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
264 /*** United States keyboard layout (phantom key version) */
265 /* (XFree86 reports the <> key even if it's not physically there) */
266 static const char main_key_US_phantom
[MAIN_LEN
][4] =
268 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
269 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
270 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
271 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
272 "<>" /* the phantom key */
275 /*** United States keyboard layout (dvorak version) */
276 static const char main_key_US_dvorak
[MAIN_LEN
][4] =
278 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
279 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
280 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
281 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
284 /*** British keyboard layout */
285 static const char main_key_UK
[MAIN_LEN
][4] =
287 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
288 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
290 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
294 /*** French keyboard layout (setxkbmap fr) */
295 static const char main_key_FR
[MAIN_LEN
][4] =
297 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
298 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
299 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
300 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
304 /*** Icelandic keyboard layout (setxkbmap is) */
305 static const char main_key_IS
[MAIN_LEN
][4] =
307 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
308 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
309 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
310 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
314 /*** German keyboard layout (setxkbmap de) */
315 static const char main_key_DE
[MAIN_LEN
][4] =
317 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","´`",
318 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
319 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
320 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
324 /*** German keyboard layout without dead keys */
325 static const char main_key_DE_nodead
[MAIN_LEN
][4] =
327 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
328 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
330 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
334 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
335 static const char main_key_DE_nodead_105
[MAIN_LEN
][4] =
337 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
338 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
339 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
340 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
343 /*** Swiss German keyboard layout (setxkbmap ch -variant de) */
344 static const char main_key_SG
[MAIN_LEN
][4] =
346 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
347 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
348 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
349 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
353 /*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
354 static const char main_key_SF
[MAIN_LEN
][4] =
356 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
357 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
358 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
359 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
363 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
364 static const char main_key_NO
[MAIN_LEN
][4] =
366 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
367 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
368 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
369 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
373 /*** Danish keyboard layout (setxkbmap dk) */
374 static const char main_key_DA
[MAIN_LEN
][4] =
376 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
377 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
378 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
379 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
383 /*** Swedish keyboard layout (setxkbmap se) */
384 static const char main_key_SE
[MAIN_LEN
][4] =
386 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
387 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
388 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
389 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
393 /*** Estonian keyboard layout (setxkbmap ee) */
394 static const char main_key_ET
[MAIN_LEN
][4] =
396 "·~","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
397 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ",
398 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
399 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
403 /*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
404 static const char main_key_CF
[MAIN_LEN
][4] =
406 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
407 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
408 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
409 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
413 /*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
414 static const char main_key_CA_fr
[MAIN_LEN
][4] =
416 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
417 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
418 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
419 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
423 /*** Canadian keyboard layout (setxkbmap ca) */
424 static const char main_key_CA
[MAIN_LEN
][4] =
426 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
427 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
428 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
429 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
433 /*** Portuguese keyboard layout (setxkbmap pt) */
434 static const char main_key_PT
[MAIN_LEN
][4] =
436 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
437 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
438 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
439 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
443 /*** Italian keyboard layout (setxkbmap it) */
444 static const char main_key_IT
[MAIN_LEN
][4] =
446 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
447 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
448 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
449 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
453 /*** Finnish keyboard layout (setxkbmap fi) */
454 static const char main_key_FI
[MAIN_LEN
][4] =
456 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
457 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
458 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
459 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
463 /*** Bulgarian bds keyboard layout */
464 static const char main_key_BG_bds
[MAIN_LEN
][4] =
466 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
467 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
468 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
469 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
470 "<>" /* the phantom key */
473 /*** Bulgarian phonetic keyboard layout */
474 static const char main_key_BG_phonetic
[MAIN_LEN
][4] =
476 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
477 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
478 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
479 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
480 "<>" /* the phantom key */
483 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
484 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
485 static const char main_key_BY
[MAIN_LEN
][4] =
487 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
488 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
489 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
490 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
494 /*** Russian keyboard layout (contributed by Pavel Roskin) */
495 static const char main_key_RU
[MAIN_LEN
][4] =
497 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
498 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
499 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
500 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
503 /*** Russian keyboard layout (phantom key version) */
504 static const char main_key_RU_phantom
[MAIN_LEN
][4] =
506 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
507 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
508 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
509 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
510 "<>" /* the phantom key */
513 /*** Russian keyboard layout KOI8-R */
514 static const char main_key_RU_koi8r
[MAIN_LEN
][4] =
516 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
517 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
518 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
519 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
520 "<>" /* the phantom key */
523 /*** Russian keyboard layout cp1251 */
524 static const char main_key_RU_cp1251
[MAIN_LEN
][4] =
526 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
527 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
528 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
529 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
530 "<>" /* the phantom key */
533 /*** Russian phonetic keyboard layout */
534 static const char main_key_RU_phonetic
[MAIN_LEN
][4] =
536 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
537 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
538 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
539 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
540 "<>" /* the phantom key */
543 /*** Ukrainian keyboard layout KOI8-U */
544 static const char main_key_UA
[MAIN_LEN
][4] =
546 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
547 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
548 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
549 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
550 "<>" /* the phantom key */
553 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
554 /*** (as it appears on most of keyboards sold today) */
555 static const char main_key_UA_std
[MAIN_LEN
][4] =
557 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
558 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
559 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
560 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
561 "<>" /* the phantom key */
564 /*** Russian keyboard layout KOI8-R (pair to the previous) */
565 static const char main_key_RU_std
[MAIN_LEN
][4] =
567 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
568 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
569 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
570 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
571 "<>" /* the phantom key */
574 /*** Spanish keyboard layout (setxkbmap es) */
575 static const char main_key_ES
[MAIN_LEN
][4] =
577 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
578 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
579 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
580 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
584 /*** Belgian keyboard layout ***/
585 static const char main_key_BE
[MAIN_LEN
][4] =
587 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
588 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
589 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
590 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
594 /*** Hungarian keyboard layout (setxkbmap hu) */
595 static const char main_key_HU
[MAIN_LEN
][4] =
597 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
598 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
599 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
600 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
604 /*** Polish (programmer's) keyboard layout ***/
605 static const char main_key_PL
[MAIN_LEN
][4] =
607 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
608 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
609 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
610 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
614 /*** Slovenian keyboard layout (setxkbmap si) ***/
615 static const char main_key_SI
[MAIN_LEN
][4] =
617 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
618 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
619 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
620 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
624 /*** Serbian keyboard layout (setxkbmap sr) ***/
625 static const char main_key_SR
[MAIN_LEN
][4] =
627 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
628 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
629 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
630 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
631 "<>" /* the phantom key */
634 /*** Serbian keyboard layout (setxkbmap us,sr) ***/
635 static const char main_key_US_SR
[MAIN_LEN
][4] =
637 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
638 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
639 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
640 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
641 "<>" /* the phantom key */
644 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
645 static const char main_key_HR_jelly
[MAIN_LEN
][4] =
647 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
648 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
649 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
650 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
654 /*** Croatian keyboard layout (setxkbmap hr) ***/
655 static const char main_key_HR
[MAIN_LEN
][4] =
657 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
658 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
659 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
660 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
664 /*** Japanese 106 keyboard layout ***/
665 static const char main_key_JA_jp106
[MAIN_LEN
][4] =
667 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
668 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
669 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
670 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
674 static const char main_key_JA_macjp
[MAIN_LEN
][4] =
676 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
677 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
678 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
679 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
683 /*** Japanese pc98x1 keyboard layout ***/
684 static const char main_key_JA_pc98x1
[MAIN_LEN
][4] =
686 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
687 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
688 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
689 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
693 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
694 static const char main_key_PT_br
[MAIN_LEN
][4] =
696 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
697 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
698 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
699 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
702 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
703 static const char main_key_PT_br_alt_gr
[MAIN_LEN
][4] =
705 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
706 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
707 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
708 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
711 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
712 static const char main_key_US_intl
[MAIN_LEN
][4] =
714 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
715 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
716 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
717 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
720 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
721 - dead_abovering replaced with degree - no symbol in iso8859-2
722 - brokenbar replaced with bar */
723 static const char main_key_SK
[MAIN_LEN
][4] =
725 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
726 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
727 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
728 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
732 /*** Czech keyboard layout (setxkbmap cz) */
733 static const char main_key_CZ
[MAIN_LEN
][4] =
735 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
736 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
737 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
738 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
742 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
743 static const char main_key_CZ_qwerty
[MAIN_LEN
][4] =
745 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
746 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
747 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
748 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
752 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
753 static const char main_key_SK_prog
[MAIN_LEN
][4] =
755 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
756 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
757 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
758 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
762 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
763 static const char main_key_CS
[MAIN_LEN
][4] =
765 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
766 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
767 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
768 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
772 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
773 static const char main_key_LA
[MAIN_LEN
][4] =
775 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
776 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
777 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
778 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
782 /*** Lithuanian keyboard layout (setxkbmap lt) */
783 static const char main_key_LT_B
[MAIN_LEN
][4] =
785 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
786 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
787 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
788 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
792 /*** Turkish keyboard Layout */
793 static const char main_key_TK
[MAIN_LEN
][4] =
795 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
796 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
797 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
798 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
801 /*** Turkish keyboard layout (setxkbmap tr) */
802 static const char main_key_TR
[MAIN_LEN
][4] =
804 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
805 "qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
806 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
807 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
811 /*** Turkish F keyboard layout (setxkbmap trf) */
812 static const char main_key_TR_F
[MAIN_LEN
][4] =
814 "+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
815 "fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
816 "uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
817 "jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
821 /*** Israelian keyboard layout (setxkbmap us,il) */
822 static const char main_key_IL
[MAIN_LEN
][4] =
824 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
825 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
826 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
827 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
831 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
832 static const char main_key_IL_phonetic
[MAIN_LEN
][4] =
834 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
835 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
836 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
837 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
841 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
842 static const char main_key_IL_saharon
[MAIN_LEN
][4] =
844 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
845 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
846 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
847 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
851 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
852 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
853 message since they have different characters in gr and el XFree86 layouts. */
854 static const char main_key_EL
[MAIN_LEN
][4] =
856 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
857 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
858 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
859 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
863 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
864 static const char main_key_th
[MAIN_LEN
][4] =
866 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
867 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pPÂ","[{º°","]}Å,",
868 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
869 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
872 /*** VNC keyboard layout */
873 static const WORD main_key_scan_vnc
[MAIN_LEN
] =
875 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
876 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,
880 static const WORD main_key_vkey_vnc
[MAIN_LEN
] =
882 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS
,VK_OEM_PLUS
,VK_OEM_4
,VK_OEM_6
,VK_OEM_1
,VK_OEM_7
,VK_OEM_3
,VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,VK_OEM_5
,
883 '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',
887 static const char main_key_vnc
[MAIN_LEN
][4] =
889 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
890 "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"
893 /*** Dutch keyboard layout (setxkbmap nl) ***/
894 static const char main_key_NL
[MAIN_LEN
][4] =
896 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
897 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
898 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
899 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
905 /*** Layout table. Add your keyboard mappings to this list */
906 static const struct {
907 LCID lcid
; /* input locale identifier, look for LOCALE_ILANGUAGE
908 in the appropriate dlls/kernel/nls/.nls file */
910 const char (*key
)[MAIN_LEN
][4];
911 const WORD (*scan
)[MAIN_LEN
]; /* scan codes mapping */
912 const WORD (*vkey
)[MAIN_LEN
]; /* virtual key codes mapping */
914 {0x0409, "United States keyboard layout", &main_key_US
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
915 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
916 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak
, &main_key_scan_dvorak
, &main_key_vkey_dvorak
},
917 {0x0409, "United States International keyboard layout", &main_key_US_intl
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
918 {0x0809, "British keyboard layout", &main_key_UK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
919 {0x0407, "German keyboard layout", &main_key_DE
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
920 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
921 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
922 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105
, &main_key_scan_qwerty
, &main_key_vkey_qwertz_105
},
923 {0x0807, "Swiss German keyboard layout", &main_key_SG
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
924 {0x100c, "Swiss French keyboard layout", &main_key_SF
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
925 {0x041d, "Swedish keyboard layout", &main_key_SE
, &main_key_scan_qwerty
, &main_key_vkey_qwerty_v2
},
926 {0x0425, "Estonian keyboard layout", &main_key_ET
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
927 {0x0414, "Norwegian keyboard layout", &main_key_NO
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
928 {0x0406, "Danish keyboard layout", &main_key_DA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
929 {0x040c, "French keyboard layout", &main_key_FR
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
930 {0x0c0c, "Canadian French keyboard layout", &main_key_CF
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
931 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
932 {0x0c0c, "Canadian keyboard layout", &main_key_CA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
933 {0x080c, "Belgian keyboard layout", &main_key_BE
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
934 {0x0816, "Portuguese keyboard layout", &main_key_PT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
935 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br
, &main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
936 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr
,&main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
937 {0x040b, "Finnish keyboard layout", &main_key_FI
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
938 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
939 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
940 {0x0423, "Belarusian keyboard layout", &main_key_BY
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
941 {0x0419, "Russian keyboard layout", &main_key_RU
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
942 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
943 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
944 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
945 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
946 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
947 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
948 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
949 {0x040a, "Spanish keyboard layout", &main_key_ES
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
950 {0x0410, "Italian keyboard layout", &main_key_IT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
951 {0x040f, "Icelandic keyboard layout", &main_key_IS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
952 {0x040e, "Hungarian keyboard layout", &main_key_HU
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
953 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
954 {0x0424, "Slovenian keyboard layout", &main_key_SI
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
955 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
956 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
957 {0x041a, "Croatian keyboard layout", &main_key_HR
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
958 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
959 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106
, &main_key_scan_qwerty_jp106
, &main_key_vkey_qwerty_jp106
},
960 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp
, &main_key_scan_qwerty_macjp
, &main_key_vkey_qwerty_macjp
},
961 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
962 {0x041b, "Slovak keyboard layout", &main_key_SK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
963 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
964 {0x0405, "Czech keyboard layout", &main_key_CS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
965 {0x0405, "Czech keyboard layout cz", &main_key_CZ
, &main_key_scan_qwerty
, &main_key_vkey_qwertz
},
966 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
967 {0x040a, "Latin American keyboard layout", &main_key_LA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
968 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
969 {0x041f, "Turkish keyboard layout", &main_key_TK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
970 {0x041f, "Turkish keyboard layout tr", &main_key_TR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
971 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
972 {0x040d, "Israelian keyboard layout", &main_key_IL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
973 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
974 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
975 {0x0409, "VNC keyboard layout", &main_key_vnc
, &main_key_scan_vnc
, &main_key_vkey_vnc
},
976 {0x0408, "Greek keyboard layout", &main_key_EL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
977 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
978 {0x0413, "Dutch keyboard layout", &main_key_NL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
980 {0, NULL
, NULL
, NULL
, NULL
} /* sentinel */
982 static unsigned kbd_layout
=0; /* index into above table of layouts */
984 /* maybe more of these scancodes should be extended? */
985 /* extended must be set for ALT_R, CTRL_R,
986 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
987 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
988 /* FIXME should we set extended bit for NumLock ? My
989 * Windows does ... DF */
990 /* Yes, to distinguish based on scan codes, also
991 for PrtScn key ... GA */
993 static const WORD nonchar_key_vkey
[256] =
996 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
998 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
999 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
1000 0, 0, 0, VK_ESCAPE
, 0, 0, 0, 0, /* FF18 */
1002 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
1003 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
1004 0, VK_HANGUL
, 0, 0, VK_HANJA
, 0, 0, 0, /* FF30 */
1005 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
1006 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
1007 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
1009 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, /* FF50 */
1010 VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
,
1011 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1013 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0,0,0, VK_APPS
, /* FF60 */
1014 0, VK_CANCEL
, VK_HELP
, VK_CANCEL
, 0, 0, 0, 0, /* FF68 */
1015 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1017 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK
, /* FF78 */
1018 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1019 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
1020 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
1021 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, /* FF98 */
1022 VK_END
, VK_CLEAR
, VK_INSERT
, VK_DELETE
,
1023 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1024 0, 0, VK_MULTIPLY
, VK_ADD
, /* FFA8 */
1025 VK_SEPARATOR
, VK_SUBTRACT
, VK_DECIMAL
, VK_DIVIDE
,
1026 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, /* FFB0 */
1027 VK_NUMPAD4
, VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
,
1028 VK_NUMPAD8
, VK_NUMPAD9
, 0, 0, 0, VK_OEM_NEC_EQUAL
, /* FFB8 */
1031 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
1032 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
, 0, 0, /* FFC8 */
1033 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
1034 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1036 0, VK_LSHIFT
, VK_RSHIFT
, VK_LCONTROL
, /* FFE0 */
1037 VK_RCONTROL
, VK_CAPITAL
, 0, VK_MENU
,
1038 VK_MENU
, VK_LMENU
, VK_RMENU
, 0, 0, 0, 0, 0, /* FFE8 */
1039 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1040 0, 0, 0, 0, 0, 0, 0, VK_DELETE
/* FFF8 */
1043 static const WORD nonchar_key_scan
[256] =
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1048 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1049 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1050 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1059 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1062 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
1063 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
1067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1068 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1069 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1070 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1072 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1073 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1074 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1077 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1078 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
1079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1082 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1083 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
1084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1088 static const WORD xfree86_vendor_key_vkey
[256] =
1090 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1091 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1092 0, VK_VOLUME_DOWN
, VK_VOLUME_MUTE
, VK_VOLUME_UP
, /* 1008FF10 */
1093 VK_MEDIA_PLAY_PAUSE
, VK_MEDIA_STOP
,
1094 VK_MEDIA_PREV_TRACK
, VK_MEDIA_NEXT_TRACK
,
1095 0, VK_LAUNCH_MAIL
, 0, VK_BROWSER_SEARCH
, /* 1008FF18 */
1096 0, 0, 0, VK_BROWSER_HOME
,
1097 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK
, VK_BROWSER_FORWARD
, /* 1008FF20 */
1098 VK_BROWSER_STOP
, VK_BROWSER_REFRESH
, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1099 VK_BROWSER_FAVORITES
, 0, VK_LAUNCH_MEDIA_SELECT
, 0, /* 1008FF30 */
1101 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1102 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1103 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1104 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1105 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1106 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1107 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1108 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1109 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1110 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1111 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1112 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1113 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1114 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1115 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1116 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1117 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1118 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1119 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1120 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1121 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1122 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1123 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1124 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1125 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1128 /* Returns the Windows virtual key code associated with the X event <e> */
1129 /* x11 lock must be held */
1130 static WORD
EVENT_event_to_vkey( XIC xic
, XKeyEvent
*e
)
1136 /* Clients should pass only KeyPress events to XmbLookupString */
1137 if (xic
&& e
->type
== KeyPress
)
1138 XmbLookupString(xic
, e
, buf
, sizeof(buf
), &keysym
, &status
);
1140 XLookupString(e
, buf
, sizeof(buf
), &keysym
, NULL
);
1142 if ((e
->state
& NumLockMask
) &&
1143 (keysym
== XK_KP_Separator
|| keysym
== XK_KP_Decimal
||
1144 (keysym
>= XK_KP_0
&& keysym
<= XK_KP_9
)))
1145 /* Only the Keypad keys 0-9 and . send different keysyms
1146 * depending on the NumLock state */
1147 return nonchar_key_vkey
[keysym
& 0xFF];
1149 TRACE_(key
)("e->keycode = %x\n", e
->keycode
);
1151 return keyc2vkey
[e
->keycode
];
1155 /***********************************************************************
1156 * X11DRV_send_keyboard_input
1158 void X11DRV_send_keyboard_input( WORD wVk
, WORD wScan
, DWORD event_flags
, DWORD time
,
1159 DWORD dwExtraInfo
, UINT injected_flags
)
1162 KBDLLHOOKSTRUCT hook
;
1163 WORD flags
, wVkStripped
, wVkL
, wVkR
, vk_hook
= wVk
;
1166 flags
= LOBYTE(wScan
);
1168 if (event_flags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1169 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1171 /* strip left/right for menu, control, shift */
1177 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1178 wVkStripped
= VK_MENU
;
1185 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1186 wVkStripped
= VK_CONTROL
;
1193 wVk
= (event_flags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1194 wVkStripped
= VK_SHIFT
;
1199 wVkStripped
= wVkL
= wVkR
= wVk
;
1202 if (event_flags
& KEYEVENTF_KEYUP
)
1205 if ((key_state_table
[VK_MENU
] & 0x80) &&
1206 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1207 || !(key_state_table
[VK_CONTROL
] & 0x80)))
1209 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1210 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1211 message
= WM_SYSKEYUP
;
1214 flags
|= KF_REPEAT
| KF_UP
;
1218 message
= WM_KEYDOWN
;
1219 if ((key_state_table
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1220 !(key_state_table
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1222 message
= WM_SYSKEYDOWN
;
1223 TrackSysKey
= wVkStripped
;
1225 if (key_state_table
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1228 TRACE_(key
)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
1229 wVk
, MAKELPARAM( 1, flags
), key_state_table
[wVk
] );
1231 /* Hook gets whatever key was sent. */
1232 hook
.vkCode
= vk_hook
;
1233 hook
.scanCode
= wScan
;
1234 hook
.flags
= (flags
>> 8) | injected_flags
;
1236 hook
.dwExtraInfo
= dwExtraInfo
;
1237 if (HOOK_CallHooks( WH_KEYBOARD_LL
, HC_ACTION
, message
, (LPARAM
)&hook
, TRUE
)) return;
1239 if (event_flags
& KEYEVENTF_KEYUP
)
1241 key_state_table
[wVk
] &= ~0x80;
1242 key_state_table
[wVkStripped
] = key_state_table
[wVkL
] | key_state_table
[wVkR
];
1246 if (!(key_state_table
[wVk
] & 0x80)) key_state_table
[wVk
] ^= 0x01;
1247 key_state_table
[wVk
] |= 0xc0;
1248 key_state_table
[wVkStripped
] = key_state_table
[wVkL
] | key_state_table
[wVkR
];
1251 if (key_state_table
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1253 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1255 SERVER_START_REQ( send_hardware_message
)
1257 req
->id
= (injected_flags
& LLKHF_INJECTED
) ? 0 : GetCurrentThreadId();
1261 req
->lparam
= MAKELPARAM( 1 /* repeat count */, flags
);
1262 req
->x
= cursor_pos
.x
;
1263 req
->y
= cursor_pos
.y
;
1265 req
->info
= dwExtraInfo
;
1266 wine_server_call( req
);
1272 /***********************************************************************
1273 * KEYBOARD_UpdateOneState
1275 * Updates internal state for <vkey>, depending on key <state> under X
1278 static inline void KEYBOARD_UpdateOneState ( WORD vkey
, WORD scan
, int state
, DWORD time
)
1280 /* Do something if internal table state != X state for keycode */
1281 if (((key_state_table
[vkey
& 0xff] & 0x80)!=0) != state
)
1283 DWORD flags
= vkey
& 0x100 ? KEYEVENTF_EXTENDEDKEY
: 0;
1285 if (!state
) flags
|= KEYEVENTF_KEYUP
;
1287 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1288 vkey
, key_state_table
[vkey
& 0xff]);
1290 /* Fake key being pressed inside wine */
1291 X11DRV_send_keyboard_input( vkey
& 0xff, scan
& 0xff, flags
, time
, 0, 0 );
1293 TRACE("State after %#.2x\n", key_state_table
[vkey
& 0xff]);
1297 /***********************************************************************
1298 * X11DRV_KeymapNotify
1300 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1302 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1303 * from wine to another application and back.
1304 * Toggle keys are handled in HandleEvent.
1306 void X11DRV_KeymapNotify( HWND hwnd
, XEvent
*event
)
1309 DWORD time
= GetCurrentTime();
1311 /* the minimum keycode is always greater or equal to 8, so we can
1312 * skip the first 8 values, hence start at 1
1314 for (i
= 1; i
< 32; i
++)
1316 for (j
= 0; j
< 8; j
++)
1318 WORD vkey
= keyc2vkey
[(i
* 8) + j
];
1319 WORD scan
= keyc2scan
[(i
* 8) + j
];
1320 int state
= (event
->xkeymap
.key_vector
[i
] & (1<<j
)) != 0;
1330 KEYBOARD_UpdateOneState( vkey
, scan
, state
, time
);
1337 static void update_lock_state(BYTE vkey
, WORD scan
, DWORD time
)
1339 DWORD flags
= vkey
== VK_NUMLOCK
? KEYEVENTF_EXTENDEDKEY
: 0;
1341 if (key_state_table
[vkey
] & 0x80) flags
^= KEYEVENTF_KEYUP
;
1343 X11DRV_send_keyboard_input( vkey
, scan
, flags
, time
, 0, 0 );
1344 X11DRV_send_keyboard_input( vkey
, scan
, flags
^ KEYEVENTF_KEYUP
, time
, 0, 0 );
1347 /***********************************************************************
1350 * Handle a X key event
1352 void X11DRV_KeyEvent( HWND hwnd
, XEvent
*xev
)
1354 XKeyEvent
*event
= &xev
->xkey
;
1357 WORD vkey
= 0, bScan
;
1360 XIC xic
= X11DRV_get_ic( hwnd
);
1361 DWORD event_time
= EVENT_x11_time_to_win32_time(event
->time
);
1364 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1365 event
->type
, event
->window
, event
->state
, event
->keycode
);
1368 /* Clients should pass only KeyPress events to XmbLookupString */
1369 if (xic
&& event
->type
== KeyPress
)
1370 ascii_chars
= XmbLookupString(xic
, event
, Str
, sizeof(Str
), &keysym
, &status
);
1372 ascii_chars
= XLookupString(event
, Str
, sizeof(Str
), &keysym
, NULL
);
1373 wine_tsx11_unlock();
1375 TRACE_(key
)("nbyte = %d, status 0x%x\n", ascii_chars
, status
);
1377 if (status
== XBufferOverflow
)
1378 ERR("Buffer Overflow need %i!\n",ascii_chars
);
1380 if (status
== XLookupChars
)
1382 X11DRV_XIMLookupChars( Str
, ascii_chars
);
1386 /* If XKB extensions are used, the state mask for AltGr will use the group
1387 index instead of the modifier mask. The group index is set in bits
1388 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1389 pressed, look if the group index is different than 0. From XKB
1390 extension documentation, the group index for AltGr should be 2
1391 (event->state = 0x2000). It's probably better to not assume a
1392 predefined group index and find it dynamically
1394 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1395 /* Save also all possible modifier states. */
1396 AltGrMask
= event
->state
& (0x6000 | Mod1Mask
| Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
);
1402 ksname
= XKeysymToString(keysym
);
1403 wine_tsx11_unlock();
1406 TRACE_(key
)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
1407 (event
->type
== KeyPress
) ? "KeyPress" : "KeyRelease",
1408 keysym
, ksname
, ascii_chars
, debugstr_an(Str
, ascii_chars
));
1412 vkey
= EVENT_event_to_vkey(xic
,event
);
1413 /* X returns keycode 0 for composed characters */
1414 if (!vkey
&& ascii_chars
) vkey
= VK_NONAME
;
1415 wine_tsx11_unlock();
1417 TRACE_(key
)("keycode 0x%x converted to vkey 0x%x\n",
1418 event
->keycode
, vkey
);
1423 if ( event
->type
== KeyRelease
) dwFlags
|= KEYEVENTF_KEYUP
;
1424 if ( vkey
& 0x100 ) dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
1427 /* Note: X sets the below states on key down and clears them on key up.
1428 Windows triggers them on key down. */
1430 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1431 if (!(key_state_table
[VK_CAPITAL
] & 0x01) != !(event
->state
& LockMask
) &&
1434 TRACE("Adjusting CapsLock state (%#.2x)\n", key_state_table
[VK_CAPITAL
]);
1435 update_lock_state(VK_CAPITAL
, 0x3A, event_time
);
1438 /* Adjust the NUMLOCK state if it has been changed outside wine */
1439 if (!(key_state_table
[VK_NUMLOCK
] & 0x01) != !(event
->state
& NumLockMask
) &&
1440 (vkey
& 0xff) != VK_NUMLOCK
)
1442 TRACE("Adjusting NumLock state (%#.2x)\n", key_state_table
[VK_NUMLOCK
]);
1443 update_lock_state(VK_NUMLOCK
, 0x45, event_time
);
1446 /* Adjust the SCROLLLOCK state if it has been changed outside wine */
1447 if (!(key_state_table
[VK_SCROLL
] & 0x01) != !(event
->state
& ScrollLockMask
) &&
1450 TRACE("Adjusting ScrLock state (%#.2x)\n", key_state_table
[VK_SCROLL
]);
1451 update_lock_state(VK_SCROLL
, 0x46, event_time
);
1454 /* we get this event repeatedly if we hold down the key (keyboard repeat) */
1455 if ((VK_F12
== vkey
) && (event
->type
== KeyPress
) && getenv("WINEDELAY")) {
1456 __wine_dbg_toggle_block();
1459 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
1460 TRACE_(key
)("bScan = 0x%02x.\n", bScan
);
1462 X11DRV_send_keyboard_input( vkey
& 0xff, bScan
, dwFlags
, event_time
, 0, 0 );
1465 /**********************************************************************
1466 * X11DRV_KEYBOARD_DetectLayout
1468 * Called from X11DRV_InitKeyboard
1469 * This routine walks through the defined keyboard layouts and selects
1470 * whichever matches most closely.
1471 * X11 lock must be held.
1474 X11DRV_KEYBOARD_DetectLayout( Display
*display
)
1476 unsigned current
, match
, mismatch
, seq
, i
, syms
;
1477 int score
, keyc
, key
, pkey
, ok
;
1479 const char (*lkey
)[MAIN_LEN
][4];
1480 unsigned max_seq
= 0;
1481 int max_score
= 0, ismatch
= 0;
1484 syms
= keysyms_per_keycode
;
1486 WARN("%d keysyms per keycode not supported, set to 4\n", syms
);
1490 memset( ckey
, 0, sizeof(ckey
) );
1491 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1492 /* get data for keycode from X server */
1493 for (i
= 0; i
< syms
; i
++) {
1494 if (!(keysym
= XKeycodeToKeysym (display
, keyc
, i
))) continue;
1495 /* Allow both one-byte and two-byte national keysyms */
1496 if ((keysym
< 0x8000) && (keysym
!= ' '))
1499 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[keyc
][i
], 1, NULL
))
1502 TRACE("XKB could not translate keysym %ld\n", keysym
);
1503 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1504 * with appropriate ShiftMask and Mode_switch, use XLookupString
1505 * to get character in the local encoding.
1507 ckey
[keyc
][i
] = keysym
& 0xFF;
1511 ckey
[keyc
][i
] = KEYBOARD_MapDeadKeysym(keysym
);
1516 for (current
= 0; main_key_tab
[current
].comment
; current
++) {
1517 TRACE("Attempting to match against \"%s\"\n", main_key_tab
[current
].comment
);
1522 lkey
= main_key_tab
[current
].key
;
1524 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1525 if (ckey
[keyc
][0]) {
1526 /* search for a match in layout table */
1527 /* right now, we just find an absolute match for defined positions */
1528 /* (undefined positions are ignored, so if it's defined as "3#" in */
1529 /* the table, it's okay that the X server has "3#£", for example) */
1530 /* however, the score will be higher for longer matches */
1531 for (key
= 0; key
< MAIN_LEN
; key
++) {
1532 for (ok
= 0, i
= 0; (ok
>= 0) && (i
< syms
); i
++) {
1533 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] == ckey
[keyc
][i
]))
1535 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[keyc
][i
]))
1543 /* count the matches and mismatches */
1546 /* and how much the keycode order matches */
1547 if (key
> pkey
) seq
++;
1550 /* print spaces instead of \0's */
1552 for (i
= 0; i
< 4; i
++) str
[i
] = ckey
[keyc
][i
] ? ckey
[keyc
][i
] : ' ';
1554 TRACE_(key
)("mismatch for keysym 0x%04lX, keycode %d, got %s\n", keysym
, keyc
, str
);
1560 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1561 match
, mismatch
, seq
, score
);
1562 if ((score
> max_score
) ||
1563 ((score
== max_score
) && (seq
> max_seq
))) {
1564 /* best match so far */
1565 kbd_layout
= current
;
1568 ismatch
= !mismatch
;
1571 /* we're done, report results if necessary */
1573 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1574 main_key_tab
[kbd_layout
].comment
);
1576 TRACE("detected layout is \"%s\"\n", main_key_tab
[kbd_layout
].comment
);
1579 /**********************************************************************
1580 * X11DRV_InitKeyboard
1582 void X11DRV_InitKeyboard( Display
*display
)
1585 XModifierKeymap
*mmp
;
1589 WORD scan
, vkey
, OEMvkey
;
1590 int keyc
, i
, keyn
, syms
;
1591 char ckey
[4]={0,0,0,0};
1592 const char (*lkey
)[MAIN_LEN
][4];
1593 char vkey_used
[256] = { 0 };
1596 XDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
1597 ksp
= XGetKeyboardMapping(display
, min_keycode
,
1598 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
1599 /* We are only interested in keysyms_per_keycode.
1600 There is no need to hold a local copy of the keysyms table */
1603 mmp
= XGetModifierMapping(display
);
1604 kcp
= mmp
->modifiermap
;
1605 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
1609 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
1614 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
1615 if (XKeycodeToKeysym(display
, *kcp
, k
) == XK_Num_Lock
)
1617 NumLockMask
= 1 << i
;
1618 TRACE_(key
)("NumLockMask is %x\n", NumLockMask
);
1620 else if (XKeycodeToKeysym(display
, *kcp
, k
) == XK_Scroll_Lock
)
1622 ScrollLockMask
= 1 << i
;
1623 TRACE_(key
)("ScrollLockMask is %x\n", ScrollLockMask
);
1627 XFreeModifiermap(mmp
);
1629 /* Detect the keyboard layout */
1630 X11DRV_KEYBOARD_DetectLayout( display
);
1631 lkey
= main_key_tab
[kbd_layout
].key
;
1632 syms
= (keysyms_per_keycode
> 4) ? 4 : keysyms_per_keycode
;
1634 /* Now build two conversion arrays :
1635 * keycode -> vkey + scancode + extended
1636 * vkey + extended -> keycode */
1638 e2
.display
= display
;
1641 OEMvkey
= VK_OEM_8
; /* next is available. */
1642 memset(keyc2vkey
, 0, sizeof(keyc2vkey
));
1643 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1649 e2
.keycode
= (KeyCode
)keyc
;
1650 have_chars
= XLookupString(&e2
, buf
, sizeof(buf
), &keysym
, NULL
);
1652 if (keysym
) /* otherwise, keycode not used */
1654 if ((keysym
>> 8) == 0xFF) /* non-character key */
1656 vkey
= nonchar_key_vkey
[keysym
& 0xff];
1657 scan
= nonchar_key_scan
[keysym
& 0xff];
1658 /* set extended bit when necessary */
1659 if (scan
& 0x100) vkey
|= 0x100;
1660 } else if ((keysym
>> 8) == 0x1008FF) { /* XFree86 vendor keys */
1661 vkey
= xfree86_vendor_key_vkey
[keysym
& 0xff];
1662 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
1665 } else if (keysym
== 0x20) { /* Spacebar */
1668 } else if (have_chars
) {
1669 /* we seem to need to search the layout-dependent scancodes */
1670 int maxlen
=0,maxval
=-1,ok
;
1671 for (i
=0; i
<syms
; i
++) {
1672 keysym
= XKeycodeToKeysym(display
, keyc
, i
);
1673 if ((keysym
<0x8000) && (keysym
!=' '))
1676 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[i
], 1, NULL
))
1679 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1680 * with appropriate ShiftMask and Mode_switch, use XLookupString
1681 * to get character in the local encoding.
1683 ckey
[i
] = keysym
& 0xFF;
1686 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
1689 /* find key with longest match streak */
1690 for (keyn
=0; keyn
<MAIN_LEN
; keyn
++) {
1691 for (ok
=(*lkey
)[keyn
][i
=0]; ok
&&(i
<4); i
++)
1692 if ((*lkey
)[keyn
][i
] && (*lkey
)[keyn
][i
]!=ckey
[i
]) ok
=0;
1693 if (!ok
) i
--; /* we overshot */
1694 if (ok
||(i
>maxlen
)) {
1695 maxlen
=i
; maxval
=keyn
;
1701 const WORD (*lscan
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].scan
;
1702 const WORD (*lvkey
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].vkey
;
1703 scan
= (*lscan
)[maxval
];
1704 vkey
= (*lvkey
)[maxval
];
1708 TRACE("keycode %04x => vkey %04x\n", e2
.keycode
, vkey
);
1709 keyc2vkey
[e2
.keycode
] = vkey
;
1710 keyc2scan
[e2
.keycode
] = scan
;
1711 if ((vkey
& 0xff) && vkey_used
[(vkey
& 0xff)])
1712 WARN("vkey %04x is being used by more than one keycode\n", vkey
);
1713 vkey_used
[(vkey
& 0xff)] = 1;
1716 #define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
1717 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1719 vkey
= keyc2vkey
[keyc
] & 0xff;
1723 e2
.keycode
= (KeyCode
)keyc
;
1724 keysym
= XLookupKeysym(&e2
, 0);
1728 /* find a suitable layout-dependent VK code */
1729 /* (most Winelib apps ought to be able to work without layout tables!) */
1730 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1732 keysym
= XLookupKeysym(&e2
, i
);
1733 if ((keysym
>= XK_0
&& keysym
<= XK_9
)
1734 || (keysym
>= XK_A
&& keysym
<= XK_Z
)) {
1735 vkey
= VKEY_IF_NOT_USED(keysym
);
1739 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1741 keysym
= XLookupKeysym(&e2
, i
);
1744 case ';': vkey
= VKEY_IF_NOT_USED(VK_OEM_1
); break;
1745 case '/': vkey
= VKEY_IF_NOT_USED(VK_OEM_2
); break;
1746 case '`': vkey
= VKEY_IF_NOT_USED(VK_OEM_3
); break;
1747 case '[': vkey
= VKEY_IF_NOT_USED(VK_OEM_4
); break;
1748 case '\\': vkey
= VKEY_IF_NOT_USED(VK_OEM_5
); break;
1749 case ']': vkey
= VKEY_IF_NOT_USED(VK_OEM_6
); break;
1750 case '\'': vkey
= VKEY_IF_NOT_USED(VK_OEM_7
); break;
1751 case ',': vkey
= VKEY_IF_NOT_USED(VK_OEM_COMMA
); break;
1752 case '.': vkey
= VKEY_IF_NOT_USED(VK_OEM_PERIOD
); break;
1753 case '-': vkey
= VKEY_IF_NOT_USED(VK_OEM_MINUS
); break;
1754 case '+': vkey
= VKEY_IF_NOT_USED(VK_OEM_PLUS
); break;
1760 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1761 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1766 case 0xc1 : OEMvkey
=0xdb; break;
1767 case 0xe5 : OEMvkey
=0xe9; break;
1768 case 0xf6 : OEMvkey
=0xf5; WARN("No more OEM vkey available!\n");
1770 } while (OEMvkey
< 0xf5 && vkey_used
[OEMvkey
]);
1772 vkey
= VKEY_IF_NOT_USED(OEMvkey
);
1774 if (TRACE_ON(keyboard
))
1776 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1777 OEMvkey
, e2
.keycode
);
1779 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
1783 keysym
= XLookupKeysym(&e2
, i
);
1784 ksname
= XKeysymToString(keysym
);
1786 ksname
= "NoSymbol";
1787 TRACE( "%lX (%s) ", keysym
, ksname
);
1795 TRACE("keycode %04x => vkey %04x\n", e2
.keycode
, vkey
);
1796 keyc2vkey
[e2
.keycode
] = vkey
;
1799 #undef VKEY_IF_NOT_USED
1801 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1802 for (scan
= 0x60, keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1803 if (keyc2vkey
[keyc
]&&!keyc2scan
[keyc
]) {
1805 keysym
= XKeycodeToKeysym(display
, keyc
, 0);
1806 ksname
= XKeysymToString(keysym
);
1807 if (!ksname
) ksname
= "NoSymbol";
1809 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1811 TRACE_(key
)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan
,keyc
,ksname
);
1812 keyc2scan
[keyc
]=scan
++;
1815 wine_tsx11_unlock();
1819 /**********************************************************************
1820 * GetAsyncKeyState (X11DRV.@)
1822 SHORT
X11DRV_GetAsyncKeyState(INT key
)
1826 /* Photoshop livelocks unless mouse events are included here */
1827 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL
, 0, QS_KEY
| QS_MOUSE
, 0 );
1829 retval
= ((key_state_table
[key
] & 0x40) ? 0x0001 : 0) |
1830 ((key_state_table
[key
] & 0x80) ? 0x8000 : 0);
1831 key_state_table
[key
] &= ~0x40;
1832 TRACE_(key
)("(%x) -> %x\n", key
, retval
);
1837 /***********************************************************************
1838 * GetKeyboardLayoutList (X11DRV.@)
1840 UINT
X11DRV_GetKeyboardLayoutList(INT size
, HKL
*hkl
)
1844 TRACE("%d, %p\n", size
, hkl
);
1848 size
= 4096; /* hope we will never have that many */
1852 for (i
= 0; main_key_tab
[i
].comment
&& (i
< size
); i
++)
1856 ULONG_PTR layout
= main_key_tab
[i
].lcid
;
1859 /* see comment for GetKeyboardLayout */
1860 langid
= PRIMARYLANGID(LANGIDFROMLCID(layout
));
1861 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
1862 layout
|= 0xe001 << 16; /* FIXME */
1864 layout
|= layout
<< 16;
1866 hkl
[i
] = (HKL
)layout
;
1873 /***********************************************************************
1874 * GetKeyboardLayout (X11DRV.@)
1876 HKL
X11DRV_GetKeyboardLayout(DWORD dwThreadid
)
1881 if (dwThreadid
&& dwThreadid
!= GetCurrentThreadId())
1882 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid
);
1885 layout
= main_key_tab
[kbd_layout
].lcid
;
1888 * Winword uses return value of GetKeyboardLayout as a codepage
1889 * to translate ANSI keyboard messages to unicode. But we have
1890 * a problem with it: for instance Polish keyboard layout is
1891 * identical to the US one, and therefore instead of the Polish
1892 * locale id we return the US one.
1894 layout
= GetUserDefaultLCID();
1897 * Microsoft Office expects this value to be something specific
1898 * for Japanese and Korean Windows with an IME the value is 0xe001
1899 * We should probably check to see if an IME exists and if so then
1900 * set this word properly.
1902 langid
= PRIMARYLANGID(LANGIDFROMLCID(layout
));
1903 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
1904 layout
|= 0xe001 << 16; /* FIXME */
1906 layout
|= layout
<< 16;
1912 /***********************************************************************
1913 * GetKeyboardLayoutName (X11DRV.@)
1915 BOOL
X11DRV_GetKeyboardLayoutName(LPWSTR name
)
1917 static const WCHAR formatW
[] = {'%','0','8','l','x',0};
1921 layout
= main_key_tab
[kbd_layout
].lcid
;
1922 /* see comment for GetKeyboardLayout */
1923 langid
= PRIMARYLANGID(LANGIDFROMLCID(layout
));
1924 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
1925 layout
|= 0xe001 << 16; /* FIXME */
1927 layout
|= layout
<< 16;
1929 sprintfW(name
, formatW
, layout
);
1930 TRACE("returning %s\n", debugstr_w(name
));
1935 /***********************************************************************
1936 * LoadKeyboardLayout (X11DRV.@)
1938 HKL
X11DRV_LoadKeyboardLayout(LPCWSTR name
, UINT flags
)
1940 FIXME("%s, %04x: stub!\n", debugstr_w(name
), flags
);
1941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1946 /***********************************************************************
1947 * UnloadKeyboardLayout (X11DRV.@)
1949 BOOL
X11DRV_UnloadKeyboardLayout(HKL hkl
)
1951 FIXME("%p: stub!\n", hkl
);
1952 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1957 /***********************************************************************
1958 * ActivateKeyboardLayout (X11DRV.@)
1960 HKL
X11DRV_ActivateKeyboardLayout(HKL hkl
, UINT flags
)
1962 FIXME("%p, %04x: stub!\n", hkl
, flags
);
1963 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1968 /***********************************************************************
1969 * X11DRV_MappingNotify
1971 void X11DRV_MappingNotify( HWND dummy
, XEvent
*event
)
1976 XRefreshKeyboardMapping(&event
->xmapping
);
1977 wine_tsx11_unlock();
1978 X11DRV_InitKeyboard( event
->xmapping
.display
);
1981 if (!hwnd
) hwnd
= GetActiveWindow();
1982 PostMessageW(hwnd
, WM_INPUTLANGCHANGEREQUEST
,
1983 0 /*FIXME*/, (LPARAM
)X11DRV_GetKeyboardLayout(0));
1987 /***********************************************************************
1988 * VkKeyScanEx (X11DRV.@)
1990 * Note: Windows ignores HKL parameter and uses current active layout instead
1992 SHORT
X11DRV_VkKeyScanEx(WCHAR wChar
, HKL hkl
)
1994 Display
*display
= thread_init_display();
2001 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2002 * is UTF-8 (multibyte encoding)?
2004 if (!WideCharToMultiByte(CP_UNIXCP
, 0, &wChar
, 1, &cChar
, 1, NULL
, NULL
))
2006 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar
);
2010 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar
, cChar
);
2012 /* char->keysym (same for ANSI chars) */
2013 keysym
= (unsigned char)cChar
; /* (!) cChar is signed */
2014 if (keysym
<= 27) keysym
+= 0xFF00; /* special chars : return, backspace... */
2017 keycode
= XKeysymToKeycode(display
, keysym
); /* keysym -> keycode */
2020 if (keysym
>= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2022 ret
= 0x0240 + cChar
; /* 0x0200 indicates a control character */
2023 TRACE(" ... returning ctrl char %#.2x\n", ret
);
2024 wine_tsx11_unlock();
2027 /* It didn't work ... let's try with deadchar code. */
2028 TRACE("retrying with | 0xFE00\n");
2029 keycode
= XKeysymToKeycode(display
, keysym
| 0xFE00);
2031 wine_tsx11_unlock();
2033 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
2034 cChar
, keysym
, keysym
, keycode
, keycode
);
2036 /* keycode -> (keyc2vkey) vkey */
2037 ret
= keyc2vkey
[keycode
];
2039 if (!keycode
|| !ret
)
2041 TRACE("keycode for '%c' not found, returning -1\n", cChar
);
2047 for (i
= 0; i
< 4; i
++) /* find shift state */
2049 if (XKeycodeToKeysym(display
, keycode
, i
) == keysym
)
2055 wine_tsx11_unlock();
2061 WARN("Keysym %lx not found while parsing the keycode table\n", keysym
);
2065 case 1: ret
+= 0x0100; break;
2066 case 2: ret
+= 0x0600; break;
2067 case 3: ret
+= 0x0700; break;
2070 index : 0 adds 0x0000
2071 index : 1 adds 0x0100 (shift)
2072 index : ? adds 0x0200 (ctrl)
2073 index : 2 adds 0x0600 (ctrl+alt)
2074 index : 3 adds 0x0700 (ctrl+alt+shift)
2077 TRACE(" ... returning %#.2x\n", ret
);
2081 /***********************************************************************
2082 * MapVirtualKeyEx (X11DRV.@)
2084 UINT
X11DRV_MapVirtualKeyEx(UINT wCode
, UINT wMapType
, HKL hkl
)
2086 Display
*display
= thread_init_display();
2088 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
2090 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode
, wMapType
, hkl
);
2091 if (hkl
!= X11DRV_GetKeyboardLayout(0))
2092 FIXME("keyboard layout %p is not supported\n", hkl
);
2096 case MAPVK_VK_TO_VSC
: /* vkey-code to scan-code */
2097 case MAPVK_VK_TO_VSC_EX
:
2103 case VK_SHIFT
: wCode
= VK_LSHIFT
; break;
2104 case VK_CONTROL
: wCode
= VK_LCONTROL
; break;
2105 case VK_MENU
: wCode
= VK_LMENU
; break;
2108 /* let's do vkey -> keycode -> scan */
2109 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2110 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
) break;
2112 if (keyc
> max_keycode
)
2114 TRACE("returning no scan-code.\n");
2117 returnMVK (keyc2scan
[keyc
] & 0xFF);
2119 case MAPVK_VSC_TO_VK
: /* scan-code to vkey-code */
2120 case MAPVK_VSC_TO_VK_EX
:
2125 /* let's do scan -> keycode -> vkey */
2126 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
2127 if ((keyc2scan
[keyc
] & 0xFF) == (wCode
& 0xFF))
2129 vkey
= keyc2vkey
[keyc
] & 0xFF;
2130 /* Only stop if it's not a numpad vkey; otherwise keep
2131 looking for a potential better vkey. */
2132 if (vkey
&& (vkey
< VK_NUMPAD0
|| VK_DIVIDE
< vkey
))
2138 TRACE("returning no vkey-code.\n");
2142 if (wMapType
== MAPVK_VSC_TO_VK
)
2147 vkey
= VK_SHIFT
; break;
2150 vkey
= VK_CONTROL
; break;
2153 vkey
= VK_MENU
; break;
2158 case MAPVK_VK_TO_CHAR
: /* vkey-code to unshifted ANSI code */
2160 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2161 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2162 * key.. Looks like something is wrong with the MS docs?
2163 * This is only true for letters, for example VK_0 returns '0' not ')'.
2164 * - hence we use the lock mask to ensure this happens.
2166 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2172 e
.display
= display
;
2178 /* We exit on the first keycode found, to speed up the thing. */
2179 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2180 { /* Find a keycode that could have generated this virtual key */
2181 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
2182 { /* We filter the extended bit, we don't know it */
2183 e
.keycode
= keyc
; /* Store it temporarily */
2184 if ((EVENT_event_to_vkey(0,&e
) & 0xFF) != wCode
) {
2185 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2186 state), so set it to 0, we'll find another one */
2191 if ((wCode
>=VK_NUMPAD0
) && (wCode
<=VK_NUMPAD9
))
2192 e
.keycode
= XKeysymToKeycode(e
.display
, wCode
-VK_NUMPAD0
+XK_KP_0
);
2194 if (wCode
==VK_DECIMAL
)
2195 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2199 WARN("Unknown virtual key %X !!!\n", wCode
);
2200 wine_tsx11_unlock();
2201 return 0; /* whatever */
2203 TRACE("Found keycode %d (0x%2X)\n",e
.keycode
,e
.keycode
);
2205 len
= XLookupString(&e
, s
, sizeof(s
), &keysym
, NULL
);
2206 wine_tsx11_unlock();
2211 if (MultiByteToWideChar(CP_UNIXCP
, 0, s
, len
, &wch
, 1))
2212 returnMVK(toupperW(wch
));
2214 TRACE("returning no ANSI.\n");
2217 default: /* reserved */
2218 FIXME("Unknown wMapType %d !\n", wMapType
);
2224 /***********************************************************************
2225 * GetKeyNameText (X11DRV.@)
2227 INT
X11DRV_GetKeyNameText(LONG lParam
, LPWSTR lpBuffer
, INT nSize
)
2229 Display
*display
= thread_init_display();
2230 int vkey
, ansi
, scanCode
;
2236 scanCode
= lParam
>> 16;
2237 scanCode
&= 0x1ff; /* keep "extended-key" flag with code */
2239 vkey
= X11DRV_MapVirtualKeyEx(scanCode
, MAPVK_VSC_TO_VK_EX
, X11DRV_GetKeyboardLayout(0));
2241 /* handle "don't care" bit (0x02000000) */
2242 if (!(lParam
& 0x02000000)) {
2245 /* R-Shift is "special" - it is an extended key with separate scan code */
2261 ansi
= X11DRV_MapVirtualKeyEx(vkey
, MAPVK_VK_TO_CHAR
, X11DRV_GetKeyboardLayout(0));
2262 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode
, vkey
, ansi
);
2264 /* first get the name of the "regular" keys which is the Upper case
2265 value of the keycap imprint. */
2266 if ( ((ansi
>= 0x21) && (ansi
<= 0x7e)) &&
2267 (scanCode
!= 0x137) && /* PrtScn */
2268 (scanCode
!= 0x135) && /* numpad / */
2269 (scanCode
!= 0x37 ) && /* numpad * */
2270 (scanCode
!= 0x4a ) && /* numpad - */
2271 (scanCode
!= 0x4e ) ) /* numpad + */
2273 if ((nSize
>= 2) && lpBuffer
)
2275 *lpBuffer
= toupperW((WCHAR
)ansi
);
2283 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2284 without "extended-key" flag. However Wine generates scancode
2285 *with* "extended-key" flag. Seems to occur *only* for the
2286 function keys. Soooo.. We will leave the table alone and
2287 fudge the lookup here till the other part is found and fixed!!! */
2289 if ( ((scanCode
>= 0x13b) && (scanCode
<= 0x144)) ||
2290 (scanCode
== 0x157) || (scanCode
== 0x158))
2291 scanCode
&= 0xff; /* remove "extended-key" flag for Fx keys */
2293 /* let's do scancode -> keycode -> keysym -> String */
2295 for (keyi
=min_keycode
; keyi
<=max_keycode
; keyi
++)
2296 if ((keyc2scan
[keyi
]) == scanCode
)
2298 if (keyi
<= max_keycode
)
2301 keyc
= (KeyCode
) keyi
;
2302 keys
= XKeycodeToKeysym(display
, keyc
, 0);
2303 name
= XKeysymToString(keys
);
2304 wine_tsx11_unlock();
2305 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2306 scanCode
, keyc
, (int)keys
, name
);
2307 if (lpBuffer
&& nSize
&& name
)
2309 MultiByteToWideChar(CP_UNIXCP
, 0, name
, -1, lpBuffer
, nSize
);
2310 lpBuffer
[nSize
- 1] = 0;
2315 /* Finally issue WARN for unknown keys */
2317 WARN("(%08x,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam
,lpBuffer
,nSize
,vkey
,ansi
);
2318 if (lpBuffer
&& nSize
)
2323 /***********************************************************************
2324 * X11DRV_KEYBOARD_MapDeadKeysym
2326 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
2330 /* symbolic ASCII is the same as defined in rfc1345 */
2331 #ifdef XK_dead_tilde
2332 case XK_dead_tilde
:
2334 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2335 return '~'; /* '? */
2336 #ifdef XK_dead_acute
2337 case XK_dead_acute
:
2339 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2340 return 0xb4; /* '' */
2341 #ifdef XK_dead_circumflex
2342 case XK_dead_circumflex
:
2344 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2345 return '^'; /* '> */
2346 #ifdef XK_dead_grave
2347 case XK_dead_grave
:
2349 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2350 return '`'; /* '! */
2351 #ifdef XK_dead_diaeresis
2352 case XK_dead_diaeresis
:
2354 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2355 return 0xa8; /* ': */
2356 #ifdef XK_dead_cedilla
2357 case XK_dead_cedilla
:
2358 return 0xb8; /* ', */
2360 #ifdef XK_dead_macron
2361 case XK_dead_macron
:
2362 return '-'; /* 'm isn't defined on iso-8859-x */
2364 #ifdef XK_dead_breve
2365 case XK_dead_breve
:
2366 return 0xa2; /* '( */
2368 #ifdef XK_dead_abovedot
2369 case XK_dead_abovedot
:
2370 return 0xff; /* '. */
2372 #ifdef XK_dead_abovering
2373 case XK_dead_abovering
:
2374 return '0'; /* '0 isn't defined on iso-8859-x */
2376 #ifdef XK_dead_doubleacute
2377 case XK_dead_doubleacute
:
2378 return 0xbd; /* '" */
2380 #ifdef XK_dead_caron
2381 case XK_dead_caron
:
2382 return 0xb7; /* '< */
2384 #ifdef XK_dead_ogonek
2385 case XK_dead_ogonek
:
2386 return 0xb2; /* '; */
2388 /* FIXME: I don't know this three.
2391 case XK_dead_voiced_sound :
2393 case XK_dead_semivoiced_sound :
2397 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
2401 /***********************************************************************
2402 * ToUnicodeEx (X11DRV.@)
2404 * The ToUnicode function translates the specified virtual-key code and keyboard
2405 * state to the corresponding Windows character or characters.
2407 * If the specified key is a dead key, the return value is negative. Otherwise,
2408 * it is one of the following values:
2410 * 0 The specified virtual key has no translation for the current state of the keyboard.
2411 * 1 One Windows character was copied to the buffer.
2412 * 2 Two characters were copied to the buffer. This usually happens when a
2413 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2414 * be composed with the specified virtual key to form a single character.
2416 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2419 INT
X11DRV_ToUnicodeEx(UINT virtKey
, UINT scanCode
, LPBYTE lpKeyState
,
2420 LPWSTR bufW
, int bufW_size
, UINT flags
, HKL hkl
)
2422 Display
*display
= thread_init_display();
2432 if (scanCode
& 0x8000)
2434 TRACE("Key UP, doing nothing\n" );
2438 if (hkl
!= X11DRV_GetKeyboardLayout(0))
2439 FIXME("keyboard layout %p is not supported\n", hkl
);
2441 if ((lpKeyState
[VK_MENU
] & 0x80) && (lpKeyState
[VK_CONTROL
] & 0x80))
2443 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2447 e
.display
= display
;
2453 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
2454 if (!focus
) focus
= GetActiveWindow();
2455 e
.window
= X11DRV_get_whole_window( focus
);
2456 xic
= X11DRV_get_ic( focus
);
2458 if (lpKeyState
[VK_SHIFT
] & 0x80)
2460 TRACE("ShiftMask = %04x\n", ShiftMask
);
2461 e
.state
|= ShiftMask
;
2463 if (lpKeyState
[VK_CAPITAL
] & 0x01)
2465 TRACE("LockMask = %04x\n", LockMask
);
2466 e
.state
|= LockMask
;
2468 if (lpKeyState
[VK_CONTROL
] & 0x80)
2470 TRACE("ControlMask = %04x\n", ControlMask
);
2471 e
.state
|= ControlMask
;
2473 if (lpKeyState
[VK_NUMLOCK
] & 0x01)
2475 TRACE("NumLockMask = %04x\n", NumLockMask
);
2476 e
.state
|= NumLockMask
;
2479 /* Restore saved AltGr state */
2480 TRACE("AltGrMask = %04x\n", AltGrMask
);
2481 e
.state
|= AltGrMask
;
2483 TRACE_(key
)("(%04X, %04X) : faked state = 0x%04x\n",
2484 virtKey
, scanCode
, e
.state
);
2486 /* We exit on the first keycode found, to speed up the thing. */
2487 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
2488 { /* Find a keycode that could have generated this virtual key */
2489 if ((keyc2vkey
[keyc
] & 0xFF) == virtKey
)
2490 { /* We filter the extended bit, we don't know it */
2491 e
.keycode
= keyc
; /* Store it temporarily */
2492 if ((EVENT_event_to_vkey(xic
,&e
) & 0xFF) != virtKey
) {
2493 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
2494 state), so set it to 0, we'll find another one */
2499 if (virtKey
>= VK_LEFT
&& virtKey
<= VK_DOWN
)
2500 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
- VK_LEFT
+ XK_Left
);
2502 if ((virtKey
>=VK_NUMPAD0
) && (virtKey
<=VK_NUMPAD9
))
2503 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
-VK_NUMPAD0
+XK_KP_0
);
2505 if (virtKey
==VK_DECIMAL
)
2506 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
2508 if (virtKey
==VK_SEPARATOR
)
2509 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Separator
);
2511 if (!e
.keycode
&& virtKey
!= VK_NONAME
)
2513 WARN("Unknown virtual key %X !!!\n", virtKey
);
2514 wine_tsx11_unlock();
2517 else TRACE("Found keycode %d (0x%2X)\n",e
.keycode
,e
.keycode
);
2519 TRACE_(key
)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2520 e
.type
, e
.window
, e
.state
, e
.keycode
);
2522 /* Clients should pass only KeyPress events to XmbLookupString,
2523 * e.type was set to KeyPress above.
2526 ret
= XmbLookupString(xic
, &e
, lpChar
, sizeof(lpChar
), &keysym
, &status
);
2528 ret
= XLookupString(&e
, lpChar
, sizeof(lpChar
), &keysym
, NULL
);
2529 wine_tsx11_unlock();
2531 TRACE_(key
)("nbyte = %d, status 0x%x\n", ret
, status
);
2533 if (status
== XBufferOverflow
)
2534 ERR("Buffer Overflow need %d!\n", ret
);
2541 ksname
= XKeysymToString(keysym
);
2542 wine_tsx11_unlock();
2543 if (!ksname
) ksname
= "No Name";
2544 TRACE_(key
)("%s : keysym=%lX (%s), # of chars=%d / %s\n",
2545 (e
.type
== KeyPress
) ? "KeyPress" : "KeyRelease",
2546 keysym
, ksname
, ret
, debugstr_an(lpChar
, ret
));
2554 /* An ugly hack for EuroSign: X can't translate it to a character
2555 for some locales. */
2556 if (keysym
== XK_EuroSign
)
2563 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2564 /* Here we change it back. */
2565 if (keysym
== XK_ISO_Left_Tab
)
2572 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
2575 MultiByteToWideChar(CP_UNIXCP
, 0, &dead_char
, 1, bufW
, bufW_size
);
2580 if (keysym
>= 0x01000100 && keysym
<= 0x0100ffff)
2582 /* Unicode direct mapping */
2583 bufW
[0] = keysym
& 0xffff;
2587 else if ((keysym
>> 8) == 0x1008FF) {
2597 ksname
= XKeysymToString(keysym
);
2598 wine_tsx11_unlock();
2601 if ((keysym
>> 8) != 0xff)
2603 WARN("no char for keysym %04lX (%s) :\n",
2605 WARN("virtKey=%X, scanCode=%X, keycode=%X, state=%X\n",
2606 virtKey
, scanCode
, e
.keycode
, e
.state
);
2610 else { /* ret != 0 */
2611 /* We have a special case to handle : Shift + arrow, shift + home, ...
2612 X returns a char for it, but Windows doesn't. Let's eat it. */
2613 if (!(e
.state
& NumLockMask
) /* NumLock is off */
2614 && (e
.state
& ShiftMask
) /* Shift is pressed */
2615 && (keysym
>=XK_KP_0
) && (keysym
<=XK_KP_9
))
2621 /* more areas where X returns characters but Windows does not
2622 CTRL + number or CTRL + symbol */
2623 if (e
.state
& ControlMask
)
2625 if (((keysym
>=33) && (keysym
< 'A')) ||
2626 ((keysym
> 'Z') && (keysym
< 'a')))
2633 /* We have another special case for delete key (XK_Delete) on an
2634 extended keyboard. X returns a char for it, but Windows doesn't */
2635 if (keysym
== XK_Delete
)
2640 else if((lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
2641 && (keysym
== XK_KP_Decimal
))
2646 else if((lpKeyState
[VK_CONTROL
] & 0x80) /* Control is pressed */
2647 && (keysym
== XK_Return
|| keysym
== XK_KP_Enter
))
2653 /* Hack to detect an XLookupString hard-coded to Latin1 */
2654 if (ret
== 1 && keysym
>= 0x00a0 && keysym
<= 0x00ff && (BYTE
)lpChar
[0] == keysym
)
2656 bufW
[0] = (BYTE
)lpChar
[0];
2660 /* perform translation to unicode */
2663 TRACE_(key
)("Translating char 0x%02x to unicode\n", *(BYTE
*)lpChar
);
2664 ret
= MultiByteToWideChar(CP_UNIXCP
, 0, lpChar
, ret
, bufW
, bufW_size
);
2669 TRACE_(key
)("ToUnicode about to return %d with char %x %s\n",
2670 ret
, (ret
&& bufW
) ? bufW
[0] : 0, bufW
? "" : "(no buffer)");
2674 /***********************************************************************
2677 void X11DRV_Beep(void)
2680 XBell(gdi_display
, 0);
2681 wine_tsx11_unlock();