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>
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
35 #include <X11/XKBlib.h>
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
47 #include "wine/winuser16.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
54 WINE_DECLARE_DEBUG_CHANNEL(key);
55 WINE_DECLARE_DEBUG_CHANNEL(dinput);
57 int min_keycode, max_keycode, keysyms_per_keycode;
58 WORD keyc2vkey[256], keyc2scan[256];
60 static LPBYTE pKeyStateTable;
61 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
62 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
64 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
66 /* Keyboard translation tables */
68 static const WORD main_key_scan_qwerty[MAIN_LEN] =
70 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
71 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
72 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
73 /* q w e r t y u i o p [ ] */
74 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
75 /* a s d f g h j k l ; ' \ */
76 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
77 /* z x c v b n m , . / */
78 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
79 0x56 /* the 102nd key (actually to the right of l-shift) */
82 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
84 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
85 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
86 /* q w e r t y u i o p [ ] */
87 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
88 /* a s d f g h j k l ; ' \ */
89 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
90 /* \ z x c v b n m , . / */
91 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
92 0x56, /* the 102nd key (actually to the right of l-shift) */
95 static const WORD main_key_scan_dvorak[MAIN_LEN] =
97 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
98 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
99 /* ' , . p y f g c r l / = */
100 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
101 /* a o e u i d h t n s - \ */
102 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
103 /* ; q j k x b m w v z */
104 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
105 0x56 /* the 102nd key (actually to the right of l-shift) */
108 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
110 /* NOTE: this layout must concur with the scan codes layout above */
111 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
112 VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
113 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_7,VK_OEM_5,
114 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
115 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
118 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
120 /* NOTE: this layout must concur with the scan codes layout above */
121 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
122 VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
123 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_8,VK_OEM_5,
124 VK_OEM_7,VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
125 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
128 static const WORD main_key_vkey_azerty[MAIN_LEN] =
130 /* NOTE: this layout must concur with the scan codes layout above */
131 VK_OEM_7,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_PLUS,
132 VK_A,VK_Z,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_6,VK_OEM_1,
133 VK_Q,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_M,VK_OEM_3,VK_OEM_5,
134 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
135 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
138 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
140 /* NOTE: this layout must concur with the scan codes layout above */
141 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_6,
142 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,VK_P,VK_Y,VK_F,VK_G,VK_C,VK_R,VK_L,VK_OEM_2,VK_OEM_PLUS,
143 VK_A,VK_O,VK_E,VK_U,VK_I,VK_D,VK_H,VK_T,VK_N,VK_S,VK_OEM_MINUS,VK_OEM_5,
144 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
145 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
148 /* FIXME: add other layouts, such as German QWERTZ */
150 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
152 /* the VK mappings for the main keyboard will be auto-assigned as before,
153 so what we have here is just the character tables */
154 /* order: Normal, Shift, AltGr, Shift-AltGr */
155 /* We recommend you write just what is guaranteed to be correct (i.e. what's
156 written on the keycaps), not the bunch of special characters behind AltGr
157 and Shift-AltGr if it can vary among different X servers */
158 /* Remember that your 102nd key (to the right of l-shift) should be on a
159 separate line, see existing tables */
160 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
161 /* Remember to also add your new table to the layout index table far below! */
163 /*** German Logitech Desktop Pro keyboard layout */
164 static const char main_key_DE_logitech[MAIN_LEN][4] =
166 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
167 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
168 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
169 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
173 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
174 static const char main_key_US[MAIN_LEN][4] =
176 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
177 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
178 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
179 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
182 /*** United States keyboard layout (phantom key version) */
183 /* (XFree86 reports the <> key even if it's not physically there) */
184 static const char main_key_US_phantom[MAIN_LEN][4] =
186 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
187 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
188 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
189 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
190 "<>" /* the phantom key */
193 /*** United States keyboard layout (dvorak version) */
194 static const char main_key_US_dvorak[MAIN_LEN][4] =
196 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
197 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
198 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
199 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
202 /*** British keyboard layout */
203 static const char main_key_UK[MAIN_LEN][4] =
205 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
206 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
207 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
208 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
212 /*** French keyboard layout (contributed by Eric Pouech) */
213 static const char main_key_FR[MAIN_LEN][4] =
215 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
216 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
217 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
218 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
222 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
223 static const char main_key_IS[MAIN_LEN][4] =
225 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
226 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
227 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
228 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
232 /*** German keyboard layout (contributed by Ulrich Weigand) */
233 static const char main_key_DE[MAIN_LEN][4] =
235 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
236 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
237 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
238 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
242 /*** German keyboard layout without dead keys */
243 static const char main_key_DE_nodead[MAIN_LEN][4] =
245 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
246 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
247 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
248 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
252 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
253 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
255 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
256 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
257 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
258 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
261 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
262 static const char main_key_SG[MAIN_LEN][4] =
264 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
265 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
266 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
267 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
271 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
272 static const char main_key_SF[MAIN_LEN][4] =
274 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
275 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
276 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
277 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
281 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
282 static const char main_key_NO[MAIN_LEN][4] =
284 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
285 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
286 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
287 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
291 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
292 static const char main_key_DA[MAIN_LEN][4] =
294 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
295 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
296 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
297 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
301 /*** Swedish keyboard layout (contributed by Peter Bortas) */
302 static const char main_key_SE[MAIN_LEN][4] =
304 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
305 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
306 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
307 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
311 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
312 static const char main_key_ET[MAIN_LEN][4] =
314 "·~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
315 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
316 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
317 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
321 /*** Canadian French keyboard layout */
322 static const char main_key_CF[MAIN_LEN][4] =
324 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
325 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
326 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
327 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
331 /*** Portuguese keyboard layout */
332 static const char main_key_PT[MAIN_LEN][4] =
334 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
335 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
336 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
337 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
341 /*** Italian keyboard layout */
342 static const char main_key_IT[MAIN_LEN][4] =
344 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
345 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
346 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
347 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
351 /*** Finnish keyboard layout */
352 static const char main_key_FI[MAIN_LEN][4] =
354 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
355 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
356 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
357 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
361 /*** Bulgarian bds keyboard layout */
362 static const char main_key_BG_bds[MAIN_LEN][4] =
364 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
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ïÏ",",<ðÐ",".>ëË","/?áÁ",
368 "<>" /* the phantom key */
371 /*** Bulgarian phonetic keyboard layout */
372 static const char main_key_BG_phonetic[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ìÌ",",<",".>","/?",
378 "<>" /* the phantom key */
381 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
382 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
383 static const char main_key_BY[MAIN_LEN][4] =
385 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
386 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
387 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
388 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
392 /*** Russian keyboard layout (contributed by Pavel Roskin) */
393 static const char main_key_RU[MAIN_LEN][4] =
395 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
396 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
397 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
398 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
401 /*** Russian keyboard layout (phantom key version) */
402 static const char main_key_RU_phantom[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Øø",",<Ââ",".>Àà","/?",
408 "<>" /* the phantom key */
411 /*** Russian keyboard layout KOI8-R */
412 static const char main_key_RU_koi8r[MAIN_LEN][4] =
414 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
415 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
416 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
417 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
418 "<>" /* the phantom key */
421 /*** Ukrainian keyboard layout KOI8-U */
422 static const char main_key_UA[MAIN_LEN][4] =
424 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)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Øø",",<Ââ",".>Àà","/?/?",
428 "<>" /* the phantom key */
431 /*** Spanish keyboard layout (contributed by José Marcos López) */
432 static const char main_key_ES[MAIN_LEN][4] =
434 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
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",",;",".:","-_",
441 /*** Belgian keyboard layout ***/
442 static const char main_key_BE[MAIN_LEN][4] =
444 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
445 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
446 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
447 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
451 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
452 static const char main_key_HU[MAIN_LEN][4] =
454 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
455 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
456 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
457 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
461 /*** Polish (programmer's) keyboard layout ***/
462 static const char main_key_PL[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",",<",".>","/?",
471 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
472 static const char main_key_SI[MAIN_LEN][4] =
474 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
475 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
476 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
477 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
481 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
482 static const char main_key_HR_jelly[MAIN_LEN][4] =
484 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","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",",<",".>","/?",
491 /*** Croatian keyboard layout ***/
492 static const char main_key_HR[MAIN_LEN][4] =
494 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
495 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
496 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
497 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
501 /*** Japanese 106 keyboard layout ***/
502 static const char main_key_JA_jp106[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",",<",".>","/?",
511 /*** Japanese pc98x1 keyboard layout ***/
512 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
514 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","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",",<",".>","/?",
521 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
522 static const char main_key_PT_br[MAIN_LEN][4] =
524 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
525 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
526 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
527 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
531 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
532 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
534 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
535 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
536 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
537 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
541 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
542 static const char main_key_US_intl[MAIN_LEN][4] =
544 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
545 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
546 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
547 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
550 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
551 - dead_abovering replaced with degree - no symbol in iso8859-2
552 - brokenbar replaced with bar */
553 static const char main_key_SK[MAIN_LEN][4] =
555 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
556 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
557 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
558 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
562 /*** Czech keyboard layout (setxkbmap cz) */
563 static const char main_key_CZ[MAIN_LEN][4] =
565 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
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 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
573 static const char main_key_CZ_qwerty[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 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
583 static const char main_key_SK_prog[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 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
593 static const char main_key_CS[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 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
603 static const char main_key_LA[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",",;",".:","-_",
612 /*** Lithuanian (Baltic) keyboard layout (pc/lt in XFree86 4.3.0, contributed by Nerijus Baliûnas) */
613 static const char main_key_LT_B[MAIN_LEN][4] =
615 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
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",",<",".>","/?"
621 /*** Turkish keyboard Layout */
622 static const char main_key_TK[MAIN_LEN][4] =
624 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
625 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
626 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
627 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
630 /*** Israeli keyboard layout */
631 static const char main_key_IL[MAIN_LEN][4] =
633 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
634 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
635 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
636 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
639 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
640 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
641 message since they have different characters in gr and el XFree86 layouts. */
642 static const char main_key_EL[MAIN_LEN][4] =
644 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
645 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
646 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
647 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
651 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
652 static const char main_key_th[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·?",",<Á²",".>ãÌ","/?½Æ"
660 /*** VNC keyboard layout */
661 static const WORD main_key_scan_vnc[MAIN_LEN] =
663 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
664 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,
668 static const WORD main_key_vkey_vnc[MAIN_LEN] =
670 VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_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,
671 VK_A,VK_B,VK_C,VK_D,VK_E,VK_F,VK_G,VK_H,VK_I,VK_J,VK_K,VK_L,VK_M,VK_N,VK_O,VK_P,VK_Q,VK_R,VK_S,VK_T,VK_U,VK_V,VK_W,VK_X,VK_Y,VK_Z,
675 static const char main_key_vnc[MAIN_LEN][4] =
677 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
678 "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"
681 /*** Layout table. Add your keyboard mappings to this list */
682 static const struct {
684 const char (*key)[MAIN_LEN][4];
685 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
686 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
688 {"United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
689 {"United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
691 {"British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
693 {"German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
694 {"German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
695 {"German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
696 {"Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
697 {"Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
698 {"Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
699 {"Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
700 {"Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
701 {"French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
702 {"Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
703 {"Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
704 {"Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
705 {"Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
706 {"Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
707 {"Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
708 {"United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
709 {"Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
710 {"Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
711 {"Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
712 {"Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
713 {"Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
714 {"Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
715 {"Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
716 {"Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
717 {"Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
718 {"Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
719 {"Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
720 {"Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
721 {"Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
722 {"Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
723 {"Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
724 {"Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
725 {"Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
726 {"Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
727 {"Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
728 {"Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
729 {"Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
730 {"Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
731 {"Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
732 {"Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
733 {"Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
734 {"Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
735 {"Israeli keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
736 {"VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
737 {"Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
738 {"Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
740 {NULL, NULL, NULL, NULL} /* sentinel */
742 static unsigned kbd_layout=0; /* index into above table of layouts */
744 /* maybe more of these scancodes should be extended? */
745 /* extended must be set for ALT_R, CTRL_R,
746 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
747 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
748 /* FIXME should we set extended bit for NumLock ? My
749 * Windows does ... DF */
750 /* Yes, to distinguish based on scan codes, also
751 for PrtScn key ... GA */
753 static const WORD nonchar_key_vkey[256] =
756 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
758 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
759 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
760 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
762 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
763 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
764 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
765 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
766 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
767 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
769 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
770 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
771 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
773 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
774 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
775 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
777 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
778 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
779 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
780 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
781 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
782 VK_END, 0, VK_INSERT, VK_DELETE,
783 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
784 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
785 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
786 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
787 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
788 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
791 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
792 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
793 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
794 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
796 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
797 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
798 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
799 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
800 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
803 static const WORD nonchar_key_scan[256] =
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
808 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
809 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
810 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
819 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
822 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
823 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
830 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
832 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
833 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
834 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
837 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
838 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
842 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
843 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
849 /* Returns the Windows virtual key code associated with the X event <e> */
850 /* x11 lock must be held */
851 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
856 XmbLookupString(xic, e, NULL, 0, &keysym, NULL);
858 XLookupString(e, NULL, 0, &keysym, NULL);
860 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
861 && (e->state & NumLockMask))
862 /* Only the Keypad keys 0-9 and . send different keysyms
863 * depending on the NumLock state */
864 return nonchar_key_vkey[keysym & 0xFF];
866 return keyc2vkey[e->keycode];
869 static BOOL NumState=FALSE, CapsState=FALSE;
872 /***********************************************************************
873 * send_keyboard_input
875 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
879 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
880 input.u.ki.wVk = wVk;
881 input.u.ki.wScan = wScan;
882 input.u.ki.dwFlags = dwFlags;
883 input.u.ki.time = time;
884 input.u.ki.dwExtraInfo = 0;
885 SendInput( 1, &input, sizeof(input) );
889 /**********************************************************************
890 * KEYBOARD_GenerateMsg
892 * Generate Down+Up messages when NumLock or CapsLock is pressed.
894 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
897 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
899 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
903 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
904 don't treat it. It's from the same key press. Then the state goes to ON.
905 And from there, a 'release' event will switch off the toggle key. */
907 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
910 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
911 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
912 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
914 if (Evtype!=KeyPress)
916 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
917 send_keyboard_input( vkey, scan, down, event_time );
918 send_keyboard_input( vkey, scan, up, event_time );
920 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
923 else /* it was OFF */
924 if (Evtype==KeyPress)
926 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
927 send_keyboard_input( vkey, scan, down, event_time );
928 send_keyboard_input( vkey, scan, up, event_time );
929 *State=TRUE; /* Goes to intermediary state before going to ON */
930 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
935 /***********************************************************************
936 * KEYBOARD_UpdateOneState
938 * Updates internal state for <vkey>, depending on key <state> under X
941 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
943 /* Do something if internal table state != X state for keycode */
944 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
946 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
947 vkey, pKeyStateTable[vkey]);
949 /* Fake key being pressed inside wine */
950 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
952 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
956 /***********************************************************************
957 * X11DRV_KeymapNotify
959 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
961 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
962 * from wine to another application and back.
963 * Toggle keys are handled in HandleEvent.
965 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
967 int i, j, alt, control, shift;
968 DWORD time = GetCurrentTime();
970 alt = control = shift = 0;
971 for (i = 0; i < 32; i++)
973 if (!event->key_vector[i]) continue;
974 for (j = 0; j < 8; j++)
976 if (!(event->key_vector[i] & (1<<j))) continue;
977 switch(keyc2vkey[(i * 8) + j] & 0xff)
979 case VK_MENU: alt = 1; break;
980 case VK_CONTROL: control = 1; break;
981 case VK_SHIFT: shift = 1; break;
985 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
986 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
987 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
990 /***********************************************************************
993 * Handle a X key event
995 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
999 WORD vkey = 0, bScan;
1002 XIC xic = X11DRV_get_ic( hwnd );
1003 DWORD event_time = event->time - X11DRV_server_startticks;
1007 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, NULL);
1009 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1010 wine_tsx11_unlock();
1012 /* Ignore some unwanted events */
1013 if ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1014 keysym == XK_Mode_switch)
1016 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
1020 TRACE_(key)("state = %X\n", event->state);
1022 /* If XKB extensions are used, the state mask for AltGr will use the group
1023 index instead of the modifier mask. The group index is set in bits
1024 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1025 pressed, look if the group index is different than 0. From XKB
1026 extension documentation, the group index for AltGr should be 2
1027 (event->state = 0x2000). It's probably better to not assume a
1028 predefined group index and find it dynamically
1030 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1031 /* Save also all possible modifier states. */
1032 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1034 Str[ascii_chars] = '\0';
1038 ksname = TSXKeysymToString(keysym);
1041 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1042 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1043 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1047 vkey = EVENT_event_to_vkey(xic,event);
1048 /* X returns keycode 0 for composed characters */
1049 if (!vkey && ascii_chars) vkey = VK_NONAME;
1050 wine_tsx11_unlock();
1052 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1053 event->keycode, vkey);
1057 switch (vkey & 0xff)
1060 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1063 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1064 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1065 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1068 /* Adjust the NUMLOCK state if it has been changed outside wine */
1069 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1071 TRACE("Adjusting NumLock state.\n");
1072 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1073 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1075 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1076 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1078 TRACE("Adjusting Caps Lock state.\n");
1079 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1080 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1082 /* Not Num nor Caps : end of intermediary states for both. */
1086 bScan = keyc2scan[event->keycode] & 0xFF;
1087 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1090 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1091 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1093 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1098 /**********************************************************************
1099 * X11DRV_KEYBOARD_DetectLayout
1101 * Called from X11DRV_InitKeyboard
1102 * This routine walks through the defined keyboard layouts and selects
1103 * whichever matches most closely.
1104 * X11 lock must be held.
1107 X11DRV_KEYBOARD_DetectLayout (void)
1109 Display *display = thread_display();
1110 unsigned current, match, mismatch, seq;
1111 int score, keyc, i, key, pkey, ok, syms;
1113 const char (*lkey)[MAIN_LEN][4];
1114 unsigned max_seq = 0;
1115 int max_score = 0, ismatch = 0;
1119 syms = keysyms_per_keycode;
1121 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1124 for (current = 0; main_key_tab[current].comment; current++) {
1125 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1130 lkey = main_key_tab[current].key;
1132 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1133 /* get data for keycode from X server */
1134 for (i = 0; i < syms; i++) {
1135 keysym = XKeycodeToKeysym (display, keyc, i);
1136 /* Allow both one-byte and two-byte national keysyms */
1137 if ((keysym < 0x8000) && (keysym != ' '))
1140 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1143 TRACE("XKB could not translate keysym %ld\n", keysym);
1144 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1145 * with appropriate ShiftMask and Mode_switch, use XLookupString
1146 * to get character in the local encoding.
1148 ckey[i] = keysym & 0xFF;
1152 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1156 /* search for a match in layout table */
1157 /* right now, we just find an absolute match for defined positions */
1158 /* (undefined positions are ignored, so if it's defined as "3#" in */
1159 /* the table, it's okay that the X server has "3#£", for example) */
1160 /* however, the score will be higher for longer matches */
1161 for (key = 0; key < MAIN_LEN; key++) {
1162 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1163 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1165 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1173 /* count the matches and mismatches */
1176 /* and how much the keycode order matches */
1177 if (key > pkey) seq++;
1180 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1186 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1187 match, mismatch, seq, score);
1188 if ((score > max_score) ||
1189 ((score == max_score) && (seq > max_seq))) {
1190 /* best match so far */
1191 kbd_layout = current;
1194 ismatch = !mismatch;
1197 /* we're done, report results if necessary */
1200 "Your keyboard layout was not found!\n"
1201 "Using closest match instead (%s) for scancode mapping.\n"
1202 "Please define your layout in dlls/x11drv/keyboard.c and submit them\n"
1203 "to us for inclusion into future Wine releases.\n"
1204 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1205 main_key_tab[kbd_layout].comment);
1208 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1211 /**********************************************************************
1212 * InitKeyboard (X11DRV.@)
1214 void X11DRV_InitKeyboard( BYTE *key_state_table )
1216 Display *display = thread_display();
1218 XModifierKeymap *mmp;
1222 WORD scan, vkey, OEMvkey;
1223 int keyc, i, keyn, syms;
1224 char ckey[4]={0,0,0,0};
1225 const char (*lkey)[MAIN_LEN][4];
1227 pKeyStateTable = key_state_table;
1230 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1231 ksp = XGetKeyboardMapping(display, min_keycode,
1232 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1233 /* We are only interested in keysyms_per_keycode.
1234 There is no need to hold a local copy of the keysyms table */
1237 mmp = XGetModifierMapping(display);
1238 kcp = mmp->modifiermap;
1239 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1243 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1248 for (k = 0; k < keysyms_per_keycode; k += 1)
1249 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1251 NumLockMask = 1 << i;
1252 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1256 XFreeModifiermap(mmp);
1258 /* Detect the keyboard layout */
1259 X11DRV_KEYBOARD_DetectLayout();
1260 lkey = main_key_tab[kbd_layout].key;
1261 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1263 /* Now build two conversion arrays :
1264 * keycode -> vkey + scancode + extended
1265 * vkey + extended -> keycode */
1267 e2.display = display;
1270 OEMvkey = VK_OEM_7; /* next is available. */
1271 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1273 e2.keycode = (KeyCode)keyc;
1274 XLookupString(&e2, NULL, 0, &keysym, NULL);
1276 if (keysym) /* otherwise, keycode not used */
1278 if ((keysym >> 8) == 0xFF) /* non-character key */
1280 vkey = nonchar_key_vkey[keysym & 0xff];
1281 scan = nonchar_key_scan[keysym & 0xff];
1282 /* set extended bit when necessary */
1283 if (scan & 0x100) vkey |= 0x100;
1284 } else if (keysym == 0x20) { /* Spacebar */
1288 /* we seem to need to search the layout-dependent scancodes */
1289 int maxlen=0,maxval=-1,ok;
1290 for (i=0; i<syms; i++) {
1291 keysym = XKeycodeToKeysym(display, keyc, i);
1292 if ((keysym<0x8000) && (keysym!=' '))
1295 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1298 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1299 * with appropriate ShiftMask and Mode_switch, use XLookupString
1300 * to get character in the local encoding.
1302 ckey[i] = keysym & 0xFF;
1305 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1308 /* find key with longest match streak */
1309 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1310 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1311 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1312 if (ok||(i>maxlen)) {
1313 maxlen=i; maxval=keyn;
1319 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1320 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1321 scan = (*lscan)[maxval];
1322 vkey = (*lvkey)[maxval];
1326 /* find a suitable layout-dependent VK code */
1327 /* (most Winelib apps ought to be able to work without layout tables!) */
1328 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1330 keysym = XLookupKeysym(&e2, i);
1331 if ((keysym >= VK_0 && keysym <= VK_9)
1332 || (keysym >= VK_A && keysym <= VK_Z)) {
1337 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1339 keysym = XLookupKeysym(&e2, i);
1342 case ';': vkey = VK_OEM_1; break;
1343 case '/': vkey = VK_OEM_2; break;
1344 case '`': vkey = VK_OEM_3; break;
1345 case '[': vkey = VK_OEM_4; break;
1346 case '\\': vkey = VK_OEM_5; break;
1347 case ']': vkey = VK_OEM_6; break;
1348 case '\'': vkey = VK_OEM_7; break;
1349 case ',': vkey = VK_OEM_COMMA; break;
1350 case '.': vkey = VK_OEM_PERIOD; break;
1351 case '-': vkey = VK_OEM_MINUS; break;
1352 case '+': vkey = VK_OEM_PLUS; break;
1358 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1359 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1362 case 0xc1 : OEMvkey=0xdb; break;
1363 case 0xe5 : OEMvkey=0xe9; break;
1364 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1369 if (TRACE_ON(keyboard))
1371 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1372 OEMvkey, e2.keycode);
1374 for (i = 0; i < keysyms_per_keycode; i += 1)
1378 keysym = XLookupKeysym(&e2, i);
1379 ksname = XKeysymToString(keysym);
1381 ksname = "NoSymbol";
1382 TRACE( "%lX (%s) ", keysym, ksname);
1388 keyc2vkey[e2.keycode] = vkey;
1389 keyc2scan[e2.keycode] = scan;
1392 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1393 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1394 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1396 keysym = XKeycodeToKeysym(display, keyc, 0);
1397 ksname = XKeysymToString(keysym);
1398 if (!ksname) ksname = "NoSymbol";
1400 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1402 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1403 keyc2scan[keyc]=scan++;
1406 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1407 kcControl = XKeysymToKeycode(display, XK_Control_L);
1408 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1409 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1410 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1411 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1412 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1413 wine_tsx11_unlock();
1417 /***********************************************************************
1418 * X11DRV_MappingNotify
1420 void X11DRV_MappingNotify( XMappingEvent *event )
1422 TSXRefreshKeyboardMapping(event);
1423 X11DRV_InitKeyboard( pKeyStateTable );
1427 /***********************************************************************
1428 * VkKeyScan (X11DRV.@)
1430 WORD X11DRV_VkKeyScan(CHAR cChar)
1432 Display *display = thread_display();
1438 /* char->keysym (same for ANSI chars) */
1439 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1440 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1442 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1444 { /* It didn't work ... let's try with deadchar code. */
1445 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1448 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1449 cChar,keysym,keysym,keycode);
1453 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1454 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1457 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1459 case 1 : highbyte = 0x0100; break;
1460 case 2 : highbyte = 0x0600; break;
1461 case 3 : highbyte = 0x0700; break;
1462 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1465 index : 0 adds 0x0000
1466 index : 1 adds 0x0100 (shift)
1467 index : ? adds 0x0200 (ctrl)
1468 index : 2 adds 0x0600 (ctrl+alt)
1469 index : 3 adds 0x0700 (ctrl+alt+shift)
1472 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1473 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1476 /***********************************************************************
1477 * MapVirtualKey (X11DRV.@)
1479 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1481 Display *display = thread_display();
1483 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1485 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1487 case 0: { /* vkey-code to scan-code */
1488 /* let's do vkey -> keycode -> scan */
1490 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1491 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1492 returnMVK (keyc2scan[keyc] & 0xFF);
1493 TRACE("returning no scan-code.\n");
1496 case 1: { /* scan-code to vkey-code */
1497 /* let's do scan -> keycode -> vkey */
1499 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1500 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1501 returnMVK (keyc2vkey[keyc] & 0xFF);
1502 TRACE("returning no vkey-code.\n");
1505 case 2: { /* vkey-code to unshifted ANSI code */
1506 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1507 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1508 * key.. Looks like something is wrong with the MS docs?
1509 * This is only true for letters, for example VK_0 returns '0' not ')'.
1510 * - hence we use the lock mask to ensure this happens.
1512 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1517 e.display = display;
1520 /* LockMask should behave exactly like caps lock - upercase
1521 * the letter keys and thats about it. */
1526 /* We exit on the first keycode found, to speed up the thing. */
1527 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1528 { /* Find a keycode that could have generated this virtual key */
1529 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1530 { /* We filter the extended bit, we don't know it */
1531 e.keycode = keyc; /* Store it temporarily */
1532 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1533 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1534 state), so set it to 0, we'll find another one */
1539 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1540 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1542 if (wCode==VK_DECIMAL)
1543 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1547 WARN("Unknown virtual key %X !!! \n", wCode);
1548 wine_tsx11_unlock();
1549 return 0; /* whatever */
1551 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1553 if (XLookupString(&e, s, 2, &keysym, NULL))
1555 wine_tsx11_unlock();
1559 TRACE("returning no ANSI.\n");
1560 wine_tsx11_unlock();
1564 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1565 /* left and right */
1566 FIXME(" stub for NT\n");
1569 default: /* reserved */
1570 WARN("Unknown wMapType %d !\n", wMapType);
1576 /***********************************************************************
1577 * GetKeyNameText (X11DRV.@)
1579 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1581 int vkey, ansi, scanCode;
1587 scanCode = lParam >> 16;
1588 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1590 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1591 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1593 /* handle "don't care" bit (0x02000000) */
1594 if (!(lParam & 0x02000000)) {
1613 ansi = X11DRV_MapVirtualKey(vkey, 2);
1614 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1616 /* first get the name of the "regular" keys which is the Upper case
1617 value of the keycap imprint. */
1618 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1619 (scanCode != 0x137) && /* PrtScn */
1620 (scanCode != 0x135) && /* numpad / */
1621 (scanCode != 0x37 ) && /* numpad * */
1622 (scanCode != 0x4a ) && /* numpad - */
1623 (scanCode != 0x4e ) ) /* numpad + */
1625 if ((nSize >= 2) && lpBuffer)
1627 *lpBuffer = toupper((char)ansi);
1635 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1636 without "extended-key" flag. However Wine generates scancode
1637 *with* "extended-key" flag. Seems to occur *only* for the
1638 function keys. Soooo.. We will leave the table alone and
1639 fudge the lookup here till the other part is found and fixed!!! */
1641 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1642 (scanCode == 0x157) || (scanCode == 0x158))
1643 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1645 /* let's do scancode -> keycode -> keysym -> String */
1647 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1648 if ((keyc2scan[keyi]) == scanCode)
1650 if (keyi <= max_keycode)
1652 keyc = (KeyCode) keyi;
1653 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1654 name = TSXKeysymToString(keys);
1655 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1656 scanCode, keyc, (int)keys, name);
1657 if (lpBuffer && nSize && name)
1659 lstrcpynA(lpBuffer, name, nSize);
1664 /* Finally issue FIXME for unknown keys */
1666 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1667 if (lpBuffer && nSize)
1672 /***********************************************************************
1673 * X11DRV_KEYBOARD_MapDeadKeysym
1675 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1679 /* symbolic ASCII is the same as defined in rfc1345 */
1680 #ifdef XK_dead_tilde
1681 case XK_dead_tilde :
1683 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1684 return '~'; /* '? */
1685 #ifdef XK_dead_acute
1686 case XK_dead_acute :
1688 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1689 return 0xb4; /* '' */
1690 #ifdef XK_dead_circumflex
1691 case XK_dead_circumflex:
1693 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1694 return '^'; /* '> */
1695 #ifdef XK_dead_grave
1696 case XK_dead_grave :
1698 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1699 return '`'; /* '! */
1700 #ifdef XK_dead_diaeresis
1701 case XK_dead_diaeresis :
1703 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1704 return 0xa8; /* ': */
1705 #ifdef XK_dead_cedilla
1706 case XK_dead_cedilla :
1707 return 0xb8; /* ', */
1709 #ifdef XK_dead_macron
1710 case XK_dead_macron :
1711 return '-'; /* 'm isn't defined on iso-8859-x */
1713 #ifdef XK_dead_breve
1714 case XK_dead_breve :
1715 return 0xa2; /* '( */
1717 #ifdef XK_dead_abovedot
1718 case XK_dead_abovedot :
1719 return 0xff; /* '. */
1721 #ifdef XK_dead_abovering
1722 case XK_dead_abovering :
1723 return '0'; /* '0 isn't defined on iso-8859-x */
1725 #ifdef XK_dead_doubleacute
1726 case XK_dead_doubleacute :
1727 return 0xbd; /* '" */
1729 #ifdef XK_dead_caron
1730 case XK_dead_caron :
1731 return 0xb7; /* '< */
1733 #ifdef XK_dead_ogonek
1734 case XK_dead_ogonek :
1735 return 0xb2; /* '; */
1737 /* FIXME: I don't know this three.
1740 case XK_dead_voiced_sound :
1742 case XK_dead_semivoiced_sound :
1746 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1750 /***********************************************************************
1751 * ToUnicode (X11DRV.@)
1753 * The ToUnicode function translates the specified virtual-key code and keyboard
1754 * state to the corresponding Windows character or characters.
1756 * If the specified key is a dead key, the return value is negative. Otherwise,
1757 * it is one of the following values:
1759 * 0 The specified virtual key has no translation for the current state of the keyboard.
1760 * 1 One Windows character was copied to the buffer.
1761 * 2 Two characters were copied to the buffer. This usually happens when a
1762 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1763 * be composed with the specified virtual key to form a single character.
1765 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1768 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1769 LPWSTR bufW, int bufW_size, UINT flags)
1771 Display *display = thread_display();
1780 if (scanCode & 0x8000)
1782 TRACE("Key UP, doing nothing\n" );
1786 e.display = display;
1792 if (focus) focus = GetAncestor( focus, GA_ROOT );
1793 if (!focus) focus = GetActiveWindow();
1794 e.window = X11DRV_get_whole_window( focus );
1795 xic = X11DRV_get_ic( focus );
1797 if (lpKeyState[VK_SHIFT] & 0x80)
1799 TRACE("ShiftMask = %04x\n", ShiftMask);
1800 e.state |= ShiftMask;
1802 if (lpKeyState[VK_CAPITAL] & 0x01)
1804 TRACE("LockMask = %04x\n", LockMask);
1805 e.state |= LockMask;
1807 if (lpKeyState[VK_CONTROL] & 0x80)
1809 TRACE("ControlMask = %04x\n", ControlMask);
1810 e.state |= ControlMask;
1812 if (lpKeyState[VK_NUMLOCK] & 0x01)
1814 TRACE("NumLockMask = %04x\n", NumLockMask);
1815 e.state |= NumLockMask;
1818 /* Restore saved AltGr state */
1819 TRACE("AltGrMask = %04x\n", AltGrMask);
1820 e.state |= AltGrMask;
1822 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1823 virtKey, scanCode, e.state);
1825 /* We exit on the first keycode found, to speed up the thing. */
1826 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1827 { /* Find a keycode that could have generated this virtual key */
1828 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1829 { /* We filter the extended bit, we don't know it */
1830 e.keycode = keyc; /* Store it temporarily */
1831 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
1832 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1833 state), so set it to 0, we'll find another one */
1838 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1839 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1841 if (virtKey==VK_DECIMAL)
1842 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1844 if (!e.keycode && virtKey != VK_NONAME)
1846 WARN("Unknown virtual key %X !!! \n",virtKey);
1847 wine_tsx11_unlock();
1848 return virtKey; /* whatever */
1850 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1853 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
1855 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
1856 wine_tsx11_unlock();
1862 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1865 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
1872 ksname = TSXKeysymToString(keysym);
1875 if ((keysym >> 8) != 0xff)
1877 ERR("Please report: no char for keysym %04lX (%s) :\n",
1879 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1880 virtKey, scanCode, e.keycode, e.state);
1884 else { /* ret != 0 */
1885 /* We have a special case to handle : Shift + arrow, shift + home, ...
1886 X returns a char for it, but Windows doesn't. Let's eat it. */
1887 if (!(e.state & NumLockMask) /* NumLock is off */
1888 && (e.state & ShiftMask) /* Shift is pressed */
1889 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1895 /* more areas where X returns characters but Windows does not
1896 CTRL + number or CTRL + symbol */
1897 if (e.state & ControlMask)
1899 if (((keysym>=33) && (keysym < 'A')) ||
1900 ((keysym > 'Z') && (keysym < 'a')))
1907 /* We have another special case for delete key (XK_Delete) on an
1908 extended keyboard. X returns a char for it, but Windows doesn't */
1909 if (keysym == XK_Delete)
1914 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1915 && (keysym == XK_KP_Decimal))
1921 /* perform translation to unicode */
1924 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
1925 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
1929 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1930 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1934 /***********************************************************************
1937 void X11DRV_Beep(void)
1939 TSXBell(thread_display(), 0);