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>
43 #include "wine/winuser16.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
50 WINE_DECLARE_DEBUG_CHANNEL(key);
51 WINE_DECLARE_DEBUG_CHANNEL(dinput);
53 int min_keycode, max_keycode, keysyms_per_keycode;
54 WORD keyc2vkey[256], keyc2scan[256];
56 static LPBYTE pKeyStateTable;
57 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
58 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
60 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
63 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
65 /* Keyboard translation tables */
67 static const WORD main_key_scan_qwerty[MAIN_LEN] =
69 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
70 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
71 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
72 /* q w e r t y u i o p [ ] */
73 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
74 /* a s d f g h j k l ; ' \ */
75 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
76 /* z x c v b n m , . / */
77 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
78 0x56 /* the 102nd key (actually to the right of l-shift) */
81 static const WORD main_key_scan_dvorak[MAIN_LEN] =
83 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
84 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
85 /* ' , . p y f g c r l / = */
86 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
87 /* a o e u i d h t n s - \ */
88 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
89 /* ; q j k x b m w v z */
90 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
91 0x56 /* the 102nd key (actually to the right of l-shift) */
94 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
96 /* NOTE: this layout must concur with the scan codes layout above */
97 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,
98 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,
99 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,
100 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
101 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
104 static const WORD main_key_vkey_azerty[MAIN_LEN] =
106 /* NOTE: this layout must concur with the scan codes layout above */
107 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,
108 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,
109 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,
110 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
111 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
114 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
116 /* NOTE: this layout must concur with the scan codes layout above */
117 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,
118 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,
119 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,
120 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
121 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
124 /* FIXME: add other layouts, such as German QWERTZ */
126 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
128 /* the VK mappings for the main keyboard will be auto-assigned as before,
129 so what we have here is just the character tables */
130 /* order: Normal, Shift, AltGr, Shift-AltGr */
131 /* We recommend you write just what is guaranteed to be correct (i.e. what's
132 written on the keycaps), not the bunch of special characters behind AltGr
133 and Shift-AltGr if it can vary among different X servers */
134 /* Remember that your 102nd key (to the right of l-shift) should be on a
135 separate line, see existing tables */
136 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
137 /* Remember to also add your new table to the layout index table far below! */
139 /*** German Logitech Desktop Pro keyboard layout */
140 static const char main_key_DE_logitech[MAIN_LEN][4] =
142 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
143 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
144 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
145 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
149 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
150 static const char main_key_US[MAIN_LEN][4] =
152 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
153 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
154 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
155 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
158 /*** United States keyboard layout (phantom key version) */
159 /* (XFree86 reports the <> key even if it's not physically there) */
160 static const char main_key_US_phantom[MAIN_LEN][4] =
162 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
163 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
164 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
165 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
166 "<>" /* the phantom key */
169 /*** United States keyboard layout (dvorak version) */
170 static const char main_key_US_dvorak[MAIN_LEN][4] =
172 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
173 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
174 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
175 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
178 /*** British keyboard layout */
179 static const char main_key_UK[MAIN_LEN][4] =
181 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
182 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
183 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
184 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
188 /*** French keyboard layout (contributed by Eric Pouech) */
189 static const char main_key_FR[MAIN_LEN][4] =
191 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
192 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
193 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
194 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
198 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
199 static const char main_key_IS[MAIN_LEN][4] =
201 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
202 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
203 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
204 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
208 /*** German keyboard layout (contributed by Ulrich Weigand) */
209 static const char main_key_DE[MAIN_LEN][4] =
211 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
212 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
213 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
214 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
218 /*** German keyboard layout without dead keys */
219 static const char main_key_DE_nodead[MAIN_LEN][4] =
221 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
222 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
223 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
224 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
228 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
229 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
231 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
232 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
233 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
234 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
237 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
238 static const char main_key_SG[MAIN_LEN][4] =
240 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
241 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
242 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
243 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
247 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
248 static const char main_key_SF[MAIN_LEN][4] =
250 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
251 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
252 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
253 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
257 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
258 static const char main_key_NO[MAIN_LEN][4] =
260 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
261 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
262 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
263 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
267 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
268 static const char main_key_DA[MAIN_LEN][4] =
270 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
271 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
272 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
273 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
277 /*** Swedish keyboard layout (contributed by Peter Bortas) */
278 static const char main_key_SE[MAIN_LEN][4] =
280 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
281 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
282 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
283 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
287 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
288 static const char main_key_ET[MAIN_LEN][4] =
290 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
291 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
292 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
293 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
297 /*** Canadian French keyboard layout */
298 static const char main_key_CF[MAIN_LEN][4] =
300 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
301 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
302 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
303 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
307 /*** Portuguese keyboard layout */
308 static const char main_key_PT[MAIN_LEN][4] =
310 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
311 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
312 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
313 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
317 /*** Italian keyboard layout */
318 static const char main_key_IT[MAIN_LEN][4] =
320 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
321 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
322 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
323 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
327 /*** Finnish keyboard layout */
328 static const char main_key_FI[MAIN_LEN][4] =
330 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
331 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
332 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
333 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
337 /*** Bulgarian bds keyboard layout */
338 static const char main_key_BG_bds[MAIN_LEN][4] =
340 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
341 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
342 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
343 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
344 "<>" /* the phantom key */
347 /*** Bulgarian phonetic keyboard layout */
348 static const char main_key_BG_phonetic[MAIN_LEN][4] =
350 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
351 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
352 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
353 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
354 "<>" /* the phantom key */
357 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
358 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
359 static const char main_key_BY[MAIN_LEN][4] =
361 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
362 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
363 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
364 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
368 /*** Russian keyboard layout (contributed by Pavel Roskin) */
369 static const char main_key_RU[MAIN_LEN][4] =
371 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
372 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
373 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
374 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
377 /*** Russian keyboard layout (phantom key version) */
378 static const char main_key_RU_phantom[MAIN_LEN][4] =
380 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
381 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
382 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
383 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
384 "<>" /* the phantom key */
387 /*** Russian keyboard layout KOI8-R */
388 static const char main_key_RU_koi8r[MAIN_LEN][4] =
390 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
391 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
392 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
393 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
394 "<>" /* the phantom key */
397 /*** Ukrainian keyboard layout KOI8-U */
398 static const char main_key_UA[MAIN_LEN][4] =
400 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
401 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
402 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
403 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
404 "<>" /* the phantom key */
407 /*** Spanish keyboard layout (contributed by José Marcos López) */
408 static const char main_key_ES[MAIN_LEN][4] =
410 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
411 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
412 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
413 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
417 /*** Belgian keyboard layout ***/
418 static const char main_key_BE[MAIN_LEN][4] =
420 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
421 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
422 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
423 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
427 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
428 static const char main_key_HU[MAIN_LEN][4] =
430 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
431 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
432 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
433 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
437 /*** Polish (programmer's) keyboard layout ***/
438 static const char main_key_PL[MAIN_LEN][4] =
440 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
441 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
442 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
443 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
447 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
448 static const char main_key_SI[MAIN_LEN][4] =
450 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
451 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
452 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
453 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
457 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
458 static const char main_key_HR_jelly[MAIN_LEN][4] =
460 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
461 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
462 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
463 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
467 /*** Croatian keyboard layout ***/
468 static const char main_key_HR[MAIN_LEN][4] =
470 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
471 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
472 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
473 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
477 /*** Japanese 106 keyboard layout ***/
478 static const char main_key_JA_jp106[MAIN_LEN][4] =
480 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
481 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
482 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
483 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
487 /*** Japanese pc98x1 keyboard layout ***/
488 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
490 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
491 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
492 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
493 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
497 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
498 static const char main_key_PT_br[MAIN_LEN][4] =
500 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
501 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
502 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
503 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?"
506 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
507 static const char main_key_US_intl[MAIN_LEN][4] =
509 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
510 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
511 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
512 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
515 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
516 - dead_abovering replaced with degree - no symbol in iso8859-2
517 - brokenbar replaced with bar */
518 static const char main_key_SK[MAIN_LEN][4] =
520 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
521 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
522 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
523 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
527 /*** Czech keyboard layout (setxkbmap cz) */
528 static const char main_key_CZ[MAIN_LEN][4] =
530 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
531 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
532 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
533 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
537 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
538 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
540 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
541 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
542 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
543 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
547 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
548 static const char main_key_SK_prog[MAIN_LEN][4] =
550 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
551 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
552 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
553 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
557 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
558 static const char main_key_CS[MAIN_LEN][4] =
560 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
561 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
562 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
563 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
567 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
568 static const char main_key_LA[MAIN_LEN][4] =
570 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
571 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
572 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
573 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
577 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
578 static const char main_key_LT_B[MAIN_LEN][4] =
580 "`~","1àÀ","2èÈ","3æÆ","4ëË","5áÁ","6ðÐ","7øØ","8ûÛ","9¥(","0´)","-_","=þÞ","\\|",
581 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
582 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
583 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
586 /*** Turkish keyboard Layout */
587 static const char main_key_TK[MAIN_LEN][4] =
589 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
590 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
591 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
592 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
595 /*** Israeli keyboard layout */
596 static const char main_key_IL[MAIN_LEN][4] =
598 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
599 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
600 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
601 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
604 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
605 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
606 message since they have different characters in gr and el XFree86 layouts. */
607 static const char main_key_EL[MAIN_LEN][4] =
609 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
610 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
611 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
612 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
616 /*** VNC keyboard layout */
617 static const WORD main_key_scan_vnc[MAIN_LEN] =
619 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
620 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,
624 static const WORD main_key_vkey_vnc[MAIN_LEN] =
626 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,
627 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,
631 static const char main_key_vnc[MAIN_LEN][4] =
633 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
634 "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"
637 /*** Layout table. Add your keyboard mappings to this list */
638 static const struct {
640 const UINT layout_cp; /* Code page for this layout */
641 const char (*key)[MAIN_LEN][4];
642 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
643 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
645 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
646 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
647 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
648 {"British keyboard layout", 28605, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
649 {"German keyboard layout", 28605, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
650 {"German keyboard layout without dead keys", 28605, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
651 {"German keyboard layout for logitech desktop pro", 28605, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
652 {"German keyboard layout without dead keys 105", 28605, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
653 {"Swiss German keyboard layout", 28605, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
654 {"Swedish keyboard layout", 28605, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
655 {"Estonian keyboard layout", 28605, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
656 {"Norwegian keyboard layout", 28605, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
657 {"Danish keyboard layout", 28605, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
658 {"French keyboard layout", 28605, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
659 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
660 {"Belgian keyboard layout", 28605, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
661 {"Swiss French keyboard layout", 28605, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
662 {"Portuguese keyboard layout", 28605, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
663 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
664 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
665 {"Finnish keyboard layout", 28605, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
666 {"Bulgarian bds keyboard layout", 1251, &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
667 {"Bulgarian phonetic keyboard layout", 1251, &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
668 {"Belarusian keyboard layout", 1251, &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
669 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
670 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
671 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
672 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
673 {"Spanish keyboard layout", 28605, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
674 {"Italian keyboard layout", 28605, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
675 {"Icelandic keyboard layout", 28605, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
676 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
677 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
678 {"Slovenian keyboard layout", 28592, &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
679 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
680 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
681 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
682 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
683 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
684 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
685 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
686 {"Czech keyboard layout cz", 28592, &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
687 {"Czech keyboard layout cz_qwerty", 28592, &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
688 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
689 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
691 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"VNC keyboard layout", 28605, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
693 {"Greek keyboard layout", 28597, &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
695 {NULL, 0, NULL, NULL, NULL} /* sentinel */
697 static unsigned kbd_layout=0; /* index into above table of layouts */
699 /* maybe more of these scancodes should be extended? */
700 /* extended must be set for ALT_R, CTRL_R,
701 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
702 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
703 /* FIXME should we set extended bit for NumLock ? My
704 * Windows does ... DF */
705 /* Yes, to distinguish based on scan codes, also
706 for PrtScn key ... GA */
708 static const WORD nonchar_key_vkey[256] =
711 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
713 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
714 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
715 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
717 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
718 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
719 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
720 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
721 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
722 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
724 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
725 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
726 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
728 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
729 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
730 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
732 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
733 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
734 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
735 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
736 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
737 VK_END, 0, VK_INSERT, VK_DELETE,
738 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
739 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
740 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
741 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
742 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
743 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
746 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
747 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
748 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
749 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
751 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
752 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
753 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
754 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
755 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
758 static const WORD nonchar_key_scan[256] =
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
763 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
764 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
765 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
774 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
777 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
778 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
785 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
787 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
788 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
789 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
792 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
793 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
797 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
798 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
804 /* Returns the Windows virtual key code associated with the X event <e> */
805 /* x11 lock must be held */
806 static WORD EVENT_event_to_vkey( XKeyEvent *e)
810 XLookupString(e, NULL, 0, &keysym, NULL);
812 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
813 && (e->state & NumLockMask))
814 /* Only the Keypad keys 0-9 and . send different keysyms
815 * depending on the NumLock state */
816 return nonchar_key_vkey[keysym & 0xFF];
818 return keyc2vkey[e->keycode];
821 static BOOL NumState=FALSE, CapsState=FALSE;
824 /***********************************************************************
825 * send_keyboard_input
827 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
831 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
832 input.u.ki.wVk = wVk;
833 input.u.ki.wScan = wScan;
834 input.u.ki.dwFlags = dwFlags;
835 input.u.ki.time = time;
836 input.u.ki.dwExtraInfo = 0;
837 SendInput( 1, &input, sizeof(input) );
841 /**********************************************************************
842 * KEYBOARD_GenerateMsg
844 * Generate Down+Up messages when NumLock or CapsLock is pressed.
846 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
849 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
851 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
855 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
856 don't treat it. It's from the same key press. Then the state goes to ON.
857 And from there, a 'release' event will switch off the toggle key. */
859 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
862 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
863 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
864 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
866 if (Evtype!=KeyPress)
868 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
869 send_keyboard_input( vkey, scan, down, event_time );
870 send_keyboard_input( vkey, scan, up, event_time );
872 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
875 else /* it was OFF */
876 if (Evtype==KeyPress)
878 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
879 send_keyboard_input( vkey, scan, down, event_time );
880 send_keyboard_input( vkey, scan, up, event_time );
881 *State=TRUE; /* Goes to intermediary state before going to ON */
882 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
887 /***********************************************************************
888 * KEYBOARD_UpdateOneState
890 * Updates internal state for <vkey>, depending on key <state> under X
893 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
895 /* Do something if internal table state != X state for keycode */
896 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
898 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
899 vkey, pKeyStateTable[vkey]);
901 /* Fake key being pressed inside wine */
902 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
904 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
908 /***********************************************************************
909 * X11DRV_KeymapNotify
911 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
913 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
914 * from wine to another application and back.
915 * Toggle keys are handled in HandleEvent.
917 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
919 int i, j, alt, control, shift;
920 DWORD time = GetCurrentTime();
922 alt = control = shift = 0;
923 for (i = 0; i < 32; i++)
925 if (!event->key_vector[i]) continue;
926 for (j = 0; j < 8; j++)
928 if (!(event->key_vector[i] & (1<<j))) continue;
929 switch(keyc2vkey[(i * 8) + j] & 0xff)
931 case VK_MENU: alt = 1; break;
932 case VK_CONTROL: control = 1; break;
933 case VK_SHIFT: shift = 1; break;
937 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
938 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
939 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
942 /***********************************************************************
945 * Handle a X key event
947 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
951 WORD vkey = 0, bScan;
955 DWORD event_time = event->time - X11DRV_server_startticks;
957 /* this allows support for dead keys */
958 if ((event->keycode >> 8) == 0x10)
959 event->keycode=(event->keycode & 0xff);
962 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
965 /* Ignore some unwanted events */
966 if (keysym == XK_ISO_Prev_Group ||
967 keysym == XK_ISO_Next_Group ||
968 keysym == XK_Mode_switch)
970 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
974 TRACE_(key)("state = %X\n", event->state);
976 /* If XKB extensions are used, the state mask for AltGr will use the group
977 index instead of the modifier mask. The group index is set in bits
978 13-14 of the state field in the XKeyEvent structure. So if AltGr is
979 pressed, look if the group index is different than 0. From XKB
980 extension documentation, the group index for AltGr should be 2
981 (event->state = 0x2000). It's probably better to not assume a
982 predefined group index and find it dynamically
984 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
985 AltGrMask = event->state & 0x6000;
987 Str[ascii_chars] = '\0';
991 ksname = TSXKeysymToString(keysym);
994 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
995 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
996 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1000 vkey = EVENT_event_to_vkey(event);
1001 wine_tsx11_unlock();
1003 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1004 event->keycode, vkey);
1008 switch (vkey & 0xff)
1011 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1014 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1015 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1016 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1019 /* Adjust the NUMLOCK state if it has been changed outside wine */
1020 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1022 TRACE("Adjusting NumLock state.\n");
1023 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1024 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1026 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1027 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1029 TRACE("Adjusting Caps Lock state.\n");
1030 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1031 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1033 /* Not Num nor Caps : end of intermediary states for both. */
1037 bScan = keyc2scan[event->keycode] & 0xFF;
1038 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1041 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1042 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1044 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1049 /**********************************************************************
1050 * X11DRV_KEYBOARD_DetectLayout
1052 * Called from X11DRV_InitKeyboard
1053 * This routine walks through the defined keyboard layouts and selects
1054 * whichever matches most closely.
1055 * X11 lock must be held.
1058 X11DRV_KEYBOARD_DetectLayout (void)
1060 Display *display = thread_display();
1061 unsigned current, match, mismatch, seq;
1062 int score, keyc, i, key, pkey, ok, syms;
1064 const char (*lkey)[MAIN_LEN][4];
1065 unsigned max_seq = 0;
1066 int max_score = 0, ismatch = 0;
1070 syms = keysyms_per_keycode;
1072 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1075 for (current = 0; main_key_tab[current].comment; current++) {
1076 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1081 lkey = main_key_tab[current].key;
1083 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1084 /* get data for keycode from X server */
1085 for (i = 0; i < syms; i++) {
1086 keysym = XKeycodeToKeysym (display, keyc, i);
1087 /* Allow both one-byte and two-byte national keysyms */
1088 if ((keysym < 0x8000) && (keysym != ' '))
1089 ckey[i] = keysym & 0xFF;
1091 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1095 /* search for a match in layout table */
1096 /* right now, we just find an absolute match for defined positions */
1097 /* (undefined positions are ignored, so if it's defined as "3#" in */
1098 /* the table, it's okay that the X server has "3#£", for example) */
1099 /* however, the score will be higher for longer matches */
1100 for (key = 0; key < MAIN_LEN; key++) {
1101 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1102 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1104 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1112 /* count the matches and mismatches */
1115 /* and how much the keycode order matches */
1116 if (key > pkey) seq++;
1119 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1125 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1126 match, mismatch, seq, score);
1127 if ((score > max_score) ||
1128 ((score == max_score) && (seq > max_seq))) {
1129 /* best match so far */
1130 kbd_layout = current;
1133 ismatch = !mismatch;
1136 /* we're done, report results if necessary */
1139 "Your keyboard layout was not found!\n"
1140 "Using closest match instead (%s) for scancode mapping.\n"
1141 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1142 "to us for inclusion into future Wine releases.\n"
1143 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1144 main_key_tab[kbd_layout].comment);
1147 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1150 /**********************************************************************
1151 * InitKeyboard (X11DRV.@)
1153 void X11DRV_InitKeyboard( BYTE *key_state_table )
1156 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1158 Display *display = thread_display();
1160 XModifierKeymap *mmp;
1164 WORD scan, vkey, OEMvkey;
1165 int keyc, i, keyn, syms;
1166 char ckey[4]={0,0,0,0};
1167 const char (*lkey)[MAIN_LEN][4];
1169 pKeyStateTable = key_state_table;
1173 is_xkb = XkbQueryExtension(display,
1174 &xkb_opcode, &xkb_event, &xkb_error,
1175 &xkb_major, &xkb_minor);
1177 /* we have XKB, approximate Windows behaviour */
1178 XkbSetDetectableAutoRepeat(display, True, NULL);
1181 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1182 ksp = XGetKeyboardMapping(display, min_keycode,
1183 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1184 /* We are only interested in keysyms_per_keycode.
1185 There is no need to hold a local copy of the keysyms table */
1188 mmp = XGetModifierMapping(display);
1189 kcp = mmp->modifiermap;
1190 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1194 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1199 for (k = 0; k < keysyms_per_keycode; k += 1)
1200 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1202 NumLockMask = 1 << i;
1203 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1207 XFreeModifiermap(mmp);
1209 /* Detect the keyboard layout */
1210 X11DRV_KEYBOARD_DetectLayout();
1211 lkey = main_key_tab[kbd_layout].key;
1212 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1214 /* Now build two conversion arrays :
1215 * keycode -> vkey + scancode + extended
1216 * vkey + extended -> keycode */
1218 e2.display = display;
1221 OEMvkey = VK_OEM_7; /* next is available. */
1222 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1224 e2.keycode = (KeyCode)keyc;
1225 XLookupString(&e2, NULL, 0, &keysym, NULL);
1227 if (keysym) /* otherwise, keycode not used */
1229 if ((keysym >> 8) == 0xFF) /* non-character key */
1231 vkey = nonchar_key_vkey[keysym & 0xff];
1232 scan = nonchar_key_scan[keysym & 0xff];
1233 /* set extended bit when necessary */
1234 if (scan & 0x100) vkey |= 0x100;
1235 } else if (keysym == 0x20) { /* Spacebar */
1239 /* we seem to need to search the layout-dependent scancodes */
1240 int maxlen=0,maxval=-1,ok;
1241 for (i=0; i<syms; i++) {
1242 keysym = XKeycodeToKeysym(display, keyc, i);
1243 if ((keysym<0x800) && (keysym!=' ')) {
1244 ckey[i] = keysym & 0xFF;
1246 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1249 /* find key with longest match streak */
1250 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1251 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1252 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1253 if (ok||(i>maxlen)) {
1254 maxlen=i; maxval=keyn;
1260 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1261 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1262 scan = (*lscan)[maxval];
1263 vkey = (*lvkey)[maxval];
1267 /* find a suitable layout-dependent VK code */
1268 /* (most Winelib apps ought to be able to work without layout tables!) */
1269 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1271 keysym = XLookupKeysym(&e2, i);
1272 if ((keysym >= VK_0 && keysym <= VK_9)
1273 || (keysym >= VK_A && keysym <= VK_Z)) {
1278 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1280 keysym = XLookupKeysym(&e2, i);
1283 case ';': vkey = VK_OEM_1; break;
1284 case '/': vkey = VK_OEM_2; break;
1285 case '`': vkey = VK_OEM_3; break;
1286 case '[': vkey = VK_OEM_4; break;
1287 case '\\': vkey = VK_OEM_5; break;
1288 case ']': vkey = VK_OEM_6; break;
1289 case '\'': vkey = VK_OEM_7; break;
1290 case ',': vkey = VK_OEM_COMMA; break;
1291 case '.': vkey = VK_OEM_PERIOD; break;
1292 case '-': vkey = VK_OEM_MINUS; break;
1293 case '+': vkey = VK_OEM_PLUS; break;
1299 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1300 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1303 case 0xc1 : OEMvkey=0xdb; break;
1304 case 0xe5 : OEMvkey=0xe9; break;
1305 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1310 if (TRACE_ON(keyboard))
1312 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1313 OEMvkey, e2.keycode);
1315 for (i = 0; i < keysyms_per_keycode; i += 1)
1319 keysym = XLookupKeysym(&e2, i);
1320 ksname = XKeysymToString(keysym);
1322 ksname = "NoSymbol";
1323 DPRINTF( "%lX (%s) ", keysym, ksname);
1329 keyc2vkey[e2.keycode] = vkey;
1330 keyc2scan[e2.keycode] = scan;
1333 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1334 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1335 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1337 keysym = XKeycodeToKeysym(display, keyc, 0);
1338 ksname = XKeysymToString(keysym);
1339 if (!ksname) ksname = "NoSymbol";
1341 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1343 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1344 keyc2scan[keyc]=scan++;
1347 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1348 kcControl = XKeysymToKeycode(display, XK_Control_L);
1349 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1350 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1351 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1352 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1353 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1354 wine_tsx11_unlock();
1358 /***********************************************************************
1359 * X11DRV_MappingNotify
1361 void X11DRV_MappingNotify( XMappingEvent *event )
1363 TSXRefreshKeyboardMapping(event);
1364 X11DRV_InitKeyboard( pKeyStateTable );
1368 /***********************************************************************
1369 * VkKeyScan (X11DRV.@)
1371 WORD X11DRV_VkKeyScan(CHAR cChar)
1373 Display *display = thread_display();
1379 /* char->keysym (same for ANSI chars) */
1380 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1381 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1383 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1385 { /* It didn't work ... let's try with deadchar code. */
1386 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1389 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1390 cChar,keysym,keysym,keycode);
1394 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1395 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1398 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1400 case 1 : highbyte = 0x0100; break;
1401 case 2 : highbyte = 0x0600; break;
1402 case 3 : highbyte = 0x0700; break;
1403 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1406 index : 0 adds 0x0000
1407 index : 1 adds 0x0100 (shift)
1408 index : ? adds 0x0200 (ctrl)
1409 index : 2 adds 0x0600 (ctrl+alt)
1410 index : 3 adds 0x0700 (ctrl+alt+shift)
1413 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1414 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1417 /***********************************************************************
1418 * MapVirtualKey (X11DRV.@)
1420 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1422 Display *display = thread_display();
1424 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1426 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1428 case 0: { /* vkey-code to scan-code */
1429 /* let's do vkey -> keycode -> scan */
1431 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1432 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1433 returnMVK (keyc2scan[keyc] & 0xFF);
1434 TRACE("returning no scan-code.\n");
1437 case 1: { /* scan-code to vkey-code */
1438 /* let's do scan -> keycode -> vkey */
1440 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1441 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1442 returnMVK (keyc2vkey[keyc] & 0xFF);
1443 TRACE("returning no vkey-code.\n");
1446 case 2: { /* vkey-code to unshifted ANSI code */
1447 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1448 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1449 * key.. Looks like something is wrong with the MS docs?
1450 * This is only true for letters, for example VK_0 returns '0' not ')'.
1451 * - hence we use the lock mask to ensure this happens.
1453 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1458 e.display = display;
1461 /* LockMask should behave exactly like caps lock - upercase
1462 * the letter keys and thats about it. */
1467 /* We exit on the first keycode found, to speed up the thing. */
1468 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1469 { /* Find a keycode that could have generated this virtual key */
1470 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1471 { /* We filter the extended bit, we don't know it */
1472 e.keycode = keyc; /* Store it temporarily */
1473 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1474 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1475 state), so set it to 0, we'll find another one */
1480 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1481 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1483 if (wCode==VK_DECIMAL)
1484 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1488 WARN("Unknown virtual key %X !!! \n", wCode);
1489 wine_tsx11_unlock();
1490 return 0; /* whatever */
1492 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1494 if (XLookupString(&e, s, 2, &keysym, NULL))
1496 wine_tsx11_unlock();
1500 TRACE("returning no ANSI.\n");
1501 wine_tsx11_unlock();
1505 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1506 /* left and right */
1507 FIXME(" stub for NT\n");
1510 default: /* reserved */
1511 WARN("Unknown wMapType %d !\n", wMapType);
1517 /***********************************************************************
1518 * GetKeyNameText (X11DRV.@)
1520 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1522 int vkey, ansi, scanCode;
1528 scanCode = lParam >> 16;
1529 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1531 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1532 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1534 /* handle "don't care" bit (0x02000000) */
1535 if (!(lParam & 0x02000000)) {
1554 ansi = X11DRV_MapVirtualKey(vkey, 2);
1555 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1557 /* first get the name of the "regular" keys which is the Upper case
1558 value of the keycap imprint. */
1559 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1560 (scanCode != 0x137) && /* PrtScn */
1561 (scanCode != 0x135) && /* numpad / */
1562 (scanCode != 0x37 ) && /* numpad * */
1563 (scanCode != 0x4a ) && /* numpad - */
1564 (scanCode != 0x4e ) ) /* numpad + */
1566 if ((nSize >= 2) && lpBuffer)
1568 *lpBuffer = toupper((char)ansi);
1576 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1577 without "extended-key" flag. However Wine generates scancode
1578 *with* "extended-key" flag. Seems to occur *only* for the
1579 function keys. Soooo.. We will leave the table alone and
1580 fudge the lookup here till the other part is found and fixed!!! */
1582 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1583 (scanCode == 0x157) || (scanCode == 0x158))
1584 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1586 /* let's do scancode -> keycode -> keysym -> String */
1588 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1589 if ((keyc2scan[keyi]) == scanCode)
1591 if (keyi <= max_keycode)
1593 keyc = (KeyCode) keyi;
1594 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1595 name = TSXKeysymToString(keys);
1596 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1597 scanCode, keyc, (int)keys, name);
1598 if (lpBuffer && nSize && name)
1600 lstrcpynA(lpBuffer, name, nSize);
1605 /* Finally issue FIXME for unknown keys */
1607 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1608 if (lpBuffer && nSize)
1613 /***********************************************************************
1614 * X11DRV_KEYBOARD_MapDeadKeysym
1616 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1620 /* symbolic ASCII is the same as defined in rfc1345 */
1621 #ifdef XK_dead_tilde
1622 case XK_dead_tilde :
1624 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1625 return '~'; /* '? */
1626 #ifdef XK_dead_acute
1627 case XK_dead_acute :
1629 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1630 return 0xb4; /* '' */
1631 #ifdef XK_dead_circumflex
1632 case XK_dead_circumflex:
1634 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1635 return '^'; /* '> */
1636 #ifdef XK_dead_grave
1637 case XK_dead_grave :
1639 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1640 return '`'; /* '! */
1641 #ifdef XK_dead_diaeresis
1642 case XK_dead_diaeresis :
1644 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1645 return 0xa8; /* ': */
1646 #ifdef XK_dead_cedilla
1647 case XK_dead_cedilla :
1648 return 0xb8; /* ', */
1650 #ifdef XK_dead_macron
1651 case XK_dead_macron :
1652 return '-'; /* 'm isn't defined on iso-8859-x */
1654 #ifdef XK_dead_breve
1655 case XK_dead_breve :
1656 return 0xa2; /* '( */
1658 #ifdef XK_dead_abovedot
1659 case XK_dead_abovedot :
1660 return 0xff; /* '. */
1662 #ifdef XK_dead_abovering
1663 case XK_dead_abovering :
1664 return '0'; /* '0 isn't defined on iso-8859-x */
1666 #ifdef XK_dead_doubleacute
1667 case XK_dead_doubleacute :
1668 return 0xbd; /* '" */
1670 #ifdef XK_dead_caron
1671 case XK_dead_caron :
1672 return 0xb7; /* '< */
1674 #ifdef XK_dead_ogonek
1675 case XK_dead_ogonek :
1676 return 0xb2; /* '; */
1678 /* FIXME: I don't know this three.
1681 case XK_dead_voiced_sound :
1683 case XK_dead_semivoiced_sound :
1687 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1691 /***********************************************************************
1692 * ToUnicode (X11DRV.@)
1694 * The ToUnicode function translates the specified virtual-key code and keyboard
1695 * state to the corresponding Windows character or characters.
1697 * If the specified key is a dead key, the return value is negative. Otherwise,
1698 * it is one of the following values:
1700 * 0 The specified virtual key has no translation for the current state of the keyboard.
1701 * 1 One Windows character was copied to the buffer.
1702 * 2 Two characters were copied to the buffer. This usually happens when a
1703 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1704 * be composed with the specified virtual key to form a single character.
1706 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1709 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1710 LPWSTR bufW, int bufW_size, UINT flags)
1712 Display *display = thread_display();
1719 if (scanCode & 0x8000)
1721 TRACE("Key UP, doing nothing\n" );
1724 e.display = display;
1727 if (lpKeyState[VK_SHIFT] & 0x80)
1729 TRACE("ShiftMask = %04x\n", ShiftMask);
1730 e.state |= ShiftMask;
1732 if (lpKeyState[VK_CAPITAL] & 0x01)
1734 TRACE("LockMask = %04x\n", LockMask);
1735 e.state |= LockMask;
1737 if (lpKeyState[VK_CONTROL] & 0x80)
1739 TRACE("ControlMask = %04x\n", ControlMask);
1740 e.state |= ControlMask;
1742 if (lpKeyState[VK_NUMLOCK] & 0x01)
1744 TRACE("NumLockMask = %04x\n", NumLockMask);
1745 e.state |= NumLockMask;
1748 /* Restore saved AltGr state */
1749 TRACE("AltGrMask = %04x\n", AltGrMask);
1750 e.state |= AltGrMask;
1752 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1753 virtKey, scanCode, e.state);
1755 /* We exit on the first keycode found, to speed up the thing. */
1756 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1757 { /* Find a keycode that could have generated this virtual key */
1758 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1759 { /* We filter the extended bit, we don't know it */
1760 e.keycode = keyc; /* Store it temporarily */
1761 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1762 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1763 state), so set it to 0, we'll find another one */
1768 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1769 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1771 if (virtKey==VK_DECIMAL)
1772 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1776 WARN("Unknown virtual key %X !!! \n",virtKey);
1777 wine_tsx11_unlock();
1778 return virtKey; /* whatever */
1780 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1782 ret = XLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1783 wine_tsx11_unlock();
1789 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1792 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1799 ksname = TSXKeysymToString(keysym);
1802 if ((keysym >> 8) != 0xff)
1804 ERR("Please report: no char for keysym %04lX (%s) :\n",
1806 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1807 virtKey, scanCode, e.keycode, e.state);
1811 else { /* ret != 0 */
1812 /* We have a special case to handle : Shift + arrow, shift + home, ...
1813 X returns a char for it, but Windows doesn't. Let's eat it. */
1814 if (!(e.state & NumLockMask) /* NumLock is off */
1815 && (e.state & ShiftMask) /* Shift is pressed */
1816 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1822 /* more areas where X returns characters but Windows does not
1823 CTRL + number or CTRL + symbol */
1824 if (e.state & ControlMask)
1826 if (((keysym>=33) && (keysym < 'A')) ||
1827 ((keysym > 'Z') && (keysym < 'a')))
1834 /* We have another special case for delete key (XK_Delete) on an
1835 extended keyboard. X returns a char for it, but Windows doesn't */
1836 if (keysym == XK_Delete)
1841 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1842 && (keysym == XK_KP_Decimal))
1848 /* perform translation to unicode */
1851 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1852 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1853 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1857 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1858 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1862 /***********************************************************************
1865 void X11DRV_Beep(void)
1867 TSXBell(thread_display(), 0);