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 */
1014 ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1015 keysym == XK_Mode_switch))
1017 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
1021 TRACE_(key)("state = %X\n", event->state);
1023 /* If XKB extensions are used, the state mask for AltGr will use the group
1024 index instead of the modifier mask. The group index is set in bits
1025 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1026 pressed, look if the group index is different than 0. From XKB
1027 extension documentation, the group index for AltGr should be 2
1028 (event->state = 0x2000). It's probably better to not assume a
1029 predefined group index and find it dynamically
1031 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1032 /* Save also all possible modifier states. */
1033 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1035 Str[ascii_chars] = '\0';
1039 ksname = TSXKeysymToString(keysym);
1042 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1043 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1044 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1048 vkey = EVENT_event_to_vkey(xic,event);
1049 /* X returns keycode 0 for composed characters */
1050 if (!vkey && ascii_chars) vkey = VK_NONAME;
1051 wine_tsx11_unlock();
1053 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1054 event->keycode, vkey);
1058 switch (vkey & 0xff)
1061 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1064 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1065 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1066 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1069 /* Adjust the NUMLOCK state if it has been changed outside wine */
1070 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1072 TRACE("Adjusting NumLock state.\n");
1073 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1074 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1076 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1077 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1079 TRACE("Adjusting Caps Lock state.\n");
1080 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1081 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1083 /* Not Num nor Caps : end of intermediary states for both. */
1087 bScan = keyc2scan[event->keycode] & 0xFF;
1088 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1091 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1092 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1094 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1099 /**********************************************************************
1100 * X11DRV_KEYBOARD_DetectLayout
1102 * Called from X11DRV_InitKeyboard
1103 * This routine walks through the defined keyboard layouts and selects
1104 * whichever matches most closely.
1105 * X11 lock must be held.
1108 X11DRV_KEYBOARD_DetectLayout (void)
1110 Display *display = thread_display();
1111 unsigned current, match, mismatch, seq;
1112 int score, keyc, i, key, pkey, ok, syms;
1114 const char (*lkey)[MAIN_LEN][4];
1115 unsigned max_seq = 0;
1116 int max_score = 0, ismatch = 0;
1120 syms = keysyms_per_keycode;
1122 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1125 for (current = 0; main_key_tab[current].comment; current++) {
1126 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1131 lkey = main_key_tab[current].key;
1133 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1134 /* get data for keycode from X server */
1135 for (i = 0; i < syms; i++) {
1136 keysym = XKeycodeToKeysym (display, keyc, i);
1137 /* Allow both one-byte and two-byte national keysyms */
1138 if ((keysym < 0x8000) && (keysym != ' '))
1141 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1144 TRACE("XKB could not translate keysym %ld\n", keysym);
1145 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1146 * with appropriate ShiftMask and Mode_switch, use XLookupString
1147 * to get character in the local encoding.
1149 ckey[i] = keysym & 0xFF;
1153 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1157 /* search for a match in layout table */
1158 /* right now, we just find an absolute match for defined positions */
1159 /* (undefined positions are ignored, so if it's defined as "3#" in */
1160 /* the table, it's okay that the X server has "3#£", for example) */
1161 /* however, the score will be higher for longer matches */
1162 for (key = 0; key < MAIN_LEN; key++) {
1163 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1164 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1166 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1174 /* count the matches and mismatches */
1177 /* and how much the keycode order matches */
1178 if (key > pkey) seq++;
1181 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1187 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1188 match, mismatch, seq, score);
1189 if ((score > max_score) ||
1190 ((score == max_score) && (seq > max_seq))) {
1191 /* best match so far */
1192 kbd_layout = current;
1195 ismatch = !mismatch;
1198 /* we're done, report results if necessary */
1201 "Your keyboard layout was not found!\n"
1202 "Using closest match instead (%s) for scancode mapping.\n"
1203 "Please define your layout in dlls/x11drv/keyboard.c and submit them\n"
1204 "to us for inclusion into future Wine releases.\n"
1205 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1206 main_key_tab[kbd_layout].comment);
1209 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1212 /**********************************************************************
1213 * InitKeyboard (X11DRV.@)
1215 void X11DRV_InitKeyboard( BYTE *key_state_table )
1217 Display *display = thread_display();
1219 XModifierKeymap *mmp;
1223 WORD scan, vkey, OEMvkey;
1224 int keyc, i, keyn, syms;
1225 char ckey[4]={0,0,0,0};
1226 const char (*lkey)[MAIN_LEN][4];
1228 pKeyStateTable = key_state_table;
1231 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1232 ksp = XGetKeyboardMapping(display, min_keycode,
1233 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1234 /* We are only interested in keysyms_per_keycode.
1235 There is no need to hold a local copy of the keysyms table */
1238 mmp = XGetModifierMapping(display);
1239 kcp = mmp->modifiermap;
1240 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1244 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1249 for (k = 0; k < keysyms_per_keycode; k += 1)
1250 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1252 NumLockMask = 1 << i;
1253 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1257 XFreeModifiermap(mmp);
1259 /* Detect the keyboard layout */
1260 X11DRV_KEYBOARD_DetectLayout();
1261 lkey = main_key_tab[kbd_layout].key;
1262 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1264 /* Now build two conversion arrays :
1265 * keycode -> vkey + scancode + extended
1266 * vkey + extended -> keycode */
1268 e2.display = display;
1271 OEMvkey = VK_OEM_7; /* next is available. */
1272 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1274 e2.keycode = (KeyCode)keyc;
1275 XLookupString(&e2, NULL, 0, &keysym, NULL);
1277 if (keysym) /* otherwise, keycode not used */
1279 if ((keysym >> 8) == 0xFF) /* non-character key */
1281 vkey = nonchar_key_vkey[keysym & 0xff];
1282 scan = nonchar_key_scan[keysym & 0xff];
1283 /* set extended bit when necessary */
1284 if (scan & 0x100) vkey |= 0x100;
1285 } else if (keysym == 0x20) { /* Spacebar */
1289 /* we seem to need to search the layout-dependent scancodes */
1290 int maxlen=0,maxval=-1,ok;
1291 for (i=0; i<syms; i++) {
1292 keysym = XKeycodeToKeysym(display, keyc, i);
1293 if ((keysym<0x8000) && (keysym!=' '))
1296 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1299 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1300 * with appropriate ShiftMask and Mode_switch, use XLookupString
1301 * to get character in the local encoding.
1303 ckey[i] = keysym & 0xFF;
1306 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1309 /* find key with longest match streak */
1310 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1311 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1312 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1313 if (ok||(i>maxlen)) {
1314 maxlen=i; maxval=keyn;
1320 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1321 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1322 scan = (*lscan)[maxval];
1323 vkey = (*lvkey)[maxval];
1327 /* find a suitable layout-dependent VK code */
1328 /* (most Winelib apps ought to be able to work without layout tables!) */
1329 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1331 keysym = XLookupKeysym(&e2, i);
1332 if ((keysym >= VK_0 && keysym <= VK_9)
1333 || (keysym >= VK_A && keysym <= VK_Z)) {
1338 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1340 keysym = XLookupKeysym(&e2, i);
1343 case ';': vkey = VK_OEM_1; break;
1344 case '/': vkey = VK_OEM_2; break;
1345 case '`': vkey = VK_OEM_3; break;
1346 case '[': vkey = VK_OEM_4; break;
1347 case '\\': vkey = VK_OEM_5; break;
1348 case ']': vkey = VK_OEM_6; break;
1349 case '\'': vkey = VK_OEM_7; break;
1350 case ',': vkey = VK_OEM_COMMA; break;
1351 case '.': vkey = VK_OEM_PERIOD; break;
1352 case '-': vkey = VK_OEM_MINUS; break;
1353 case '+': vkey = VK_OEM_PLUS; break;
1359 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1360 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1363 case 0xc1 : OEMvkey=0xdb; break;
1364 case 0xe5 : OEMvkey=0xe9; break;
1365 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1370 if (TRACE_ON(keyboard))
1372 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1373 OEMvkey, e2.keycode);
1375 for (i = 0; i < keysyms_per_keycode; i += 1)
1379 keysym = XLookupKeysym(&e2, i);
1380 ksname = XKeysymToString(keysym);
1382 ksname = "NoSymbol";
1383 TRACE( "%lX (%s) ", keysym, ksname);
1389 keyc2vkey[e2.keycode] = vkey;
1390 keyc2scan[e2.keycode] = scan;
1393 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1394 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1395 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1397 keysym = XKeycodeToKeysym(display, keyc, 0);
1398 ksname = XKeysymToString(keysym);
1399 if (!ksname) ksname = "NoSymbol";
1401 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1403 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1404 keyc2scan[keyc]=scan++;
1407 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1408 kcControl = XKeysymToKeycode(display, XK_Control_L);
1409 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1410 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1411 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1412 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1413 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1414 wine_tsx11_unlock();
1418 /***********************************************************************
1419 * X11DRV_MappingNotify
1421 void X11DRV_MappingNotify( XMappingEvent *event )
1423 TSXRefreshKeyboardMapping(event);
1424 X11DRV_InitKeyboard( pKeyStateTable );
1428 /***********************************************************************
1429 * VkKeyScan (X11DRV.@)
1431 WORD X11DRV_VkKeyScan(CHAR cChar)
1433 Display *display = thread_display();
1439 /* char->keysym (same for ANSI chars) */
1440 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1441 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1443 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1445 { /* It didn't work ... let's try with deadchar code. */
1446 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1449 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1450 cChar,keysym,keysym,keycode);
1454 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1455 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1458 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1460 case 1 : highbyte = 0x0100; break;
1461 case 2 : highbyte = 0x0600; break;
1462 case 3 : highbyte = 0x0700; break;
1463 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1466 index : 0 adds 0x0000
1467 index : 1 adds 0x0100 (shift)
1468 index : ? adds 0x0200 (ctrl)
1469 index : 2 adds 0x0600 (ctrl+alt)
1470 index : 3 adds 0x0700 (ctrl+alt+shift)
1473 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1474 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1477 /***********************************************************************
1478 * MapVirtualKey (X11DRV.@)
1480 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1482 Display *display = thread_display();
1484 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1486 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1488 case 0: { /* vkey-code to scan-code */
1489 /* let's do vkey -> keycode -> scan */
1491 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1492 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1493 returnMVK (keyc2scan[keyc] & 0xFF);
1494 TRACE("returning no scan-code.\n");
1497 case 1: { /* scan-code to vkey-code */
1498 /* let's do scan -> keycode -> vkey */
1500 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1501 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1502 returnMVK (keyc2vkey[keyc] & 0xFF);
1503 TRACE("returning no vkey-code.\n");
1506 case 2: { /* vkey-code to unshifted ANSI code */
1507 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1508 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1509 * key.. Looks like something is wrong with the MS docs?
1510 * This is only true for letters, for example VK_0 returns '0' not ')'.
1511 * - hence we use the lock mask to ensure this happens.
1513 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1518 e.display = display;
1521 /* LockMask should behave exactly like caps lock - upercase
1522 * the letter keys and thats about it. */
1527 /* We exit on the first keycode found, to speed up the thing. */
1528 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1529 { /* Find a keycode that could have generated this virtual key */
1530 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1531 { /* We filter the extended bit, we don't know it */
1532 e.keycode = keyc; /* Store it temporarily */
1533 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1534 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1535 state), so set it to 0, we'll find another one */
1540 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1541 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1543 if (wCode==VK_DECIMAL)
1544 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1548 WARN("Unknown virtual key %X !!! \n", wCode);
1549 wine_tsx11_unlock();
1550 return 0; /* whatever */
1552 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1554 if (XLookupString(&e, s, 2, &keysym, NULL))
1556 wine_tsx11_unlock();
1560 TRACE("returning no ANSI.\n");
1561 wine_tsx11_unlock();
1565 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1566 /* left and right */
1567 FIXME(" stub for NT\n");
1570 default: /* reserved */
1571 WARN("Unknown wMapType %d !\n", wMapType);
1577 /***********************************************************************
1578 * GetKeyNameText (X11DRV.@)
1580 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1582 int vkey, ansi, scanCode;
1588 scanCode = lParam >> 16;
1589 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1591 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1592 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1594 /* handle "don't care" bit (0x02000000) */
1595 if (!(lParam & 0x02000000)) {
1614 ansi = X11DRV_MapVirtualKey(vkey, 2);
1615 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1617 /* first get the name of the "regular" keys which is the Upper case
1618 value of the keycap imprint. */
1619 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1620 (scanCode != 0x137) && /* PrtScn */
1621 (scanCode != 0x135) && /* numpad / */
1622 (scanCode != 0x37 ) && /* numpad * */
1623 (scanCode != 0x4a ) && /* numpad - */
1624 (scanCode != 0x4e ) ) /* numpad + */
1626 if ((nSize >= 2) && lpBuffer)
1628 *lpBuffer = toupper((char)ansi);
1636 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1637 without "extended-key" flag. However Wine generates scancode
1638 *with* "extended-key" flag. Seems to occur *only* for the
1639 function keys. Soooo.. We will leave the table alone and
1640 fudge the lookup here till the other part is found and fixed!!! */
1642 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1643 (scanCode == 0x157) || (scanCode == 0x158))
1644 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1646 /* let's do scancode -> keycode -> keysym -> String */
1648 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1649 if ((keyc2scan[keyi]) == scanCode)
1651 if (keyi <= max_keycode)
1653 keyc = (KeyCode) keyi;
1654 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1655 name = TSXKeysymToString(keys);
1656 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1657 scanCode, keyc, (int)keys, name);
1658 if (lpBuffer && nSize && name)
1660 lstrcpynA(lpBuffer, name, nSize);
1665 /* Finally issue FIXME for unknown keys */
1667 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1668 if (lpBuffer && nSize)
1673 /***********************************************************************
1674 * X11DRV_KEYBOARD_MapDeadKeysym
1676 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1680 /* symbolic ASCII is the same as defined in rfc1345 */
1681 #ifdef XK_dead_tilde
1682 case XK_dead_tilde :
1684 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1685 return '~'; /* '? */
1686 #ifdef XK_dead_acute
1687 case XK_dead_acute :
1689 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1690 return 0xb4; /* '' */
1691 #ifdef XK_dead_circumflex
1692 case XK_dead_circumflex:
1694 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1695 return '^'; /* '> */
1696 #ifdef XK_dead_grave
1697 case XK_dead_grave :
1699 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1700 return '`'; /* '! */
1701 #ifdef XK_dead_diaeresis
1702 case XK_dead_diaeresis :
1704 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1705 return 0xa8; /* ': */
1706 #ifdef XK_dead_cedilla
1707 case XK_dead_cedilla :
1708 return 0xb8; /* ', */
1710 #ifdef XK_dead_macron
1711 case XK_dead_macron :
1712 return '-'; /* 'm isn't defined on iso-8859-x */
1714 #ifdef XK_dead_breve
1715 case XK_dead_breve :
1716 return 0xa2; /* '( */
1718 #ifdef XK_dead_abovedot
1719 case XK_dead_abovedot :
1720 return 0xff; /* '. */
1722 #ifdef XK_dead_abovering
1723 case XK_dead_abovering :
1724 return '0'; /* '0 isn't defined on iso-8859-x */
1726 #ifdef XK_dead_doubleacute
1727 case XK_dead_doubleacute :
1728 return 0xbd; /* '" */
1730 #ifdef XK_dead_caron
1731 case XK_dead_caron :
1732 return 0xb7; /* '< */
1734 #ifdef XK_dead_ogonek
1735 case XK_dead_ogonek :
1736 return 0xb2; /* '; */
1738 /* FIXME: I don't know this three.
1741 case XK_dead_voiced_sound :
1743 case XK_dead_semivoiced_sound :
1747 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1751 /***********************************************************************
1752 * ToUnicode (X11DRV.@)
1754 * The ToUnicode function translates the specified virtual-key code and keyboard
1755 * state to the corresponding Windows character or characters.
1757 * If the specified key is a dead key, the return value is negative. Otherwise,
1758 * it is one of the following values:
1760 * 0 The specified virtual key has no translation for the current state of the keyboard.
1761 * 1 One Windows character was copied to the buffer.
1762 * 2 Two characters were copied to the buffer. This usually happens when a
1763 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1764 * be composed with the specified virtual key to form a single character.
1766 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1769 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1770 LPWSTR bufW, int bufW_size, UINT flags)
1772 Display *display = thread_display();
1781 if (scanCode & 0x8000)
1783 TRACE("Key UP, doing nothing\n" );
1787 e.display = display;
1793 if (focus) focus = GetAncestor( focus, GA_ROOT );
1794 if (!focus) focus = GetActiveWindow();
1795 e.window = X11DRV_get_whole_window( focus );
1796 xic = X11DRV_get_ic( focus );
1798 if (lpKeyState[VK_SHIFT] & 0x80)
1800 TRACE("ShiftMask = %04x\n", ShiftMask);
1801 e.state |= ShiftMask;
1803 if (lpKeyState[VK_CAPITAL] & 0x01)
1805 TRACE("LockMask = %04x\n", LockMask);
1806 e.state |= LockMask;
1808 if (lpKeyState[VK_CONTROL] & 0x80)
1810 TRACE("ControlMask = %04x\n", ControlMask);
1811 e.state |= ControlMask;
1813 if (lpKeyState[VK_NUMLOCK] & 0x01)
1815 TRACE("NumLockMask = %04x\n", NumLockMask);
1816 e.state |= NumLockMask;
1819 /* Restore saved AltGr state */
1820 TRACE("AltGrMask = %04x\n", AltGrMask);
1821 e.state |= AltGrMask;
1823 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1824 virtKey, scanCode, e.state);
1826 /* We exit on the first keycode found, to speed up the thing. */
1827 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1828 { /* Find a keycode that could have generated this virtual key */
1829 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1830 { /* We filter the extended bit, we don't know it */
1831 e.keycode = keyc; /* Store it temporarily */
1832 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
1833 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1834 state), so set it to 0, we'll find another one */
1839 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1840 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1842 if (virtKey==VK_DECIMAL)
1843 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1845 if (!e.keycode && virtKey != VK_NONAME)
1847 WARN("Unknown virtual key %X !!! \n",virtKey);
1848 wine_tsx11_unlock();
1849 return virtKey; /* whatever */
1851 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1854 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
1856 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
1857 wine_tsx11_unlock();
1863 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1866 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
1873 ksname = TSXKeysymToString(keysym);
1876 if ((keysym >> 8) != 0xff)
1878 ERR("Please report: no char for keysym %04lX (%s) :\n",
1880 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1881 virtKey, scanCode, e.keycode, e.state);
1885 else { /* ret != 0 */
1886 /* We have a special case to handle : Shift + arrow, shift + home, ...
1887 X returns a char for it, but Windows doesn't. Let's eat it. */
1888 if (!(e.state & NumLockMask) /* NumLock is off */
1889 && (e.state & ShiftMask) /* Shift is pressed */
1890 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1896 /* more areas where X returns characters but Windows does not
1897 CTRL + number or CTRL + symbol */
1898 if (e.state & ControlMask)
1900 if (((keysym>=33) && (keysym < 'A')) ||
1901 ((keysym > 'Z') && (keysym < 'a')))
1908 /* We have another special case for delete key (XK_Delete) on an
1909 extended keyboard. X returns a char for it, but Windows doesn't */
1910 if (keysym == XK_Delete)
1915 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1916 && (keysym == XK_KP_Decimal))
1922 /* perform translation to unicode */
1925 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
1926 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
1930 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1931 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1935 /***********************************************************************
1938 void X11DRV_Beep(void)
1940 TSXBell(thread_display(), 0);