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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include <X11/Xresource.h>
32 #include <X11/Xutil.h>
34 #include <X11/XKBlib.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
47 #include "wine/winuser16.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
55 WINE_DECLARE_DEBUG_CHANNEL(key);
56 WINE_DECLARE_DEBUG_CHANNEL(dinput);
58 static int min_keycode, max_keycode, keysyms_per_keycode;
59 static WORD keyc2vkey[256], keyc2scan[256];
61 static LPBYTE pKeyStateTable;
62 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
63 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
65 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
67 /* Keyboard translation tables */
69 static const WORD main_key_scan_qwerty[MAIN_LEN] =
71 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
72 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
73 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
74 /* q w e r t y u i o p [ ] */
75 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
76 /* a s d f g h j k l ; ' \ */
77 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
78 /* z x c v b n m , . / */
79 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
80 0x56 /* the 102nd key (actually to the right of l-shift) */
83 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
85 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
86 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
87 /* q w e r t y u i o p [ ] */
88 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
89 /* a s d f g h j k l ; ' \ */
90 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
91 /* \ z x c v b n m , . / */
92 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
93 0x56, /* the 102nd key (actually to the right of l-shift) */
96 static const WORD main_key_scan_dvorak[MAIN_LEN] =
98 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
99 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
100 /* ' , . p y f g c r l / = */
101 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
102 /* a o e u i d h t n s - \ */
103 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
104 /* ; q j k x b m w v z */
105 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
106 0x56 /* the 102nd key (actually to the right of l-shift) */
109 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
111 /* NOTE: this layout must concur with the scan codes layout above */
112 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
113 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
114 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
115 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
116 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
119 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
121 /* NOTE: this layout must concur with the scan codes layout above */
122 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
123 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
124 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
125 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
126 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
129 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
131 /* NOTE: this layout must concur with the scan codes layout above */
132 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
133 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
134 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
135 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
136 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
139 static const WORD main_key_vkey_qwertz_105[MAIN_LEN] =
141 /* NOTE: this layout must concur with the scan codes layout above */
142 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
143 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
144 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
145 VK_OEM_102,'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2
148 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
150 /* NOTE: this layout must concur with the scan codes layout above */
151 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
152 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
153 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
154 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
155 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
158 static const WORD main_key_vkey_azerty[MAIN_LEN] =
160 /* NOTE: this layout must concur with the scan codes layout above */
161 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
162 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
163 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
164 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
165 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
168 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
170 /* NOTE: this layout must concur with the scan codes layout above */
171 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
172 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
173 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
174 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
175 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
178 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
180 /* the VK mappings for the main keyboard will be auto-assigned as before,
181 so what we have here is just the character tables */
182 /* order: Normal, Shift, AltGr, Shift-AltGr */
183 /* We recommend you write just what is guaranteed to be correct (i.e. what's
184 written on the keycaps), not the bunch of special characters behind AltGr
185 and Shift-AltGr if it can vary among different X servers */
186 /* Remember that your 102nd key (to the right of l-shift) should be on a
187 separate line, see existing tables */
188 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
189 /* Remember to also add your new table to the layout index table far below! */
191 /*** German Logitech Desktop Pro keyboard layout */
192 static const char main_key_DE_logitech[MAIN_LEN][4] =
194 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
195 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
196 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
197 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
201 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
202 static const char main_key_US[MAIN_LEN][4] =
204 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
205 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
206 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
207 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
210 /*** United States keyboard layout (phantom key version) */
211 /* (XFree86 reports the <> key even if it's not physically there) */
212 static const char main_key_US_phantom[MAIN_LEN][4] =
214 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
215 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
216 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
217 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
218 "<>" /* the phantom key */
221 /*** United States keyboard layout (dvorak version) */
222 static const char main_key_US_dvorak[MAIN_LEN][4] =
224 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
225 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
226 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
227 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
230 /*** British keyboard layout */
231 static const char main_key_UK[MAIN_LEN][4] =
233 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
234 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
235 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
236 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
240 /*** French keyboard layout (contributed by Eric Pouech) */
241 static const char main_key_FR[MAIN_LEN][4] =
243 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
244 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
245 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
246 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
250 /*** Icelandic keyboard layout (setxkbmap is) */
251 static const char main_key_IS[MAIN_LEN][4] =
253 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
254 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
255 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
256 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
260 /*** German keyboard layout (contributed by Ulrich Weigand) */
261 static const char main_key_DE[MAIN_LEN][4] =
263 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
264 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
265 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
266 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
270 /*** German keyboard layout without dead keys */
271 static const char main_key_DE_nodead[MAIN_LEN][4] =
273 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
274 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
275 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
276 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
280 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
281 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
283 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
284 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
285 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
286 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
289 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
290 static const char main_key_SG[MAIN_LEN][4] =
292 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
293 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
294 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
295 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
299 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
300 static const char main_key_SF[MAIN_LEN][4] =
302 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
303 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
304 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
305 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
309 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
310 static const char main_key_NO[MAIN_LEN][4] =
312 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
313 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
314 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
315 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
319 /*** Danish keyboard layout (setxkbmap dk) */
320 static const char main_key_DA[MAIN_LEN][4] =
322 "½§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
323 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
325 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
329 /*** Swedish keyboard layout (setxkbmap se) */
330 static const char main_key_SE[MAIN_LEN][4] =
332 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
333 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
334 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
335 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
339 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
340 static const char main_key_ET[MAIN_LEN][4] =
342 "·~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
343 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
344 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
345 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
349 /*** Canadian French keyboard layout */
350 static const char main_key_CF[MAIN_LEN][4] =
352 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
353 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
354 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
355 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
359 /*** Canadian CAN/CSA Z243.200-92 keyboard layout
360 *** Contributed by Jean-Michel Dault <jmdault@revolutionlinux.com> */
361 static const char main_key_CA[MAIN_LEN][4] =
364 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
365 "qQ","wW","eE","rR¶®","tT","yY","uU","iI","oOøØ","pPþÞ","^¨åÅ","çÇ~",
366 "aAæÆ","sSß§","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
367 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
371 /*** Portuguese keyboard layout (setxkbmap pt) */
372 static const char main_key_PT[MAIN_LEN][4] =
374 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
375 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
376 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
377 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
381 /*** Italian keyboard layout (setxkbmap it) */
382 static const char main_key_IT[MAIN_LEN][4] =
384 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
385 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
386 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
387 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
391 /*** Finnish keyboard layout (setxkbmap fi) */
392 static const char main_key_FI[MAIN_LEN][4] =
394 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
395 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
396 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
397 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
401 /*** Bulgarian bds keyboard layout */
402 static const char main_key_BG_bds[MAIN_LEN][4] =
404 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
405 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
406 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
407 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
408 "<>" /* the phantom key */
411 /*** Bulgarian phonetic keyboard layout */
412 static const char main_key_BG_phonetic[MAIN_LEN][4] =
414 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
415 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
416 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
417 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
418 "<>" /* the phantom key */
421 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
422 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
423 static const char main_key_BY[MAIN_LEN][4] =
425 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
426 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
427 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
428 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
432 /*** Russian keyboard layout (contributed by Pavel Roskin) */
433 static const char main_key_RU[MAIN_LEN][4] =
435 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
436 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
437 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
438 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
441 /*** Russian keyboard layout (phantom key version) */
442 static const char main_key_RU_phantom[MAIN_LEN][4] =
444 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
445 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
446 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
447 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
448 "<>" /* the phantom key */
451 /*** Russian keyboard layout KOI8-R */
452 static const char main_key_RU_koi8r[MAIN_LEN][4] =
454 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
455 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
456 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
457 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
458 "<>" /* the phantom key */
461 /*** Russian keyboard layout cp1251 */
462 static const char main_key_RU_cp1251[MAIN_LEN][4] =
464 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
465 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
466 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
467 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
468 "<>" /* the phantom key */
471 /*** Russian phonetic keyboard layout */
472 static const char main_key_RU_phonetic[MAIN_LEN][4] =
474 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
475 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
476 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
477 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
478 "<>" /* the phantom key */
481 /*** Ukrainian keyboard layout KOI8-U */
482 static const char main_key_UA[MAIN_LEN][4] =
484 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
485 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
486 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
487 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
488 "<>" /* the phantom key */
491 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
492 /*** (as it appears on most of keyboards sold today) */
493 static const char main_key_UA_std[MAIN_LEN][4] =
495 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
496 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
497 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
498 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
499 "<>" /* the phantom key */
502 /*** Russian keyboard layout KOI8-R (pair to the previous) */
503 static const char main_key_RU_std[MAIN_LEN][4] =
505 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
506 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
507 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
508 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
509 "<>" /* the phantom key */
512 /*** Spanish keyboard layout (setxkbmap es) */
513 static const char main_key_ES[MAIN_LEN][4] =
515 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
516 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
517 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
518 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
522 /*** Belgian keyboard layout ***/
523 static const char main_key_BE[MAIN_LEN][4] =
525 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
526 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
527 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
528 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
532 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
533 static const char main_key_HU[MAIN_LEN][4] =
535 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
536 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
537 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
538 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:>","-_*",
542 /*** Polish (programmer's) keyboard layout ***/
543 static const char main_key_PL[MAIN_LEN][4] =
545 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
546 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
547 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
548 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
552 /*** Slovenian keyboard layout (setxkbmap si) ***/
553 static const char main_key_SI[MAIN_LEN][4] =
555 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
556 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
557 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
558 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
562 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
563 static const char main_key_HR_jelly[MAIN_LEN][4] =
565 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
566 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
567 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
568 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
572 /*** Croatian keyboard layout (setxkbmap hr) ***/
573 static const char main_key_HR[MAIN_LEN][4] =
575 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
576 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
577 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
578 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
582 /*** Japanese 106 keyboard layout ***/
583 static const char main_key_JA_jp106[MAIN_LEN][4] =
585 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
586 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
587 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
588 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
592 /*** Japanese pc98x1 keyboard layout ***/
593 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
595 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
596 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
597 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
598 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
602 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
603 static const char main_key_PT_br[MAIN_LEN][4] =
605 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
606 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
607 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
608 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
611 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
612 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
614 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
615 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
616 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
617 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
620 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
621 static const char main_key_US_intl[MAIN_LEN][4] =
623 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
624 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
625 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
626 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
629 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
630 - dead_abovering replaced with degree - no symbol in iso8859-2
631 - brokenbar replaced with bar */
632 static const char main_key_SK[MAIN_LEN][4] =
634 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
635 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
636 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
637 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
641 /*** Czech keyboard layout (setxkbmap cz) */
642 static const char main_key_CZ[MAIN_LEN][4] =
644 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
645 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
646 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
647 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
651 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
652 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
654 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
655 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
656 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
657 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
661 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
662 static const char main_key_SK_prog[MAIN_LEN][4] =
664 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
665 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
666 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
667 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
671 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
672 static const char main_key_CS[MAIN_LEN][4] =
674 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
675 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
676 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
677 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
681 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
682 static const char main_key_LA[MAIN_LEN][4] =
684 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
685 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
686 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
687 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
691 /*** Lithuanian (Baltic) keyboard layout (pc/lt in XFree86 4.3.0, contributed by Nerijus Baliûnas) */
692 static const char main_key_LT_B[MAIN_LEN][4] =
694 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
695 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
696 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
697 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
700 /*** Turkish keyboard Layout */
701 static const char main_key_TK[MAIN_LEN][4] =
703 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
704 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
705 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
706 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
709 /*** Turkish keyboard layout (setxkbmap tr) */
710 static const char main_key_TR[MAIN_LEN][4] =
712 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
713 "qQ","wW","eE","rR","tT","yY","uU","ýI","oO","pP","ðÐ","üÜ",
714 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;",
715 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
719 /*** Israelian keyboard layout (setxkbmap us,il) */
720 static const char main_key_IL[MAIN_LEN][4] =
722 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
723 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
724 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
725 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
729 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
730 static const char main_key_IL_phonetic[MAIN_LEN][4] =
732 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
733 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
734 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
735 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
739 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
740 static const char main_key_IL_saharon[MAIN_LEN][4] =
742 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
743 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
744 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
745 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
749 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
750 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
751 message since they have different characters in gr and el XFree86 layouts. */
752 static const char main_key_EL[MAIN_LEN][4] =
754 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
755 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
756 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
757 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
761 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
762 static const char main_key_th[MAIN_LEN][4] =
764 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
765 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pPÂ","[{º°","]}Å,",
766 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
767 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
770 /*** VNC keyboard layout */
771 static const WORD main_key_scan_vnc[MAIN_LEN] =
773 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
774 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,
778 static const WORD main_key_vkey_vnc[MAIN_LEN] =
780 '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,
781 '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',
785 static const char main_key_vnc[MAIN_LEN][4] =
787 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
788 "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"
791 /*** Dutch keyboard layout (setxkbmap nl) ***/
792 static const char main_key_NL[MAIN_LEN][4] =
794 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
795 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
796 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
797 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
803 /*** Layout table. Add your keyboard mappings to this list */
804 static const struct {
805 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
806 in the appropriate dlls/kernel/nls/.nls file */
808 const char (*key)[MAIN_LEN][4];
809 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
810 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
812 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
813 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
814 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
815 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
816 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
817 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
818 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
819 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
820 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwertz_105},
821 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
822 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
823 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
824 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
825 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
826 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
827 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
828 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
829 {0x0c0c, "Canadian CAN/CSA-Z243.200-92 keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
830 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
831 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
832 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
833 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
834 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
835 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
836 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
837 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
838 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
839 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
840 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
841 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
842 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
843 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
844 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
845 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
846 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
847 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
848 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
849 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
850 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
851 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
852 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
853 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
854 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
855 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
856 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
857 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
858 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
859 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
860 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
861 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
862 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
863 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
864 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
865 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
866 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
867 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
868 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
869 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
870 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
871 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
873 {0, NULL, NULL, NULL, NULL} /* sentinel */
875 static unsigned kbd_layout=0; /* index into above table of layouts */
877 /* maybe more of these scancodes should be extended? */
878 /* extended must be set for ALT_R, CTRL_R,
879 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
880 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
881 /* FIXME should we set extended bit for NumLock ? My
882 * Windows does ... DF */
883 /* Yes, to distinguish based on scan codes, also
884 for PrtScn key ... GA */
886 static const WORD nonchar_key_vkey[256] =
889 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
891 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
892 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
893 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
895 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
896 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
897 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
898 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
899 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
900 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
902 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
903 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
904 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
906 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
907 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
908 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
910 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
911 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
912 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
913 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
914 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
915 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
916 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
917 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
918 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
919 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
920 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
921 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
924 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
925 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
926 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
927 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
929 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
930 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
931 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
932 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
933 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
936 static const WORD nonchar_key_scan[256] =
939 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
941 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
942 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
943 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
945 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
946 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
948 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
949 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
950 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
952 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
953 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
955 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
956 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
959 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
961 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
962 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
963 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
965 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
966 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
967 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
970 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
971 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
972 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
975 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
976 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
982 /* Returns the Windows virtual key code associated with the X event <e> */
983 /* x11 lock must be held */
984 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
989 XmbLookupString(xic, e, NULL, 0, &keysym, NULL);
991 XLookupString(e, NULL, 0, &keysym, NULL);
993 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
994 && (e->state & NumLockMask))
995 /* Only the Keypad keys 0-9 and . send different keysyms
996 * depending on the NumLock state */
997 return nonchar_key_vkey[keysym & 0xFF];
999 TRACE_(key)("e->keycode = %x\n", e->keycode);
1001 return keyc2vkey[e->keycode];
1004 static BOOL NumState=FALSE, CapsState=FALSE;
1007 /***********************************************************************
1008 * send_keyboard_input
1010 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
1014 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
1015 input.u.ki.wVk = wVk;
1016 input.u.ki.wScan = wScan;
1017 input.u.ki.dwFlags = dwFlags;
1018 input.u.ki.time = time;
1019 input.u.ki.dwExtraInfo = 0;
1020 SendInput( 1, &input, sizeof(input) );
1024 /**********************************************************************
1025 * KEYBOARD_GenerateMsg
1027 * Generate Down+Up messages when NumLock or CapsLock is pressed.
1029 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
1032 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
1034 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
1038 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
1039 don't treat it. It's from the same key press. Then the state goes to ON.
1040 And from there, a 'release' event will switch off the toggle key. */
1042 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
1045 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
1046 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
1047 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
1049 if (Evtype!=KeyPress)
1051 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
1052 send_keyboard_input( vkey, scan, down, event_time );
1053 send_keyboard_input( vkey, scan, up, event_time );
1055 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
1058 else /* it was OFF */
1059 if (Evtype==KeyPress)
1061 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
1062 send_keyboard_input( vkey, scan, down, event_time );
1063 send_keyboard_input( vkey, scan, up, event_time );
1064 *State=TRUE; /* Goes to intermediary state before going to ON */
1065 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
1070 /***********************************************************************
1071 * KEYBOARD_UpdateOneState
1073 * Updates internal state for <vkey>, depending on key <state> under X
1076 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
1078 /* Do something if internal table state != X state for keycode */
1079 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
1081 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1082 vkey, pKeyStateTable[vkey]);
1084 /* Fake key being pressed inside wine */
1085 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
1087 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
1091 /***********************************************************************
1092 * X11DRV_KeymapNotify
1094 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1096 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1097 * from wine to another application and back.
1098 * Toggle keys are handled in HandleEvent.
1100 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1102 int i, j, alt, control, shift;
1103 DWORD time = GetCurrentTime();
1105 alt = control = shift = 0;
1106 for (i = 0; i < 32; i++)
1108 if (!event->xkeymap.key_vector[i]) continue;
1109 for (j = 0; j < 8; j++)
1111 if (!(event->xkeymap.key_vector[i] & (1<<j))) continue;
1112 switch(keyc2vkey[(i * 8) + j] & 0xff)
1114 case VK_MENU: alt = 1; break;
1115 case VK_CONTROL: control = 1; break;
1116 case VK_SHIFT: shift = 1; break;
1120 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
1121 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
1122 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
1125 /***********************************************************************
1128 * Handle a X key event
1130 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1132 XKeyEvent *event = &xev->xkey;
1135 WORD vkey = 0, bScan;
1138 XIC xic = X11DRV_get_ic( hwnd );
1139 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1142 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1143 event->type, event->window, event->state, event->keycode);
1147 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
1149 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1150 wine_tsx11_unlock();
1152 /* Ignore some unwanted events */
1153 if ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1154 keysym == XK_Mode_switch)
1157 TRACE("Ignoring %s keyboard event\n", XKeysymToString(keysym));
1158 wine_tsx11_unlock();
1162 TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status);
1164 if (status == XBufferOverflow)
1165 ERR("Buffer Overflow need %i!\n",ascii_chars);
1167 if (status == XLookupChars)
1169 X11DRV_XIMLookupChars( Str, ascii_chars );
1173 /* If XKB extensions are used, the state mask for AltGr will use the group
1174 index instead of the modifier mask. The group index is set in bits
1175 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1176 pressed, look if the group index is different than 0. From XKB
1177 extension documentation, the group index for AltGr should be 2
1178 (event->state = 0x2000). It's probably better to not assume a
1179 predefined group index and find it dynamically
1181 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1182 /* Save also all possible modifier states. */
1183 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1185 Str[ascii_chars] = '\0';
1190 ksname = XKeysymToString(keysym);
1191 wine_tsx11_unlock();
1194 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / 0x%02x / '%s'\n",
1195 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1196 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1200 vkey = EVENT_event_to_vkey(xic,event);
1201 /* X returns keycode 0 for composed characters */
1202 if (!vkey && ascii_chars) vkey = VK_NONAME;
1203 wine_tsx11_unlock();
1205 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1206 event->keycode, vkey);
1210 switch (vkey & 0xff)
1213 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1216 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1217 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1218 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1221 /* Adjust the NUMLOCK state if it has been changed outside wine */
1222 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1224 TRACE("Adjusting NumLock state.\n");
1225 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1226 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1228 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1229 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1231 TRACE("Adjusting Caps Lock state.\n");
1232 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1233 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1235 /* Not Num nor Caps : end of intermediary states for both. */
1239 bScan = keyc2scan[event->keycode] & 0xFF;
1240 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1243 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1244 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1246 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1251 /**********************************************************************
1252 * X11DRV_KEYBOARD_DetectLayout
1254 * Called from X11DRV_InitKeyboard
1255 * This routine walks through the defined keyboard layouts and selects
1256 * whichever matches most closely.
1257 * X11 lock must be held.
1260 X11DRV_KEYBOARD_DetectLayout (void)
1262 Display *display = thread_display();
1263 unsigned current, match, mismatch, seq, i, syms;
1264 int score, keyc, key, pkey, ok;
1266 const char (*lkey)[MAIN_LEN][4];
1267 unsigned max_seq = 0;
1268 int max_score = 0, ismatch = 0;
1272 syms = keysyms_per_keycode;
1274 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1277 for (current = 0; main_key_tab[current].comment; current++) {
1278 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1283 lkey = main_key_tab[current].key;
1285 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1286 /* get data for keycode from X server */
1287 for (i = 0; i < syms; i++) {
1288 keysym = XKeycodeToKeysym (display, keyc, i);
1289 /* Allow both one-byte and two-byte national keysyms */
1290 if ((keysym < 0x8000) && (keysym != ' '))
1293 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1296 TRACE("XKB could not translate keysym %ld\n", keysym);
1297 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1298 * with appropriate ShiftMask and Mode_switch, use XLookupString
1299 * to get character in the local encoding.
1301 ckey[i] = keysym & 0xFF;
1305 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1309 /* search for a match in layout table */
1310 /* right now, we just find an absolute match for defined positions */
1311 /* (undefined positions are ignored, so if it's defined as "3#" in */
1312 /* the table, it's okay that the X server has "3#£", for example) */
1313 /* however, the score will be higher for longer matches */
1314 for (key = 0; key < MAIN_LEN; key++) {
1315 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1316 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1318 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1326 /* count the matches and mismatches */
1329 /* and how much the keycode order matches */
1330 if (key > pkey) seq++;
1333 /* print spaces instead of \0's */
1334 for (i = 0; i < sizeof(ckey); i++) if (!ckey[i]) ckey[i] = ' ';
1335 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %c%c%c%c\n",
1336 keysym, keyc, ckey[0], ckey[1], ckey[2], ckey[3]);
1342 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1343 match, mismatch, seq, score);
1344 if ((score > max_score) ||
1345 ((score == max_score) && (seq > max_seq))) {
1346 /* best match so far */
1347 kbd_layout = current;
1350 ismatch = !mismatch;
1353 /* we're done, report results if necessary */
1355 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1356 main_key_tab[kbd_layout].comment);
1358 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1361 /**********************************************************************
1362 * InitKeyboard (X11DRV.@)
1364 void X11DRV_InitKeyboard( BYTE *key_state_table )
1366 Display *display = thread_display();
1368 XModifierKeymap *mmp;
1372 WORD scan, vkey, OEMvkey;
1373 int keyc, i, keyn, syms;
1374 char ckey[4]={0,0,0,0};
1375 const char (*lkey)[MAIN_LEN][4];
1377 pKeyStateTable = key_state_table;
1380 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1381 ksp = XGetKeyboardMapping(display, min_keycode,
1382 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1383 /* We are only interested in keysyms_per_keycode.
1384 There is no need to hold a local copy of the keysyms table */
1387 mmp = XGetModifierMapping(display);
1388 kcp = mmp->modifiermap;
1389 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1393 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1398 for (k = 0; k < keysyms_per_keycode; k += 1)
1399 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1401 NumLockMask = 1 << i;
1402 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1406 XFreeModifiermap(mmp);
1408 /* Detect the keyboard layout */
1409 X11DRV_KEYBOARD_DetectLayout();
1410 lkey = main_key_tab[kbd_layout].key;
1411 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1413 /* Now build two conversion arrays :
1414 * keycode -> vkey + scancode + extended
1415 * vkey + extended -> keycode */
1417 e2.display = display;
1420 OEMvkey = VK_OEM_8; /* next is available. */
1421 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1427 e2.keycode = (KeyCode)keyc;
1428 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1430 if (keysym) /* otherwise, keycode not used */
1432 if ((keysym >> 8) == 0xFF) /* non-character key */
1434 vkey = nonchar_key_vkey[keysym & 0xff];
1435 scan = nonchar_key_scan[keysym & 0xff];
1436 /* set extended bit when necessary */
1437 if (scan & 0x100) vkey |= 0x100;
1438 } else if (keysym == 0x20) { /* Spacebar */
1441 } else if (have_chars) {
1442 /* we seem to need to search the layout-dependent scancodes */
1443 int maxlen=0,maxval=-1,ok;
1444 for (i=0; i<syms; i++) {
1445 keysym = XKeycodeToKeysym(display, keyc, i);
1446 if ((keysym<0x8000) && (keysym!=' '))
1449 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1452 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1453 * with appropriate ShiftMask and Mode_switch, use XLookupString
1454 * to get character in the local encoding.
1456 ckey[i] = keysym & 0xFF;
1459 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1462 /* find key with longest match streak */
1463 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1464 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1465 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1466 if (ok||(i>maxlen)) {
1467 maxlen=i; maxval=keyn;
1473 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1474 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1475 scan = (*lscan)[maxval];
1476 vkey = (*lvkey)[maxval];
1479 #if 0 /* this breaks VK_OEM_x VKeys in some layout tables by inserting
1480 * a VK code into a not appropriate place.
1482 /* find a suitable layout-dependent VK code */
1483 /* (most Winelib apps ought to be able to work without layout tables!) */
1484 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1486 keysym = XLookupKeysym(&e2, i);
1487 if ((keysym >= VK_0 && keysym <= VK_9)
1488 || (keysym >= VK_A && keysym <= VK_Z)) {
1493 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1495 keysym = XLookupKeysym(&e2, i);
1498 case ';': vkey = VK_OEM_1; break;
1499 case '/': vkey = VK_OEM_2; break;
1500 case '`': vkey = VK_OEM_3; break;
1501 case '[': vkey = VK_OEM_4; break;
1502 case '\\': vkey = VK_OEM_5; break;
1503 case ']': vkey = VK_OEM_6; break;
1504 case '\'': vkey = VK_OEM_7; break;
1505 case ',': vkey = VK_OEM_COMMA; break;
1506 case '.': vkey = VK_OEM_PERIOD; break;
1507 case '-': vkey = VK_OEM_MINUS; break;
1508 case '+': vkey = VK_OEM_PLUS; break;
1514 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1515 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1518 case 0xc1 : OEMvkey=0xdb; break;
1519 case 0xe5 : OEMvkey=0xe9; break;
1520 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1525 if (TRACE_ON(keyboard))
1527 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1528 OEMvkey, e2.keycode);
1530 for (i = 0; i < keysyms_per_keycode; i += 1)
1534 keysym = XLookupKeysym(&e2, i);
1535 ksname = XKeysymToString(keysym);
1537 ksname = "NoSymbol";
1538 TRACE( "%lX (%s) ", keysym, ksname);
1545 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1546 keyc2vkey[e2.keycode] = vkey;
1547 keyc2scan[e2.keycode] = scan;
1550 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1551 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1552 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1554 keysym = XKeycodeToKeysym(display, keyc, 0);
1555 ksname = XKeysymToString(keysym);
1556 if (!ksname) ksname = "NoSymbol";
1558 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1560 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1561 keyc2scan[keyc]=scan++;
1564 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1565 kcControl = XKeysymToKeycode(display, XK_Control_L);
1566 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1567 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1568 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1569 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1570 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1571 wine_tsx11_unlock();
1575 /***********************************************************************
1576 * GetKeyboardLayoutList (X11DRV.@)
1578 UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
1582 TRACE("%d, %p\n", size, hkl);
1586 size = 4096; /* hope we will never have that many */
1590 for (i = 0; main_key_tab[i].comment && (i < size); i++)
1594 DWORD layout = main_key_tab[i].lcid;
1597 /* see comment for GetKeyboardLayout */
1598 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1599 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1600 layout |= 0xe001 << 16; /* FIXME */
1602 layout |= layout << 16;
1604 hkl[i] = (HKL)layout;
1611 /***********************************************************************
1612 * GetKeyboardLayout (X11DRV.@)
1614 HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1619 if (dwThreadid && dwThreadid != GetCurrentThreadId())
1620 FIXME("couldn't return keyboard layout for thread %04lx\n", dwThreadid);
1623 layout = main_key_tab[kbd_layout].lcid;
1626 * Winword uses return value of GetKeyboardLayout as a codepage
1627 * to translate ANSI keyboard messages to unicode. But we have
1628 * a problem with it: for instance Polish keyboard layout is
1629 * identical to the US one, and therefore instead of the Polish
1630 * locale id we return the US one.
1632 layout = GetUserDefaultLCID();
1635 * Microsoft Office expects this value to be something specific
1636 * for Japanese and Korean Windows with an IME the value is 0xe001
1637 * We should probably check to see if an IME exists and if so then
1638 * set this word properly.
1640 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1641 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1642 layout |= 0xe001 << 16; /* FIXME */
1644 layout |= layout << 16;
1650 /***********************************************************************
1651 * GetKeyboardLayoutName (X11DRV.@)
1653 BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1655 static const WCHAR formatW[] = {'%','0','8','l','x',0};
1659 layout = main_key_tab[kbd_layout].lcid;
1660 /* see comment for GetKeyboardLayout */
1661 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1662 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1663 layout |= 0xe001 << 16; /* FIXME */
1665 layout |= layout << 16;
1667 sprintfW(name, formatW, layout);
1668 TRACE("returning %s\n", debugstr_w(name));
1673 /***********************************************************************
1674 * LoadKeyboardLayout (X11DRV.@)
1676 HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1678 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1679 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1684 /***********************************************************************
1685 * UnloadKeyboardLayout (X11DRV.@)
1687 BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
1689 FIXME("%p: stub!\n", hkl);
1690 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1695 /***********************************************************************
1696 * ActivateKeyboardLayout (X11DRV.@)
1698 HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1700 FIXME("%p, %04x: stub!\n", hkl, flags);
1701 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1706 /***********************************************************************
1707 * X11DRV_MappingNotify
1709 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1714 XRefreshKeyboardMapping(&event->xmapping);
1715 wine_tsx11_unlock();
1716 X11DRV_InitKeyboard( pKeyStateTable );
1719 if (!hwnd) hwnd = GetActiveWindow();
1720 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1721 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1725 /***********************************************************************
1726 * VkKeyScanEx (X11DRV.@)
1728 * Note: Windows ignores HKL parameter and uses current active layout instead
1730 SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1732 Display *display = thread_display();
1739 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
1741 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1745 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1747 /* char->keysym (same for ANSI chars) */
1748 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1749 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1752 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1754 { /* It didn't work ... let's try with deadchar code. */
1755 TRACE("retrying with | 0xFE00\n");
1756 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
1758 wine_tsx11_unlock();
1760 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
1761 cChar, keysym, keysym, keycode, keycode);
1763 /* keycode -> (keyc2vkey) vkey */
1764 ret = keyc2vkey[keycode];
1766 if (!keycode || !ret)
1768 TRACE("keycode for '%c' not found, returning -1\n", cChar);
1774 for (i = 0; i < 4; i++) /* find shift state */
1776 if (XKeycodeToKeysym(display, keycode, i) == keysym)
1782 wine_tsx11_unlock();
1788 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
1792 case 1: ret += 0x0100; break;
1793 case 2: ret += 0x0600; break;
1794 case 3: ret += 0x0700; break;
1797 index : 0 adds 0x0000
1798 index : 1 adds 0x0100 (shift)
1799 index : ? adds 0x0200 (ctrl)
1800 index : 2 adds 0x0600 (ctrl+alt)
1801 index : 3 adds 0x0700 (ctrl+alt+shift)
1804 TRACE(" ... returning %#.2x\n", ret);
1808 /***********************************************************************
1809 * MapVirtualKeyEx (X11DRV.@)
1811 UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
1813 Display *display = thread_display();
1815 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1817 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1818 if (hkl != X11DRV_GetKeyboardLayout(0))
1819 FIXME("keyboard layout %p is not supported\n", hkl);
1822 case 0: { /* vkey-code to scan-code */
1823 /* let's do vkey -> keycode -> scan */
1825 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1826 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1827 returnMVK (keyc2scan[keyc] & 0xFF);
1828 TRACE("returning no scan-code.\n");
1831 case 1: { /* scan-code to vkey-code */
1832 /* let's do scan -> keycode -> vkey */
1834 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1835 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1836 returnMVK (keyc2vkey[keyc] & 0xFF);
1837 TRACE("returning no vkey-code.\n");
1840 case 2: { /* vkey-code to unshifted ANSI code */
1841 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1842 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1843 * key.. Looks like something is wrong with the MS docs?
1844 * This is only true for letters, for example VK_0 returns '0' not ')'.
1845 * - hence we use the lock mask to ensure this happens.
1847 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1852 e.display = display;
1855 /* LockMask should behave exactly like caps lock - upercase
1856 * the letter keys and thats about it. */
1861 /* We exit on the first keycode found, to speed up the thing. */
1862 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1863 { /* Find a keycode that could have generated this virtual key */
1864 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1865 { /* We filter the extended bit, we don't know it */
1866 e.keycode = keyc; /* Store it temporarily */
1867 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1868 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1869 state), so set it to 0, we'll find another one */
1874 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1875 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1877 if (wCode==VK_DECIMAL)
1878 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1882 WARN("Unknown virtual key %X !!! \n", wCode);
1883 wine_tsx11_unlock();
1884 return 0; /* whatever */
1886 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1888 if (XLookupString(&e, s, 2, &keysym, NULL))
1890 wine_tsx11_unlock();
1894 TRACE("returning no ANSI.\n");
1895 wine_tsx11_unlock();
1899 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1900 /* left and right */
1901 FIXME(" stub for NT\n");
1904 default: /* reserved */
1905 WARN("Unknown wMapType %d !\n", wMapType);
1911 /***********************************************************************
1912 * GetKeyNameText (X11DRV.@)
1914 INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
1916 int vkey, ansi, scanCode;
1922 scanCode = lParam >> 16;
1923 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1925 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1926 vkey = X11DRV_MapVirtualKeyEx(scanCode, 1, X11DRV_GetKeyboardLayout(0));
1928 /* handle "don't care" bit (0x02000000) */
1929 if (!(lParam & 0x02000000)) {
1948 ansi = X11DRV_MapVirtualKeyEx(vkey, 2, X11DRV_GetKeyboardLayout(0));
1949 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1951 /* first get the name of the "regular" keys which is the Upper case
1952 value of the keycap imprint. */
1953 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1954 (scanCode != 0x137) && /* PrtScn */
1955 (scanCode != 0x135) && /* numpad / */
1956 (scanCode != 0x37 ) && /* numpad * */
1957 (scanCode != 0x4a ) && /* numpad - */
1958 (scanCode != 0x4e ) ) /* numpad + */
1960 if ((nSize >= 2) && lpBuffer)
1962 *lpBuffer = toupperW((WCHAR)ansi);
1970 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1971 without "extended-key" flag. However Wine generates scancode
1972 *with* "extended-key" flag. Seems to occur *only* for the
1973 function keys. Soooo.. We will leave the table alone and
1974 fudge the lookup here till the other part is found and fixed!!! */
1976 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1977 (scanCode == 0x157) || (scanCode == 0x158))
1978 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1980 /* let's do scancode -> keycode -> keysym -> String */
1982 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1983 if ((keyc2scan[keyi]) == scanCode)
1985 if (keyi <= max_keycode)
1988 keyc = (KeyCode) keyi;
1989 keys = XKeycodeToKeysym(thread_display(), keyc, 0);
1990 name = XKeysymToString(keys);
1991 wine_tsx11_unlock();
1992 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1993 scanCode, keyc, (int)keys, name);
1994 if (lpBuffer && nSize && name)
1996 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
1997 lpBuffer[nSize - 1] = 0;
2002 /* Finally issue FIXME for unknown keys */
2004 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2005 if (lpBuffer && nSize)
2010 /***********************************************************************
2011 * X11DRV_KEYBOARD_MapDeadKeysym
2013 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2017 /* symbolic ASCII is the same as defined in rfc1345 */
2018 #ifdef XK_dead_tilde
2019 case XK_dead_tilde :
2021 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2022 return '~'; /* '? */
2023 #ifdef XK_dead_acute
2024 case XK_dead_acute :
2026 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2027 return 0xb4; /* '' */
2028 #ifdef XK_dead_circumflex
2029 case XK_dead_circumflex:
2031 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2032 return '^'; /* '> */
2033 #ifdef XK_dead_grave
2034 case XK_dead_grave :
2036 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2037 return '`'; /* '! */
2038 #ifdef XK_dead_diaeresis
2039 case XK_dead_diaeresis :
2041 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2042 return 0xa8; /* ': */
2043 #ifdef XK_dead_cedilla
2044 case XK_dead_cedilla :
2045 return 0xb8; /* ', */
2047 #ifdef XK_dead_macron
2048 case XK_dead_macron :
2049 return '-'; /* 'm isn't defined on iso-8859-x */
2051 #ifdef XK_dead_breve
2052 case XK_dead_breve :
2053 return 0xa2; /* '( */
2055 #ifdef XK_dead_abovedot
2056 case XK_dead_abovedot :
2057 return 0xff; /* '. */
2059 #ifdef XK_dead_abovering
2060 case XK_dead_abovering :
2061 return '0'; /* '0 isn't defined on iso-8859-x */
2063 #ifdef XK_dead_doubleacute
2064 case XK_dead_doubleacute :
2065 return 0xbd; /* '" */
2067 #ifdef XK_dead_caron
2068 case XK_dead_caron :
2069 return 0xb7; /* '< */
2071 #ifdef XK_dead_ogonek
2072 case XK_dead_ogonek :
2073 return 0xb2; /* '; */
2075 /* FIXME: I don't know this three.
2078 case XK_dead_voiced_sound :
2080 case XK_dead_semivoiced_sound :
2084 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2088 /***********************************************************************
2089 * ToUnicodeEx (X11DRV.@)
2091 * The ToUnicode function translates the specified virtual-key code and keyboard
2092 * state to the corresponding Windows character or characters.
2094 * If the specified key is a dead key, the return value is negative. Otherwise,
2095 * it is one of the following values:
2097 * 0 The specified virtual key has no translation for the current state of the keyboard.
2098 * 1 One Windows character was copied to the buffer.
2099 * 2 Two characters were copied to the buffer. This usually happens when a
2100 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2101 * be composed with the specified virtual key to form a single character.
2103 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2106 INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2107 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2109 Display *display = thread_display();
2118 if (scanCode & 0x8000)
2120 TRACE("Key UP, doing nothing\n" );
2124 if (hkl != X11DRV_GetKeyboardLayout(0))
2125 FIXME("keyboard layout %p is not supported\n", hkl);
2127 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2129 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2133 e.display = display;
2139 if (focus) focus = GetAncestor( focus, GA_ROOT );
2140 if (!focus) focus = GetActiveWindow();
2141 e.window = X11DRV_get_whole_window( focus );
2142 xic = X11DRV_get_ic( focus );
2144 if (lpKeyState[VK_SHIFT] & 0x80)
2146 TRACE("ShiftMask = %04x\n", ShiftMask);
2147 e.state |= ShiftMask;
2149 if (lpKeyState[VK_CAPITAL] & 0x01)
2151 TRACE("LockMask = %04x\n", LockMask);
2152 e.state |= LockMask;
2154 if (lpKeyState[VK_CONTROL] & 0x80)
2156 TRACE("ControlMask = %04x\n", ControlMask);
2157 e.state |= ControlMask;
2159 if (lpKeyState[VK_NUMLOCK] & 0x01)
2161 TRACE("NumLockMask = %04x\n", NumLockMask);
2162 e.state |= NumLockMask;
2165 /* Restore saved AltGr state */
2166 TRACE("AltGrMask = %04x\n", AltGrMask);
2167 e.state |= AltGrMask;
2169 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2170 virtKey, scanCode, e.state);
2172 /* We exit on the first keycode found, to speed up the thing. */
2173 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2174 { /* Find a keycode that could have generated this virtual key */
2175 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2176 { /* We filter the extended bit, we don't know it */
2177 e.keycode = keyc; /* Store it temporarily */
2178 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2179 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2180 state), so set it to 0, we'll find another one */
2185 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2186 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2188 if (virtKey==VK_DECIMAL)
2189 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2191 if (!e.keycode && virtKey != VK_NONAME)
2193 WARN("Unknown virtual key %X !!! \n",virtKey);
2194 wine_tsx11_unlock();
2195 return virtKey; /* whatever */
2197 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2199 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2200 e.type, e.window, e.state, e.keycode);
2203 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
2205 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
2206 wine_tsx11_unlock();
2213 /* An ugly hack for EuroSign: X can't translate it to a character
2214 for some locales. */
2215 if (keysym == XK_EuroSign)
2222 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2223 /* Here we change it back. */
2224 if (keysym == XK_ISO_Left_Tab)
2231 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2234 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2242 ksname = XKeysymToString(keysym);
2243 wine_tsx11_unlock();
2246 if ((keysym >> 8) != 0xff)
2248 ERR("Please report: no char for keysym %04lX (%s) :\n",
2250 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
2251 virtKey, scanCode, e.keycode, e.state);
2255 else { /* ret != 0 */
2256 /* We have a special case to handle : Shift + arrow, shift + home, ...
2257 X returns a char for it, but Windows doesn't. Let's eat it. */
2258 if (!(e.state & NumLockMask) /* NumLock is off */
2259 && (e.state & ShiftMask) /* Shift is pressed */
2260 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2266 /* more areas where X returns characters but Windows does not
2267 CTRL + number or CTRL + symbol */
2268 if (e.state & ControlMask)
2270 if (((keysym>=33) && (keysym < 'A')) ||
2271 ((keysym > 'Z') && (keysym < 'a')))
2278 /* We have another special case for delete key (XK_Delete) on an
2279 extended keyboard. X returns a char for it, but Windows doesn't */
2280 if (keysym == XK_Delete)
2285 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2286 && (keysym == XK_KP_Decimal))
2292 /* perform translation to unicode */
2295 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2296 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2301 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
2302 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
2306 /***********************************************************************
2309 void X11DRV_Beep(void)
2312 XBell(thread_display(), 0);
2313 wine_tsx11_unlock();