With some apps a fault was possible in ExtractAssociatedIcon.
[wine.git] / windows / x11drv / keyboard.c
blob5b89e6b0938b3b613745d06cc07060fe5db64a4a
1 /*
2 * X11 keyboard driver
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
12 #include "config.h"
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
21 #include <ctype.h>
22 #include <string.h>
24 #include "windef.h"
25 #include "wingdi.h"
26 #include "wine/winuser16.h"
27 #include "dinput.h"
28 #include "debugtools.h"
29 #include "user.h"
30 #include "keyboard.h"
31 #include "message.h"
32 #include "winnls.h"
33 #include "win.h"
34 #include "x11drv.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 */
53 #define MAIN_LEN 48
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",",<",".>","/?",
104 "\\|"
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",",?",";.",":/","!§",
114 "<>"
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",",;",".:","þÞ",
124 "<>|"
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",",;",".:","-_",
134 "<>"
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",",;",".:","-_",
144 "<>"
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",",;",".:","-_",
154 "<>\\"
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",",;",".:","-_",
164 "<>\\"
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",",;",".:","-_",
174 "<>"
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",",;",".:","-_",
184 "<>\\"
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",",;",".:","-_",
194 "<>|"
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",",'-",".","éÉ",
204 "«»°"
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", ",;", ".:", "-_",
214 "<>"
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",",;",".:","-_",
233 "<>|"
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",",;",".:","-_",
252 "<>"
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",",?",";.",":/","=+~",
262 "<>\\"
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",",?;",".:·","-_*",
272 "íÍ<"
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",",<",".>","/?",
282 "<>|"
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",",<",".>","/?",
292 "<>|"
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§",",;",".:","-_/",
302 "<>"
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",",<",".>","/?",
312 "\\_",
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",",<",".>","/?",
322 "\\_",
327 /*** Layout table. Add your keyboard mappings to this list */
328 static struct {
329 WORD lang, ansi_codepage, oem_codepage;
330 const char (*key)[MAIN_LEN][4];
331 } main_key_tab[]={
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},
360 {0} /* sentinel */
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)
462 KeySym keysym;
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,
486 DWORD event_time )
488 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
489 DWORD up, down;
491 if (*State) {
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. */
495 *State=FALSE;
496 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
497 } else
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 );
510 *State=FALSE;
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
559 * about them)
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];
568 TRACE("called\n");
569 if (!TSXQueryKeymap(display, keys_return)) {
570 ERR("Error getting keymap !");
571 return;
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));
578 #undef KeyState
581 /***********************************************************************
582 * X11DRV_KEYBOARD_HandleEvent
584 * Handle a X key event
586 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
588 char Str[24];
589 XComposeStatus cs;
590 KeySym keysym;
591 WORD vkey = 0, bScan;
592 DWORD dwFlags;
593 static BOOL force_extended = FALSE; /* hack for AltGr translation */
595 int ascii_chars;
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;
637 return;
640 Str[ascii_chars] = '\0';
641 if (TRACE_ON(key)){
642 char *ksname;
644 ksname = TSXKeysymToString(keysym);
645 if (!ksname)
646 ksname = "No Name";
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);
658 if (vkey)
660 switch (vkey & 0xff)
662 case VK_NUMLOCK:
663 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
664 event_time );
665 break;
666 case VK_CAPITAL:
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,
669 event_time );
670 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
671 break;
672 default:
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,
678 event_time );
679 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
680 event_time );
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,
687 event_time );
688 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
689 event_time );
691 /* Not Num nor Caps : end of intermediary states for both. */
692 NumState = FALSE;
693 CapsState = FALSE;
695 bScan = keyc2scan[event->keycode] & 0xFF;
696 TRACE_(key)("bScan = 0x%02x.\n", bScan);
698 dwFlags = 0;
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.
716 static void
717 X11DRV_KEYBOARD_DetectLayout (void)
719 unsigned current, match, mismatch, seq;
720 int score, keyc, i, key, pkey, ok, syms;
721 KeySym keysym;
722 const char (*lkey)[MAIN_LEN][4];
723 unsigned max_seq = 0;
724 int max_score = 0, ismatch = 0;
725 char ckey[4] =
726 {0, 0, 0, 0};
728 syms = keysyms_per_keycode;
729 if (syms > 4) {
730 WARN("%d keysyms per keycode not supported, set to 4", syms);
731 syms = 4;
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);
736 match = 0;
737 mismatch = 0;
738 score = 0;
739 seq = 0;
740 lkey = main_key_tab[current].key;
741 pkey = -1;
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;
749 else {
750 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
753 if (ckey[0]) {
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]))
762 ok++;
763 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
764 ok = -1;
766 if (ok > 0) {
767 score += ok;
768 break;
771 /* count the matches and mismatches */
772 if (ok > 0) {
773 match++;
774 /* and how much the keycode order matches */
775 if (key > pkey) seq++;
776 pkey = key;
777 } else {
778 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
779 ckey[0]);
780 mismatch++;
781 score -= syms;
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;
791 max_score = score;
792 max_seq = seq;
793 ismatch = !mismatch;
796 /* we're done, report results if necessary */
797 if (!ismatch) {
798 FIXME(
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)
814 KeySym *ksp;
815 XModifierKeymap *mmp;
816 KeySym keysym;
817 KeyCode *kcp;
818 XKeyEvent e2;
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 */
829 TSXFree(ksp);
830 mmp = TSXGetModifierMapping(display);
831 kcp = mmp->modifiermap;
832 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
834 int j;
836 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
837 if (*kcp)
839 int k;
841 for (k = 0; k < keysyms_per_keycode; k += 1)
842 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
844 AltGrMask = 1 << i;
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;
866 e2.state = 0;
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);
873 vkey = 0; scan = 0;
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 */
899 vkey = VK_DELETE;
900 scan = 0x153;
902 /* set extended bit when necessary */
903 if (scan & 0x100) vkey |= 0x100;
904 } else if (keysym == 0x20) { /* Spacebar */
905 vkey = VK_SPACE;
906 scan = 0x39;
907 } else {
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;
914 } else {
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;
925 if (ok) break;
927 if (maxval>=0) {
928 /* got it */
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)) {
940 vkey = keysym;
944 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
946 keysym = TSXLookupKeysym(&e2, i);
947 switch (keysym)
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;
963 if (!vkey)
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]) */
967 switch (++OEMvkey)
969 case 0xc1 : OEMvkey=0xdb; break;
970 case 0xe5 : OEMvkey=0xe9; break;
971 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
974 vkey = OEMvkey;
976 if (TRACE_ON(keyboard))
978 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
979 OEMvkey, e2.keycode);
980 TRACE("(");
981 for (i = 0; i < keysyms_per_keycode; i += 1)
983 char *ksname;
985 keysym = TSXLookupKeysym(&e2, i);
986 ksname = TSXKeysymToString(keysym);
987 if (!ksname)
988 ksname = "NoSymbol";
989 DPRINTF( "%lX (%s) ", keysym, ksname);
991 DPRINTF(")\n");
995 keyc2vkey[e2.keycode] = vkey;
996 keyc2scan[e2.keycode] = scan;
997 } /* for */
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]) {
1002 char *ksname;
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)
1027 KeyCode keycode;
1028 KeySym keysym;
1029 int i,index;
1030 int highbyte=0;
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 */
1037 if (!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);
1045 if (keycode)
1047 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1048 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1049 switch (index) {
1050 case -1 :
1051 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1052 case 0 : 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);
1078 switch(wMapType) {
1079 case 0: { /* vkey-code to scan-code */
1080 /* let's do vkey -> keycode -> scan */
1081 int keyc;
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");
1086 return 0; }
1088 case 1: { /* scan-code to vkey-code */
1089 /* let's do scan -> keycode -> vkey */
1090 int keyc;
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");
1095 return 0; }
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 */
1101 XKeyEvent e;
1102 KeySym keysym;
1103 int keyc;
1104 char s[2];
1105 e.display = display;
1106 e.state = 0; /* unshifted */
1108 e.keycode = 0;
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);
1128 if (!e.keycode)
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))
1136 returnMVK (*s);
1138 TRACE("returning no ANSI.\n");
1139 return 0;
1142 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1143 /* left and right */
1144 FIXME(" stub for NT\n");
1145 return 0;
1147 default: /* reserved */
1148 WARN("Unknown wMapType %d !\n", wMapType);
1149 return 0;
1151 return 0;
1154 /***********************************************************************
1155 * X11DRV_KEYBOARD_GetKeyNameText
1157 INT16 X11DRV_KEYBOARD_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1159 int vkey, ansi, scanCode;
1160 KeyCode keyc;
1161 KeySym keys;
1162 char *name;
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)) {
1172 switch (vkey) {
1173 case VK_LSHIFT:
1174 case VK_RSHIFT:
1175 vkey = VK_SHIFT;
1176 break;
1177 case VK_LCONTROL:
1178 case VK_RCONTROL:
1179 vkey = VK_CONTROL;
1180 break;
1181 case VK_LMENU:
1182 case VK_RMENU:
1183 vkey = VK_MENU;
1184 break;
1185 default:
1186 break;
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);
1205 *(lpBuffer+1) = 0;
1206 return 1;
1208 else
1209 return 0;
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)
1226 break;
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);
1236 return 1;
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)
1244 *lpBuffer = 0;
1245 return 0;
1248 /***********************************************************************
1249 * X11DRV_KEYBOARD_MapDeadKeysym
1251 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1253 switch (keysym)
1255 /* symbolic ASCII is the same as defined in rfc1345 */
1256 #ifdef XK_dead_tilde
1257 case XK_dead_tilde :
1258 #endif
1259 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1260 return '~'; /* '? */
1261 #ifdef XK_dead_acute
1262 case XK_dead_acute :
1263 #endif
1264 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1265 return 0xb4; /* '' */
1266 #ifdef XK_dead_circumflex
1267 case XK_dead_circumflex:
1268 #endif
1269 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1270 return '^'; /* '> */
1271 #ifdef XK_dead_grave
1272 case XK_dead_grave :
1273 #endif
1274 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1275 return '`'; /* '! */
1276 #ifdef XK_dead_diaeresis
1277 case XK_dead_diaeresis :
1278 #endif
1279 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1280 return 0xa8; /* ': */
1281 #ifdef XK_dead_cedilla
1282 case XK_dead_cedilla :
1283 return 0xb8; /* ', */
1284 #endif
1285 #ifdef XK_dead_macron
1286 case XK_dead_macron :
1287 return '-'; /* 'm isn't defined on iso-8859-x */
1288 #endif
1289 #ifdef XK_dead_breve
1290 case XK_dead_breve :
1291 return 0xa2; /* '( */
1292 #endif
1293 #ifdef XK_dead_abovedot
1294 case XK_dead_abovedot :
1295 return 0xff; /* '. */
1296 #endif
1297 #ifdef XK_dead_abovering
1298 case XK_dead_abovering :
1299 return '0'; /* '0 isn't defined on iso-8859-x */
1300 #endif
1301 #ifdef XK_dead_doubleacute
1302 case XK_dead_doubleacute :
1303 return 0xbd; /* '" */
1304 #endif
1305 #ifdef XK_dead_caron
1306 case XK_dead_caron :
1307 return 0xb7; /* '< */
1308 #endif
1309 #ifdef XK_dead_ogonek
1310 case XK_dead_ogonek :
1311 return 0xb2; /* '; */
1312 #endif
1313 /* FIXME: I don't know this three.
1314 case XK_dead_iota :
1315 return 'i';
1316 case XK_dead_voiced_sound :
1317 return 'v';
1318 case XK_dead_semivoiced_sound :
1319 return 's';
1322 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1323 return 0;
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:
1334 * Value Meaning
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)
1348 XKeyEvent e;
1349 KeySym keysym;
1350 static XComposeStatus cs;
1351 INT ret;
1352 int keyc;
1354 if (scanCode==0) {
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");
1358 return 0;
1360 if (scanCode & 0x8000)
1362 TRACE("Key UP, doing nothing\n" );
1363 return 0;
1365 e.display = display;
1366 e.keycode = 0;
1367 e.state = 0;
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;
1376 else
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);
1402 if (!e.keycode)
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);
1410 if (ret == 0)
1412 BYTE dead_char = 0;
1414 ((char*)lpChar)[1] = '\0';
1415 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1416 if (dead_char)
1418 *(char*)lpChar = dead_char;
1419 ret = -1;
1421 else
1423 char *ksname;
1425 ksname = TSXKeysymToString(keysym);
1426 if (!ksname)
1427 ksname = "No Name";
1428 if ((keysym >> 8) != 0xff)
1430 ERR("Please report: no char for keysym %04lX (%s) :\n",
1431 keysym, ksname);
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))
1444 *(char*)lpChar = 0;
1445 ret = 0;
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)
1452 *(char*)lpChar = 0;
1453 ret = 0;
1457 TRACE_(key)("ToAscii about to return %d with char %x\n",
1458 ret, *(char*)lpChar);
1459 return ret;
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;
1481 if(bActivate)
1482 keyboard_value.bell_percent = -1;
1483 else
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)
1502 if (len==256) {
1503 int keyc,vkey;
1505 memset(ptr,0,256);
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;
1516 return TRUE;
1518 WARN("whoops, X11DRV_KEYBOARD_GetState got len %ld?\n", len);
1519 return TRUE;
1522 /***********************************************************************
1523 * X11DRV_KEYBOARD_GetDIData
1525 BOOL X11DRV_KEYBOARD_GetDIData(
1526 BYTE *keystate,
1527 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1528 LPDWORD entries, DWORD flags)
1530 int keyc,n,vkey,xentries;
1532 /* FIXME !!! */
1534 if (entries)
1535 xentries = *entries;
1536 else
1537 xentries = 1;
1539 n = 0;
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))
1546 continue;
1547 if (dod) {
1548 /* add an entry */
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 */
1553 n++;
1555 if (!(flags & DIGDD_PEEK))
1556 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1560 if (n) TRACE_(dinput)("%d entries\n",n);
1561 *entries = n;
1563 return TRUE;
1566 /***********************************************************************
1567 * X11DRV_KEYBOARD_GetKeyboardConfig
1569 void X11DRV_KEYBOARD_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1570 XKeyboardState xks;
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;
1588 if (X_mask)
1589 TSXChangeKeyboardControl(display, X_mask, &xkc);