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 "ts_xresource.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 /*** Russian keyboard layout (contributed by Pavel Roskin) */
358 static const char main_key_RU[MAIN_LEN][4] =
360 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
361 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
362 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
363 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
366 /*** Russian keyboard layout (phantom key version) */
367 static const char main_key_RU_phantom[MAIN_LEN][4] =
369 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
370 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
371 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
372 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
373 "<>" /* the phantom key */
376 /*** Russian keyboard layout KOI8-R */
377 static const char main_key_RU_koi8r[MAIN_LEN][4] =
379 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
380 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
381 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
382 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
383 "<>" /* the phantom key */
386 /*** Ukrainian keyboard layout KOI8-U */
387 static const char main_key_UA[MAIN_LEN][4] =
389 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
390 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
391 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
392 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
393 "<>" /* the phantom key */
396 /*** Spanish keyboard layout (contributed by José Marcos López) */
397 static const char main_key_ES[MAIN_LEN][4] =
399 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
400 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
401 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
402 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
406 /*** Belgian keyboard layout ***/
407 static const char main_key_BE[MAIN_LEN][4] =
409 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
410 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
411 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
412 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
416 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
417 static const char main_key_HU[MAIN_LEN][4] =
419 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
420 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
421 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
422 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
426 /*** Polish (programmer's) keyboard layout ***/
427 static const char main_key_PL[MAIN_LEN][4] =
429 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
430 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
431 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
432 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
436 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
437 static const char main_key_SI[MAIN_LEN][4] =
439 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
440 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
441 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
442 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
446 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
447 static const char main_key_HR_jelly[MAIN_LEN][4] =
449 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
450 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
451 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
452 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
456 /*** Croatian keyboard layout ***/
457 static const char main_key_HR[MAIN_LEN][4] =
459 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
460 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
461 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
462 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
466 /*** Japanese 106 keyboard layout ***/
467 static const char main_key_JA_jp106[MAIN_LEN][4] =
469 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
470 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
471 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
472 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
476 /*** Japanese pc98x1 keyboard layout ***/
477 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
479 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
480 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
481 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
482 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
486 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
487 static const char main_key_PT_br[MAIN_LEN][4] =
489 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
490 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
491 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
492 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?"
495 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
496 static const char main_key_US_intl[MAIN_LEN][4] =
498 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
499 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
500 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
501 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
504 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
505 - dead_abovering replaced with degree - no symbol in iso8859-2
506 - brokenbar replaced with bar */
507 static const char main_key_SK[MAIN_LEN][4] =
509 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
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",",?",".:","-_",
516 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
517 static const char main_key_SK_prog[MAIN_LEN][4] =
519 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
520 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
521 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
522 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
526 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
527 static const char main_key_CS[MAIN_LEN][4] =
529 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
530 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
531 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
532 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
536 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
537 static const char main_key_LA[MAIN_LEN][4] =
539 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
540 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
541 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
542 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
546 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
547 static const char main_key_LT_B[MAIN_LEN][4] =
549 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
550 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
551 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
552 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
555 /*** Turkish keyboard Layout */
556 static const char main_key_TK[MAIN_LEN][4] =
558 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
559 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
560 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
561 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
564 /*** Israeli keyboard layout */
565 static const char main_key_IL[MAIN_LEN][4] =
567 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
568 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
569 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
570 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
573 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
574 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
575 message since they have different characters in gr and el XFree86 layouts. */
576 static const char main_key_EL[MAIN_LEN][4] =
578 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
579 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
580 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
581 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
585 /*** VNC keyboard layout */
586 static const WORD main_key_scan_vnc[MAIN_LEN] =
588 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
589 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,
593 static const WORD main_key_vkey_vnc[MAIN_LEN] =
595 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,
596 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,
600 static const char main_key_vnc[MAIN_LEN][4] =
602 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
603 "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"
606 /*** Layout table. Add your keyboard mappings to this list */
607 static const struct {
609 const UINT layout_cp; /* Code page for this layout */
610 const char (*key)[MAIN_LEN][4];
611 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
612 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
614 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
615 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
616 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
617 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
618 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
619 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
620 {"German keyboard layout for logitech desktop pro", 28591, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
621 {"German keyboard layout without dead keys 105", 28591, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
622 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
623 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
624 {"Estonian keyboard layout", 28591, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
625 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
626 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
627 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
628 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
629 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
630 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
631 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
632 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
633 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
634 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
635 {"Bulgarian bds keyboard layout", 1251, &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
636 {"Bulgarian phonetic keyboard layout", 1251, &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
637 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
638 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
639 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
640 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
641 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
642 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
643 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
644 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
645 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
646 {"Slovenian keyboard layout", 28592, &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
647 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
648 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
649 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
650 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
651 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
652 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
653 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
654 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
655 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
656 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
657 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
658 {"VNC keyboard layout", 28591, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
659 {"Greek keyboard layout", 28597, &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
661 {NULL, 0, NULL, NULL, NULL} /* sentinel */
663 static unsigned kbd_layout=0; /* index into above table of layouts */
665 /* maybe more of these scancodes should be extended? */
666 /* extended must be set for ALT_R, CTRL_R,
667 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
668 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
669 /* FIXME should we set extended bit for NumLock ? My
670 * Windows does ... DF */
671 /* Yes, to distinguish based on scan codes, also
672 for PrtScn key ... GA */
674 static const WORD nonchar_key_vkey[256] =
677 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
679 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
680 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
681 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
683 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
684 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
685 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
686 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
687 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
688 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
690 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
691 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
692 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
694 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
695 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
696 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
698 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
699 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
700 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
701 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
702 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
703 VK_END, 0, VK_INSERT, VK_DELETE,
704 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
705 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
706 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
707 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
708 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
709 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
712 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
713 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
714 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
715 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
717 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
718 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
719 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
720 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
721 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
724 static const WORD nonchar_key_scan[256] =
727 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
729 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
730 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
731 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
734 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
735 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
736 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
737 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
738 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
740 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
743 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
744 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
751 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
753 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
754 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
755 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
758 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
759 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
763 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
764 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
770 /* Returns the Windows virtual key code associated with the X event <e> */
771 static WORD EVENT_event_to_vkey( XKeyEvent *e)
775 TSXLookupString(e, NULL, 0, &keysym, NULL);
777 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
778 && (e->state & NumLockMask))
779 /* Only the Keypad keys 0-9 and . send different keysyms
780 * depending on the NumLock state */
781 return nonchar_key_vkey[keysym & 0xFF];
783 return keyc2vkey[e->keycode];
786 static BOOL NumState=FALSE, CapsState=FALSE;
789 /***********************************************************************
790 * send_keyboard_input
792 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
796 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
797 input.u.ki.wVk = wVk;
798 input.u.ki.wScan = wScan;
799 input.u.ki.dwFlags = dwFlags;
800 input.u.ki.time = time;
801 input.u.ki.dwExtraInfo = 0;
802 SendInput( 1, &input, sizeof(input) );
806 /**********************************************************************
807 * KEYBOARD_GenerateMsg
809 * Generate Down+Up messages when NumLock or CapsLock is pressed.
811 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
814 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
816 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
820 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
821 don't treat it. It's from the same key press. Then the state goes to ON.
822 And from there, a 'release' event will switch off the toggle key. */
824 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
827 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
828 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
829 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
831 if (Evtype!=KeyPress)
833 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
834 send_keyboard_input( vkey, scan, down, event_time );
835 send_keyboard_input( vkey, scan, up, event_time );
837 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
840 else /* it was OFF */
841 if (Evtype==KeyPress)
843 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
844 send_keyboard_input( vkey, scan, down, event_time );
845 send_keyboard_input( vkey, scan, up, event_time );
846 *State=TRUE; /* Goes to intermediary state before going to ON */
847 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
852 /***********************************************************************
853 * KEYBOARD_UpdateOneState
855 * Updates internal state for <vkey>, depending on key <state> under X
858 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
860 /* Do something if internal table state != X state for keycode */
861 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
863 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
864 vkey, pKeyStateTable[vkey]);
866 /* Fake key being pressed inside wine */
867 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
869 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
873 /***********************************************************************
874 * X11DRV_KeymapNotify
876 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
878 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
879 * from wine to another application and back.
880 * Toggle keys are handled in HandleEvent.
882 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
884 int i, j, alt, control, shift;
885 DWORD time = GetCurrentTime();
887 alt = control = shift = 0;
888 for (i = 0; i < 32; i++)
890 if (!event->key_vector[i]) continue;
891 for (j = 0; j < 8; j++)
893 if (!(event->key_vector[i] & (1<<j))) continue;
894 switch(keyc2vkey[(i * 8) + j] & 0xff)
896 case VK_MENU: alt = 1; break;
897 case VK_CONTROL: control = 1; break;
898 case VK_SHIFT: shift = 1; break;
902 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
903 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
904 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
907 /***********************************************************************
910 * Handle a X key event
912 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
916 WORD vkey = 0, bScan;
920 DWORD event_time = event->time - X11DRV_server_startticks;
922 /* this allows support for dead keys */
923 if ((event->keycode >> 8) == 0x10)
924 event->keycode=(event->keycode & 0xff);
926 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
928 /* Ignore some unwanted events */
929 if (keysym == XK_ISO_Prev_Group ||
930 keysym == XK_ISO_Next_Group ||
931 keysym == XK_Mode_switch)
933 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
937 TRACE_(key)("state = %X\n", event->state);
939 /* If XKB extensions is used, the state mask for AltGr will used the group
940 index instead of the modifier mask. The group index is set in bits
941 13-14 of the state field in the XKeyEvent structure. So if AltGr is
942 pressed, look if the group index is diferent than 0. From XKB
943 extension documentation, the group index should for AltGr should
944 be 2 (event->state = 0x2000). It's probably better to not assume a
945 predefined group index and find it dynamically
947 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
948 AltGrMask = event->state & 0x6000;
950 Str[ascii_chars] = '\0';
954 ksname = TSXKeysymToString(keysym);
957 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
958 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
959 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
962 vkey = EVENT_event_to_vkey(event);
964 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
965 event->keycode, vkey);
972 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
975 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
976 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
977 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
980 /* Adjust the NUMLOCK state if it has been changed outside wine */
981 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
983 TRACE("Adjusting NumLock state. \n");
984 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
985 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
987 /* Adjust the CAPSLOCK state if it has been changed outside wine */
988 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
990 TRACE("Adjusting Caps Lock state.\n");
991 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
992 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
994 /* Not Num nor Caps : end of intermediary states for both. */
998 bScan = keyc2scan[event->keycode] & 0xFF;
999 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1002 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1003 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1005 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1010 /**********************************************************************
1011 * X11DRV_KEYBOARD_DetectLayout
1013 * Called from X11DRV_InitKeyboard
1014 * This routine walks through the defined keyboard layouts and selects
1015 * whichever matches most closely.
1018 X11DRV_KEYBOARD_DetectLayout (void)
1020 Display *display = thread_display();
1021 unsigned current, match, mismatch, seq;
1022 int score, keyc, i, key, pkey, ok, syms;
1024 const char (*lkey)[MAIN_LEN][4];
1025 unsigned max_seq = 0;
1026 int max_score = 0, ismatch = 0;
1030 syms = keysyms_per_keycode;
1032 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1035 for (current = 0; main_key_tab[current].comment; current++) {
1036 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1041 lkey = main_key_tab[current].key;
1043 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1044 /* get data for keycode from X server */
1045 for (i = 0; i < syms; i++) {
1046 keysym = TSXKeycodeToKeysym (display, keyc, i);
1047 /* Allow both one-byte and two-byte national keysyms */
1048 if ((keysym < 0x8000) && (keysym != ' '))
1049 ckey[i] = keysym & 0xFF;
1051 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1055 /* search for a match in layout table */
1056 /* right now, we just find an absolute match for defined positions */
1057 /* (undefined positions are ignored, so if it's defined as "3#" in */
1058 /* the table, it's okay that the X server has "3#£", for example) */
1059 /* however, the score will be higher for longer matches */
1060 for (key = 0; key < MAIN_LEN; key++) {
1061 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1062 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1064 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1072 /* count the matches and mismatches */
1075 /* and how much the keycode order matches */
1076 if (key > pkey) seq++;
1079 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
1086 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1087 match, mismatch, seq, score);
1088 if ((score > max_score) ||
1089 ((score == max_score) && (seq > max_seq))) {
1090 /* best match so far */
1091 kbd_layout = current;
1094 ismatch = !mismatch;
1097 /* we're done, report results if necessary */
1100 "Your keyboard layout was not found!\n"
1101 "Using closest match instead (%s) for scancode mapping.\n"
1102 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1103 "to us for inclusion into future Wine releases.\n"
1104 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1105 main_key_tab[kbd_layout].comment);
1108 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1111 /**********************************************************************
1112 * InitKeyboard (X11DRV.@)
1114 void X11DRV_InitKeyboard( BYTE *key_state_table )
1117 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1119 Display *display = thread_display();
1121 XModifierKeymap *mmp;
1125 WORD scan, vkey, OEMvkey;
1126 int keyc, i, keyn, syms;
1127 char ckey[4]={0,0,0,0};
1128 const char (*lkey)[MAIN_LEN][4];
1130 pKeyStateTable = key_state_table;
1134 is_xkb = XkbQueryExtension(display,
1135 &xkb_opcode, &xkb_event, &xkb_error,
1136 &xkb_major, &xkb_minor);
1138 /* we have XKB, approximate Windows behaviour */
1139 XkbSetDetectableAutoRepeat(display, True, NULL);
1141 wine_tsx11_unlock();
1143 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
1144 ksp = TSXGetKeyboardMapping(display, min_keycode,
1145 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1146 /* We are only interested in keysyms_per_keycode.
1147 There is no need to hold a local copy of the keysyms table */
1149 mmp = TSXGetModifierMapping(display);
1150 kcp = mmp->modifiermap;
1151 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1155 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1160 for (k = 0; k < keysyms_per_keycode; k += 1)
1161 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1163 NumLockMask = 1 << i;
1164 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1168 TSXFreeModifiermap(mmp);
1170 /* Detect the keyboard layout */
1171 X11DRV_KEYBOARD_DetectLayout();
1172 lkey = main_key_tab[kbd_layout].key;
1173 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1175 /* Now build two conversion arrays :
1176 * keycode -> vkey + scancode + extended
1177 * vkey + extended -> keycode */
1179 e2.display = display;
1182 OEMvkey = VK_OEM_7; /* next is available. */
1183 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1185 e2.keycode = (KeyCode)keyc;
1186 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1188 if (keysym) /* otherwise, keycode not used */
1190 if ((keysym >> 8) == 0xFF) /* non-character key */
1192 vkey = nonchar_key_vkey[keysym & 0xff];
1193 scan = nonchar_key_scan[keysym & 0xff];
1194 /* set extended bit when necessary */
1195 if (scan & 0x100) vkey |= 0x100;
1196 } else if (keysym == 0x20) { /* Spacebar */
1200 /* we seem to need to search the layout-dependent scancodes */
1201 int maxlen=0,maxval=-1,ok;
1202 for (i=0; i<syms; i++) {
1203 keysym = TSXKeycodeToKeysym(display, keyc, i);
1204 if ((keysym<0x800) && (keysym!=' ')) {
1205 ckey[i] = keysym & 0xFF;
1207 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1210 /* find key with longest match streak */
1211 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1212 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1213 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1214 if (ok||(i>maxlen)) {
1215 maxlen=i; maxval=keyn;
1221 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1222 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1223 scan = (*lscan)[maxval];
1224 vkey = (*lvkey)[maxval];
1228 /* find a suitable layout-dependent VK code */
1229 /* (most Winelib apps ought to be able to work without layout tables!) */
1230 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1232 keysym = TSXLookupKeysym(&e2, i);
1233 if ((keysym >= VK_0 && keysym <= VK_9)
1234 || (keysym >= VK_A && keysym <= VK_Z)) {
1239 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1241 keysym = TSXLookupKeysym(&e2, i);
1244 case ';': vkey = VK_OEM_1; break;
1245 case '/': vkey = VK_OEM_2; break;
1246 case '`': vkey = VK_OEM_3; break;
1247 case '[': vkey = VK_OEM_4; break;
1248 case '\\': vkey = VK_OEM_5; break;
1249 case ']': vkey = VK_OEM_6; break;
1250 case '\'': vkey = VK_OEM_7; break;
1251 case ',': vkey = VK_OEM_COMMA; break;
1252 case '.': vkey = VK_OEM_PERIOD; break;
1253 case '-': vkey = VK_OEM_MINUS; break;
1254 case '+': vkey = VK_OEM_PLUS; break;
1260 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1261 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1264 case 0xc1 : OEMvkey=0xdb; break;
1265 case 0xe5 : OEMvkey=0xe9; break;
1266 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1271 if (TRACE_ON(keyboard))
1273 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1274 OEMvkey, e2.keycode);
1276 for (i = 0; i < keysyms_per_keycode; i += 1)
1280 keysym = TSXLookupKeysym(&e2, i);
1281 ksname = TSXKeysymToString(keysym);
1283 ksname = "NoSymbol";
1284 DPRINTF( "%lX (%s) ", keysym, ksname);
1290 keyc2vkey[e2.keycode] = vkey;
1291 keyc2scan[e2.keycode] = scan;
1294 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1295 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1296 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1298 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1299 ksname = TSXKeysymToString(keysym);
1300 if (!ksname) ksname = "NoSymbol";
1302 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1304 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1305 keyc2scan[keyc]=scan++;
1308 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1309 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1310 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1311 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1312 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1313 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1314 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1318 /***********************************************************************
1319 * X11DRV_MappingNotify
1321 void X11DRV_MappingNotify( XMappingEvent *event )
1323 TSXRefreshKeyboardMapping(event);
1324 X11DRV_InitKeyboard( pKeyStateTable );
1328 /***********************************************************************
1329 * VkKeyScan (X11DRV.@)
1331 WORD X11DRV_VkKeyScan(CHAR cChar)
1333 Display *display = thread_display();
1339 /* char->keysym (same for ANSI chars) */
1340 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1341 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1343 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1345 { /* It didn't work ... let's try with deadchar code. */
1346 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1349 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1350 cChar,keysym,keysym,keycode);
1354 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1355 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1358 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1360 case 1 : highbyte = 0x0100; break;
1361 case 2 : highbyte = 0x0600; break;
1362 case 3 : highbyte = 0x0700; break;
1363 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1366 index : 0 adds 0x0000
1367 index : 1 adds 0x0100 (shift)
1368 index : ? adds 0x0200 (ctrl)
1369 index : 2 adds 0x0600 (ctrl+alt)
1370 index : 3 adds 0x0700 (ctrl+alt+shift)
1373 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1374 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1377 /***********************************************************************
1378 * MapVirtualKey (X11DRV.@)
1380 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1382 Display *display = thread_display();
1384 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1386 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1388 case 0: { /* vkey-code to scan-code */
1389 /* let's do vkey -> keycode -> scan */
1391 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1392 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1393 returnMVK (keyc2scan[keyc] & 0xFF);
1394 TRACE("returning no scan-code.\n");
1397 case 1: { /* scan-code to vkey-code */
1398 /* let's do scan -> keycode -> vkey */
1400 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1401 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1402 returnMVK (keyc2vkey[keyc] & 0xFF);
1403 TRACE("returning no vkey-code.\n");
1406 case 2: { /* vkey-code to unshifted ANSI code */
1407 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1408 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1409 * key.. Looks like something is wrong with the MS docs?
1410 * This is only true for letters, for example VK_0 returns '0' not ')'.
1411 * - hence we use the lock mask to ensure this happens.
1413 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1418 e.display = display;
1421 /* LockMask should behave exactly like caps lock - upercase
1422 * the letter keys and thats about it. */
1425 /* We exit on the first keycode found, to speed up the thing. */
1426 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1427 { /* Find a keycode that could have generated this virtual key */
1428 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1429 { /* We filter the extended bit, we don't know it */
1430 e.keycode = keyc; /* Store it temporarily */
1431 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1432 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1433 state), so set it to 0, we'll find another one */
1438 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1439 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1441 if (wCode==VK_DECIMAL)
1442 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1446 WARN("Unknown virtual key %X !!! \n", wCode);
1447 return 0; /* whatever */
1449 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1451 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1454 TRACE("returning no ANSI.\n");
1458 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1459 /* left and right */
1460 FIXME(" stub for NT\n");
1463 default: /* reserved */
1464 WARN("Unknown wMapType %d !\n", wMapType);
1470 /***********************************************************************
1471 * GetKeyNameText (X11DRV.@)
1473 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1475 int vkey, ansi, scanCode;
1481 scanCode = lParam >> 16;
1482 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1484 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1485 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1487 /* handle "don't care" bit (0x02000000) */
1488 if (!(lParam & 0x02000000)) {
1507 ansi = X11DRV_MapVirtualKey(vkey, 2);
1508 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1510 /* first get the name of the "regular" keys which is the Upper case
1511 value of the keycap imprint. */
1512 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1513 (scanCode != 0x137) && /* PrtScn */
1514 (scanCode != 0x135) && /* numpad / */
1515 (scanCode != 0x37 ) && /* numpad * */
1516 (scanCode != 0x4a ) && /* numpad - */
1517 (scanCode != 0x4e ) ) /* numpad + */
1519 if ((nSize >= 2) && lpBuffer)
1521 *lpBuffer = toupper((char)ansi);
1529 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1530 without "extended-key" flag. However Wine generates scancode
1531 *with* "extended-key" flag. Seems to occur *only* for the
1532 function keys. Soooo.. We will leave the table alone and
1533 fudge the lookup here till the other part is found and fixed!!! */
1535 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1536 (scanCode == 0x157) || (scanCode == 0x158))
1537 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1539 /* let's do scancode -> keycode -> keysym -> String */
1541 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1542 if ((keyc2scan[keyi]) == scanCode)
1544 if (keyi <= max_keycode)
1546 keyc = (KeyCode) keyi;
1547 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1548 name = TSXKeysymToString(keys);
1549 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1550 scanCode, keyc, (int)keys, name);
1551 if (lpBuffer && nSize && name)
1553 lstrcpynA(lpBuffer, name, nSize);
1558 /* Finally issue FIXME for unknown keys */
1560 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1561 if (lpBuffer && nSize)
1566 /***********************************************************************
1567 * X11DRV_KEYBOARD_MapDeadKeysym
1569 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1573 /* symbolic ASCII is the same as defined in rfc1345 */
1574 #ifdef XK_dead_tilde
1575 case XK_dead_tilde :
1577 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1578 return '~'; /* '? */
1579 #ifdef XK_dead_acute
1580 case XK_dead_acute :
1582 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1583 return 0xb4; /* '' */
1584 #ifdef XK_dead_circumflex
1585 case XK_dead_circumflex:
1587 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1588 return '^'; /* '> */
1589 #ifdef XK_dead_grave
1590 case XK_dead_grave :
1592 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1593 return '`'; /* '! */
1594 #ifdef XK_dead_diaeresis
1595 case XK_dead_diaeresis :
1597 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1598 return 0xa8; /* ': */
1599 #ifdef XK_dead_cedilla
1600 case XK_dead_cedilla :
1601 return 0xb8; /* ', */
1603 #ifdef XK_dead_macron
1604 case XK_dead_macron :
1605 return '-'; /* 'm isn't defined on iso-8859-x */
1607 #ifdef XK_dead_breve
1608 case XK_dead_breve :
1609 return 0xa2; /* '( */
1611 #ifdef XK_dead_abovedot
1612 case XK_dead_abovedot :
1613 return 0xff; /* '. */
1615 #ifdef XK_dead_abovering
1616 case XK_dead_abovering :
1617 return '0'; /* '0 isn't defined on iso-8859-x */
1619 #ifdef XK_dead_doubleacute
1620 case XK_dead_doubleacute :
1621 return 0xbd; /* '" */
1623 #ifdef XK_dead_caron
1624 case XK_dead_caron :
1625 return 0xb7; /* '< */
1627 #ifdef XK_dead_ogonek
1628 case XK_dead_ogonek :
1629 return 0xb2; /* '; */
1631 /* FIXME: I don't know this three.
1634 case XK_dead_voiced_sound :
1636 case XK_dead_semivoiced_sound :
1640 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1644 /***********************************************************************
1645 * ToUnicode (X11DRV.@)
1647 * The ToUnicode function translates the specified virtual-key code and keyboard
1648 * state to the corresponding Windows character or characters.
1650 * If the specified key is a dead key, the return value is negative. Otherwise,
1651 * it is one of the following values:
1653 * 0 The specified virtual key has no translation for the current state of the keyboard.
1654 * 1 One Windows character was copied to the buffer.
1655 * 2 Two characters were copied to the buffer. This usually happens when a
1656 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1657 * be composed with the specified virtual key to form a single character.
1659 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1662 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1663 LPWSTR bufW, int bufW_size, UINT flags)
1665 Display *display = thread_display();
1672 if (scanCode & 0x8000)
1674 TRACE("Key UP, doing nothing\n" );
1677 e.display = display;
1680 if (lpKeyState[VK_SHIFT] & 0x80)
1682 TRACE("ShiftMask = %04x\n", ShiftMask);
1683 e.state |= ShiftMask;
1685 if (lpKeyState[VK_CAPITAL] & 0x01)
1687 TRACE("LockMask = %04x\n", LockMask);
1688 e.state |= LockMask;
1690 if (lpKeyState[VK_CONTROL] & 0x80)
1692 TRACE("ControlMask = %04x\n", ControlMask);
1693 e.state |= ControlMask;
1695 if (lpKeyState[VK_NUMLOCK] & 0x01)
1697 TRACE("NumLockMask = %04x\n", NumLockMask);
1698 e.state |= NumLockMask;
1701 /* Restore saved AltGr state */
1702 TRACE("AltGrMask = %04x\n", AltGrMask);
1703 e.state |= AltGrMask;
1705 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1706 virtKey, scanCode, e.state);
1707 /* We exit on the first keycode found, to speed up the thing. */
1708 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1709 { /* Find a keycode that could have generated this virtual key */
1710 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1711 { /* We filter the extended bit, we don't know it */
1712 e.keycode = keyc; /* Store it temporarily */
1713 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1714 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1715 state), so set it to 0, we'll find another one */
1720 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1721 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1723 if (virtKey==VK_DECIMAL)
1724 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1728 WARN("Unknown virtual key %X !!! \n",virtKey);
1729 return virtKey; /* whatever */
1731 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1733 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1738 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1741 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1748 ksname = TSXKeysymToString(keysym);
1751 if ((keysym >> 8) != 0xff)
1753 ERR("Please report: no char for keysym %04lX (%s) :\n",
1755 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1756 virtKey, scanCode, e.keycode, e.state);
1760 else { /* ret != 0 */
1761 /* We have a special case to handle : Shift + arrow, shift + home, ...
1762 X returns a char for it, but Windows doesn't. Let's eat it. */
1763 if (!(e.state & NumLockMask) /* NumLock is off */
1764 && (e.state & ShiftMask) /* Shift is pressed */
1765 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1771 /* more areas where X returns characters but Windows does not
1772 CTRL + number or CTRL + symbol*/
1773 if (e.state & ControlMask)
1775 if (((keysym>=33) && (keysym < 'A')) ||
1776 ((keysym > 'Z') && (keysym < 'a')))
1783 /* We have another special case for delete key (XK_Delete) on an
1784 extended keyboard. X returns a char for it, but Windows doesn't */
1785 if (keysym == XK_Delete)
1790 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1791 && (keysym == XK_KP_Decimal))
1797 /* perform translation to unicode */
1800 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1801 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1802 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1806 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1807 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1811 /***********************************************************************
1814 void X11DRV_Beep(void)
1816 TSXBell(thread_display(), 0);