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"
26 #include "wine/winuser16.h"
28 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(keyboard)
37 DECLARE_DEBUG_CHANNEL(key)
38 DECLARE_DEBUG_CHANNEL(dinput)
40 extern BYTE InputKeyStateTable[256];
42 extern LPBYTE pKeyStateTable;
44 int min_keycode, max_keycode, keysyms_per_keycode;
45 WORD keyc2vkey[256], keyc2scan[256];
47 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
48 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
50 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
52 /* Keyboard translation tables */
54 static const int main_key_scan[MAIN_LEN] =
56 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
57 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
58 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
59 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
60 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
61 0x56 /* the 102nd key (actually to the right of l-shift) */
64 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
66 /* the VK mappings for the main keyboard will be auto-assigned as before,
67 so what we have here is just the character tables */
68 /* order: Normal, Shift, AltGr, Shift-AltGr */
69 /* We recommend you write just what is guaranteed to be correct (i.e. what's
70 written on the keycaps), not the bunch of special characters behind AltGr
71 and Shift-AltGr if it can vary among different X servers */
72 /* Remember that your 102nd key (to the right of l-shift) should be on a
73 separate line, see existing tables */
74 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
75 /* Remember to also add your new table to the layout index table far below! */
77 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
78 static const char main_key_US[MAIN_LEN][4] =
80 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
81 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
82 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
83 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
86 /*** United States keyboard layout (phantom key version) */
87 /* (XFree86 reports the <> key even if it's not physically there) */
88 static const char main_key_US_phantom[MAIN_LEN][4] =
90 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
91 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
92 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
93 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
94 "<>" /* the phantom key */
97 /*** British keyboard layout */
98 static const char main_key_UK[MAIN_LEN][4] =
100 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
101 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
102 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
103 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
107 /*** French keyboard layout (contributed by Eric Pouech) */
108 static const char main_key_FR[MAIN_LEN][4] =
110 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
111 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
112 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
113 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
117 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
118 static const char main_key_IS[MAIN_LEN][4] =
120 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
121 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
122 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
123 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
127 /*** German keyboard layout (contributed by Ulrich Weigand) */
128 static const char main_key_DE[MAIN_LEN][4] =
130 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
131 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
132 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
133 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
137 /*** German keyboard layout without dead keys */
138 static const char main_key_DE_nodead[MAIN_LEN][4] =
140 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
141 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
142 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
143 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
147 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
148 static const char main_key_SG[MAIN_LEN][4] =
150 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
151 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
152 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
153 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
157 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
158 static const char main_key_SF[MAIN_LEN][4] =
160 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
161 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
162 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
163 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
167 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
168 static const char main_key_NO[MAIN_LEN][4] =
170 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
171 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
172 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
173 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
177 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
178 static const char main_key_DA[MAIN_LEN][4] =
180 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
181 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
182 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
183 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
187 /*** Swedish keyboard layout (contributed by Peter Bortas) */
188 static const char main_key_SE[MAIN_LEN][4] =
190 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
191 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
192 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
193 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
197 /*** Canadian French keyboard layout */
198 static const char main_key_CF[MAIN_LEN][4] =
200 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
201 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
202 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
203 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
207 /*** Portuguese keyboard layout */
208 static const char main_key_PT[MAIN_LEN][4] =
210 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
211 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
212 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
213 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
217 /*** Italian keyboard layout */
218 static const char main_key_IT[MAIN_LEN][4] =
220 "\\|","1!1","2\"2","3?3","4$","5%½","6&¾","7/{","8([","9)]","0=}","'?`","i^~",
221 "qQ@","wW","eE","rR?","tT","yY","uU","iI","oOo","pP?","ee[","+*]",
222 "aAae","sS?","dD?","fF","gG","hH","jJ","kK","lL","oc@","a?#","u?",
223 "zZ<","xX>","cC","vV","bB","nN","mM?",",;",".:*","-_","<>|"
226 /*** Finnish keyboard layout */
227 static const char main_key_FI[MAIN_LEN][4] =
229 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
230 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
231 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
232 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
236 /*** Russian keyboard layout (contributed by Pavel Roskin) */
237 static const char main_key_RU[MAIN_LEN][4] =
239 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
240 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
241 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
242 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
245 /*** Spanish keyboard layout (contributed by José Marcos López) */
246 static const char main_key_ES[MAIN_LEN][4] =
248 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
249 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
251 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
255 /*** Belgian keyboard layout ***/
256 static const char main_key_BE[MAIN_LEN][4] =
258 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
259 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
260 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
261 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
265 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
266 static const char main_key_HU[MAIN_LEN][4] =
268 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
269 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
270 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
271 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
275 /*** Polish (programmer's) keyboard layout ***/
276 static const char main_key_PL[MAIN_LEN][4] =
278 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
279 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
280 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
281 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
285 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
286 static const char main_key_HR_jelly[MAIN_LEN][4] =
288 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
289 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
290 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
291 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
295 /*** Croatian keyboard layout ***/
296 static const char main_key_HR[MAIN_LEN][4] =
298 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
299 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
300 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
301 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
305 /*** Japanese 106 keyboard layout ***/
306 static const char main_key_JA_jp106[MAIN_LEN][4] =
308 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
309 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
310 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
311 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
315 /*** Japanese pc98x1 keyboard layout ***/
316 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
318 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
319 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
320 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
321 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
327 /*** Layout table. Add your keyboard mappings to this list */
329 WORD lang, ansi_codepage, oem_codepage;
330 const char (*key)[MAIN_LEN][4];
332 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), 1252, 437, &main_key_US},
333 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), 1252, 437, &main_key_US_phantom},
334 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK), 1252, 850, &main_key_UK},
335 {MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), 1252, 850, &main_key_DE},
336 {MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), 1252, 850, &main_key_DE_nodead},
337 {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_SWISS), 1252, 850, &main_key_SG},
338 {MAKELANGID(LANG_SWEDISH,SUBLANG_SWEDISH), 1252, 850, &main_key_SE},
339 {MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &main_key_NO},
340 {MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), 1252, 865, &main_key_DA},
341 {MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), 1252, 850, &main_key_FR},
342 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_CANADIAN), 1252, 863, &main_key_CF},
343 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_BELGIAN), 1252, 850, &main_key_BE},
344 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_SWISS), 1252, 850, &main_key_SF},
345 {MAKELANGID(LANG_WALON,SUBLANG_DEFAULT), 1252, 850, &main_key_BE},
346 {MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), 1252, 860, &main_key_PT},
347 {MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), 1252, 850, &main_key_FI},
348 {MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), 1251, 866, &main_key_RU},
349 {MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), 1252, 850, &main_key_ES},
350 {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), 1252, 850, &main_key_BE},
351 {MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), 1252, 850, &main_key_IT},
352 {MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), 1252, 850, &main_key_IS},
353 {MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), 1252, 850, &main_key_HU},
354 {MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), 1250, 852, &main_key_PL},
355 {MAKELANGID(LANG_CROATIAN,SUBLANG_CROATIAN), 1250, 852, &main_key_HR},
356 {MAKELANGID(LANG_CROATIAN,SUBLANG_CROATIAN), 1250, 852, &main_key_HR_jelly},
357 {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), 932, 932, &main_key_JA_jp106},
358 {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), 932, 932, &main_key_JA_pc98x1},
362 static unsigned kbd_layout=0; /* index into above table of layouts */
364 /* maybe more of these scancodes should be extended? */
365 /* extended must be set for ALT_R, CTRL_R,
366 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
367 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
368 /* FIXME should we set extended bit for NumLock ? My
369 * Windows does ... DF */
370 /* Yes, to distinguish based on scan codes, also
371 for PrtScn key ... GA */
373 static const int special_key_vkey[] =
375 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
376 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
377 0, 0, 0, VK_ESCAPE /* FF18 */
379 static const int special_key_scan[] =
381 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
382 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
383 0, 0, 0, 0x01 /* FF18 */
386 static const int cursor_key_vkey[] =
388 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
389 VK_NEXT, VK_END /* FF50 */
391 static const int cursor_key_scan[] =
393 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
396 static const int misc_key_vkey[] =
398 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
399 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
401 static const int misc_key_scan[] =
403 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
404 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
407 static const int keypad_key_vkey[] =
409 0, VK_NUMLOCK, /* FF7E */
410 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
411 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
412 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
413 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
414 VK_INSERT, VK_DELETE, /* FF98 */
415 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
416 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
417 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
418 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
419 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
420 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
422 static const int keypad_key_scan[] =
424 0x138, 0x145, /* FF7E */
425 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
426 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
427 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
428 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
429 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
430 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
431 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
432 0x48, 0x49 /* FFB8 */
435 static const int function_key_vkey[] =
437 VK_F1, VK_F2, /* FFBE */
438 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
439 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
441 static const int function_key_scan[] =
443 0x3B, 0x3C, /* FFBE */
444 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
445 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
448 static const int modifier_key_vkey[] =
450 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
451 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
453 static const int modifier_key_scan[] =
455 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
456 0x38, 0x138, 0x38, 0x138 /* FFE7 */
459 /* Returns the Windows virtual key code associated with the X event <e> */
460 static WORD EVENT_event_to_vkey( XKeyEvent *e)
464 TSXLookupString(e, NULL, 0, &keysym, NULL);
466 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
467 && (e->state & NumLockMask))
468 /* Only the Keypad keys 0-9 and . send different keysyms
469 * depending on the NumLock state */
470 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
472 return keyc2vkey[e->keycode];
475 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
477 /**********************************************************************
478 * KEYBOARD_GenerateMsg
480 * Generate Down+Up messages when NumLock or CapsLock is pressed.
482 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
485 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
488 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
492 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
493 don't treat it. It's from the same key press. Then the state goes to ON.
494 And from there, a 'release' event will switch off the toggle key. */
496 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
499 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
500 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
501 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
503 if (Evtype!=KeyPress)
505 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
506 KEYBOARD_SendEvent( vkey, scan, down,
507 event_x, event_y, event_time );
508 KEYBOARD_SendEvent( vkey, scan, up,
509 event_x, event_y, event_time );
511 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
514 else /* it was OFF */
515 if (Evtype==KeyPress)
517 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
518 KEYBOARD_SendEvent( vkey, scan, down,
519 event_x, event_y, event_time );
520 KEYBOARD_SendEvent( vkey, scan, up,
521 event_x, event_y, event_time );
522 *State=TRUE; /* Goes to intermediary state before going to ON */
523 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
528 /***********************************************************************
529 * KEYBOARD_UpdateOneState
531 * Updates internal state for <vkey>, depending on key <state> under X
534 static void KEYBOARD_UpdateOneState ( int vkey, int state )
536 /* Do something if internal table state != X state for keycode */
537 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
539 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
540 vkey, pKeyStateTable[vkey]);
542 /* Fake key being pressed inside wine */
543 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
544 0, 0, GetTickCount() );
546 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
550 /***********************************************************************
551 * X11DRV_KEYBOARD_UpdateState
553 * Update modifiers state (Ctrl, Alt, Shift)
554 * when window is activated (called by EVENT_FocusIn in event.c)
556 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
557 * from wine to another application and back.
558 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
561 void X11DRV_KEYBOARD_UpdateState ( void )
563 /* extract a bit from the char[32] bit suite */
564 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
566 char keys_return[32];
569 if (!TSXQueryKeymap(display, keys_return)) {
570 ERR("Error getting keymap !");
574 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
575 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
576 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
577 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
581 /***********************************************************************
582 * X11DRV_KEYBOARD_HandleEvent
584 * Handle a X key event
586 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
591 WORD vkey = 0, bScan;
593 static BOOL force_extended = FALSE; /* hack for AltGr translation */
597 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
598 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
599 DWORD event_time = event->time;
601 /* this allows support for dead keys */
602 if ((event->keycode >> 8) == 0x10)
603 event->keycode=(event->keycode & 0xff);
605 ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
607 TRACE_(key)("EVENT_key : state = %X\n", event->state);
609 /* If XKB extensions is used, the state mask for AltGr will used the group
610 index instead of the modifier mask. The group index is set in bits
611 13-14 of the state field in the XKeyEvent structure. So if AltGr is
612 pressed, look if the group index is diferent than 0. From XKB
613 extension documentation, the group index should for AltGr should
614 be 2 (event->state = 0x2000). It's probably better to not assume a
615 predefined group index and find it dynamically
617 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
618 if ( AltGrState && (event->state & 0x6000) )
619 AltGrMask = event->state & 0x6000;
621 if (keysym == XK_Mode_switch)
623 TRACE_(key)("Alt Gr key event received\n");
624 event->keycode = kcControl; /* Simulate Control */
625 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
627 event->keycode = kcAlt; /* Simulate Alt */
628 force_extended = TRUE;
629 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
630 force_extended = FALSE;
632 /* Here we save the pressed/released state of the AltGr key, to be able to
633 identify the group index associated with AltGr on the next key pressed *
634 see comment above. */
635 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
640 Str[ascii_chars] = '\0';
644 ksname = TSXKeysymToString(keysym);
647 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
648 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
649 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
652 vkey = EVENT_event_to_vkey(event);
653 if (force_extended) vkey |= 0x100;
655 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
656 event->keycode, vkey);
663 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
667 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
668 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
670 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
673 /* Adjust the NUMLOCK state if it has been changed outside wine */
674 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
676 TRACE("Adjusting NumLock state. \n");
677 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
679 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
682 /* Adjust the CAPSLOCK state if it has been changed outside wine */
683 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
685 TRACE("Adjusting Caps Lock state.\n");
686 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
688 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
691 /* Not Num nor Caps : end of intermediary states for both. */
695 bScan = keyc2scan[event->keycode] & 0xFF;
696 TRACE_(key)("bScan = 0x%02x.\n", bScan);
699 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
700 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
701 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
703 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
704 event_x, event_y, event_time );
709 /**********************************************************************
710 * X11DRV_KEYBOARD_DetectLayout
712 * Called from X11DRV_KEYBOARD_Init
713 * This routine walks through the defined keyboard layouts and selects
714 * whichever matches most closely.
717 X11DRV_KEYBOARD_DetectLayout (void)
719 unsigned current, match, mismatch, seq;
720 int score, keyc, i, key, pkey, ok, syms;
722 const char (*lkey)[MAIN_LEN][4];
723 unsigned max_seq = 0;
724 int max_score = 0, ismatch = 0;
728 syms = keysyms_per_keycode;
730 WARN("%d keysyms per keycode not supported, set to 4", syms);
733 for (current = 0; main_key_tab[current].lang; current++) {
734 TRACE("Attempting to match against layout %04x\n",
735 main_key_tab[current].lang);
740 lkey = main_key_tab[current].key;
742 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
743 /* get data for keycode from X server */
744 for (i = 0; i < syms; i++) {
745 keysym = TSXKeycodeToKeysym (display, keyc, i);
746 /* Allow both one-byte and two-byte national keysyms */
747 if ((keysym < 0x800) && (keysym != ' '))
748 ckey[i] = keysym & 0xFF;
750 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
754 /* search for a match in layout table */
755 /* right now, we just find an absolute match for defined positions */
756 /* (undefined positions are ignored, so if it's defined as "3#" in */
757 /* the table, it's okay that the X server has "3#£", for example) */
758 /* however, the score will be higher for longer matches */
759 for (key = 0; key < MAIN_LEN; key++) {
760 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
761 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
763 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
771 /* count the matches and mismatches */
774 /* and how much the keycode order matches */
775 if (key > pkey) seq++;
778 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
785 TRACE("matches=%d, mismatches=%d, score=%d\n",
786 match, mismatch, score);
787 if ((score > max_score) ||
788 ((score == max_score) && (seq > max_seq))) {
789 /* best match so far */
790 kbd_layout = current;
796 /* we're done, report results if necessary */
799 "Your keyboard layout was not found!\n"
800 "Instead using closest match (%04x) for scancode mapping.\n"
801 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
802 "to us for inclusion into future Wine releases.\n"
803 "See documentation/keyboard for more information.\n",
804 main_key_tab[kbd_layout].lang);
806 TRACE("detected layout is %04x\n", main_key_tab[kbd_layout].lang);
809 /**********************************************************************
810 * X11DRV_KEYBOARD_Init
812 void X11DRV_KEYBOARD_Init(void)
815 XModifierKeymap *mmp;
819 WORD scan, vkey, OEMvkey;
820 int keyc, i, keyn, syms;
821 char ckey[4]={0,0,0,0};
822 const char (*lkey)[MAIN_LEN][4];
824 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
825 ksp = TSXGetKeyboardMapping(display, min_keycode,
826 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
827 /* We are only interested in keysyms_per_keycode.
828 There is no need to hold a local copy of the keysyms table */
830 mmp = TSXGetModifierMapping(display);
831 kcp = mmp->modifiermap;
832 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
836 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
841 for (k = 0; k < keysyms_per_keycode; k += 1)
842 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
845 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
847 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
849 NumLockMask = 1 << i;
850 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
854 TSXFreeModifiermap(mmp);
856 /* Detect the keyboard layout */
857 X11DRV_KEYBOARD_DetectLayout();
858 lkey = main_key_tab[kbd_layout].key;
859 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
861 /* Now build two conversion arrays :
862 * keycode -> vkey + scancode + extended
863 * vkey + extended -> keycode */
865 e2.display = display;
868 OEMvkey = VK_OEM_7; /* next is available. */
869 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
871 e2.keycode = (KeyCode)keyc;
872 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
874 if (keysym) /* otherwise, keycode not used */
876 if ((keysym >> 8) == 0xFF) /* non-character key */
878 int key = keysym & 0xff;
880 if (key >= 0x08 && key <= 0x1B) { /* special key */
881 vkey = special_key_vkey[key - 0x08];
882 scan = special_key_scan[key - 0x08];
883 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
884 vkey = cursor_key_vkey[key - 0x50];
885 scan = cursor_key_scan[key - 0x50];
886 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
887 vkey = misc_key_vkey[key - 0x60];
888 scan = misc_key_scan[key - 0x60];
889 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
890 vkey = keypad_key_vkey[key - 0x7E];
891 scan = keypad_key_scan[key - 0x7E];
892 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
893 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
894 scan = function_key_scan[key - 0xBE];
895 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
896 vkey = modifier_key_vkey[key - 0xE1];
897 scan = modifier_key_scan[key - 0xE1];
898 } else if (key == 0xFF) { /* DEL key */
902 /* set extended bit when necessary */
903 if (scan & 0x100) vkey |= 0x100;
904 } else if (keysym == 0x20) { /* Spacebar */
908 /* we seem to need to search the layout-dependent scancodes */
909 int maxlen=0,maxval=-1,ok;
910 for (i=0; i<syms; i++) {
911 keysym = TSXKeycodeToKeysym(display, keyc, i);
912 if ((keysym<0x800) && (keysym!=' ')) {
913 ckey[i] = keysym & 0xFF;
915 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
918 /* find key with longest match streak */
919 for (keyn=0; keyn<MAIN_LEN; keyn++) {
920 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
921 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
922 if (ok||(i>maxlen)) {
923 maxlen=i; maxval=keyn;
929 scan = main_key_scan[maxval];
933 /* find a suitable layout-dependent VK code */
934 /* (most Winelib apps ought to be able to work without layout tables!) */
935 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
937 keysym = TSXLookupKeysym(&e2, i);
938 if ((keysym >= VK_0 && keysym <= VK_9)
939 || (keysym >= VK_A && keysym <= VK_Z)) {
944 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
946 keysym = TSXLookupKeysym(&e2, i);
949 case ';': vkey = VK_OEM_1; break;
950 case '/': vkey = VK_OEM_2; break;
951 case '`': vkey = VK_OEM_3; break;
952 case '[': vkey = VK_OEM_4; break;
953 case '\\': vkey = VK_OEM_5; break;
954 case ']': vkey = VK_OEM_6; break;
955 case '\'': vkey = VK_OEM_7; break;
956 case ',': vkey = VK_OEM_COMMA; break;
957 case '.': vkey = VK_OEM_PERIOD; break;
958 case '-': vkey = VK_OEM_MINUS; break;
959 case '+': vkey = VK_OEM_PLUS; break;
965 /* Others keys: let's assign OEM virtual key codes in the allowed range,
966 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
969 case 0xc1 : OEMvkey=0xdb; break;
970 case 0xe5 : OEMvkey=0xe9; break;
971 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
976 if (TRACE_ON(keyboard))
978 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
979 OEMvkey, e2.keycode);
981 for (i = 0; i < keysyms_per_keycode; i += 1)
985 keysym = TSXLookupKeysym(&e2, i);
986 ksname = TSXKeysymToString(keysym);
989 DPRINTF( "%lX (%s) ", keysym, ksname);
995 keyc2vkey[e2.keycode] = vkey;
996 keyc2scan[e2.keycode] = scan;
999 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1000 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1001 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1003 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1004 ksname = TSXKeysymToString(keysym);
1005 if (!ksname) ksname = "NoSymbol";
1007 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1009 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1010 keyc2scan[keyc]=scan++;
1013 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1014 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1015 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1016 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1017 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1018 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1019 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1022 /***********************************************************************
1023 * X11DRV_KEYBOARD_VkKeyScan
1025 WORD X11DRV_KEYBOARD_VkKeyScan(CHAR cChar)
1032 /* char->keysym (same for ANSI chars) */
1033 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1034 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1036 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1038 { /* It didn't work ... let's try with deadchar code. */
1039 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1042 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1043 cChar,keysym,keysym,keycode);
1047 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1048 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1051 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1053 case 1 : highbyte = 0x0100; break;
1054 case 2 : highbyte = 0x0600; break;
1055 case 3 : highbyte = 0x0700; break;
1056 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1059 index : 0 adds 0x0000
1060 index : 1 adds 0x0100 (shift)
1061 index : ? adds 0x0200 (ctrl)
1062 index : 2 adds 0x0600 (ctrl+alt)
1063 index : 3 adds 0x0700 (ctrl+alt+shift)
1066 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1067 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1070 /***********************************************************************
1071 * X11DRV_KEYBOARD_MapVirtualKey
1073 UINT16 X11DRV_KEYBOARD_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1075 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1077 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1079 case 0: { /* vkey-code to scan-code */
1080 /* let's do vkey -> keycode -> scan */
1082 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1083 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1084 returnMVK (keyc2scan[keyc] & 0xFF);
1085 TRACE("returning no scan-code.\n");
1088 case 1: { /* scan-code to vkey-code */
1089 /* let's do scan -> keycode -> vkey */
1091 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1092 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1093 returnMVK (keyc2vkey[keyc] & 0xFF);
1094 TRACE("returning no vkey-code.\n");
1097 case 2: { /* vkey-code to unshifted ANSI code */
1098 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1099 /* My Windows returns 'A'. */
1100 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1105 e.display = display;
1106 e.state = 0; /* unshifted */
1109 /* We exit on the first keycode found, to speed up the thing. */
1110 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1111 { /* Find a keycode that could have generated this virtual key */
1112 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1113 { /* We filter the extended bit, we don't know it */
1114 e.keycode = keyc; /* Store it temporarily */
1115 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1116 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1117 state), so set it to 0, we'll find another one */
1122 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1123 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1125 if (wCode==VK_DECIMAL)
1126 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1130 WARN("Unknown virtual key %X !!! \n", wCode);
1131 return 0; /* whatever */
1133 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1135 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1138 TRACE("returning no ANSI.\n");
1142 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1143 /* left and right */
1144 FIXME(" stub for NT\n");
1147 default: /* reserved */
1148 WARN("Unknown wMapType %d !\n", wMapType);
1154 /***********************************************************************
1155 * X11DRV_KEYBOARD_GetKeyNameText
1157 INT16 X11DRV_KEYBOARD_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1159 int vkey, ansi, scanCode;
1164 scanCode = lParam >> 16;
1165 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1167 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1168 vkey = X11DRV_KEYBOARD_MapVirtualKey(scanCode, 1);
1170 /* handle "don't care" bit (0x02000000) */
1171 if (!(lParam & 0x02000000)) {
1190 ansi = X11DRV_KEYBOARD_MapVirtualKey(vkey, 2);
1191 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1193 /* first get the name of the "regular" keys which is the Upper case
1194 value of the keycap imprint. */
1195 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1196 (scanCode != 0x137) && /* PrtScn */
1197 (scanCode != 0x135) && /* numpad / */
1198 (scanCode != 0x37 ) && /* numpad * */
1199 (scanCode != 0x4a ) && /* numpad - */
1200 (scanCode != 0x4e ) ) /* numpad + */
1202 if ((nSize >= 2) && lpBuffer)
1204 *lpBuffer = toupper((char)ansi);
1212 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1213 without "extended-key" flag. However Wine generates scancode
1214 *with* "extended-key" flag. Seems to occur *only* for the
1215 function keys. Soooo.. We will leave the table alone and
1216 fudge the lookup here till the other part is found and fixed!!! */
1218 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1219 (scanCode == 0x157) || (scanCode == 0x158))
1220 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1222 /* let's do scancode -> keycode -> keysym -> String */
1224 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1225 if ((keyc2scan[keyc]) == scanCode)
1227 if (keyc <= max_keycode)
1229 keys = TSXKeycodeToKeysym(display, keyc, 0);
1230 name = TSXKeysymToString(keys);
1231 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1232 scanCode, keyc, (int)keys, name);
1233 if (lpBuffer && nSize && name)
1235 lstrcpynA(lpBuffer, name, nSize);
1240 /* Finally issue FIXME for unknown keys */
1242 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1243 if (lpBuffer && nSize)
1248 /***********************************************************************
1249 * X11DRV_KEYBOARD_MapDeadKeysym
1251 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1255 /* symbolic ASCII is the same as defined in rfc1345 */
1256 #ifdef XK_dead_tilde
1257 case XK_dead_tilde :
1259 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1260 return '~'; /* '? */
1261 #ifdef XK_dead_acute
1262 case XK_dead_acute :
1264 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1265 return 0xb4; /* '' */
1266 #ifdef XK_dead_circumflex
1267 case XK_dead_circumflex:
1269 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1270 return '^'; /* '> */
1271 #ifdef XK_dead_grave
1272 case XK_dead_grave :
1274 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1275 return '`'; /* '! */
1276 #ifdef XK_dead_diaeresis
1277 case XK_dead_diaeresis :
1279 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1280 return 0xa8; /* ': */
1281 #ifdef XK_dead_cedilla
1282 case XK_dead_cedilla :
1283 return 0xb8; /* ', */
1285 #ifdef XK_dead_macron
1286 case XK_dead_macron :
1287 return '-'; /* 'm isn't defined on iso-8859-x */
1289 #ifdef XK_dead_breve
1290 case XK_dead_breve :
1291 return 0xa2; /* '( */
1293 #ifdef XK_dead_abovedot
1294 case XK_dead_abovedot :
1295 return 0xff; /* '. */
1297 #ifdef XK_dead_abovering
1298 case XK_dead_abovering :
1299 return '0'; /* '0 isn't defined on iso-8859-x */
1301 #ifdef XK_dead_doubleacute
1302 case XK_dead_doubleacute :
1303 return 0xbd; /* '" */
1305 #ifdef XK_dead_caron
1306 case XK_dead_caron :
1307 return 0xb7; /* '< */
1309 #ifdef XK_dead_ogonek
1310 case XK_dead_ogonek :
1311 return 0xb2; /* '; */
1313 /* FIXME: I don't know this three.
1316 case XK_dead_voiced_sound :
1318 case XK_dead_semivoiced_sound :
1322 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1326 /***********************************************************************
1327 * X11DRV_KEYBOARD_ToAscii
1329 * The ToAscii function translates the specified virtual-key code and keyboard
1330 * state to the corresponding Windows character or characters.
1332 * If the specified key is a dead key, the return value is negative. Otherwise,
1333 * it is one of the following values:
1335 * 0 The specified virtual key has no translation for the current state of the keyboard.
1336 * 1 One Windows character was copied to the buffer.
1337 * 2 Two characters were copied to the buffer. This usually happens when a
1338 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1339 * be composed with the specified virtual key to form a single character.
1341 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1344 INT16 X11DRV_KEYBOARD_ToAscii(
1345 UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1346 LPVOID lpChar, UINT16 flags)
1350 static XComposeStatus cs;
1355 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1356 event is generated by windows. Just ignore it. */
1357 TRACE("scanCode=0, doing nothing\n");
1360 if (scanCode & 0x8000)
1362 TRACE("Key UP, doing nothing\n" );
1365 e.display = display;
1368 if (lpKeyState[VK_SHIFT] & 0x80)
1369 e.state |= ShiftMask;
1370 if (lpKeyState[VK_CAPITAL] & 0x01)
1371 e.state |= LockMask;
1372 if (lpKeyState[VK_CONTROL] & 0x80)
1374 if (lpKeyState[VK_MENU] & 0x80)
1375 e.state |= AltGrMask;
1377 e.state |= ControlMask;
1379 if (lpKeyState[VK_NUMLOCK] & 0x01)
1380 e.state |= NumLockMask;
1381 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1382 virtKey, scanCode, e.state);
1383 /* We exit on the first keycode found, to speed up the thing. */
1384 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1385 { /* Find a keycode that could have generated this virtual key */
1386 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1387 { /* We filter the extended bit, we don't know it */
1388 e.keycode = keyc; /* Store it temporarily */
1389 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1390 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1391 state), so set it to 0, we'll find another one */
1396 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1397 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1399 if (virtKey==VK_DECIMAL)
1400 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1404 WARN("Unknown virtual key %X !!! \n",virtKey);
1405 return virtKey; /* whatever */
1407 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1409 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1414 ((char*)lpChar)[1] = '\0';
1415 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1418 *(char*)lpChar = dead_char;
1425 ksname = TSXKeysymToString(keysym);
1428 if ((keysym >> 8) != 0xff)
1430 ERR("Please report: no char for keysym %04lX (%s) :\n",
1432 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1433 virtKey, scanCode, e.keycode, e.state);
1437 else { /* ret = 1 */
1438 /* We have a special case to handle : Shift + arrow, shift + home, ...
1439 X returns a char for it, but Windows doesn't. Let's eat it. */
1440 if (!(lpKeyState[VK_NUMLOCK] & 0x01) /* NumLock is off */
1441 && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1442 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1448 /* We have another special case for delete key (XK_Delete) on an
1449 extended keyboard. X returns a char for it, but Windows doesn't */
1450 if (keysym == XK_Delete)
1457 TRACE_(key)("ToAscii about to return %d with char %x\n",
1458 ret, *(char*)lpChar);
1462 /***********************************************************************
1463 * X11DRV_KEYBOARD_GetBeepActive
1465 BOOL X11DRV_KEYBOARD_GetBeepActive()
1467 XKeyboardState keyboard_state;
1469 TSXGetKeyboardControl(display, &keyboard_state);
1471 return keyboard_state.bell_percent != 0;
1474 /***********************************************************************
1475 * X11DRV_KEYBOARD_SetBeepActive
1477 void X11DRV_KEYBOARD_SetBeepActive(BOOL bActivate)
1479 XKeyboardControl keyboard_value;
1482 keyboard_value.bell_percent = -1;
1484 keyboard_value.bell_percent = 0;
1486 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1489 /***********************************************************************
1490 * X11DRV_KEYBOARD_Beep
1492 void X11DRV_KEYBOARD_Beep()
1494 TSXBell(display, 0);
1497 /***********************************************************************
1498 * X11DRV_KEYBOARD_GetDIState
1500 BOOL X11DRV_KEYBOARD_GetDIState(DWORD len, LPVOID ptr)
1506 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1508 /* X keycode to virtual key */
1509 vkey = keyc2vkey[keyc] & 0xFF;
1510 /* The windows scancode is keyc-min_keycode */
1511 if (InputKeyStateTable[vkey]&0x80) {
1512 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1513 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1518 WARN("whoops, X11DRV_KEYBOARD_GetState got len %ld?\n", len);
1522 /***********************************************************************
1523 * X11DRV_KEYBOARD_GetDIData
1525 BOOL X11DRV_KEYBOARD_GetDIData(
1527 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1528 LPDWORD entries, DWORD flags)
1530 int keyc,n,vkey,xentries;
1535 xentries = *entries;
1541 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1543 /* X keycode to virtual key */
1544 vkey = keyc2vkey[keyc] & 0xFF;
1545 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1549 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1550 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1551 dod[n].dwTimeStamp = 0; /* umm */
1552 dod[n].dwSequence = 0; /* umm */
1555 if (!(flags & DIGDD_PEEK))
1556 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1560 if (n) TRACE_(dinput)("%d entries\n",n);
1566 /***********************************************************************
1567 * X11DRV_KEYBOARD_GetKeyboardConfig
1569 void X11DRV_KEYBOARD_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1572 /* For the moment, only get the auto-repeat mode */
1573 TSXGetKeyboardControl(display, &xks);
1574 cfg->auto_repeat = xks.global_auto_repeat;
1577 /***********************************************************************
1578 * X11DRV_KEYBOARD_SetKeyboardConfig
1580 extern void X11DRV_KEYBOARD_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1581 XKeyboardControl xkc;
1582 unsigned long X_mask = 0;
1584 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1585 X_mask |= KBAutoRepeatMode;
1586 xkc.auto_repeat_mode = cfg->auto_repeat;
1589 TSXChangeKeyboardControl(display, X_mask, &xkc);