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>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
45 #include "wine/winuser16.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
52 WINE_DECLARE_DEBUG_CHANNEL(key);
53 WINE_DECLARE_DEBUG_CHANNEL(dinput);
55 int min_keycode, max_keycode, keysyms_per_keycode;
56 WORD keyc2vkey[256], keyc2scan[256];
58 static LPBYTE pKeyStateTable;
59 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
60 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
62 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
65 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
67 /* Keyboard translation tables */
69 static const WORD main_key_scan_qwerty[MAIN_LEN] =
71 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
72 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
73 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
74 /* q w e r t y u i o p [ ] */
75 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
76 /* a s d f g h j k l ; ' \ */
77 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
78 /* z x c v b n m , . / */
79 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
80 0x56 /* the 102nd key (actually to the right of l-shift) */
83 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
85 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
86 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
87 /* q w e r t y u i o p [ ] */
88 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
89 /* a s d f g h j k l ; ' \ */
90 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
91 /* \ z x c v b n m , . / */
92 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
93 0x56, /* the 102nd key (actually to the right of l-shift) */
96 static const WORD main_key_scan_dvorak[MAIN_LEN] =
98 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
99 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
100 /* ' , . p y f g c r l / = */
101 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
102 /* a o e u i d h t n s - \ */
103 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
104 /* ; q j k x b m w v z */
105 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
106 0x56 /* the 102nd key (actually to the right of l-shift) */
109 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
111 /* NOTE: this layout must concur with the scan codes layout above */
112 VK_OEM_3,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,
113 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,
114 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,
115 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
116 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
119 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
121 /* NOTE: this layout must concur with the scan codes layout above */
122 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,
123 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,
124 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,
125 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,
126 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
129 static const WORD main_key_vkey_azerty[MAIN_LEN] =
131 /* NOTE: this layout must concur with the scan codes layout above */
132 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,
133 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,
134 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,
135 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
136 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
139 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
141 /* NOTE: this layout must concur with the scan codes layout above */
142 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,
143 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,
144 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,
145 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
146 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
149 /* FIXME: add other layouts, such as German QWERTZ */
151 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
153 /* the VK mappings for the main keyboard will be auto-assigned as before,
154 so what we have here is just the character tables */
155 /* order: Normal, Shift, AltGr, Shift-AltGr */
156 /* We recommend you write just what is guaranteed to be correct (i.e. what's
157 written on the keycaps), not the bunch of special characters behind AltGr
158 and Shift-AltGr if it can vary among different X servers */
159 /* Remember that your 102nd key (to the right of l-shift) should be on a
160 separate line, see existing tables */
161 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
162 /* Remember to also add your new table to the layout index table far below! */
164 /*** German Logitech Desktop Pro keyboard layout */
165 static const char main_key_DE_logitech[MAIN_LEN][4] =
167 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
168 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
169 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
170 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
174 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
175 static const char main_key_US[MAIN_LEN][4] =
177 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
178 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
179 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
180 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
183 /*** United States keyboard layout (phantom key version) */
184 /* (XFree86 reports the <> key even if it's not physically there) */
185 static const char main_key_US_phantom[MAIN_LEN][4] =
187 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
188 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
189 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
190 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
191 "<>" /* the phantom key */
194 /*** United States keyboard layout (dvorak version) */
195 static const char main_key_US_dvorak[MAIN_LEN][4] =
197 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
198 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
199 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
200 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
203 /*** British keyboard layout */
204 static const char main_key_UK[MAIN_LEN][4] =
206 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
207 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
208 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
209 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
213 /*** French keyboard layout (contributed by Eric Pouech) */
214 static const char main_key_FR[MAIN_LEN][4] =
216 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
217 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
218 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
219 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
223 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
224 static const char main_key_IS[MAIN_LEN][4] =
226 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
227 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
228 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
229 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
233 /*** German keyboard layout (contributed by Ulrich Weigand) */
234 static const char main_key_DE[MAIN_LEN][4] =
236 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
237 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
238 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
239 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
243 /*** German keyboard layout without dead keys */
244 static const char main_key_DE_nodead[MAIN_LEN][4] =
246 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
247 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
248 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
249 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
253 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
254 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
256 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
257 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
258 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
259 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
262 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
263 static const char main_key_SG[MAIN_LEN][4] =
265 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
266 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
267 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
268 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
272 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
273 static const char main_key_SF[MAIN_LEN][4] =
275 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
276 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
277 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
278 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
282 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
283 static const char main_key_NO[MAIN_LEN][4] =
285 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
286 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
287 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
288 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
292 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
293 static const char main_key_DA[MAIN_LEN][4] =
295 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
296 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
297 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
298 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
302 /*** Swedish keyboard layout (contributed by Peter Bortas) */
303 static const char main_key_SE[MAIN_LEN][4] =
305 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
306 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
307 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
308 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
312 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
313 static const char main_key_ET[MAIN_LEN][4] =
315 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
316 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
317 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
318 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
322 /*** Canadian French keyboard layout */
323 static const char main_key_CF[MAIN_LEN][4] =
325 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
326 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
327 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
328 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
332 /*** Portuguese keyboard layout */
333 static const char main_key_PT[MAIN_LEN][4] =
335 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
336 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
337 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
338 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
342 /*** Italian keyboard layout */
343 static const char main_key_IT[MAIN_LEN][4] =
345 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
346 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
347 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
348 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
352 /*** Finnish keyboard layout */
353 static const char main_key_FI[MAIN_LEN][4] =
355 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
356 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
357 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
358 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
362 /*** Bulgarian bds keyboard layout */
363 static const char main_key_BG_bds[MAIN_LEN][4] =
365 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
366 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
367 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
368 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
369 "<>" /* the phantom key */
372 /*** Bulgarian phonetic keyboard layout */
373 static const char main_key_BG_phonetic[MAIN_LEN][4] =
375 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
376 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
377 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
378 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
379 "<>" /* the phantom key */
382 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
383 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
384 static const char main_key_BY[MAIN_LEN][4] =
386 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
387 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
388 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
389 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
393 /*** Russian keyboard layout (contributed by Pavel Roskin) */
394 static const char main_key_RU[MAIN_LEN][4] =
396 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
397 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
398 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
399 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
402 /*** Russian keyboard layout (phantom key version) */
403 static const char main_key_RU_phantom[MAIN_LEN][4] =
405 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
406 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
407 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
408 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
409 "<>" /* the phantom key */
412 /*** Russian keyboard layout KOI8-R */
413 static const char main_key_RU_koi8r[MAIN_LEN][4] =
415 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
416 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
417 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
418 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
419 "<>" /* the phantom key */
422 /*** Ukrainian keyboard layout KOI8-U */
423 static const char main_key_UA[MAIN_LEN][4] =
425 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
426 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
427 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
428 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
429 "<>" /* the phantom key */
432 /*** Spanish keyboard layout (contributed by José Marcos López) */
433 static const char main_key_ES[MAIN_LEN][4] =
435 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
436 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
437 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
438 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
442 /*** Belgian keyboard layout ***/
443 static const char main_key_BE[MAIN_LEN][4] =
445 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
446 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
447 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
448 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
452 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
453 static const char main_key_HU[MAIN_LEN][4] =
455 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
456 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
457 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
458 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
462 /*** Polish (programmer's) keyboard layout ***/
463 static const char main_key_PL[MAIN_LEN][4] =
465 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
466 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
467 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
468 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
472 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
473 static const char main_key_SI[MAIN_LEN][4] =
475 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
476 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
477 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
478 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
482 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
483 static const char main_key_HR_jelly[MAIN_LEN][4] =
485 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
486 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
487 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
488 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
492 /*** Croatian keyboard layout ***/
493 static const char main_key_HR[MAIN_LEN][4] =
495 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
496 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
497 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
498 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
502 /*** Japanese 106 keyboard layout ***/
503 static const char main_key_JA_jp106[MAIN_LEN][4] =
505 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
506 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
507 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
508 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
512 /*** Japanese pc98x1 keyboard layout ***/
513 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
515 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
516 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
517 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
518 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
522 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
523 static const char main_key_PT_br[MAIN_LEN][4] =
525 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
526 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
527 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
528 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
532 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
533 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
535 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
536 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
537 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
538 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
542 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
543 static const char main_key_US_intl[MAIN_LEN][4] =
545 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
546 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
547 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
548 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
551 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
552 - dead_abovering replaced with degree - no symbol in iso8859-2
553 - brokenbar replaced with bar */
554 static const char main_key_SK[MAIN_LEN][4] =
556 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
557 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
558 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
559 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
563 /*** Czech keyboard layout (setxkbmap cz) */
564 static const char main_key_CZ[MAIN_LEN][4] =
566 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
567 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
568 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
569 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
573 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
574 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
576 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
577 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
578 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
579 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
583 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
584 static const char main_key_SK_prog[MAIN_LEN][4] =
586 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
587 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
588 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
589 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
593 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
594 static const char main_key_CS[MAIN_LEN][4] =
596 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
597 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
598 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
599 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
603 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
604 static const char main_key_LA[MAIN_LEN][4] =
606 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
607 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
608 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
609 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
613 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
614 static const char main_key_LT_B[MAIN_LEN][4] =
616 "`~","1àÀ","2èÈ","3æÆ","4ëË","5áÁ","6ðÐ","7øØ","8ûÛ","9¥(","0´)","-_","=þÞ","\\|",
617 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
618 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
619 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
622 /*** Turkish keyboard Layout */
623 static const char main_key_TK[MAIN_LEN][4] =
625 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
626 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
627 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
628 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
631 /*** Israeli keyboard layout */
632 static const char main_key_IL[MAIN_LEN][4] =
634 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
635 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
636 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
637 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
640 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
641 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
642 message since they have different characters in gr and el XFree86 layouts. */
643 static const char main_key_EL[MAIN_LEN][4] =
645 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
646 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
647 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
648 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
652 /*** VNC keyboard layout */
653 static const WORD main_key_scan_vnc[MAIN_LEN] =
655 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
656 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,
660 static const WORD main_key_vkey_vnc[MAIN_LEN] =
662 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,
663 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,
667 static const char main_key_vnc[MAIN_LEN][4] =
669 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
670 "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"
673 /*** Layout table. Add your keyboard mappings to this list */
674 static const struct {
676 const UINT layout_cp; /* Code page for this layout */
677 const char (*key)[MAIN_LEN][4];
678 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
679 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
681 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
682 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
683 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
684 {"British keyboard layout", 28605, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
685 {"German keyboard layout", 28605, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
686 {"German keyboard layout without dead keys", 28605, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
687 {"German keyboard layout for logitech desktop pro", 28605, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
688 {"German keyboard layout without dead keys 105", 28605, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
689 {"Swiss German keyboard layout", 28605, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"Swedish keyboard layout", 28605, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
691 {"Estonian keyboard layout", 28605, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"Norwegian keyboard layout", 28605, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
693 {"Danish keyboard layout", 28605, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
694 {"French keyboard layout", 28605, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
695 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
696 {"Belgian keyboard layout", 28605, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
697 {"Swiss French keyboard layout", 28605, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
698 {"Portuguese keyboard layout", 28605, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
699 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
700 {"Brazilian ABNT-2 keyboard layout ALT GR", 28591, &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
701 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
702 {"Finnish keyboard layout", 28605, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
703 {"Bulgarian bds keyboard layout", 1251, &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
704 {"Bulgarian phonetic keyboard layout", 1251, &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
705 {"Belarusian keyboard layout", 1251, &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
706 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
707 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
708 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
709 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
710 {"Spanish keyboard layout", 28605, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
711 {"Italian keyboard layout", 28605, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
712 {"Icelandic keyboard layout", 28605, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
713 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
714 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
715 {"Slovenian keyboard layout", 28592, &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
716 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
717 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
718 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
719 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
720 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
721 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
722 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
723 {"Czech keyboard layout cz", 28592, &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
724 {"Czech keyboard layout cz_qwerty", 28592, &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
725 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
726 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
727 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
728 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
729 {"VNC keyboard layout", 28605, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
730 {"Greek keyboard layout", 28597, &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
732 {NULL, 0, NULL, NULL, NULL} /* sentinel */
734 static unsigned kbd_layout=0; /* index into above table of layouts */
736 /* maybe more of these scancodes should be extended? */
737 /* extended must be set for ALT_R, CTRL_R,
738 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
739 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
740 /* FIXME should we set extended bit for NumLock ? My
741 * Windows does ... DF */
742 /* Yes, to distinguish based on scan codes, also
743 for PrtScn key ... GA */
745 static const WORD nonchar_key_vkey[256] =
748 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
750 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
751 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
752 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
754 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
755 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
756 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
757 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
758 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
759 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
761 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
762 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
763 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
765 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
766 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
767 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
769 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
770 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
771 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
772 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
773 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
774 VK_END, 0, VK_INSERT, VK_DELETE,
775 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
776 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
777 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
778 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
779 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
780 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
783 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
784 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
785 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
786 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
788 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
789 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
790 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
791 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
792 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
795 static const WORD nonchar_key_scan[256] =
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
800 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
801 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
802 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
811 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
814 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
815 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
822 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
824 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
825 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
826 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
829 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
830 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
834 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
835 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
841 /* Returns the Windows virtual key code associated with the X event <e> */
842 /* x11 lock must be held */
843 static WORD EVENT_event_to_vkey( XKeyEvent *e)
847 XLookupString(e, NULL, 0, &keysym, NULL);
849 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
850 && (e->state & NumLockMask))
851 /* Only the Keypad keys 0-9 and . send different keysyms
852 * depending on the NumLock state */
853 return nonchar_key_vkey[keysym & 0xFF];
855 return keyc2vkey[e->keycode];
858 static BOOL NumState=FALSE, CapsState=FALSE;
861 /***********************************************************************
862 * send_keyboard_input
864 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
868 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
869 input.u.ki.wVk = wVk;
870 input.u.ki.wScan = wScan;
871 input.u.ki.dwFlags = dwFlags;
872 input.u.ki.time = time;
873 input.u.ki.dwExtraInfo = 0;
874 SendInput( 1, &input, sizeof(input) );
878 /**********************************************************************
879 * KEYBOARD_GenerateMsg
881 * Generate Down+Up messages when NumLock or CapsLock is pressed.
883 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
886 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
888 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
892 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
893 don't treat it. It's from the same key press. Then the state goes to ON.
894 And from there, a 'release' event will switch off the toggle key. */
896 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
899 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
900 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
901 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
903 if (Evtype!=KeyPress)
905 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
906 send_keyboard_input( vkey, scan, down, event_time );
907 send_keyboard_input( vkey, scan, up, event_time );
909 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
912 else /* it was OFF */
913 if (Evtype==KeyPress)
915 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
916 send_keyboard_input( vkey, scan, down, event_time );
917 send_keyboard_input( vkey, scan, up, event_time );
918 *State=TRUE; /* Goes to intermediary state before going to ON */
919 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
924 /***********************************************************************
925 * KEYBOARD_UpdateOneState
927 * Updates internal state for <vkey>, depending on key <state> under X
930 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
932 /* Do something if internal table state != X state for keycode */
933 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
935 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
936 vkey, pKeyStateTable[vkey]);
938 /* Fake key being pressed inside wine */
939 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
941 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
945 /***********************************************************************
946 * X11DRV_KeymapNotify
948 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
950 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
951 * from wine to another application and back.
952 * Toggle keys are handled in HandleEvent.
954 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
956 int i, j, alt, control, shift;
957 DWORD time = GetCurrentTime();
959 alt = control = shift = 0;
960 for (i = 0; i < 32; i++)
962 if (!event->key_vector[i]) continue;
963 for (j = 0; j < 8; j++)
965 if (!(event->key_vector[i] & (1<<j))) continue;
966 switch(keyc2vkey[(i * 8) + j] & 0xff)
968 case VK_MENU: alt = 1; break;
969 case VK_CONTROL: control = 1; break;
970 case VK_SHIFT: shift = 1; break;
974 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
975 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
976 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
979 /***********************************************************************
982 * Handle a X key event
984 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
988 WORD vkey = 0, bScan;
992 DWORD event_time = event->time - X11DRV_server_startticks;
994 /* this allows support for dead keys */
995 if ((event->keycode >> 8) == 0x10)
996 event->keycode=(event->keycode & 0xff);
999 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1000 wine_tsx11_unlock();
1002 /* Ignore some unwanted events */
1003 if (keysym == XK_ISO_Prev_Group ||
1004 keysym == XK_ISO_Next_Group ||
1005 keysym == XK_Mode_switch)
1007 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
1011 TRACE_(key)("state = %X\n", event->state);
1013 /* If XKB extensions are used, the state mask for AltGr will use the group
1014 index instead of the modifier mask. The group index is set in bits
1015 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1016 pressed, look if the group index is different than 0. From XKB
1017 extension documentation, the group index for AltGr should be 2
1018 (event->state = 0x2000). It's probably better to not assume a
1019 predefined group index and find it dynamically
1021 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1022 AltGrMask = event->state & 0x6000;
1024 Str[ascii_chars] = '\0';
1028 ksname = TSXKeysymToString(keysym);
1031 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1032 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1033 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1037 vkey = EVENT_event_to_vkey(event);
1038 wine_tsx11_unlock();
1040 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1041 event->keycode, vkey);
1045 switch (vkey & 0xff)
1048 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1051 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1052 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1053 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1056 /* Adjust the NUMLOCK state if it has been changed outside wine */
1057 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1059 TRACE("Adjusting NumLock state.\n");
1060 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1061 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1063 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1064 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1066 TRACE("Adjusting Caps Lock state.\n");
1067 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1068 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1070 /* Not Num nor Caps : end of intermediary states for both. */
1074 bScan = keyc2scan[event->keycode] & 0xFF;
1075 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1078 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1079 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1081 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1086 /**********************************************************************
1087 * X11DRV_KEYBOARD_DetectLayout
1089 * Called from X11DRV_InitKeyboard
1090 * This routine walks through the defined keyboard layouts and selects
1091 * whichever matches most closely.
1092 * X11 lock must be held.
1095 X11DRV_KEYBOARD_DetectLayout (void)
1097 Display *display = thread_display();
1098 unsigned current, match, mismatch, seq;
1099 int score, keyc, i, key, pkey, ok, syms;
1101 const char (*lkey)[MAIN_LEN][4];
1102 unsigned max_seq = 0;
1103 int max_score = 0, ismatch = 0;
1107 syms = keysyms_per_keycode;
1109 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1112 for (current = 0; main_key_tab[current].comment; current++) {
1113 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1118 lkey = main_key_tab[current].key;
1120 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1121 /* get data for keycode from X server */
1122 for (i = 0; i < syms; i++) {
1123 keysym = XKeycodeToKeysym (display, keyc, i);
1124 /* Allow both one-byte and two-byte national keysyms */
1125 if ((keysym < 0x8000) && (keysym != ' '))
1126 ckey[i] = keysym & 0xFF;
1128 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1132 /* search for a match in layout table */
1133 /* right now, we just find an absolute match for defined positions */
1134 /* (undefined positions are ignored, so if it's defined as "3#" in */
1135 /* the table, it's okay that the X server has "3#£", for example) */
1136 /* however, the score will be higher for longer matches */
1137 for (key = 0; key < MAIN_LEN; key++) {
1138 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1139 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1141 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1149 /* count the matches and mismatches */
1152 /* and how much the keycode order matches */
1153 if (key > pkey) seq++;
1156 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1162 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1163 match, mismatch, seq, score);
1164 if ((score > max_score) ||
1165 ((score == max_score) && (seq > max_seq))) {
1166 /* best match so far */
1167 kbd_layout = current;
1170 ismatch = !mismatch;
1173 /* we're done, report results if necessary */
1176 "Your keyboard layout was not found!\n"
1177 "Using closest match instead (%s) for scancode mapping.\n"
1178 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1179 "to us for inclusion into future Wine releases.\n"
1180 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1181 main_key_tab[kbd_layout].comment);
1184 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1187 /**********************************************************************
1188 * InitKeyboard (X11DRV.@)
1190 void X11DRV_InitKeyboard( BYTE *key_state_table )
1193 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1195 Display *display = thread_display();
1197 XModifierKeymap *mmp;
1201 WORD scan, vkey, OEMvkey;
1202 int keyc, i, keyn, syms;
1203 char ckey[4]={0,0,0,0};
1204 const char (*lkey)[MAIN_LEN][4];
1206 pKeyStateTable = key_state_table;
1210 is_xkb = XkbQueryExtension(display,
1211 &xkb_opcode, &xkb_event, &xkb_error,
1212 &xkb_major, &xkb_minor);
1214 /* we have XKB, approximate Windows behaviour */
1215 XkbSetDetectableAutoRepeat(display, True, NULL);
1218 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1219 ksp = XGetKeyboardMapping(display, min_keycode,
1220 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1221 /* We are only interested in keysyms_per_keycode.
1222 There is no need to hold a local copy of the keysyms table */
1225 mmp = XGetModifierMapping(display);
1226 kcp = mmp->modifiermap;
1227 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1231 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1236 for (k = 0; k < keysyms_per_keycode; k += 1)
1237 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1239 NumLockMask = 1 << i;
1240 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1244 XFreeModifiermap(mmp);
1246 /* Detect the keyboard layout */
1247 X11DRV_KEYBOARD_DetectLayout();
1248 lkey = main_key_tab[kbd_layout].key;
1249 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1251 /* Now build two conversion arrays :
1252 * keycode -> vkey + scancode + extended
1253 * vkey + extended -> keycode */
1255 e2.display = display;
1258 OEMvkey = VK_OEM_7; /* next is available. */
1259 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1261 e2.keycode = (KeyCode)keyc;
1262 XLookupString(&e2, NULL, 0, &keysym, NULL);
1264 if (keysym) /* otherwise, keycode not used */
1266 if ((keysym >> 8) == 0xFF) /* non-character key */
1268 vkey = nonchar_key_vkey[keysym & 0xff];
1269 scan = nonchar_key_scan[keysym & 0xff];
1270 /* set extended bit when necessary */
1271 if (scan & 0x100) vkey |= 0x100;
1272 } else if (keysym == 0x20) { /* Spacebar */
1276 /* we seem to need to search the layout-dependent scancodes */
1277 int maxlen=0,maxval=-1,ok;
1278 for (i=0; i<syms; i++) {
1279 keysym = XKeycodeToKeysym(display, keyc, i);
1280 if ((keysym<0x800) && (keysym!=' ')) {
1281 ckey[i] = keysym & 0xFF;
1283 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1286 /* find key with longest match streak */
1287 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1288 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1289 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1290 if (ok||(i>maxlen)) {
1291 maxlen=i; maxval=keyn;
1297 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1298 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1299 scan = (*lscan)[maxval];
1300 vkey = (*lvkey)[maxval];
1304 /* find a suitable layout-dependent VK code */
1305 /* (most Winelib apps ought to be able to work without layout tables!) */
1306 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1308 keysym = XLookupKeysym(&e2, i);
1309 if ((keysym >= VK_0 && keysym <= VK_9)
1310 || (keysym >= VK_A && keysym <= VK_Z)) {
1315 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1317 keysym = XLookupKeysym(&e2, i);
1320 case ';': vkey = VK_OEM_1; break;
1321 case '/': vkey = VK_OEM_2; break;
1322 case '`': vkey = VK_OEM_3; break;
1323 case '[': vkey = VK_OEM_4; break;
1324 case '\\': vkey = VK_OEM_5; break;
1325 case ']': vkey = VK_OEM_6; break;
1326 case '\'': vkey = VK_OEM_7; break;
1327 case ',': vkey = VK_OEM_COMMA; break;
1328 case '.': vkey = VK_OEM_PERIOD; break;
1329 case '-': vkey = VK_OEM_MINUS; break;
1330 case '+': vkey = VK_OEM_PLUS; break;
1336 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1337 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1340 case 0xc1 : OEMvkey=0xdb; break;
1341 case 0xe5 : OEMvkey=0xe9; break;
1342 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1347 if (TRACE_ON(keyboard))
1349 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1350 OEMvkey, e2.keycode);
1352 for (i = 0; i < keysyms_per_keycode; i += 1)
1356 keysym = XLookupKeysym(&e2, i);
1357 ksname = XKeysymToString(keysym);
1359 ksname = "NoSymbol";
1360 DPRINTF( "%lX (%s) ", keysym, ksname);
1366 keyc2vkey[e2.keycode] = vkey;
1367 keyc2scan[e2.keycode] = scan;
1370 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1371 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1372 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1374 keysym = XKeycodeToKeysym(display, keyc, 0);
1375 ksname = XKeysymToString(keysym);
1376 if (!ksname) ksname = "NoSymbol";
1378 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1380 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1381 keyc2scan[keyc]=scan++;
1384 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1385 kcControl = XKeysymToKeycode(display, XK_Control_L);
1386 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1387 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1388 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1389 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1390 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1391 wine_tsx11_unlock();
1395 /***********************************************************************
1396 * X11DRV_MappingNotify
1398 void X11DRV_MappingNotify( XMappingEvent *event )
1400 TSXRefreshKeyboardMapping(event);
1401 X11DRV_InitKeyboard( pKeyStateTable );
1405 /***********************************************************************
1406 * VkKeyScan (X11DRV.@)
1408 WORD X11DRV_VkKeyScan(CHAR cChar)
1410 Display *display = thread_display();
1416 /* char->keysym (same for ANSI chars) */
1417 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1418 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1420 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1422 { /* It didn't work ... let's try with deadchar code. */
1423 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1426 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1427 cChar,keysym,keysym,keycode);
1431 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1432 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1435 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1437 case 1 : highbyte = 0x0100; break;
1438 case 2 : highbyte = 0x0600; break;
1439 case 3 : highbyte = 0x0700; break;
1440 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1443 index : 0 adds 0x0000
1444 index : 1 adds 0x0100 (shift)
1445 index : ? adds 0x0200 (ctrl)
1446 index : 2 adds 0x0600 (ctrl+alt)
1447 index : 3 adds 0x0700 (ctrl+alt+shift)
1450 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1451 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1454 /***********************************************************************
1455 * MapVirtualKey (X11DRV.@)
1457 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1459 Display *display = thread_display();
1461 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1463 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1465 case 0: { /* vkey-code to scan-code */
1466 /* let's do vkey -> keycode -> scan */
1468 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1469 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1470 returnMVK (keyc2scan[keyc] & 0xFF);
1471 TRACE("returning no scan-code.\n");
1474 case 1: { /* scan-code to vkey-code */
1475 /* let's do scan -> keycode -> vkey */
1477 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1478 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1479 returnMVK (keyc2vkey[keyc] & 0xFF);
1480 TRACE("returning no vkey-code.\n");
1483 case 2: { /* vkey-code to unshifted ANSI code */
1484 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1485 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1486 * key.. Looks like something is wrong with the MS docs?
1487 * This is only true for letters, for example VK_0 returns '0' not ')'.
1488 * - hence we use the lock mask to ensure this happens.
1490 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1495 e.display = display;
1498 /* LockMask should behave exactly like caps lock - upercase
1499 * the letter keys and thats about it. */
1504 /* We exit on the first keycode found, to speed up the thing. */
1505 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1506 { /* Find a keycode that could have generated this virtual key */
1507 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1508 { /* We filter the extended bit, we don't know it */
1509 e.keycode = keyc; /* Store it temporarily */
1510 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1511 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1512 state), so set it to 0, we'll find another one */
1517 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1518 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1520 if (wCode==VK_DECIMAL)
1521 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1525 WARN("Unknown virtual key %X !!! \n", wCode);
1526 wine_tsx11_unlock();
1527 return 0; /* whatever */
1529 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1531 if (XLookupString(&e, s, 2, &keysym, NULL))
1533 wine_tsx11_unlock();
1537 TRACE("returning no ANSI.\n");
1538 wine_tsx11_unlock();
1542 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1543 /* left and right */
1544 FIXME(" stub for NT\n");
1547 default: /* reserved */
1548 WARN("Unknown wMapType %d !\n", wMapType);
1554 /***********************************************************************
1555 * GetKeyNameText (X11DRV.@)
1557 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1559 int vkey, ansi, scanCode;
1565 scanCode = lParam >> 16;
1566 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1568 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1569 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1571 /* handle "don't care" bit (0x02000000) */
1572 if (!(lParam & 0x02000000)) {
1591 ansi = X11DRV_MapVirtualKey(vkey, 2);
1592 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1594 /* first get the name of the "regular" keys which is the Upper case
1595 value of the keycap imprint. */
1596 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1597 (scanCode != 0x137) && /* PrtScn */
1598 (scanCode != 0x135) && /* numpad / */
1599 (scanCode != 0x37 ) && /* numpad * */
1600 (scanCode != 0x4a ) && /* numpad - */
1601 (scanCode != 0x4e ) ) /* numpad + */
1603 if ((nSize >= 2) && lpBuffer)
1605 *lpBuffer = toupper((char)ansi);
1613 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1614 without "extended-key" flag. However Wine generates scancode
1615 *with* "extended-key" flag. Seems to occur *only* for the
1616 function keys. Soooo.. We will leave the table alone and
1617 fudge the lookup here till the other part is found and fixed!!! */
1619 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1620 (scanCode == 0x157) || (scanCode == 0x158))
1621 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1623 /* let's do scancode -> keycode -> keysym -> String */
1625 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1626 if ((keyc2scan[keyi]) == scanCode)
1628 if (keyi <= max_keycode)
1630 keyc = (KeyCode) keyi;
1631 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1632 name = TSXKeysymToString(keys);
1633 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1634 scanCode, keyc, (int)keys, name);
1635 if (lpBuffer && nSize && name)
1637 lstrcpynA(lpBuffer, name, nSize);
1642 /* Finally issue FIXME for unknown keys */
1644 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1645 if (lpBuffer && nSize)
1650 /***********************************************************************
1651 * X11DRV_KEYBOARD_MapDeadKeysym
1653 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1657 /* symbolic ASCII is the same as defined in rfc1345 */
1658 #ifdef XK_dead_tilde
1659 case XK_dead_tilde :
1661 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1662 return '~'; /* '? */
1663 #ifdef XK_dead_acute
1664 case XK_dead_acute :
1666 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1667 return 0xb4; /* '' */
1668 #ifdef XK_dead_circumflex
1669 case XK_dead_circumflex:
1671 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1672 return '^'; /* '> */
1673 #ifdef XK_dead_grave
1674 case XK_dead_grave :
1676 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1677 return '`'; /* '! */
1678 #ifdef XK_dead_diaeresis
1679 case XK_dead_diaeresis :
1681 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1682 return 0xa8; /* ': */
1683 #ifdef XK_dead_cedilla
1684 case XK_dead_cedilla :
1685 return 0xb8; /* ', */
1687 #ifdef XK_dead_macron
1688 case XK_dead_macron :
1689 return '-'; /* 'm isn't defined on iso-8859-x */
1691 #ifdef XK_dead_breve
1692 case XK_dead_breve :
1693 return 0xa2; /* '( */
1695 #ifdef XK_dead_abovedot
1696 case XK_dead_abovedot :
1697 return 0xff; /* '. */
1699 #ifdef XK_dead_abovering
1700 case XK_dead_abovering :
1701 return '0'; /* '0 isn't defined on iso-8859-x */
1703 #ifdef XK_dead_doubleacute
1704 case XK_dead_doubleacute :
1705 return 0xbd; /* '" */
1707 #ifdef XK_dead_caron
1708 case XK_dead_caron :
1709 return 0xb7; /* '< */
1711 #ifdef XK_dead_ogonek
1712 case XK_dead_ogonek :
1713 return 0xb2; /* '; */
1715 /* FIXME: I don't know this three.
1718 case XK_dead_voiced_sound :
1720 case XK_dead_semivoiced_sound :
1724 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1728 /***********************************************************************
1729 * ToUnicode (X11DRV.@)
1731 * The ToUnicode function translates the specified virtual-key code and keyboard
1732 * state to the corresponding Windows character or characters.
1734 * If the specified key is a dead key, the return value is negative. Otherwise,
1735 * it is one of the following values:
1737 * 0 The specified virtual key has no translation for the current state of the keyboard.
1738 * 1 One Windows character was copied to the buffer.
1739 * 2 Two characters were copied to the buffer. This usually happens when a
1740 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1741 * be composed with the specified virtual key to form a single character.
1743 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1746 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1747 LPWSTR bufW, int bufW_size, UINT flags)
1749 Display *display = thread_display();
1756 if (scanCode & 0x8000)
1758 TRACE("Key UP, doing nothing\n" );
1761 e.display = display;
1764 if (lpKeyState[VK_SHIFT] & 0x80)
1766 TRACE("ShiftMask = %04x\n", ShiftMask);
1767 e.state |= ShiftMask;
1769 if (lpKeyState[VK_CAPITAL] & 0x01)
1771 TRACE("LockMask = %04x\n", LockMask);
1772 e.state |= LockMask;
1774 if (lpKeyState[VK_CONTROL] & 0x80)
1776 TRACE("ControlMask = %04x\n", ControlMask);
1777 e.state |= ControlMask;
1779 if (lpKeyState[VK_NUMLOCK] & 0x01)
1781 TRACE("NumLockMask = %04x\n", NumLockMask);
1782 e.state |= NumLockMask;
1785 /* Restore saved AltGr state */
1786 TRACE("AltGrMask = %04x\n", AltGrMask);
1787 e.state |= AltGrMask;
1789 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1790 virtKey, scanCode, e.state);
1792 /* We exit on the first keycode found, to speed up the thing. */
1793 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1794 { /* Find a keycode that could have generated this virtual key */
1795 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1796 { /* We filter the extended bit, we don't know it */
1797 e.keycode = keyc; /* Store it temporarily */
1798 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1799 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1800 state), so set it to 0, we'll find another one */
1805 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1806 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1808 if (virtKey==VK_DECIMAL)
1809 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1813 WARN("Unknown virtual key %X !!! \n",virtKey);
1814 wine_tsx11_unlock();
1815 return virtKey; /* whatever */
1817 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1819 ret = XLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1820 wine_tsx11_unlock();
1826 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1829 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1836 ksname = TSXKeysymToString(keysym);
1839 if ((keysym >> 8) != 0xff)
1841 ERR("Please report: no char for keysym %04lX (%s) :\n",
1843 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1844 virtKey, scanCode, e.keycode, e.state);
1848 else { /* ret != 0 */
1849 /* We have a special case to handle : Shift + arrow, shift + home, ...
1850 X returns a char for it, but Windows doesn't. Let's eat it. */
1851 if (!(e.state & NumLockMask) /* NumLock is off */
1852 && (e.state & ShiftMask) /* Shift is pressed */
1853 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1859 /* more areas where X returns characters but Windows does not
1860 CTRL + number or CTRL + symbol */
1861 if (e.state & ControlMask)
1863 if (((keysym>=33) && (keysym < 'A')) ||
1864 ((keysym > 'Z') && (keysym < 'a')))
1871 /* We have another special case for delete key (XK_Delete) on an
1872 extended keyboard. X returns a char for it, but Windows doesn't */
1873 if (keysym == XK_Delete)
1878 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1879 && (keysym == XK_KP_Decimal))
1885 /* perform translation to unicode */
1888 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1889 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1890 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1894 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1895 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1899 /***********************************************************************
1902 void X11DRV_Beep(void)
1904 TSXBell(thread_display(), 0);