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/server.h"
52 #include "wine/unicode.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
56 WINE_DECLARE_DEBUG_CHANNEL(key);
62 #ifndef BITFIELDS_BIGENDIAN
63 unsigned long count : 16;
65 unsigned long code : 8;
66 unsigned long extended : 1;
67 unsigned long unused : 2;
68 unsigned long win_internal : 2;
69 unsigned long context : 1;
70 unsigned long previous : 1;
71 unsigned long transition : 1;
72 #ifdef BITFIELDS_BIGENDIAN
73 unsigned long count : 16;
79 /* key state table bits:
80 0x80 -> key is pressed
81 0x40 -> key got pressed since last time
82 0x01 -> key is toggled
84 BYTE key_state_table[256];
86 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
87 or a WM_KEYUP message */
89 static int min_keycode, max_keycode, keysyms_per_keycode;
90 static WORD keyc2vkey[256], keyc2scan[256];
92 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
93 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
95 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
97 /* Keyboard translation tables */
99 static const WORD main_key_scan_qwerty[MAIN_LEN] =
101 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
102 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
103 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
104 /* q w e r t y u i o p [ ] */
105 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
106 /* a s d f g h j k l ; ' \ */
107 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
108 /* z x c v b n m , . / */
109 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
110 0x56 /* the 102nd key (actually to the right of l-shift) */
113 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
115 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
116 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
117 /* q w e r t y u i o p [ ] */
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
119 /* a s d f g h j k l ; ' \ */
120 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
121 /* \ z x c v b n m , . / */
122 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
123 0x56, /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_scan_dvorak[MAIN_LEN] =
128 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
129 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
130 /* ' , . p y f g c r l / = */
131 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
132 /* a o e u i d h t n s - \ */
133 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
134 /* ; q j k x b m w v z */
135 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
136 0x56 /* the 102nd key (actually to the right of l-shift) */
139 static const WORD main_key_vkey_qwerty[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','Y','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 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
146 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
149 static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
151 /* NOTE: this layout must concur with the scan codes layout above */
152 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
153 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
154 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
155 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
156 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
159 static const WORD main_key_vkey_qwertz[MAIN_LEN] =
161 /* NOTE: this layout must concur with the scan codes layout above */
162 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
163 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
164 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
165 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
166 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
169 static const WORD main_key_vkey_qwertz_105[MAIN_LEN] =
171 /* NOTE: this layout must concur with the scan codes layout above */
172 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
173 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
174 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
175 VK_OEM_102,'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2
178 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
180 /* NOTE: this layout must concur with the scan codes layout above */
181 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
182 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
183 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
184 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
185 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
188 static const WORD main_key_vkey_azerty[MAIN_LEN] =
190 /* NOTE: this layout must concur with the scan codes layout above */
191 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
192 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
193 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
194 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
195 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
198 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
200 /* NOTE: this layout must concur with the scan codes layout above */
201 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
202 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
203 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
204 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
205 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
208 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
210 /* the VK mappings for the main keyboard will be auto-assigned as before,
211 so what we have here is just the character tables */
212 /* order: Normal, Shift, AltGr, Shift-AltGr */
213 /* We recommend you write just what is guaranteed to be correct (i.e. what's
214 written on the keycaps), not the bunch of special characters behind AltGr
215 and Shift-AltGr if it can vary among different X servers */
216 /* Remember that your 102nd key (to the right of l-shift) should be on a
217 separate line, see existing tables */
218 /* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
219 /* Remember to also add your new table to the layout index table far below! */
221 /*** German Logitech Desktop Pro keyboard layout */
222 static const char main_key_DE_logitech[MAIN_LEN][4] =
224 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
225 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
226 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
227 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
231 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
232 static const char main_key_US[MAIN_LEN][4] =
234 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
235 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
236 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
237 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
240 /*** United States keyboard layout (phantom key version) */
241 /* (XFree86 reports the <> key even if it's not physically there) */
242 static const char main_key_US_phantom[MAIN_LEN][4] =
244 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
245 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
246 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
247 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
248 "<>" /* the phantom key */
251 /*** United States keyboard layout (dvorak version) */
252 static const char main_key_US_dvorak[MAIN_LEN][4] =
254 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
255 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
256 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
257 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
260 /*** British keyboard layout */
261 static const char main_key_UK[MAIN_LEN][4] =
263 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
264 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
265 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
266 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
270 /*** French keyboard layout (contributed by Eric Pouech) */
271 static const char main_key_FR[MAIN_LEN][4] =
273 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
274 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
275 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
276 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
280 /*** Icelandic keyboard layout (setxkbmap is) */
281 static const char main_key_IS[MAIN_LEN][4] =
283 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
284 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
285 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
286 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
290 /*** German keyboard layout (contributed by Ulrich Weigand) */
291 static const char main_key_DE[MAIN_LEN][4] =
293 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
294 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
295 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
296 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
300 /*** German keyboard layout without dead keys */
301 static const char main_key_DE_nodead[MAIN_LEN][4] =
303 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
304 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
305 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
306 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
310 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
311 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
313 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
314 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
315 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
316 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
319 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
320 static const char main_key_SG[MAIN_LEN][4] =
322 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
323 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
325 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
329 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
330 static const char main_key_SF[MAIN_LEN][4] =
332 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
333 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
334 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
335 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
339 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
340 static const char main_key_NO[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 /*** Danish keyboard layout (setxkbmap dk) */
350 static const char main_key_DA[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 /*** Swedish keyboard layout (setxkbmap se) */
360 static const char main_key_SE[MAIN_LEN][4] =
362 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
363 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
364 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
365 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
369 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
370 static const char main_key_ET[MAIN_LEN][4] =
372 "·~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
373 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
374 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
375 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
379 /*** Canadian French keyboard layout */
380 static const char main_key_CF[MAIN_LEN][4] =
382 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
383 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
384 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
385 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
389 /*** Canadian CAN/CSA Z243.200-92 keyboard layout
390 *** Contributed by Jean-Michel Dault <jmdault@revolutionlinux.com> */
391 static const char main_key_CA[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 /*** Portuguese keyboard layout (setxkbmap pt) */
402 static const char main_key_PT[MAIN_LEN][4] =
404 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
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",",;",".:","-_",
411 /*** Italian keyboard layout (setxkbmap it) */
412 static const char main_key_IT[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",",;",".:","-_",
421 /*** Finnish keyboard layout (setxkbmap fi) */
422 static const char main_key_FI[MAIN_LEN][4] =
424 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
425 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
426 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
427 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
431 /*** Bulgarian bds keyboard layout */
432 static const char main_key_BG_bds[MAIN_LEN][4] =
434 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
435 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
436 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
437 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
438 "<>" /* the phantom key */
441 /*** Bulgarian phonetic keyboard layout */
442 static const char main_key_BG_phonetic[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 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
452 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
453 static const char main_key_BY[MAIN_LEN][4] =
455 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
456 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
457 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
458 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
462 /*** Russian keyboard layout (contributed by Pavel Roskin) */
463 static const char main_key_RU[MAIN_LEN][4] =
465 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
466 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
467 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
468 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
471 /*** Russian keyboard layout (phantom key version) */
472 static const char main_key_RU_phantom[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 /*** Russian keyboard layout KOI8-R */
482 static const char main_key_RU_koi8r[MAIN_LEN][4] =
484 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
485 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
486 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
487 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
488 "<>" /* the phantom key */
491 /*** Russian keyboard layout cp1251 */
492 static const char main_key_RU_cp1251[MAIN_LEN][4] =
494 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
495 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
496 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
497 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
498 "<>" /* the phantom key */
501 /*** Russian phonetic keyboard layout */
502 static const char main_key_RU_phonetic[MAIN_LEN][4] =
504 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
505 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
506 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
507 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
508 "<>" /* the phantom key */
511 /*** Ukrainian keyboard layout KOI8-U */
512 static const char main_key_UA[MAIN_LEN][4] =
514 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
515 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
516 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
517 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
518 "<>" /* the phantom key */
521 /*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
522 /*** (as it appears on most of keyboards sold today) */
523 static const char main_key_UA_std[MAIN_LEN][4] =
525 "½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
526 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
527 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
528 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
529 "<>" /* the phantom key */
532 /*** Russian keyboard layout KOI8-R (pair to the previous) */
533 static const char main_key_RU_std[MAIN_LEN][4] =
535 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
536 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
537 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
538 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
539 "<>" /* the phantom key */
542 /*** Spanish keyboard layout (setxkbmap es) */
543 static const char main_key_ES[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 /*** Belgian keyboard layout ***/
553 static const char main_key_BE[MAIN_LEN][4] =
555 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
556 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
557 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
558 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
562 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
563 static const char main_key_HU[MAIN_LEN][4] =
565 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
566 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
567 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
568 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:>","-_*",
572 /*** Polish (programmer's) keyboard layout ***/
573 static const char main_key_PL[MAIN_LEN][4] =
575 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
576 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
577 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
578 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
582 /*** Slovenian keyboard layout (setxkbmap si) ***/
583 static const char main_key_SI[MAIN_LEN][4] =
585 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
586 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
587 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
588 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
592 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
593 static const char main_key_HR_jelly[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 /*** Croatian keyboard layout (setxkbmap hr) ***/
603 static const char main_key_HR[MAIN_LEN][4] =
605 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
606 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
607 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
608 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
612 /*** Japanese 106 keyboard layout ***/
613 static const char main_key_JA_jp106[MAIN_LEN][4] =
615 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
616 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
617 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
618 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
622 /*** Japanese pc98x1 keyboard layout ***/
623 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
625 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
626 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
627 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
628 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
632 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
633 static const char main_key_PT_br[MAIN_LEN][4] =
635 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
636 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
637 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
638 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
641 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
642 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
644 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
645 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
646 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
647 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
650 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
651 static const char main_key_US_intl[MAIN_LEN][4] =
653 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
654 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
655 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
656 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
659 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
660 - dead_abovering replaced with degree - no symbol in iso8859-2
661 - brokenbar replaced with bar */
662 static const char main_key_SK[MAIN_LEN][4] =
664 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
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 (setxkbmap cz) */
672 static const char main_key_CZ[MAIN_LEN][4] =
674 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
675 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
676 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
677 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
681 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
682 static const char main_key_CZ_qwerty[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 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
692 static const char main_key_SK_prog[MAIN_LEN][4] =
694 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
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åÅ",",<",".>","/?",
701 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
702 static const char main_key_CS[MAIN_LEN][4] =
704 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
705 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
706 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
707 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
711 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
712 static const char main_key_LA[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",",;",".:","-_",
721 /*** Lithuanian (Baltic) keyboard layout (pc/lt in XFree86 4.3.0, contributed by Nerijus Baliûnas) */
722 static const char main_key_LT_B[MAIN_LEN][4] =
724 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
725 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
726 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
727 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
730 /*** Turkish keyboard Layout */
731 static const char main_key_TK[MAIN_LEN][4] =
733 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
734 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
735 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
736 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
739 /*** Turkish keyboard layout (setxkbmap tr) */
740 static const char main_key_TR[MAIN_LEN][4] =
742 "\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
743 "qQ","wW","eE","rR","tT","yY","uU","ýI","oO","pP","ðÐ","üÜ",
744 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;",
745 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
749 /*** Israelian keyboard layout (setxkbmap us,il) */
750 static const char main_key_IL[MAIN_LEN][4] =
752 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
753 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
754 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
755 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
759 /*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
760 static const char main_key_IL_phonetic[MAIN_LEN][4] =
762 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
763 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
764 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
765 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
769 /*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
770 static const char main_key_IL_saharon[MAIN_LEN][4] =
772 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
773 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
774 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
775 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
779 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
780 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
781 message since they have different characters in gr and el XFree86 layouts. */
782 static const char main_key_EL[MAIN_LEN][4] =
784 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
785 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
786 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
787 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
791 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
792 static const char main_key_th[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·?",",<Á²",".>ãÌ","/?½Æ"
800 /*** VNC keyboard layout */
801 static const WORD main_key_scan_vnc[MAIN_LEN] =
803 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
804 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,
808 static const WORD main_key_vkey_vnc[MAIN_LEN] =
810 '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,
811 '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',
815 static const char main_key_vnc[MAIN_LEN][4] =
817 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
818 "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"
821 /*** Dutch keyboard layout (setxkbmap nl) ***/
822 static const char main_key_NL[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",",;",".:","-=",
833 /*** Layout table. Add your keyboard mappings to this list */
834 static const struct {
835 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
836 in the appropriate dlls/kernel/nls/.nls file */
838 const char (*key)[MAIN_LEN][4];
839 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
840 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
842 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
843 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
844 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
845 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
846 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
847 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
848 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
849 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
850 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwertz_105},
851 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
852 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
853 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
854 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
855 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
856 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
857 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
858 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
859 {0x0c0c, "Canadian CAN/CSA-Z243.200-92 keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
860 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
861 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
862 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
863 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
864 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
865 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
866 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
867 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
868 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
869 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
870 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
871 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
872 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
873 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
874 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
875 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
876 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
877 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
878 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
879 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
880 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
881 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
882 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
883 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
884 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
885 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
886 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
887 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
888 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
889 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
890 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
891 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
892 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
893 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
894 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
895 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
896 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
897 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
898 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
899 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
900 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
901 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
903 {0, NULL, NULL, NULL, NULL} /* sentinel */
905 static unsigned kbd_layout=0; /* index into above table of layouts */
907 /* maybe more of these scancodes should be extended? */
908 /* extended must be set for ALT_R, CTRL_R,
909 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
910 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
911 /* FIXME should we set extended bit for NumLock ? My
912 * Windows does ... DF */
913 /* Yes, to distinguish based on scan codes, also
914 for PrtScn key ... GA */
916 static const WORD nonchar_key_vkey[256] =
919 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
921 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
922 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
923 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
925 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
926 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
927 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
928 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
929 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
930 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
932 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
933 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
934 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
936 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
937 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
938 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
940 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
941 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
942 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
943 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
944 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
945 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
946 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
947 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
948 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
949 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
950 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
951 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
954 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
955 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
956 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
957 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
959 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
960 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
961 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
962 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
963 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
966 static const WORD nonchar_key_scan[256] =
969 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
971 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
972 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
973 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
982 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
985 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
986 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
991 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
992 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
993 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
995 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
996 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
997 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1000 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1001 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
1002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1005 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1006 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
1007 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1012 /* Returns the Windows virtual key code associated with the X event <e> */
1013 /* x11 lock must be held */
1014 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1019 XmbLookupString(xic, e, NULL, 0, &keysym, NULL);
1021 XLookupString(e, NULL, 0, &keysym, NULL);
1023 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
1024 && (e->state & NumLockMask))
1025 /* Only the Keypad keys 0-9 and . send different keysyms
1026 * depending on the NumLock state */
1027 return nonchar_key_vkey[keysym & 0xFF];
1029 TRACE_(key)("e->keycode = %x\n", e->keycode);
1031 return keyc2vkey[e->keycode];
1034 static BOOL NumState=FALSE, CapsState=FALSE;
1037 /***********************************************************************
1038 * X11DRV_send_keyboard_input
1040 void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time,
1041 DWORD dwExtraInfo, UINT injected_flags )
1045 KBDLLHOOKSTRUCT hook;
1048 keylp.lp1.count = 1;
1049 keylp.lp1.code = wScan;
1050 keylp.lp1.extended = (dwFlags & KEYEVENTF_EXTENDEDKEY) != 0;
1051 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
1052 * don't remember where I read it - AK */
1053 /* it's '1' under windows, when a dialog box appears
1054 * and you press one of the underlined keys - DF*/
1056 /* note that there is a test for all this */
1057 if (dwFlags & KEYEVENTF_KEYUP )
1060 if ((key_state_table[VK_MENU] & 0x80) &&
1061 ((wVk == VK_MENU) || (wVk == VK_CONTROL) || !(key_state_table[VK_CONTROL] & 0x80)))
1063 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1064 (wVk != VK_MENU)) /* <ALT>-down...<something else>-up */
1065 message = WM_SYSKEYUP;
1068 key_state_table[wVk] &= ~0x80;
1069 keylp.lp1.previous = 1;
1070 keylp.lp1.transition = 1;
1074 keylp.lp1.previous = (key_state_table[wVk] & 0x80) != 0;
1075 keylp.lp1.transition = 0;
1076 if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1077 key_state_table[wVk] |= 0xc0;
1079 message = WM_KEYDOWN;
1080 if ((key_state_table[VK_MENU] & 0x80) && !(key_state_table[VK_CONTROL] & 0x80))
1082 message = WM_SYSKEYDOWN;
1087 keylp.lp1.context = (key_state_table[VK_MENU] & 0x80) != 0; /* 1 if alt */
1089 TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
1090 wVk, keylp.lp2, key_state_table[wVk] );
1093 hook.scanCode = wScan;
1094 hook.flags = (keylp.lp2 >> 24) | injected_flags;
1096 hook.dwExtraInfo = dwExtraInfo;
1097 if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1099 SERVER_START_REQ( send_message )
1101 req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1102 req->type = MSG_HARDWARE;
1107 req->lparam = keylp.lp2;
1108 req->x = cursor_pos.x;
1109 req->y = cursor_pos.y;
1111 req->info = dwExtraInfo;
1113 req->callback = NULL;
1114 wine_server_call( req );
1120 /**********************************************************************
1121 * KEYBOARD_GenerateMsg
1123 * Generate Down+Up messages when NumLock or CapsLock is pressed.
1125 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
1128 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
1130 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
1134 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
1135 don't treat it. It's from the same key press. Then the state goes to ON.
1136 And from there, a 'release' event will switch off the toggle key. */
1138 TRACE("INTERM : don't treat release of toggle key. key_state_table[%#x] = %#x\n",
1139 vkey,key_state_table[vkey]);
1142 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
1143 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
1144 if ( key_state_table[vkey] & 0x1 ) /* it was ON */
1146 if (Evtype!=KeyPress)
1148 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
1149 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1150 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1152 key_state_table[vkey] &= ~0x01; /* Toggle state to off. */
1155 else /* it was OFF */
1156 if (Evtype==KeyPress)
1158 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
1159 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1160 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1161 *State=TRUE; /* Goes to intermediary state before going to ON */
1162 key_state_table[vkey] |= 0x01; /* Toggle state to on. */
1167 /***********************************************************************
1168 * KEYBOARD_UpdateOneState
1170 * Updates internal state for <vkey>, depending on key <state> under X
1173 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
1175 /* Do something if internal table state != X state for keycode */
1176 if (((key_state_table[vkey] & 0x80)!=0) != state)
1178 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1179 vkey, key_state_table[vkey]);
1181 /* Fake key being pressed inside wine */
1182 X11DRV_send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time, 0, 0 );
1184 TRACE("State after %#.2x\n",key_state_table[vkey]);
1188 /***********************************************************************
1189 * X11DRV_KeymapNotify
1191 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1193 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1194 * from wine to another application and back.
1195 * Toggle keys are handled in HandleEvent.
1197 void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1199 int i, j, alt, control, shift;
1200 DWORD time = GetCurrentTime();
1202 alt = control = shift = 0;
1203 for (i = 0; i < 32; i++)
1205 if (!event->xkeymap.key_vector[i]) continue;
1206 for (j = 0; j < 8; j++)
1208 if (!(event->xkeymap.key_vector[i] & (1<<j))) continue;
1209 switch(keyc2vkey[(i * 8) + j] & 0xff)
1211 case VK_MENU: alt = 1; break;
1212 case VK_CONTROL: control = 1; break;
1213 case VK_SHIFT: shift = 1; break;
1217 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
1218 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
1219 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
1222 /***********************************************************************
1225 * Handle a X key event
1227 void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1229 XKeyEvent *event = &xev->xkey;
1232 WORD vkey = 0, bScan;
1235 XIC xic = X11DRV_get_ic( hwnd );
1236 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1239 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1240 event->type, event->window, event->state, event->keycode);
1244 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
1246 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1247 wine_tsx11_unlock();
1249 /* Ignore some unwanted events */
1250 if ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1251 keysym == XK_Mode_switch)
1254 TRACE("Ignoring %s keyboard event\n", XKeysymToString(keysym));
1255 wine_tsx11_unlock();
1259 TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status);
1261 if (status == XBufferOverflow)
1262 ERR("Buffer Overflow need %i!\n",ascii_chars);
1264 if (status == XLookupChars)
1266 X11DRV_XIMLookupChars( Str, ascii_chars );
1270 /* If XKB extensions are used, the state mask for AltGr will use the group
1271 index instead of the modifier mask. The group index is set in bits
1272 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1273 pressed, look if the group index is different than 0. From XKB
1274 extension documentation, the group index for AltGr should be 2
1275 (event->state = 0x2000). It's probably better to not assume a
1276 predefined group index and find it dynamically
1278 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1279 /* Save also all possible modifier states. */
1280 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1282 Str[ascii_chars] = '\0';
1287 ksname = XKeysymToString(keysym);
1288 wine_tsx11_unlock();
1291 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / 0x%02x / '%s'\n",
1292 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1293 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1297 vkey = EVENT_event_to_vkey(xic,event);
1298 /* X returns keycode 0 for composed characters */
1299 if (!vkey && ascii_chars) vkey = VK_NONAME;
1300 wine_tsx11_unlock();
1302 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1303 event->keycode, vkey);
1307 switch (vkey & 0xff)
1310 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1313 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,key_state_table[vkey]);
1314 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1315 TRACE("State after : %#.2x\n",key_state_table[vkey]);
1318 /* Adjust the NUMLOCK state if it has been changed outside wine */
1319 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1321 TRACE("Adjusting NumLock state.\n");
1322 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1323 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1325 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1326 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1328 TRACE("Adjusting Caps Lock state.\n");
1329 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1330 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1332 /* Not Num nor Caps : end of intermediary states for both. */
1336 bScan = keyc2scan[event->keycode] & 0xFF;
1337 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1340 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1341 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1343 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1348 /**********************************************************************
1349 * X11DRV_KEYBOARD_DetectLayout
1351 * Called from X11DRV_InitKeyboard
1352 * This routine walks through the defined keyboard layouts and selects
1353 * whichever matches most closely.
1354 * X11 lock must be held.
1357 X11DRV_KEYBOARD_DetectLayout (void)
1359 Display *display = thread_display();
1360 unsigned current, match, mismatch, seq, i, syms;
1361 int score, keyc, key, pkey, ok;
1363 const char (*lkey)[MAIN_LEN][4];
1364 unsigned max_seq = 0;
1365 int max_score = 0, ismatch = 0;
1369 syms = keysyms_per_keycode;
1371 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1374 for (current = 0; main_key_tab[current].comment; current++) {
1375 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1380 lkey = main_key_tab[current].key;
1382 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1383 /* get data for keycode from X server */
1384 for (i = 0; i < syms; i++) {
1385 keysym = XKeycodeToKeysym (display, keyc, i);
1386 /* Allow both one-byte and two-byte national keysyms */
1387 if ((keysym < 0x8000) && (keysym != ' '))
1390 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1393 TRACE("XKB could not translate keysym %ld\n", keysym);
1394 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1395 * with appropriate ShiftMask and Mode_switch, use XLookupString
1396 * to get character in the local encoding.
1398 ckey[i] = keysym & 0xFF;
1402 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1406 /* search for a match in layout table */
1407 /* right now, we just find an absolute match for defined positions */
1408 /* (undefined positions are ignored, so if it's defined as "3#" in */
1409 /* the table, it's okay that the X server has "3#£", for example) */
1410 /* however, the score will be higher for longer matches */
1411 for (key = 0; key < MAIN_LEN; key++) {
1412 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1413 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1415 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1423 /* count the matches and mismatches */
1426 /* and how much the keycode order matches */
1427 if (key > pkey) seq++;
1430 /* print spaces instead of \0's */
1431 for (i = 0; i < sizeof(ckey); i++) if (!ckey[i]) ckey[i] = ' ';
1432 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %c%c%c%c\n",
1433 keysym, keyc, ckey[0], ckey[1], ckey[2], ckey[3]);
1439 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1440 match, mismatch, seq, score);
1441 if ((score > max_score) ||
1442 ((score == max_score) && (seq > max_seq))) {
1443 /* best match so far */
1444 kbd_layout = current;
1447 ismatch = !mismatch;
1450 /* we're done, report results if necessary */
1452 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1453 main_key_tab[kbd_layout].comment);
1455 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1458 /**********************************************************************
1459 * X11DRV_InitKeyboard
1461 void X11DRV_InitKeyboard(void)
1463 Display *display = thread_display();
1465 XModifierKeymap *mmp;
1469 WORD scan, vkey, OEMvkey;
1470 int keyc, i, keyn, syms;
1471 char ckey[4]={0,0,0,0};
1472 const char (*lkey)[MAIN_LEN][4];
1475 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1476 ksp = XGetKeyboardMapping(display, min_keycode,
1477 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1478 /* We are only interested in keysyms_per_keycode.
1479 There is no need to hold a local copy of the keysyms table */
1482 mmp = XGetModifierMapping(display);
1483 kcp = mmp->modifiermap;
1484 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1488 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1493 for (k = 0; k < keysyms_per_keycode; k += 1)
1494 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1496 NumLockMask = 1 << i;
1497 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1501 XFreeModifiermap(mmp);
1503 /* Detect the keyboard layout */
1504 X11DRV_KEYBOARD_DetectLayout();
1505 lkey = main_key_tab[kbd_layout].key;
1506 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1508 /* Now build two conversion arrays :
1509 * keycode -> vkey + scancode + extended
1510 * vkey + extended -> keycode */
1512 e2.display = display;
1515 OEMvkey = VK_OEM_8; /* next is available. */
1516 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1522 e2.keycode = (KeyCode)keyc;
1523 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1525 if (keysym) /* otherwise, keycode not used */
1527 if ((keysym >> 8) == 0xFF) /* non-character key */
1529 vkey = nonchar_key_vkey[keysym & 0xff];
1530 scan = nonchar_key_scan[keysym & 0xff];
1531 /* set extended bit when necessary */
1532 if (scan & 0x100) vkey |= 0x100;
1533 } else if (keysym == 0x20) { /* Spacebar */
1536 } else if (have_chars) {
1537 /* we seem to need to search the layout-dependent scancodes */
1538 int maxlen=0,maxval=-1,ok;
1539 for (i=0; i<syms; i++) {
1540 keysym = XKeycodeToKeysym(display, keyc, i);
1541 if ((keysym<0x8000) && (keysym!=' '))
1544 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1547 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1548 * with appropriate ShiftMask and Mode_switch, use XLookupString
1549 * to get character in the local encoding.
1551 ckey[i] = keysym & 0xFF;
1554 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1557 /* find key with longest match streak */
1558 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1559 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1560 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1561 if (ok||(i>maxlen)) {
1562 maxlen=i; maxval=keyn;
1568 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1569 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1570 scan = (*lscan)[maxval];
1571 vkey = (*lvkey)[maxval];
1574 #if 0 /* this breaks VK_OEM_x VKeys in some layout tables by inserting
1575 * a VK code into a not appropriate place.
1577 /* find a suitable layout-dependent VK code */
1578 /* (most Winelib apps ought to be able to work without layout tables!) */
1579 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1581 keysym = XLookupKeysym(&e2, i);
1582 if ((keysym >= VK_0 && keysym <= VK_9)
1583 || (keysym >= VK_A && keysym <= VK_Z)) {
1588 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1590 keysym = XLookupKeysym(&e2, i);
1593 case ';': vkey = VK_OEM_1; break;
1594 case '/': vkey = VK_OEM_2; break;
1595 case '`': vkey = VK_OEM_3; break;
1596 case '[': vkey = VK_OEM_4; break;
1597 case '\\': vkey = VK_OEM_5; break;
1598 case ']': vkey = VK_OEM_6; break;
1599 case '\'': vkey = VK_OEM_7; break;
1600 case ',': vkey = VK_OEM_COMMA; break;
1601 case '.': vkey = VK_OEM_PERIOD; break;
1602 case '-': vkey = VK_OEM_MINUS; break;
1603 case '+': vkey = VK_OEM_PLUS; break;
1609 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1610 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1613 case 0xc1 : OEMvkey=0xdb; break;
1614 case 0xe5 : OEMvkey=0xe9; break;
1615 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1620 if (TRACE_ON(keyboard))
1622 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1623 OEMvkey, e2.keycode);
1625 for (i = 0; i < keysyms_per_keycode; i += 1)
1629 keysym = XLookupKeysym(&e2, i);
1630 ksname = XKeysymToString(keysym);
1632 ksname = "NoSymbol";
1633 TRACE( "%lX (%s) ", keysym, ksname);
1640 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
1641 keyc2vkey[e2.keycode] = vkey;
1642 keyc2scan[e2.keycode] = scan;
1645 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1646 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1647 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1649 keysym = XKeycodeToKeysym(display, keyc, 0);
1650 ksname = XKeysymToString(keysym);
1651 if (!ksname) ksname = "NoSymbol";
1653 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1655 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1656 keyc2scan[keyc]=scan++;
1659 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1660 kcControl = XKeysymToKeycode(display, XK_Control_L);
1661 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1662 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1663 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1664 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1665 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1666 wine_tsx11_unlock();
1670 /**********************************************************************
1671 * GetAsyncKeyState (X11DRV.@)
1673 SHORT X11DRV_GetAsyncKeyState(INT key)
1675 SHORT retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
1676 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
1677 key_state_table[key] &= ~0x40;
1678 TRACE_(key)("(%x) -> %x\n", key, retval);
1683 /***********************************************************************
1684 * GetKeyboardLayoutList (X11DRV.@)
1686 UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
1690 TRACE("%d, %p\n", size, hkl);
1694 size = 4096; /* hope we will never have that many */
1698 for (i = 0; main_key_tab[i].comment && (i < size); i++)
1702 DWORD layout = main_key_tab[i].lcid;
1705 /* see comment for GetKeyboardLayout */
1706 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1707 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1708 layout |= 0xe001 << 16; /* FIXME */
1710 layout |= layout << 16;
1712 hkl[i] = (HKL)layout;
1719 /***********************************************************************
1720 * GetKeyboardLayout (X11DRV.@)
1722 HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1727 if (dwThreadid && dwThreadid != GetCurrentThreadId())
1728 FIXME("couldn't return keyboard layout for thread %04lx\n", dwThreadid);
1731 layout = main_key_tab[kbd_layout].lcid;
1734 * Winword uses return value of GetKeyboardLayout as a codepage
1735 * to translate ANSI keyboard messages to unicode. But we have
1736 * a problem with it: for instance Polish keyboard layout is
1737 * identical to the US one, and therefore instead of the Polish
1738 * locale id we return the US one.
1740 layout = GetUserDefaultLCID();
1743 * Microsoft Office expects this value to be something specific
1744 * for Japanese and Korean Windows with an IME the value is 0xe001
1745 * We should probably check to see if an IME exists and if so then
1746 * set this word properly.
1748 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1749 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1750 layout |= 0xe001 << 16; /* FIXME */
1752 layout |= layout << 16;
1758 /***********************************************************************
1759 * GetKeyboardLayoutName (X11DRV.@)
1761 BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
1763 static const WCHAR formatW[] = {'%','0','8','l','x',0};
1767 layout = main_key_tab[kbd_layout].lcid;
1768 /* see comment for GetKeyboardLayout */
1769 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
1770 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1771 layout |= 0xe001 << 16; /* FIXME */
1773 layout |= layout << 16;
1775 sprintfW(name, formatW, layout);
1776 TRACE("returning %s\n", debugstr_w(name));
1781 /***********************************************************************
1782 * LoadKeyboardLayout (X11DRV.@)
1784 HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1786 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
1787 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1792 /***********************************************************************
1793 * UnloadKeyboardLayout (X11DRV.@)
1795 BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
1797 FIXME("%p: stub!\n", hkl);
1798 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1803 /***********************************************************************
1804 * ActivateKeyboardLayout (X11DRV.@)
1806 HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1808 FIXME("%p, %04x: stub!\n", hkl, flags);
1809 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1814 /***********************************************************************
1815 * X11DRV_MappingNotify
1817 void X11DRV_MappingNotify( HWND dummy, XEvent *event )
1822 XRefreshKeyboardMapping(&event->xmapping);
1823 wine_tsx11_unlock();
1824 X11DRV_InitKeyboard();
1827 if (!hwnd) hwnd = GetActiveWindow();
1828 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
1829 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
1833 /***********************************************************************
1834 * VkKeyScanEx (X11DRV.@)
1836 * Note: Windows ignores HKL parameter and uses current active layout instead
1838 SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
1840 Display *display = thread_display();
1847 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
1849 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
1853 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
1855 /* char->keysym (same for ANSI chars) */
1856 keysym = (unsigned char)cChar; /* (!) cChar is signed */
1857 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
1860 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
1862 { /* It didn't work ... let's try with deadchar code. */
1863 TRACE("retrying with | 0xFE00\n");
1864 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
1866 wine_tsx11_unlock();
1868 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
1869 cChar, keysym, keysym, keycode, keycode);
1871 /* keycode -> (keyc2vkey) vkey */
1872 ret = keyc2vkey[keycode];
1874 if (!keycode || !ret)
1876 TRACE("keycode for '%c' not found, returning -1\n", cChar);
1882 for (i = 0; i < 4; i++) /* find shift state */
1884 if (XKeycodeToKeysym(display, keycode, i) == keysym)
1890 wine_tsx11_unlock();
1896 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
1900 case 1: ret += 0x0100; break;
1901 case 2: ret += 0x0600; break;
1902 case 3: ret += 0x0700; break;
1905 index : 0 adds 0x0000
1906 index : 1 adds 0x0100 (shift)
1907 index : ? adds 0x0200 (ctrl)
1908 index : 2 adds 0x0600 (ctrl+alt)
1909 index : 3 adds 0x0700 (ctrl+alt+shift)
1912 TRACE(" ... returning %#.2x\n", ret);
1916 /***********************************************************************
1917 * MapVirtualKeyEx (X11DRV.@)
1919 UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
1921 Display *display = thread_display();
1923 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1925 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
1926 if (hkl != X11DRV_GetKeyboardLayout(0))
1927 FIXME("keyboard layout %p is not supported\n", hkl);
1930 case 0: { /* vkey-code to scan-code */
1931 /* let's do vkey -> keycode -> scan */
1933 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1934 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1935 returnMVK (keyc2scan[keyc] & 0xFF);
1936 TRACE("returning no scan-code.\n");
1939 case 1: { /* scan-code to vkey-code */
1940 /* let's do scan -> keycode -> vkey */
1942 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1943 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1944 returnMVK (keyc2vkey[keyc] & 0xFF);
1945 TRACE("returning no vkey-code.\n");
1948 case 2: { /* vkey-code to unshifted ANSI code */
1949 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1950 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1951 * key.. Looks like something is wrong with the MS docs?
1952 * This is only true for letters, for example VK_0 returns '0' not ')'.
1953 * - hence we use the lock mask to ensure this happens.
1955 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1960 e.display = display;
1963 /* LockMask should behave exactly like caps lock - upercase
1964 * the letter keys and thats about it. */
1969 /* We exit on the first keycode found, to speed up the thing. */
1970 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1971 { /* Find a keycode that could have generated this virtual key */
1972 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1973 { /* We filter the extended bit, we don't know it */
1974 e.keycode = keyc; /* Store it temporarily */
1975 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1976 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1977 state), so set it to 0, we'll find another one */
1982 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1983 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1985 if (wCode==VK_DECIMAL)
1986 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1990 WARN("Unknown virtual key %X !!! \n", wCode);
1991 wine_tsx11_unlock();
1992 return 0; /* whatever */
1994 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1996 if (XLookupString(&e, s, 2, &keysym, NULL))
1998 wine_tsx11_unlock();
2002 TRACE("returning no ANSI.\n");
2003 wine_tsx11_unlock();
2007 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
2008 /* left and right */
2009 FIXME(" stub for NT\n");
2012 default: /* reserved */
2013 WARN("Unknown wMapType %d !\n", wMapType);
2019 /***********************************************************************
2020 * GetKeyNameText (X11DRV.@)
2022 INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2024 int vkey, ansi, scanCode;
2030 scanCode = lParam >> 16;
2031 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2033 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
2034 vkey = X11DRV_MapVirtualKeyEx(scanCode, 1, X11DRV_GetKeyboardLayout(0));
2036 /* handle "don't care" bit (0x02000000) */
2037 if (!(lParam & 0x02000000)) {
2056 ansi = X11DRV_MapVirtualKeyEx(vkey, 2, X11DRV_GetKeyboardLayout(0));
2057 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
2059 /* first get the name of the "regular" keys which is the Upper case
2060 value of the keycap imprint. */
2061 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2062 (scanCode != 0x137) && /* PrtScn */
2063 (scanCode != 0x135) && /* numpad / */
2064 (scanCode != 0x37 ) && /* numpad * */
2065 (scanCode != 0x4a ) && /* numpad - */
2066 (scanCode != 0x4e ) ) /* numpad + */
2068 if ((nSize >= 2) && lpBuffer)
2070 *lpBuffer = toupperW((WCHAR)ansi);
2078 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2079 without "extended-key" flag. However Wine generates scancode
2080 *with* "extended-key" flag. Seems to occur *only* for the
2081 function keys. Soooo.. We will leave the table alone and
2082 fudge the lookup here till the other part is found and fixed!!! */
2084 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2085 (scanCode == 0x157) || (scanCode == 0x158))
2086 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2088 /* let's do scancode -> keycode -> keysym -> String */
2090 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2091 if ((keyc2scan[keyi]) == scanCode)
2093 if (keyi <= max_keycode)
2096 keyc = (KeyCode) keyi;
2097 keys = XKeycodeToKeysym(thread_display(), keyc, 0);
2098 name = XKeysymToString(keys);
2099 wine_tsx11_unlock();
2100 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2101 scanCode, keyc, (int)keys, name);
2102 if (lpBuffer && nSize && name)
2104 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2105 lpBuffer[nSize - 1] = 0;
2110 /* Finally issue FIXME for unknown keys */
2112 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2113 if (lpBuffer && nSize)
2118 /***********************************************************************
2119 * X11DRV_KEYBOARD_MapDeadKeysym
2121 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2125 /* symbolic ASCII is the same as defined in rfc1345 */
2126 #ifdef XK_dead_tilde
2127 case XK_dead_tilde :
2129 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2130 return '~'; /* '? */
2131 #ifdef XK_dead_acute
2132 case XK_dead_acute :
2134 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2135 return 0xb4; /* '' */
2136 #ifdef XK_dead_circumflex
2137 case XK_dead_circumflex:
2139 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2140 return '^'; /* '> */
2141 #ifdef XK_dead_grave
2142 case XK_dead_grave :
2144 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2145 return '`'; /* '! */
2146 #ifdef XK_dead_diaeresis
2147 case XK_dead_diaeresis :
2149 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2150 return 0xa8; /* ': */
2151 #ifdef XK_dead_cedilla
2152 case XK_dead_cedilla :
2153 return 0xb8; /* ', */
2155 #ifdef XK_dead_macron
2156 case XK_dead_macron :
2157 return '-'; /* 'm isn't defined on iso-8859-x */
2159 #ifdef XK_dead_breve
2160 case XK_dead_breve :
2161 return 0xa2; /* '( */
2163 #ifdef XK_dead_abovedot
2164 case XK_dead_abovedot :
2165 return 0xff; /* '. */
2167 #ifdef XK_dead_abovering
2168 case XK_dead_abovering :
2169 return '0'; /* '0 isn't defined on iso-8859-x */
2171 #ifdef XK_dead_doubleacute
2172 case XK_dead_doubleacute :
2173 return 0xbd; /* '" */
2175 #ifdef XK_dead_caron
2176 case XK_dead_caron :
2177 return 0xb7; /* '< */
2179 #ifdef XK_dead_ogonek
2180 case XK_dead_ogonek :
2181 return 0xb2; /* '; */
2183 /* FIXME: I don't know this three.
2186 case XK_dead_voiced_sound :
2188 case XK_dead_semivoiced_sound :
2192 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2196 /***********************************************************************
2197 * ToUnicodeEx (X11DRV.@)
2199 * The ToUnicode function translates the specified virtual-key code and keyboard
2200 * state to the corresponding Windows character or characters.
2202 * If the specified key is a dead key, the return value is negative. Otherwise,
2203 * it is one of the following values:
2205 * 0 The specified virtual key has no translation for the current state of the keyboard.
2206 * 1 One Windows character was copied to the buffer.
2207 * 2 Two characters were copied to the buffer. This usually happens when a
2208 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2209 * be composed with the specified virtual key to form a single character.
2211 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2214 INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2215 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2217 Display *display = thread_display();
2226 if (scanCode & 0x8000)
2228 TRACE("Key UP, doing nothing\n" );
2232 if (hkl != X11DRV_GetKeyboardLayout(0))
2233 FIXME("keyboard layout %p is not supported\n", hkl);
2235 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2237 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2241 e.display = display;
2247 if (focus) focus = GetAncestor( focus, GA_ROOT );
2248 if (!focus) focus = GetActiveWindow();
2249 e.window = X11DRV_get_whole_window( focus );
2250 xic = X11DRV_get_ic( focus );
2252 if (lpKeyState[VK_SHIFT] & 0x80)
2254 TRACE("ShiftMask = %04x\n", ShiftMask);
2255 e.state |= ShiftMask;
2257 if (lpKeyState[VK_CAPITAL] & 0x01)
2259 TRACE("LockMask = %04x\n", LockMask);
2260 e.state |= LockMask;
2262 if (lpKeyState[VK_CONTROL] & 0x80)
2264 TRACE("ControlMask = %04x\n", ControlMask);
2265 e.state |= ControlMask;
2267 if (lpKeyState[VK_NUMLOCK] & 0x01)
2269 TRACE("NumLockMask = %04x\n", NumLockMask);
2270 e.state |= NumLockMask;
2273 /* Restore saved AltGr state */
2274 TRACE("AltGrMask = %04x\n", AltGrMask);
2275 e.state |= AltGrMask;
2277 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2278 virtKey, scanCode, e.state);
2280 /* We exit on the first keycode found, to speed up the thing. */
2281 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2282 { /* Find a keycode that could have generated this virtual key */
2283 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2284 { /* We filter the extended bit, we don't know it */
2285 e.keycode = keyc; /* Store it temporarily */
2286 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2287 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2288 state), so set it to 0, we'll find another one */
2293 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2294 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2296 if (virtKey==VK_DECIMAL)
2297 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2299 if (!e.keycode && virtKey != VK_NONAME)
2301 WARN("Unknown virtual key %X !!! \n",virtKey);
2302 wine_tsx11_unlock();
2303 return virtKey; /* whatever */
2305 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2307 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2308 e.type, e.window, e.state, e.keycode);
2311 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
2313 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
2314 wine_tsx11_unlock();
2321 /* An ugly hack for EuroSign: X can't translate it to a character
2322 for some locales. */
2323 if (keysym == XK_EuroSign)
2330 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2331 /* Here we change it back. */
2332 if (keysym == XK_ISO_Left_Tab)
2339 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2342 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2350 ksname = XKeysymToString(keysym);
2351 wine_tsx11_unlock();
2354 if ((keysym >> 8) != 0xff)
2356 ERR("Please report: no char for keysym %04lX (%s) :\n",
2358 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
2359 virtKey, scanCode, e.keycode, e.state);
2363 else { /* ret != 0 */
2364 /* We have a special case to handle : Shift + arrow, shift + home, ...
2365 X returns a char for it, but Windows doesn't. Let's eat it. */
2366 if (!(e.state & NumLockMask) /* NumLock is off */
2367 && (e.state & ShiftMask) /* Shift is pressed */
2368 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
2374 /* more areas where X returns characters but Windows does not
2375 CTRL + number or CTRL + symbol */
2376 if (e.state & ControlMask)
2378 if (((keysym>=33) && (keysym < 'A')) ||
2379 ((keysym > 'Z') && (keysym < 'a')))
2386 /* We have another special case for delete key (XK_Delete) on an
2387 extended keyboard. X returns a char for it, but Windows doesn't */
2388 if (keysym == XK_Delete)
2393 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
2394 && (keysym == XK_KP_Decimal))
2400 /* perform translation to unicode */
2403 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
2404 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2409 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
2410 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
2414 /***********************************************************************
2417 void X11DRV_Beep(void)
2420 XBell(thread_display(), 0);
2421 wine_tsx11_unlock();