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
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
18 #include "ts_xresource.h"
21 #include <X11/XKBlib.h>
29 #include "wine/winuser16.h"
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(keyboard);
36 DECLARE_DEBUG_CHANNEL(key);
37 DECLARE_DEBUG_CHANNEL(dinput);
39 int min_keycode, max_keycode, keysyms_per_keycode;
40 WORD keyc2vkey[256], keyc2scan[256];
42 static LPBYTE pKeyStateTable;
43 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
44 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
46 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
49 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
51 /* Keyboard translation tables */
53 static const WORD main_key_scan_qwerty[MAIN_LEN] =
55 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
56 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
57 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
58 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
59 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
60 0x56 /* the 102nd key (actually to the right of l-shift) */
63 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
65 /* NOTE: this layout must concur with the scan codes layout above */
66 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,
67 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,
68 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,
69 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
70 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
73 static const WORD main_key_vkey_azerty[MAIN_LEN] =
75 /* NOTE: this layout must concur with the scan codes layout above */
76 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,
77 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,
78 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,
79 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
80 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
83 /* FIXME: add other layouts, such as DVORAK and German QWERTZ */
85 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
87 /* the VK mappings for the main keyboard will be auto-assigned as before,
88 so what we have here is just the character tables */
89 /* order: Normal, Shift, AltGr, Shift-AltGr */
90 /* We recommend you write just what is guaranteed to be correct (i.e. what's
91 written on the keycaps), not the bunch of special characters behind AltGr
92 and Shift-AltGr if it can vary among different X servers */
93 /* Remember that your 102nd key (to the right of l-shift) should be on a
94 separate line, see existing tables */
95 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
96 /* Remember to also add your new table to the layout index table far below! */
98 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
99 static const char main_key_US[MAIN_LEN][4] =
101 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
102 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
103 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
104 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
107 /*** United States keyboard layout (phantom key version) */
108 /* (XFree86 reports the <> key even if it's not physically there) */
109 static const char main_key_US_phantom[MAIN_LEN][4] =
111 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
112 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
113 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
114 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
115 "<>" /* the phantom key */
118 /*** British keyboard layout */
119 static const char main_key_UK[MAIN_LEN][4] =
121 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
122 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
123 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
124 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
128 /*** French keyboard layout (contributed by Eric Pouech) */
129 static const char main_key_FR[MAIN_LEN][4] =
131 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
132 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
133 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
134 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
138 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
139 static const char main_key_IS[MAIN_LEN][4] =
141 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
142 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
143 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
144 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
148 /*** German keyboard layout (contributed by Ulrich Weigand) */
149 static const char main_key_DE[MAIN_LEN][4] =
151 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
152 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
153 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
154 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
158 /*** German keyboard layout without dead keys */
159 static const char main_key_DE_nodead[MAIN_LEN][4] =
161 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
162 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
163 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
164 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
168 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
169 static const char main_key_SG[MAIN_LEN][4] =
171 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
172 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
173 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
174 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
178 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
179 static const char main_key_SF[MAIN_LEN][4] =
181 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
182 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
183 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
184 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
188 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
189 static const char main_key_NO[MAIN_LEN][4] =
191 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
192 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
193 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
194 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
198 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
199 static const char main_key_DA[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 /*** Swedish keyboard layout (contributed by Peter Bortas) */
209 static const char main_key_SE[MAIN_LEN][4] =
211 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
212 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
213 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
214 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
218 /*** Canadian French keyboard layout */
219 static const char main_key_CF[MAIN_LEN][4] =
221 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
222 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
223 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
224 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
228 /*** Portuguese keyboard layout */
229 static const char main_key_PT[MAIN_LEN][4] =
231 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
232 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
233 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
234 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
238 /*** Italian keyboard layout */
239 static const char main_key_IT[MAIN_LEN][4] =
241 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
242 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
243 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
244 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
248 /*** Finnish keyboard layout */
249 static const char main_key_FI[MAIN_LEN][4] =
251 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
252 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
253 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
254 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
258 /*** Russian keyboard layout (contributed by Pavel Roskin) */
259 static const char main_key_RU[MAIN_LEN][4] =
261 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
262 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
263 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
264 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
267 /*** Russian keyboard layout (phantom key version) */
268 static const char main_key_RU_phantom[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Øø",",<Ââ",".>Àà","/?",
274 "<>" /* the phantom key */
277 /*** Russian keyboard layout KOI8-R */
278 static const char main_key_RU_koi8r[MAIN_LEN][4] =
280 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
281 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
282 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
283 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
284 "<>" /* the phantom key */
287 /*** Ukrainian keyboard layout KOI8-U */
288 static const char main_key_UA[MAIN_LEN][4] =
290 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)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Øø",",<Ââ",".>Àà","/?/?",
294 "<>" /* the phantom key */
297 /*** Spanish keyboard layout (contributed by José Marcos López) */
298 static const char main_key_ES[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 /*** Belgian keyboard layout ***/
308 static const char main_key_BE[MAIN_LEN][4] =
310 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
311 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
312 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
313 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
317 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
318 static const char main_key_HU[MAIN_LEN][4] =
320 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
321 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
322 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
323 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
327 /*** Polish (programmer's) keyboard layout ***/
328 static const char main_key_PL[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 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
338 static const char main_key_HR_jelly[MAIN_LEN][4] =
340 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
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",",<",".>","/?",
347 /*** Croatian keyboard layout ***/
348 static const char main_key_HR[MAIN_LEN][4] =
350 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
351 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
352 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
353 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
357 /*** Japanese 106 keyboard layout ***/
358 static const char main_key_JA_jp106[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",",<",".>","/?",
367 /*** Japanese pc98x1 keyboard layout ***/
368 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
370 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
371 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
372 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
373 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
377 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
378 static const char main_key_PT_br[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",",<",".>","/?"
386 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
387 static const char main_key_US_intl[MAIN_LEN][4] =
389 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "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", ",<", ".>", "/?"
395 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
396 - dead_abovering replaced with degree - no symbol in iso8859-2
397 - brokenbar replaced with bar */
398 static const char main_key_SK[MAIN_LEN][4] =
400 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é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",",?<",".:>","-_*",
407 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
408 static const char main_key_SK_prog[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 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
418 static const char main_key_CS[MAIN_LEN][4] =
420 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
421 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
422 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
423 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
427 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
428 static const char main_key_LA[MAIN_LEN][4] =
430 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
431 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
432 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
433 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
437 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
438 static const char main_key_LT_B[MAIN_LEN][4] =
440 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
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",",<",".>","/?"
446 /*** Turkish keyboard Layout */
447 static const char main_key_TK[MAIN_LEN][4] =
449 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
450 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
451 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
452 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
455 /*** Layout table. Add your keyboard mappings to this list */
456 static const struct {
458 const UINT layout_cp; /* Code page for this layout */
459 const char (*key)[MAIN_LEN][4];
460 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
461 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
463 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
464 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
465 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
466 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
467 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
468 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
469 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
470 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
471 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
472 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
473 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
474 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
475 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
476 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
477 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
478 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
479 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
480 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
481 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
482 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
483 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
484 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
485 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
486 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
487 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
488 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
489 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
490 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
491 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
492 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
493 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
494 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
495 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
496 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
497 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
498 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
500 {NULL, 0, NULL, NULL, NULL} /* sentinel */
502 static unsigned kbd_layout=0; /* index into above table of layouts */
504 /* maybe more of these scancodes should be extended? */
505 /* extended must be set for ALT_R, CTRL_R,
506 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
507 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
508 /* FIXME should we set extended bit for NumLock ? My
509 * Windows does ... DF */
510 /* Yes, to distinguish based on scan codes, also
511 for PrtScn key ... GA */
513 static const WORD nonchar_key_vkey[256] =
516 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
518 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
519 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
520 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
522 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
523 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
524 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
525 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
526 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
527 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
529 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
530 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
531 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
533 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
534 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
535 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
537 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
538 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
539 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
540 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
541 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
542 VK_END, 0, VK_INSERT, VK_DELETE,
543 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
544 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
545 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
546 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
547 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
548 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
551 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
552 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
553 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
554 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
556 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
557 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
558 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
559 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
560 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
563 static const WORD nonchar_key_scan[256] =
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
568 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
569 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
570 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
579 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
582 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
583 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
590 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
592 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
593 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
594 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
597 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
598 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
602 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
603 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
609 /* Returns the Windows virtual key code associated with the X event <e> */
610 static WORD EVENT_event_to_vkey( XKeyEvent *e)
614 TSXLookupString(e, NULL, 0, &keysym, NULL);
616 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
617 && (e->state & NumLockMask))
618 /* Only the Keypad keys 0-9 and . send different keysyms
619 * depending on the NumLock state */
620 return nonchar_key_vkey[keysym & 0xFF];
622 return keyc2vkey[e->keycode];
625 static BOOL NumState=FALSE, CapsState=FALSE;
628 /***********************************************************************
629 * send_keyboard_input
631 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
635 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
636 input.u.ki.wVk = wVk;
637 input.u.ki.wScan = wScan;
638 input.u.ki.dwFlags = dwFlags;
639 input.u.ki.time = time;
640 input.u.ki.dwExtraInfo = 0;
641 SendInput( 1, &input, sizeof(input) );
645 /**********************************************************************
646 * KEYBOARD_GenerateMsg
648 * Generate Down+Up messages when NumLock or CapsLock is pressed.
650 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
653 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
655 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
659 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
660 don't treat it. It's from the same key press. Then the state goes to ON.
661 And from there, a 'release' event will switch off the toggle key. */
663 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
666 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
667 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
668 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
670 if (Evtype!=KeyPress)
672 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
673 send_keyboard_input( vkey, scan, down, event_time );
674 send_keyboard_input( vkey, scan, up, event_time );
676 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
679 else /* it was OFF */
680 if (Evtype==KeyPress)
682 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
683 send_keyboard_input( vkey, scan, down, event_time );
684 send_keyboard_input( vkey, scan, up, event_time );
685 *State=TRUE; /* Goes to intermediary state before going to ON */
686 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
691 /***********************************************************************
692 * KEYBOARD_UpdateOneState
694 * Updates internal state for <vkey>, depending on key <state> under X
697 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
699 /* Do something if internal table state != X state for keycode */
700 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
702 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
703 vkey, pKeyStateTable[vkey]);
705 /* Fake key being pressed inside wine */
706 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
708 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
712 /***********************************************************************
713 * X11DRV_KeymapNotify
715 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
717 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
718 * from wine to another application and back.
719 * Toggle keys are handled in HandleEvent.
721 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
723 int i, j, alt, control, shift;
724 DWORD time = GetCurrentTime();
726 alt = control = shift = 0;
727 for (i = 0; i < 32; i++)
729 if (!event->key_vector[i]) continue;
730 for (j = 0; j < 8; j++)
732 if (!(event->key_vector[i] & (1<<j))) continue;
733 switch(keyc2vkey[(i * 8) + j] & 0xff)
735 case VK_MENU: alt = 1; break;
736 case VK_CONTROL: control = 1; break;
737 case VK_SHIFT: shift = 1; break;
741 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
742 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
743 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
746 /***********************************************************************
749 * Handle a X key event
751 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
755 WORD vkey = 0, bScan;
759 DWORD event_time = event->time - X11DRV_server_startticks;
761 /* this allows support for dead keys */
762 if ((event->keycode >> 8) == 0x10)
763 event->keycode=(event->keycode & 0xff);
765 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
767 /* Ignore some unwanted events */
768 if (keysym == XK_ISO_Prev_Group ||
769 keysym == XK_ISO_Next_Group ||
770 keysym == XK_Mode_switch)
772 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
776 TRACE_(key)("state = %X\n", event->state);
778 /* If XKB extensions is used, the state mask for AltGr will used the group
779 index instead of the modifier mask. The group index is set in bits
780 13-14 of the state field in the XKeyEvent structure. So if AltGr is
781 pressed, look if the group index is diferent than 0. From XKB
782 extension documentation, the group index should for AltGr should
783 be 2 (event->state = 0x2000). It's probably better to not assume a
784 predefined group index and find it dynamically
786 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
787 AltGrMask = event->state & 0x6000;
789 Str[ascii_chars] = '\0';
793 ksname = TSXKeysymToString(keysym);
796 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
797 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
798 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
801 vkey = EVENT_event_to_vkey(event);
803 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
804 event->keycode, vkey);
811 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
814 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
815 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
816 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
819 /* Adjust the NUMLOCK state if it has been changed outside wine */
820 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
822 TRACE("Adjusting NumLock state. \n");
823 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
824 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
826 /* Adjust the CAPSLOCK state if it has been changed outside wine */
827 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
829 TRACE("Adjusting Caps Lock state.\n");
830 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
831 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
833 /* Not Num nor Caps : end of intermediary states for both. */
837 bScan = keyc2scan[event->keycode] & 0xFF;
838 TRACE_(key)("bScan = 0x%02x.\n", bScan);
841 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
842 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
844 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
849 /**********************************************************************
850 * X11DRV_KEYBOARD_DetectLayout
852 * Called from X11DRV_InitKeyboard
853 * This routine walks through the defined keyboard layouts and selects
854 * whichever matches most closely.
857 X11DRV_KEYBOARD_DetectLayout (void)
859 Display *display = thread_display();
860 unsigned current, match, mismatch, seq;
861 int score, keyc, i, key, pkey, ok, syms;
863 const char (*lkey)[MAIN_LEN][4];
864 unsigned max_seq = 0;
865 int max_score = 0, ismatch = 0;
869 syms = keysyms_per_keycode;
871 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
874 for (current = 0; main_key_tab[current].comment; current++) {
875 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
880 lkey = main_key_tab[current].key;
882 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
883 /* get data for keycode from X server */
884 for (i = 0; i < syms; i++) {
885 keysym = TSXKeycodeToKeysym (display, keyc, i);
886 /* Allow both one-byte and two-byte national keysyms */
887 if ((keysym < 0x800) && (keysym != ' '))
888 ckey[i] = keysym & 0xFF;
890 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
894 /* search for a match in layout table */
895 /* right now, we just find an absolute match for defined positions */
896 /* (undefined positions are ignored, so if it's defined as "3#" in */
897 /* the table, it's okay that the X server has "3#£", for example) */
898 /* however, the score will be higher for longer matches */
899 for (key = 0; key < MAIN_LEN; key++) {
900 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
901 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
903 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
911 /* count the matches and mismatches */
914 /* and how much the keycode order matches */
915 if (key > pkey) seq++;
918 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
925 TRACE("matches=%d, mismatches=%d, score=%d\n",
926 match, mismatch, score);
927 if ((score > max_score) ||
928 ((score == max_score) && (seq > max_seq))) {
929 /* best match so far */
930 kbd_layout = current;
936 /* we're done, report results if necessary */
939 "Your keyboard layout was not found!\n"
940 "Using closest match instead (%s) for scancode mapping.\n"
941 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
942 "to us for inclusion into future Wine releases.\n"
943 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
944 main_key_tab[kbd_layout].comment);
947 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
950 /**********************************************************************
951 * InitKeyboard (X11DRV.@)
953 void X11DRV_InitKeyboard( BYTE *key_state_table )
956 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
958 Display *display = thread_display();
960 XModifierKeymap *mmp;
964 WORD scan, vkey, OEMvkey;
965 int keyc, i, keyn, syms;
966 char ckey[4]={0,0,0,0};
967 const char (*lkey)[MAIN_LEN][4];
969 pKeyStateTable = key_state_table;
973 is_xkb = XkbQueryExtension(display,
974 &xkb_opcode, &xkb_event, &xkb_error,
975 &xkb_major, &xkb_minor);
977 /* we have XKB, approximate Windows behaviour */
978 XkbSetDetectableAutoRepeat(display, True, NULL);
982 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
983 ksp = TSXGetKeyboardMapping(display, min_keycode,
984 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
985 /* We are only interested in keysyms_per_keycode.
986 There is no need to hold a local copy of the keysyms table */
988 mmp = TSXGetModifierMapping(display);
989 kcp = mmp->modifiermap;
990 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
994 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
999 for (k = 0; k < keysyms_per_keycode; k += 1)
1000 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
1003 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
1005 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1007 NumLockMask = 1 << i;
1008 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1012 TSXFreeModifiermap(mmp);
1014 /* Detect the keyboard layout */
1015 X11DRV_KEYBOARD_DetectLayout();
1016 lkey = main_key_tab[kbd_layout].key;
1017 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1019 /* Now build two conversion arrays :
1020 * keycode -> vkey + scancode + extended
1021 * vkey + extended -> keycode */
1023 e2.display = display;
1026 OEMvkey = VK_OEM_7; /* next is available. */
1027 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1029 e2.keycode = (KeyCode)keyc;
1030 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1032 if (keysym) /* otherwise, keycode not used */
1034 if ((keysym >> 8) == 0xFF) /* non-character key */
1036 vkey = nonchar_key_vkey[keysym & 0xff];
1037 scan = nonchar_key_scan[keysym & 0xff];
1038 /* set extended bit when necessary */
1039 if (scan & 0x100) vkey |= 0x100;
1040 } else if (keysym == 0x20) { /* Spacebar */
1044 /* we seem to need to search the layout-dependent scancodes */
1045 int maxlen=0,maxval=-1,ok;
1046 for (i=0; i<syms; i++) {
1047 keysym = TSXKeycodeToKeysym(display, keyc, i);
1048 if ((keysym<0x800) && (keysym!=' ')) {
1049 ckey[i] = keysym & 0xFF;
1051 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1054 /* find key with longest match streak */
1055 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1056 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1057 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1058 if (ok||(i>maxlen)) {
1059 maxlen=i; maxval=keyn;
1065 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1066 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1067 scan = (*lscan)[maxval];
1068 vkey = (*lvkey)[maxval];
1072 /* find a suitable layout-dependent VK code */
1073 /* (most Winelib apps ought to be able to work without layout tables!) */
1074 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1076 keysym = TSXLookupKeysym(&e2, i);
1077 if ((keysym >= VK_0 && keysym <= VK_9)
1078 || (keysym >= VK_A && keysym <= VK_Z)) {
1083 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1085 keysym = TSXLookupKeysym(&e2, i);
1088 case ';': vkey = VK_OEM_1; break;
1089 case '/': vkey = VK_OEM_2; break;
1090 case '`': vkey = VK_OEM_3; break;
1091 case '[': vkey = VK_OEM_4; break;
1092 case '\\': vkey = VK_OEM_5; break;
1093 case ']': vkey = VK_OEM_6; break;
1094 case '\'': vkey = VK_OEM_7; break;
1095 case ',': vkey = VK_OEM_COMMA; break;
1096 case '.': vkey = VK_OEM_PERIOD; break;
1097 case '-': vkey = VK_OEM_MINUS; break;
1098 case '+': vkey = VK_OEM_PLUS; break;
1104 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1105 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1108 case 0xc1 : OEMvkey=0xdb; break;
1109 case 0xe5 : OEMvkey=0xe9; break;
1110 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1115 if (TRACE_ON(keyboard))
1117 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1118 OEMvkey, e2.keycode);
1120 for (i = 0; i < keysyms_per_keycode; i += 1)
1124 keysym = TSXLookupKeysym(&e2, i);
1125 ksname = TSXKeysymToString(keysym);
1127 ksname = "NoSymbol";
1128 DPRINTF( "%lX (%s) ", keysym, ksname);
1134 keyc2vkey[e2.keycode] = vkey;
1135 keyc2scan[e2.keycode] = scan;
1138 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1139 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1140 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1142 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1143 ksname = TSXKeysymToString(keysym);
1144 if (!ksname) ksname = "NoSymbol";
1146 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1148 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1149 keyc2scan[keyc]=scan++;
1152 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1153 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1154 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1155 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1156 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1157 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1158 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1162 /***********************************************************************
1163 * X11DRV_MappingNotify
1165 void X11DRV_MappingNotify( XMappingEvent *event )
1167 TSXRefreshKeyboardMapping(event);
1168 X11DRV_InitKeyboard( pKeyStateTable );
1172 /***********************************************************************
1173 * VkKeyScan (X11DRV.@)
1175 WORD X11DRV_VkKeyScan(CHAR cChar)
1177 Display *display = thread_display();
1183 /* char->keysym (same for ANSI chars) */
1184 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1185 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1187 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1189 { /* It didn't work ... let's try with deadchar code. */
1190 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1193 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1194 cChar,keysym,keysym,keycode);
1198 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1199 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1202 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1204 case 1 : highbyte = 0x0100; break;
1205 case 2 : highbyte = 0x0600; break;
1206 case 3 : highbyte = 0x0700; break;
1207 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1210 index : 0 adds 0x0000
1211 index : 1 adds 0x0100 (shift)
1212 index : ? adds 0x0200 (ctrl)
1213 index : 2 adds 0x0600 (ctrl+alt)
1214 index : 3 adds 0x0700 (ctrl+alt+shift)
1217 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1218 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1221 /***********************************************************************
1222 * MapVirtualKey (X11DRV.@)
1224 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1226 Display *display = thread_display();
1228 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1230 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1232 case 0: { /* vkey-code to scan-code */
1233 /* let's do vkey -> keycode -> scan */
1235 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1236 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1237 returnMVK (keyc2scan[keyc] & 0xFF);
1238 TRACE("returning no scan-code.\n");
1241 case 1: { /* scan-code to vkey-code */
1242 /* let's do scan -> keycode -> vkey */
1244 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1245 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1246 returnMVK (keyc2vkey[keyc] & 0xFF);
1247 TRACE("returning no vkey-code.\n");
1250 case 2: { /* vkey-code to unshifted ANSI code */
1251 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1252 /* My Windows returns 'A'. */
1253 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1258 e.display = display;
1259 e.state = 0; /* unshifted */
1262 /* We exit on the first keycode found, to speed up the thing. */
1263 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1264 { /* Find a keycode that could have generated this virtual key */
1265 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1266 { /* We filter the extended bit, we don't know it */
1267 e.keycode = keyc; /* Store it temporarily */
1268 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1269 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1270 state), so set it to 0, we'll find another one */
1275 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1276 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1278 if (wCode==VK_DECIMAL)
1279 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1283 WARN("Unknown virtual key %X !!! \n", wCode);
1284 return 0; /* whatever */
1286 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1288 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1291 TRACE("returning no ANSI.\n");
1295 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1296 /* left and right */
1297 FIXME(" stub for NT\n");
1300 default: /* reserved */
1301 WARN("Unknown wMapType %d !\n", wMapType);
1307 /***********************************************************************
1308 * GetKeyNameText (X11DRV.@)
1310 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1312 int vkey, ansi, scanCode;
1318 scanCode = lParam >> 16;
1319 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1321 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1322 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1324 /* handle "don't care" bit (0x02000000) */
1325 if (!(lParam & 0x02000000)) {
1344 ansi = X11DRV_MapVirtualKey(vkey, 2);
1345 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1347 /* first get the name of the "regular" keys which is the Upper case
1348 value of the keycap imprint. */
1349 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1350 (scanCode != 0x137) && /* PrtScn */
1351 (scanCode != 0x135) && /* numpad / */
1352 (scanCode != 0x37 ) && /* numpad * */
1353 (scanCode != 0x4a ) && /* numpad - */
1354 (scanCode != 0x4e ) ) /* numpad + */
1356 if ((nSize >= 2) && lpBuffer)
1358 *lpBuffer = toupper((char)ansi);
1366 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1367 without "extended-key" flag. However Wine generates scancode
1368 *with* "extended-key" flag. Seems to occur *only* for the
1369 function keys. Soooo.. We will leave the table alone and
1370 fudge the lookup here till the other part is found and fixed!!! */
1372 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1373 (scanCode == 0x157) || (scanCode == 0x158))
1374 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1376 /* let's do scancode -> keycode -> keysym -> String */
1378 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1379 if ((keyc2scan[keyi]) == scanCode)
1381 if (keyi <= max_keycode)
1383 keyc = (KeyCode) keyi;
1384 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1385 name = TSXKeysymToString(keys);
1386 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1387 scanCode, keyc, (int)keys, name);
1388 if (lpBuffer && nSize && name)
1390 lstrcpynA(lpBuffer, name, nSize);
1395 /* Finally issue FIXME for unknown keys */
1397 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1398 if (lpBuffer && nSize)
1403 /***********************************************************************
1404 * X11DRV_KEYBOARD_MapDeadKeysym
1406 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1410 /* symbolic ASCII is the same as defined in rfc1345 */
1411 #ifdef XK_dead_tilde
1412 case XK_dead_tilde :
1414 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1415 return '~'; /* '? */
1416 #ifdef XK_dead_acute
1417 case XK_dead_acute :
1419 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1420 return 0xb4; /* '' */
1421 #ifdef XK_dead_circumflex
1422 case XK_dead_circumflex:
1424 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1425 return '^'; /* '> */
1426 #ifdef XK_dead_grave
1427 case XK_dead_grave :
1429 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1430 return '`'; /* '! */
1431 #ifdef XK_dead_diaeresis
1432 case XK_dead_diaeresis :
1434 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1435 return 0xa8; /* ': */
1436 #ifdef XK_dead_cedilla
1437 case XK_dead_cedilla :
1438 return 0xb8; /* ', */
1440 #ifdef XK_dead_macron
1441 case XK_dead_macron :
1442 return '-'; /* 'm isn't defined on iso-8859-x */
1444 #ifdef XK_dead_breve
1445 case XK_dead_breve :
1446 return 0xa2; /* '( */
1448 #ifdef XK_dead_abovedot
1449 case XK_dead_abovedot :
1450 return 0xff; /* '. */
1452 #ifdef XK_dead_abovering
1453 case XK_dead_abovering :
1454 return '0'; /* '0 isn't defined on iso-8859-x */
1456 #ifdef XK_dead_doubleacute
1457 case XK_dead_doubleacute :
1458 return 0xbd; /* '" */
1460 #ifdef XK_dead_caron
1461 case XK_dead_caron :
1462 return 0xb7; /* '< */
1464 #ifdef XK_dead_ogonek
1465 case XK_dead_ogonek :
1466 return 0xb2; /* '; */
1468 /* FIXME: I don't know this three.
1471 case XK_dead_voiced_sound :
1473 case XK_dead_semivoiced_sound :
1477 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1481 /***********************************************************************
1482 * ToUnicode (X11DRV.@)
1484 * The ToUnicode function translates the specified virtual-key code and keyboard
1485 * state to the corresponding Windows character or characters.
1487 * If the specified key is a dead key, the return value is negative. Otherwise,
1488 * it is one of the following values:
1490 * 0 The specified virtual key has no translation for the current state of the keyboard.
1491 * 1 One Windows character was copied to the buffer.
1492 * 2 Two characters were copied to the buffer. This usually happens when a
1493 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1494 * be composed with the specified virtual key to form a single character.
1496 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1499 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1500 LPWSTR bufW, int bufW_size, UINT flags)
1502 Display *display = thread_display();
1510 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1511 event is generated by windows. Just ignore it. */
1512 TRACE("scanCode=0, doing nothing\n");
1515 if (scanCode & 0x8000)
1517 TRACE("Key UP, doing nothing\n" );
1520 e.display = display;
1523 if (lpKeyState[VK_SHIFT] & 0x80)
1524 e.state |= ShiftMask;
1525 if (lpKeyState[VK_CAPITAL] & 0x01)
1526 e.state |= LockMask;
1527 if (lpKeyState[VK_CONTROL] & 0x80)
1528 e.state |= ControlMask;
1529 if (lpKeyState[VK_NUMLOCK] & 0x01)
1530 e.state |= NumLockMask;
1532 /* Restore saved AltGr state */
1533 e.state |= AltGrMask;
1535 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1536 virtKey, scanCode, e.state);
1537 /* We exit on the first keycode found, to speed up the thing. */
1538 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1539 { /* Find a keycode that could have generated this virtual key */
1540 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1541 { /* We filter the extended bit, we don't know it */
1542 e.keycode = keyc; /* Store it temporarily */
1543 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1544 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1545 state), so set it to 0, we'll find another one */
1550 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1551 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1553 if (virtKey==VK_DECIMAL)
1554 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1558 WARN("Unknown virtual key %X !!! \n",virtKey);
1559 return virtKey; /* whatever */
1561 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1563 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1568 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1571 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1578 ksname = TSXKeysymToString(keysym);
1581 if ((keysym >> 8) != 0xff)
1583 ERR("Please report: no char for keysym %04lX (%s) :\n",
1585 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1586 virtKey, scanCode, e.keycode, e.state);
1590 else { /* ret != 0 */
1591 /* We have a special case to handle : Shift + arrow, shift + home, ...
1592 X returns a char for it, but Windows doesn't. Let's eat it. */
1593 if (!(e.state & NumLockMask) /* NumLock is off */
1594 && (e.state & ShiftMask) /* Shift is pressed */
1595 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1601 /* more areas where X returns characters but Windows does not
1602 CTRL + number or CTRL + symbol*/
1603 if (e.state & ControlMask)
1605 if (((keysym>=33) && (keysym < 'A')) ||
1606 ((keysym > 'Z') && (keysym < 'a')))
1613 /* We have another special case for delete key (XK_Delete) on an
1614 extended keyboard. X returns a char for it, but Windows doesn't */
1615 if (keysym == XK_Delete)
1620 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1621 && (keysym == XK_KP_Decimal))
1627 /* perform translation to unicode */
1630 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1631 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1632 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1636 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1637 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1641 /***********************************************************************
1644 void X11DRV_Beep(void)
1646 TSXBell(thread_display(), 0);