Removed to allow CVS to remove the directory.
[wine/gsoc_dplay.git] / windows / x11drv / keyboard.c
blob56d344050ee90af8347165a2b79fc967cbed987d
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 "\\_",
325 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
326 static const char main_key_PT_br[MAIN_LEN][4] =
328 "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
329 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
330 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
331 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
335 /*** Layout table. Add your keyboard mappings to this list */
336 static const struct {
337 WORD lang, ansi_codepage, oem_codepage;
338 const char (*key)[MAIN_LEN][4];
339 } main_key_tab[]={
340 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), 1252, 437, &main_key_US},
341 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), 1252, 437, &main_key_US_phantom},
342 {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK), 1252, 850, &main_key_UK},
343 {MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), 1252, 850, &main_key_DE},
344 {MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), 1252, 850, &main_key_DE_nodead},
345 {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_SWISS), 1252, 850, &main_key_SG},
346 {MAKELANGID(LANG_SWEDISH,SUBLANG_SWEDISH), 1252, 850, &main_key_SE},
347 {MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &main_key_NO},
348 {MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), 1252, 865, &main_key_DA},
349 {MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), 1252, 850, &main_key_FR},
350 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_CANADIAN), 1252, 863, &main_key_CF},
351 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_BELGIAN), 1252, 850, &main_key_BE},
352 {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_SWISS), 1252, 850, &main_key_SF},
353 {MAKELANGID(LANG_WALON,SUBLANG_DEFAULT), 1252, 850, &main_key_BE},
354 {MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), 1252, 860, &main_key_PT},
355 {MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), 1252, 850, &main_key_FI},
356 {MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), 1251, 866, &main_key_RU},
357 {MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), 1252, 850, &main_key_ES},
358 {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), 1252, 850, &main_key_BE},
359 {MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), 1252, 850, &main_key_IT},
360 {MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), 1252, 850, &main_key_IS},
361 {MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), 1252, 850, &main_key_HU},
362 {MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), 1250, 852, &main_key_PL},
363 {MAKELANGID(LANG_CROATIAN,SUBLANG_CROATIAN), 1250, 852, &main_key_HR},
364 {MAKELANGID(LANG_CROATIAN,SUBLANG_CROATIAN), 1250, 852, &main_key_HR_jelly},
365 {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), 932, 932, &main_key_JA_jp106},
366 {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), 932, 932, &main_key_JA_pc98x1},
367 {MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN), 1252, 860, &main_key_PT_br},
369 {0} /* sentinel */
371 static unsigned kbd_layout=0; /* index into above table of layouts */
373 /* maybe more of these scancodes should be extended? */
374 /* extended must be set for ALT_R, CTRL_R,
375 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
376 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
377 /* FIXME should we set extended bit for NumLock ? My
378 * Windows does ... DF */
379 /* Yes, to distinguish based on scan codes, also
380 for PrtScn key ... GA */
382 static const int special_key_vkey[] =
384 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
385 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
386 0, 0, 0, VK_ESCAPE /* FF18 */
388 static const int special_key_scan[] =
390 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
391 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
392 0, 0, 0, 0x01 /* FF18 */
395 static const int cursor_key_vkey[] =
397 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
398 VK_NEXT, VK_END /* FF50 */
400 static const int cursor_key_scan[] =
402 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
405 static const int misc_key_vkey[] =
407 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
408 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
410 static const int misc_key_scan[] =
412 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
413 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
416 static const int keypad_key_vkey[] =
418 0, VK_NUMLOCK, /* FF7E */
419 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
420 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
421 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
422 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
423 VK_INSERT, VK_DELETE, /* FF98 */
424 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
425 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
426 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
427 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
428 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
429 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
431 static const int keypad_key_scan[] =
433 0x138, 0x145, /* FF7E */
434 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
435 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
436 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
437 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
438 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
439 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
440 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
441 0x48, 0x49 /* FFB8 */
444 static const int function_key_vkey[] =
446 VK_F1, VK_F2, /* FFBE */
447 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
448 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
450 static const int function_key_scan[] =
452 0x3B, 0x3C, /* FFBE */
453 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
454 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
457 static const int modifier_key_vkey[] =
459 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
460 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
462 static const int modifier_key_scan[] =
464 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
465 0x38, 0x138, 0x38, 0x138 /* FFE7 */
468 /* Returns the Windows virtual key code associated with the X event <e> */
469 static WORD EVENT_event_to_vkey( XKeyEvent *e)
471 KeySym keysym;
473 TSXLookupString(e, NULL, 0, &keysym, NULL);
475 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
476 && (e->state & NumLockMask))
477 /* Only the Keypad keys 0-9 and . send different keysyms
478 * depending on the NumLock state */
479 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
481 return keyc2vkey[e->keycode];
484 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
486 /**********************************************************************
487 * KEYBOARD_GenerateMsg
489 * Generate Down+Up messages when NumLock or CapsLock is pressed.
491 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
494 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
495 DWORD event_time )
497 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
498 DWORD up, down;
500 if (*State) {
501 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
502 don't treat it. It's from the same key press. Then the state goes to ON.
503 And from there, a 'release' event will switch off the toggle key. */
504 *State=FALSE;
505 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
506 } else
508 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
509 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
510 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
512 if (Evtype!=KeyPress)
514 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
515 KEYBOARD_SendEvent( vkey, scan, down,
516 event_x, event_y, event_time );
517 KEYBOARD_SendEvent( vkey, scan, up,
518 event_x, event_y, event_time );
519 *State=FALSE;
520 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
523 else /* it was OFF */
524 if (Evtype==KeyPress)
526 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
527 KEYBOARD_SendEvent( vkey, scan, down,
528 event_x, event_y, event_time );
529 KEYBOARD_SendEvent( vkey, scan, up,
530 event_x, event_y, event_time );
531 *State=TRUE; /* Goes to intermediary state before going to ON */
532 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
537 /***********************************************************************
538 * KEYBOARD_UpdateOneState
540 * Updates internal state for <vkey>, depending on key <state> under X
543 static void KEYBOARD_UpdateOneState ( int vkey, int state )
545 /* Do something if internal table state != X state for keycode */
546 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
548 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
549 vkey, pKeyStateTable[vkey]);
551 /* Fake key being pressed inside wine */
552 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
553 0, 0, GetTickCount() );
555 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
559 /***********************************************************************
560 * X11DRV_KEYBOARD_UpdateState
562 * Update modifiers state (Ctrl, Alt, Shift)
563 * when window is activated (called by EVENT_FocusIn in event.c)
565 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
566 * from wine to another application and back.
567 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
568 * about them)
570 void X11DRV_KEYBOARD_UpdateState ( void )
572 /* extract a bit from the char[32] bit suite */
573 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
575 char keys_return[32];
577 TRACE("called\n");
578 if (!TSXQueryKeymap(display, keys_return)) {
579 ERR("Error getting keymap !");
580 return;
583 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
584 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
585 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
586 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
587 #undef KeyState
590 /***********************************************************************
591 * X11DRV_KEYBOARD_HandleEvent
593 * Handle a X key event
595 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
597 char Str[24];
598 XComposeStatus cs;
599 KeySym keysym;
600 WORD vkey = 0, bScan;
601 DWORD dwFlags;
602 static BOOL force_extended = FALSE; /* hack for AltGr translation */
604 int ascii_chars;
606 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
607 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
608 DWORD event_time = event->time;
610 /* this allows support for dead keys */
611 if ((event->keycode >> 8) == 0x10)
612 event->keycode=(event->keycode & 0xff);
614 ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
616 TRACE_(key)("EVENT_key : state = %X\n", event->state);
618 /* If XKB extensions is used, the state mask for AltGr will used the group
619 index instead of the modifier mask. The group index is set in bits
620 13-14 of the state field in the XKeyEvent structure. So if AltGr is
621 pressed, look if the group index is diferent than 0. From XKB
622 extension documentation, the group index should for AltGr should
623 be 2 (event->state = 0x2000). It's probably better to not assume a
624 predefined group index and find it dynamically
626 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
627 if ( AltGrState && (event->state & 0x6000) )
628 AltGrMask = event->state & 0x6000;
630 if (keysym == XK_Mode_switch)
632 TRACE_(key)("Alt Gr key event received\n");
633 event->keycode = kcControl; /* Simulate Control */
634 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
636 event->keycode = kcAlt; /* Simulate Alt */
637 force_extended = TRUE;
638 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
639 force_extended = FALSE;
641 /* Here we save the pressed/released state of the AltGr key, to be able to
642 identify the group index associated with AltGr on the next key pressed *
643 see comment above. */
644 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
646 return;
649 Str[ascii_chars] = '\0';
650 if (TRACE_ON(key)){
651 char *ksname;
653 ksname = TSXKeysymToString(keysym);
654 if (!ksname)
655 ksname = "No Name";
656 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
657 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
658 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
661 vkey = EVENT_event_to_vkey(event);
662 if (force_extended) vkey |= 0x100;
664 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
665 event->keycode, vkey);
667 if (vkey)
669 switch (vkey & 0xff)
671 case VK_NUMLOCK:
672 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
673 event_time );
674 break;
675 case VK_CAPITAL:
676 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
677 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
678 event_time );
679 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
680 break;
681 default:
682 /* Adjust the NUMLOCK state if it has been changed outside wine */
683 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
685 TRACE("Adjusting NumLock state. \n");
686 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
687 event_time );
688 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
689 event_time );
691 /* Adjust the CAPSLOCK state if it has been changed outside wine */
692 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
694 TRACE("Adjusting Caps Lock state.\n");
695 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
696 event_time );
697 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
698 event_time );
700 /* Not Num nor Caps : end of intermediary states for both. */
701 NumState = FALSE;
702 CapsState = FALSE;
704 bScan = keyc2scan[event->keycode] & 0xFF;
705 TRACE_(key)("bScan = 0x%02x.\n", bScan);
707 dwFlags = 0;
708 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
709 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
710 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
712 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
713 event_x, event_y, event_time );
718 /**********************************************************************
719 * X11DRV_KEYBOARD_DetectLayout
721 * Called from X11DRV_InitKeyboard
722 * This routine walks through the defined keyboard layouts and selects
723 * whichever matches most closely.
725 static void
726 X11DRV_KEYBOARD_DetectLayout (void)
728 unsigned current, match, mismatch, seq;
729 int score, keyc, i, key, pkey, ok, syms;
730 KeySym keysym;
731 const char (*lkey)[MAIN_LEN][4];
732 unsigned max_seq = 0;
733 int max_score = 0, ismatch = 0;
734 char ckey[4] =
735 {0, 0, 0, 0};
737 syms = keysyms_per_keycode;
738 if (syms > 4) {
739 WARN("%d keysyms per keycode not supported, set to 4", syms);
740 syms = 4;
742 for (current = 0; main_key_tab[current].lang; current++) {
743 TRACE("Attempting to match against layout %04x\n",
744 main_key_tab[current].lang);
745 match = 0;
746 mismatch = 0;
747 score = 0;
748 seq = 0;
749 lkey = main_key_tab[current].key;
750 pkey = -1;
751 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
752 /* get data for keycode from X server */
753 for (i = 0; i < syms; i++) {
754 keysym = TSXKeycodeToKeysym (display, keyc, i);
755 /* Allow both one-byte and two-byte national keysyms */
756 if ((keysym < 0x800) && (keysym != ' '))
757 ckey[i] = keysym & 0xFF;
758 else {
759 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
762 if (ckey[0]) {
763 /* search for a match in layout table */
764 /* right now, we just find an absolute match for defined positions */
765 /* (undefined positions are ignored, so if it's defined as "3#" in */
766 /* the table, it's okay that the X server has "3#£", for example) */
767 /* however, the score will be higher for longer matches */
768 for (key = 0; key < MAIN_LEN; key++) {
769 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
770 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
771 ok++;
772 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
773 ok = -1;
775 if (ok > 0) {
776 score += ok;
777 break;
780 /* count the matches and mismatches */
781 if (ok > 0) {
782 match++;
783 /* and how much the keycode order matches */
784 if (key > pkey) seq++;
785 pkey = key;
786 } else {
787 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
788 ckey[0]);
789 mismatch++;
790 score -= syms;
794 TRACE("matches=%d, mismatches=%d, score=%d\n",
795 match, mismatch, score);
796 if ((score > max_score) ||
797 ((score == max_score) && (seq > max_seq))) {
798 /* best match so far */
799 kbd_layout = current;
800 max_score = score;
801 max_seq = seq;
802 ismatch = !mismatch;
805 /* we're done, report results if necessary */
806 if (!ismatch) {
807 FIXME(
808 "Your keyboard layout was not found!\n"
809 "Instead using closest match (%04x) for scancode mapping.\n"
810 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
811 "to us for inclusion into future Wine releases.\n"
812 "See documentation/keyboard for more information.\n",
813 main_key_tab[kbd_layout].lang);
815 TRACE("detected layout is %04x\n", main_key_tab[kbd_layout].lang);
818 /**********************************************************************
819 * X11DRV_InitKeyboard
821 void X11DRV_InitKeyboard(void)
823 KeySym *ksp;
824 XModifierKeymap *mmp;
825 KeySym keysym;
826 KeyCode *kcp;
827 XKeyEvent e2;
828 WORD scan, vkey, OEMvkey;
829 int keyc, i, keyn, syms;
830 char ckey[4]={0,0,0,0};
831 const char (*lkey)[MAIN_LEN][4];
833 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
834 ksp = TSXGetKeyboardMapping(display, min_keycode,
835 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
836 /* We are only interested in keysyms_per_keycode.
837 There is no need to hold a local copy of the keysyms table */
838 TSXFree(ksp);
839 mmp = TSXGetModifierMapping(display);
840 kcp = mmp->modifiermap;
841 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
843 int j;
845 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
846 if (*kcp)
848 int k;
850 for (k = 0; k < keysyms_per_keycode; k += 1)
851 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
853 AltGrMask = 1 << i;
854 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
856 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
858 NumLockMask = 1 << i;
859 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
863 TSXFreeModifiermap(mmp);
865 /* Detect the keyboard layout */
866 X11DRV_KEYBOARD_DetectLayout();
867 lkey = main_key_tab[kbd_layout].key;
868 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
870 /* Now build two conversion arrays :
871 * keycode -> vkey + scancode + extended
872 * vkey + extended -> keycode */
874 e2.display = display;
875 e2.state = 0;
877 OEMvkey = VK_OEM_7; /* next is available. */
878 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
880 e2.keycode = (KeyCode)keyc;
881 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
882 vkey = 0; scan = 0;
883 if (keysym) /* otherwise, keycode not used */
885 if ((keysym >> 8) == 0xFF) /* non-character key */
887 int key = keysym & 0xff;
889 if (key >= 0x08 && key <= 0x1B) { /* special key */
890 vkey = special_key_vkey[key - 0x08];
891 scan = special_key_scan[key - 0x08];
892 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
893 vkey = cursor_key_vkey[key - 0x50];
894 scan = cursor_key_scan[key - 0x50];
895 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
896 vkey = misc_key_vkey[key - 0x60];
897 scan = misc_key_scan[key - 0x60];
898 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
899 vkey = keypad_key_vkey[key - 0x7E];
900 scan = keypad_key_scan[key - 0x7E];
901 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
902 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
903 scan = function_key_scan[key - 0xBE];
904 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
905 vkey = modifier_key_vkey[key - 0xE1];
906 scan = modifier_key_scan[key - 0xE1];
907 } else if (key == 0xFF) { /* DEL key */
908 vkey = VK_DELETE;
909 scan = 0x153;
911 /* set extended bit when necessary */
912 if (scan & 0x100) vkey |= 0x100;
913 } else if (keysym == 0x20) { /* Spacebar */
914 vkey = VK_SPACE;
915 scan = 0x39;
916 } else {
917 /* we seem to need to search the layout-dependent scancodes */
918 int maxlen=0,maxval=-1,ok;
919 for (i=0; i<syms; i++) {
920 keysym = TSXKeycodeToKeysym(display, keyc, i);
921 if ((keysym<0x800) && (keysym!=' ')) {
922 ckey[i] = keysym & 0xFF;
923 } else {
924 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
927 /* find key with longest match streak */
928 for (keyn=0; keyn<MAIN_LEN; keyn++) {
929 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
930 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
931 if (ok||(i>maxlen)) {
932 maxlen=i; maxval=keyn;
934 if (ok) break;
936 if (maxval>=0) {
937 /* got it */
938 scan = main_key_scan[maxval];
942 /* find a suitable layout-dependent VK code */
943 /* (most Winelib apps ought to be able to work without layout tables!) */
944 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
946 keysym = TSXLookupKeysym(&e2, i);
947 if ((keysym >= VK_0 && keysym <= VK_9)
948 || (keysym >= VK_A && keysym <= VK_Z)) {
949 vkey = keysym;
953 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
955 keysym = TSXLookupKeysym(&e2, i);
956 switch (keysym)
958 case ';': vkey = VK_OEM_1; break;
959 case '/': vkey = VK_OEM_2; break;
960 case '`': vkey = VK_OEM_3; break;
961 case '[': vkey = VK_OEM_4; break;
962 case '\\': vkey = VK_OEM_5; break;
963 case ']': vkey = VK_OEM_6; break;
964 case '\'': vkey = VK_OEM_7; break;
965 case ',': vkey = VK_OEM_COMMA; break;
966 case '.': vkey = VK_OEM_PERIOD; break;
967 case '-': vkey = VK_OEM_MINUS; break;
968 case '+': vkey = VK_OEM_PLUS; break;
972 if (!vkey)
974 /* Others keys: let's assign OEM virtual key codes in the allowed range,
975 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
976 switch (++OEMvkey)
978 case 0xc1 : OEMvkey=0xdb; break;
979 case 0xe5 : OEMvkey=0xe9; break;
980 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
983 vkey = OEMvkey;
985 if (TRACE_ON(keyboard))
987 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
988 OEMvkey, e2.keycode);
989 TRACE("(");
990 for (i = 0; i < keysyms_per_keycode; i += 1)
992 char *ksname;
994 keysym = TSXLookupKeysym(&e2, i);
995 ksname = TSXKeysymToString(keysym);
996 if (!ksname)
997 ksname = "NoSymbol";
998 DPRINTF( "%lX (%s) ", keysym, ksname);
1000 DPRINTF(")\n");
1004 keyc2vkey[e2.keycode] = vkey;
1005 keyc2scan[e2.keycode] = scan;
1006 } /* for */
1008 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1009 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1010 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1011 char *ksname;
1012 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1013 ksname = TSXKeysymToString(keysym);
1014 if (!ksname) ksname = "NoSymbol";
1016 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1018 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1019 keyc2scan[keyc]=scan++;
1022 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1023 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1024 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1025 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1026 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1027 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1028 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1031 /***********************************************************************
1032 * X11DRV_VkKeyScan
1034 WORD X11DRV_VkKeyScan(CHAR cChar)
1036 KeyCode keycode;
1037 KeySym keysym;
1038 int i,index;
1039 int highbyte=0;
1041 /* char->keysym (same for ANSI chars) */
1042 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1043 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1045 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1046 if (!keycode)
1047 { /* It didn't work ... let's try with deadchar code. */
1048 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1051 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1052 cChar,keysym,keysym,keycode);
1054 if (keycode)
1056 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1057 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1058 switch (index) {
1059 case -1 :
1060 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1061 case 0 : break;
1062 case 1 : highbyte = 0x0100; break;
1063 case 2 : highbyte = 0x0600; break;
1064 case 3 : highbyte = 0x0700; break;
1065 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1068 index : 0 adds 0x0000
1069 index : 1 adds 0x0100 (shift)
1070 index : ? adds 0x0200 (ctrl)
1071 index : 2 adds 0x0600 (ctrl+alt)
1072 index : 3 adds 0x0700 (ctrl+alt+shift)
1075 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1076 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1079 /***********************************************************************
1080 * X11DRV_MapVirtualKey
1082 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1084 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1086 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1087 switch(wMapType) {
1088 case 0: { /* vkey-code to scan-code */
1089 /* let's do vkey -> keycode -> scan */
1090 int keyc;
1091 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1092 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1093 returnMVK (keyc2scan[keyc] & 0xFF);
1094 TRACE("returning no scan-code.\n");
1095 return 0; }
1097 case 1: { /* scan-code to vkey-code */
1098 /* let's do scan -> keycode -> vkey */
1099 int keyc;
1100 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1101 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1102 returnMVK (keyc2vkey[keyc] & 0xFF);
1103 TRACE("returning no vkey-code.\n");
1104 return 0; }
1106 case 2: { /* vkey-code to unshifted ANSI code */
1107 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1108 /* My Windows returns 'A'. */
1109 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1110 XKeyEvent e;
1111 KeySym keysym;
1112 int keyc;
1113 char s[2];
1114 e.display = display;
1115 e.state = 0; /* unshifted */
1117 e.keycode = 0;
1118 /* We exit on the first keycode found, to speed up the thing. */
1119 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1120 { /* Find a keycode that could have generated this virtual key */
1121 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1122 { /* We filter the extended bit, we don't know it */
1123 e.keycode = keyc; /* Store it temporarily */
1124 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1125 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1126 state), so set it to 0, we'll find another one */
1131 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1132 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1134 if (wCode==VK_DECIMAL)
1135 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1137 if (!e.keycode)
1139 WARN("Unknown virtual key %X !!! \n", wCode);
1140 return 0; /* whatever */
1142 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1144 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1145 returnMVK (*s);
1147 TRACE("returning no ANSI.\n");
1148 return 0;
1151 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1152 /* left and right */
1153 FIXME(" stub for NT\n");
1154 return 0;
1156 default: /* reserved */
1157 WARN("Unknown wMapType %d !\n", wMapType);
1158 return 0;
1160 return 0;
1163 /***********************************************************************
1164 * X11DRV_GetKeyNameText
1166 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1168 int vkey, ansi, scanCode;
1169 KeyCode keyc;
1170 KeySym keys;
1171 char *name;
1173 scanCode = lParam >> 16;
1174 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1176 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1177 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1179 /* handle "don't care" bit (0x02000000) */
1180 if (!(lParam & 0x02000000)) {
1181 switch (vkey) {
1182 case VK_LSHIFT:
1183 case VK_RSHIFT:
1184 vkey = VK_SHIFT;
1185 break;
1186 case VK_LCONTROL:
1187 case VK_RCONTROL:
1188 vkey = VK_CONTROL;
1189 break;
1190 case VK_LMENU:
1191 case VK_RMENU:
1192 vkey = VK_MENU;
1193 break;
1194 default:
1195 break;
1199 ansi = X11DRV_MapVirtualKey(vkey, 2);
1200 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1202 /* first get the name of the "regular" keys which is the Upper case
1203 value of the keycap imprint. */
1204 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1205 (scanCode != 0x137) && /* PrtScn */
1206 (scanCode != 0x135) && /* numpad / */
1207 (scanCode != 0x37 ) && /* numpad * */
1208 (scanCode != 0x4a ) && /* numpad - */
1209 (scanCode != 0x4e ) ) /* numpad + */
1211 if ((nSize >= 2) && lpBuffer)
1213 *lpBuffer = toupper((char)ansi);
1214 *(lpBuffer+1) = 0;
1215 return 1;
1217 else
1218 return 0;
1221 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1222 without "extended-key" flag. However Wine generates scancode
1223 *with* "extended-key" flag. Seems to occur *only* for the
1224 function keys. Soooo.. We will leave the table alone and
1225 fudge the lookup here till the other part is found and fixed!!! */
1227 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1228 (scanCode == 0x157) || (scanCode == 0x158))
1229 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1231 /* let's do scancode -> keycode -> keysym -> String */
1233 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1234 if ((keyc2scan[keyc]) == scanCode)
1235 break;
1236 if (keyc <= max_keycode)
1238 keys = TSXKeycodeToKeysym(display, keyc, 0);
1239 name = TSXKeysymToString(keys);
1240 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1241 scanCode, keyc, (int)keys, name);
1242 if (lpBuffer && nSize && name)
1244 lstrcpynA(lpBuffer, name, nSize);
1245 return 1;
1249 /* Finally issue FIXME for unknown keys */
1251 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1252 if (lpBuffer && nSize)
1253 *lpBuffer = 0;
1254 return 0;
1257 /***********************************************************************
1258 * X11DRV_KEYBOARD_MapDeadKeysym
1260 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1262 switch (keysym)
1264 /* symbolic ASCII is the same as defined in rfc1345 */
1265 #ifdef XK_dead_tilde
1266 case XK_dead_tilde :
1267 #endif
1268 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1269 return '~'; /* '? */
1270 #ifdef XK_dead_acute
1271 case XK_dead_acute :
1272 #endif
1273 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1274 return 0xb4; /* '' */
1275 #ifdef XK_dead_circumflex
1276 case XK_dead_circumflex:
1277 #endif
1278 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1279 return '^'; /* '> */
1280 #ifdef XK_dead_grave
1281 case XK_dead_grave :
1282 #endif
1283 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1284 return '`'; /* '! */
1285 #ifdef XK_dead_diaeresis
1286 case XK_dead_diaeresis :
1287 #endif
1288 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1289 return 0xa8; /* ': */
1290 #ifdef XK_dead_cedilla
1291 case XK_dead_cedilla :
1292 return 0xb8; /* ', */
1293 #endif
1294 #ifdef XK_dead_macron
1295 case XK_dead_macron :
1296 return '-'; /* 'm isn't defined on iso-8859-x */
1297 #endif
1298 #ifdef XK_dead_breve
1299 case XK_dead_breve :
1300 return 0xa2; /* '( */
1301 #endif
1302 #ifdef XK_dead_abovedot
1303 case XK_dead_abovedot :
1304 return 0xff; /* '. */
1305 #endif
1306 #ifdef XK_dead_abovering
1307 case XK_dead_abovering :
1308 return '0'; /* '0 isn't defined on iso-8859-x */
1309 #endif
1310 #ifdef XK_dead_doubleacute
1311 case XK_dead_doubleacute :
1312 return 0xbd; /* '" */
1313 #endif
1314 #ifdef XK_dead_caron
1315 case XK_dead_caron :
1316 return 0xb7; /* '< */
1317 #endif
1318 #ifdef XK_dead_ogonek
1319 case XK_dead_ogonek :
1320 return 0xb2; /* '; */
1321 #endif
1322 /* FIXME: I don't know this three.
1323 case XK_dead_iota :
1324 return 'i';
1325 case XK_dead_voiced_sound :
1326 return 'v';
1327 case XK_dead_semivoiced_sound :
1328 return 's';
1331 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1332 return 0;
1335 /***********************************************************************
1336 * X11DRV_ToAscii
1338 * The ToAscii function translates the specified virtual-key code and keyboard
1339 * state to the corresponding Windows character or characters.
1341 * If the specified key is a dead key, the return value is negative. Otherwise,
1342 * it is one of the following values:
1343 * Value Meaning
1344 * 0 The specified virtual key has no translation for the current state of the keyboard.
1345 * 1 One Windows character was copied to the buffer.
1346 * 2 Two characters were copied to the buffer. This usually happens when a
1347 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1348 * be composed with the specified virtual key to form a single character.
1350 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1353 INT16 X11DRV_ToAscii(
1354 UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1355 LPVOID lpChar, UINT16 flags)
1357 XKeyEvent e;
1358 KeySym keysym;
1359 static XComposeStatus cs;
1360 INT ret;
1361 int keyc;
1363 if (scanCode==0) {
1364 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1365 event is generated by windows. Just ignore it. */
1366 TRACE("scanCode=0, doing nothing\n");
1367 return 0;
1369 if (scanCode & 0x8000)
1371 TRACE("Key UP, doing nothing\n" );
1372 return 0;
1374 e.display = display;
1375 e.keycode = 0;
1376 e.state = 0;
1377 if (lpKeyState[VK_SHIFT] & 0x80)
1378 e.state |= ShiftMask;
1379 if (lpKeyState[VK_CAPITAL] & 0x01)
1380 e.state |= LockMask;
1381 if (lpKeyState[VK_CONTROL] & 0x80)
1383 if (lpKeyState[VK_MENU] & 0x80)
1384 e.state |= AltGrMask;
1385 else
1386 e.state |= ControlMask;
1388 if (lpKeyState[VK_NUMLOCK] & 0x01)
1389 e.state |= NumLockMask;
1390 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1391 virtKey, scanCode, e.state);
1392 /* We exit on the first keycode found, to speed up the thing. */
1393 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1394 { /* Find a keycode that could have generated this virtual key */
1395 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1396 { /* We filter the extended bit, we don't know it */
1397 e.keycode = keyc; /* Store it temporarily */
1398 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1399 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1400 state), so set it to 0, we'll find another one */
1405 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1406 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1408 if (virtKey==VK_DECIMAL)
1409 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1411 if (!e.keycode)
1413 WARN("Unknown virtual key %X !!! \n",virtKey);
1414 return virtKey; /* whatever */
1416 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1418 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1419 if (ret == 0)
1421 BYTE dead_char = 0;
1423 ((char*)lpChar)[1] = '\0';
1424 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1425 if (dead_char)
1427 *(char*)lpChar = dead_char;
1428 ret = -1;
1430 else
1432 char *ksname;
1434 ksname = TSXKeysymToString(keysym);
1435 if (!ksname)
1436 ksname = "No Name";
1437 if ((keysym >> 8) != 0xff)
1439 ERR("Please report: no char for keysym %04lX (%s) :\n",
1440 keysym, ksname);
1441 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1442 virtKey, scanCode, e.keycode, e.state);
1446 else { /* ret = 1 */
1447 /* We have a special case to handle : Shift + arrow, shift + home, ...
1448 X returns a char for it, but Windows doesn't. Let's eat it. */
1449 if (!(lpKeyState[VK_NUMLOCK] & 0x01) /* NumLock is off */
1450 && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1451 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1453 *(char*)lpChar = 0;
1454 ret = 0;
1457 /* We have another special case for delete key (XK_Delete) on an
1458 extended keyboard. X returns a char for it, but Windows doesn't */
1459 if (keysym == XK_Delete)
1461 *(char*)lpChar = 0;
1462 ret = 0;
1466 TRACE_(key)("ToAscii about to return %d with char %x\n",
1467 ret, *(char*)lpChar);
1468 return ret;
1471 /***********************************************************************
1472 * X11DRV_GetBeepActive
1474 BOOL X11DRV_GetBeepActive()
1476 XKeyboardState keyboard_state;
1478 TSXGetKeyboardControl(display, &keyboard_state);
1480 return keyboard_state.bell_percent != 0;
1483 /***********************************************************************
1484 * X11DRV_SetBeepActive
1486 void X11DRV_SetBeepActive(BOOL bActivate)
1488 XKeyboardControl keyboard_value;
1490 if(bActivate)
1491 keyboard_value.bell_percent = -1;
1492 else
1493 keyboard_value.bell_percent = 0;
1495 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1498 /***********************************************************************
1499 * X11DRV_Beep
1501 void X11DRV_Beep()
1503 TSXBell(display, 0);
1506 /***********************************************************************
1507 * X11DRV_GetDIState
1509 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1511 if (len==256) {
1512 int keyc,vkey;
1514 memset(ptr,0,256);
1515 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1517 /* X keycode to virtual key */
1518 vkey = keyc2vkey[keyc] & 0xFF;
1519 /* The windows scancode is keyc-min_keycode */
1520 if (InputKeyStateTable[vkey]&0x80) {
1521 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1522 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1525 return TRUE;
1527 WARN("whoops, got len %ld?\n", len);
1528 return TRUE;
1531 /***********************************************************************
1532 * X11DRV_GetDIData
1534 BOOL X11DRV_GetDIData(
1535 BYTE *keystate,
1536 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1537 LPDWORD entries, DWORD flags)
1539 int keyc,n,vkey,xentries;
1541 /* FIXME !!! */
1543 if (entries)
1544 xentries = *entries;
1545 else
1546 xentries = 1;
1548 n = 0;
1550 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1552 /* X keycode to virtual key */
1553 vkey = keyc2vkey[keyc] & 0xFF;
1554 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1555 continue;
1556 if (dod) {
1557 /* add an entry */
1558 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1559 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1560 dod[n].dwTimeStamp = 0; /* umm */
1561 dod[n].dwSequence = 0; /* umm */
1562 n++;
1564 if (!(flags & DIGDD_PEEK))
1565 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1569 if (n) TRACE_(dinput)("%d entries\n",n);
1570 *entries = n;
1572 return TRUE;
1575 /***********************************************************************
1576 * X11DRV_GetKeyboardConfig
1578 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1579 XKeyboardState xks;
1581 /* For the moment, only get the auto-repeat mode */
1582 TSXGetKeyboardControl(display, &xks);
1583 cfg->auto_repeat = xks.global_auto_repeat;
1586 /***********************************************************************
1587 * X11DRV_SetKeyboardConfig
1589 extern void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1590 XKeyboardControl xkc;
1591 unsigned long X_mask = 0;
1593 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1594 X_mask |= KBAutoRepeatMode;
1595 xkc.auto_repeat_mode = cfg->auto_repeat;
1597 if (X_mask)
1598 TSXChangeKeyboardControl(display, X_mask, &xkc);