4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
18 #include "ts_xresource.h"
26 #include "wine/winuser16.h"
28 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(keyboard
)
37 DECLARE_DEBUG_CHANNEL(key
)
38 DECLARE_DEBUG_CHANNEL(dinput
)
40 extern BYTE InputKeyStateTable
[256];
42 extern LPBYTE pKeyStateTable
;
44 int min_keycode
, max_keycode
, keysyms_per_keycode
;
45 WORD keyc2vkey
[256], keyc2scan
[256];
47 static int NumLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
48 static int kcControl
, kcAlt
, kcShift
, kcNumLock
, kcCapsLock
; /* keycodes */
50 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
52 /* Keyboard translation tables */
54 static const int main_key_scan
[MAIN_LEN
] =
56 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
57 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
58 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
59 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
60 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
61 0x56 /* the 102nd key (actually to the right of l-shift) */
64 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
66 /* the VK mappings for the main keyboard will be auto-assigned as before,
67 so what we have here is just the character tables */
68 /* order: Normal, Shift, AltGr, Shift-AltGr */
69 /* We recommend you write just what is guaranteed to be correct (i.e. what's
70 written on the keycaps), not the bunch of special characters behind AltGr
71 and Shift-AltGr if it can vary among different X servers */
72 /* Remember that your 102nd key (to the right of l-shift) should be on a
73 separate line, see existing tables */
74 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
75 /* Remember to also add your new table to the layout index table far below! */
77 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
78 static const char main_key_US
[MAIN_LEN
][4] =
80 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
81 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
82 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
83 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
86 /*** United States keyboard layout (phantom key version) */
87 /* (XFree86 reports the <> key even if it's not physically there) */
88 static const char main_key_US_phantom
[MAIN_LEN
][4] =
90 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
91 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
92 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
93 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
94 "<>" /* the phantom key */
97 /*** British keyboard layout */
98 static const char main_key_UK
[MAIN_LEN
][4] =
100 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
101 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
102 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
103 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
107 /*** French keyboard layout (contributed by Eric Pouech) */
108 static const char main_key_FR
[MAIN_LEN
][4] =
110 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
111 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
112 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
113 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
117 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
118 static const char main_key_IS
[MAIN_LEN
][4] =
120 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
121 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
122 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
123 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
127 /*** German keyboard layout (contributed by Ulrich Weigand) */
128 static const char main_key_DE
[MAIN_LEN
][4] =
130 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
131 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
132 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
133 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
137 /*** German keyboard layout without dead keys */
138 static const char main_key_DE_nodead
[MAIN_LEN
][4] =
140 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
141 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
142 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
143 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
147 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
148 static const char main_key_SG
[MAIN_LEN
][4] =
150 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
151 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
152 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
153 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
157 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
158 static const char main_key_SF
[MAIN_LEN
][4] =
160 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
161 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
162 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
163 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
167 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
168 static const char main_key_NO
[MAIN_LEN
][4] =
170 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
171 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
172 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
173 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
177 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
178 static const char main_key_DA
[MAIN_LEN
][4] =
180 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
181 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
182 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
183 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
187 /*** Swedish keyboard layout (contributed by Peter Bortas) */
188 static const char main_key_SE
[MAIN_LEN
][4] =
190 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
191 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
192 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
193 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
197 /*** Canadian French keyboard layout */
198 static const char main_key_CF
[MAIN_LEN
][4] =
200 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
201 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
202 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
203 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
207 /*** Portuguese keyboard layout */
208 static const char main_key_PT
[MAIN_LEN
][4] =
210 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
211 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
212 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
213 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
217 /*** Italian keyboard layout */
218 static const char main_key_IT
[MAIN_LEN
][4] =
220 "\\|","1!1","2\"2","3?3","4$","5%½","6&¾","7/{","8([","9)]","0=}","'?`","i^~",
221 "qQ@","wW","eE","rR?","tT","yY","uU","iI","oOo","pP?","ee[","+*]",
222 "aAae","sS?","dD?","fF","gG","hH","jJ","kK","lL","oc@","a?#","u?",
223 "zZ<","xX>","cC","vV","bB","nN","mM?",",;",".:*","-_","<>|"
226 /*** Finnish keyboard layout */
227 static const char main_key_FI
[MAIN_LEN
][4] =
229 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
230 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
231 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
232 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
236 /*** Russian keyboard layout (contributed by Pavel Roskin) */
237 static const char main_key_RU
[MAIN_LEN
][4] =
239 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
240 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
241 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
242 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
245 /*** Spanish keyboard layout (contributed by José Marcos López) */
246 static const char main_key_ES
[MAIN_LEN
][4] =
248 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
249 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
250 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
251 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
255 /*** Belgian keyboard layout ***/
256 static const char main_key_BE
[MAIN_LEN
][4] =
258 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
259 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
260 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
261 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
265 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
266 static const char main_key_HU
[MAIN_LEN
][4] =
268 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
269 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
270 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
271 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
275 /*** Polish (programmer's) keyboard layout ***/
276 static const char main_key_PL
[MAIN_LEN
][4] =
278 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
279 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
280 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
281 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
285 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
286 static const char main_key_HR_jelly
[MAIN_LEN
][4] =
288 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
289 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
290 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
291 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
295 /*** Croatian keyboard layout ***/
296 static const char main_key_HR
[MAIN_LEN
][4] =
298 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
299 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
300 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
301 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
305 /*** Japanese 106 keyboard layout ***/
306 static const char main_key_JA_jp106
[MAIN_LEN
][4] =
308 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
309 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
310 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
311 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
315 /*** Japanese pc98x1 keyboard layout ***/
316 static const char main_key_JA_pc98x1
[MAIN_LEN
][4] =
318 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
319 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
320 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
321 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
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];
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
},
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
)
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
,
497 BOOL
* State
= (vkey
==VK_NUMLOCK
? &NumState
: &CapsState
);
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. */
505 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey
,pKeyStateTable
[vkey
]);
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
);
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
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];
578 if (!TSXQueryKeymap(display
, keys_return
)) {
579 ERR("Error getting keymap !");
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
));
590 /***********************************************************************
591 * X11DRV_KEYBOARD_HandleEvent
593 * Handle a X key event
595 void X11DRV_KEYBOARD_HandleEvent( WND
*pWnd
, XKeyEvent
*event
)
600 WORD vkey
= 0, bScan
;
602 static BOOL force_extended
= FALSE
; /* hack for AltGr translation */
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
;
649 Str
[ascii_chars
] = '\0';
653 ksname
= TSXKeysymToString(keysym
);
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
);
672 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, event
->type
, event_x
, event_y
,
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
,
679 TRACE("State after : %#.2x\n",pKeyStateTable
[vkey
]);
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
,
688 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, KeyRelease
, event_x
, event_y
,
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
,
697 KEYBOARD_GenerateMsg( VK_CAPITAL
, 0x3A, KeyRelease
, event_x
, event_y
,
700 /* Not Num nor Caps : end of intermediary states for both. */
704 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
705 TRACE_(key
)("bScan = 0x%02x.\n", bScan
);
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.
726 X11DRV_KEYBOARD_DetectLayout (void)
728 unsigned current
, match
, mismatch
, seq
;
729 int score
, keyc
, i
, key
, pkey
, ok
, syms
;
731 const char (*lkey
)[MAIN_LEN
][4];
732 unsigned max_seq
= 0;
733 int max_score
= 0, ismatch
= 0;
737 syms
= keysyms_per_keycode
;
739 WARN("%d keysyms per keycode not supported, set to 4", syms
);
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
);
749 lkey
= main_key_tab
[current
].key
;
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;
759 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
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
]))
772 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[i
]))
780 /* count the matches and mismatches */
783 /* and how much the keycode order matches */
784 if (key
> pkey
) seq
++;
787 TRACE_(key
)("mismatch for keycode %d, character %c\n", keyc
,
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
;
805 /* we're done, report results if necessary */
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)
824 XModifierKeymap
*mmp
;
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 */
839 mmp
= TSXGetModifierMapping(display
);
840 kcp
= mmp
->modifiermap
;
841 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
845 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
850 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
851 if (TSXKeycodeToKeysym(display
, *kcp
, k
) == XK_Mode_switch
)
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
;
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
);
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 */
911 /* set extended bit when necessary */
912 if (scan
& 0x100) vkey
|= 0x100;
913 } else if (keysym
== 0x20) { /* Spacebar */
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;
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
;
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
)) {
953 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
955 keysym
= TSXLookupKeysym(&e2
, i
);
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;
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]) */
978 case 0xc1 : OEMvkey
=0xdb; break;
979 case 0xe5 : OEMvkey
=0xe9; break;
980 case 0xf6 : OEMvkey
=0xf5; WARN("No more OEM vkey available!\n");
985 if (TRACE_ON(keyboard
))
987 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
988 OEMvkey
, e2
.keycode
);
990 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
994 keysym
= TSXLookupKeysym(&e2
, i
);
995 ksname
= TSXKeysymToString(keysym
);
998 DPRINTF( "%lX (%s) ", keysym
, ksname
);
1004 keyc2vkey
[e2
.keycode
] = vkey
;
1005 keyc2scan
[e2
.keycode
] = scan
;
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
]) {
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 /***********************************************************************
1034 WORD
X11DRV_VkKeyScan(CHAR cChar
)
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 */
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
);
1056 for (index
=-1, i
=0; (i
<8) && (index
<0); i
++) /* find shift state */
1057 if (TSXKeycodeToKeysym(display
,keycode
,i
)==keysym
) index
=i
;
1060 WARN("Keysym %lx not found while parsing the keycode table\n",keysym
); 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
);
1088 case 0: { /* vkey-code to scan-code */
1089 /* let's do vkey -> keycode -> scan */
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");
1097 case 1: { /* scan-code to vkey-code */
1098 /* let's do scan -> keycode -> vkey */
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");
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 */
1114 e
.display
= display
;
1115 e
.state
= 0; /* unshifted */
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
);
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
))
1147 TRACE("returning no ANSI.\n");
1151 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1152 /* left and right */
1153 FIXME(" stub for NT\n");
1156 default: /* reserved */
1157 WARN("Unknown wMapType %d !\n", wMapType
);
1163 /***********************************************************************
1164 * X11DRV_GetKeyNameText
1166 INT16
X11DRV_GetKeyNameText(LONG lParam
, LPSTR lpBuffer
, INT16 nSize
)
1168 int vkey
, ansi
, scanCode
;
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)) {
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
);
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
)
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
);
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
)
1257 /***********************************************************************
1258 * X11DRV_KEYBOARD_MapDeadKeysym
1260 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
1264 /* symbolic ASCII is the same as defined in rfc1345 */
1265 #ifdef XK_dead_tilde
1266 case XK_dead_tilde
:
1268 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1269 return '~'; /* '? */
1270 #ifdef XK_dead_acute
1271 case XK_dead_acute
:
1273 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1274 return 0xb4; /* '' */
1275 #ifdef XK_dead_circumflex
1276 case XK_dead_circumflex
:
1278 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1279 return '^'; /* '> */
1280 #ifdef XK_dead_grave
1281 case XK_dead_grave
:
1283 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1284 return '`'; /* '! */
1285 #ifdef XK_dead_diaeresis
1286 case XK_dead_diaeresis
:
1288 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1289 return 0xa8; /* ': */
1290 #ifdef XK_dead_cedilla
1291 case XK_dead_cedilla
:
1292 return 0xb8; /* ', */
1294 #ifdef XK_dead_macron
1295 case XK_dead_macron
:
1296 return '-'; /* 'm isn't defined on iso-8859-x */
1298 #ifdef XK_dead_breve
1299 case XK_dead_breve
:
1300 return 0xa2; /* '( */
1302 #ifdef XK_dead_abovedot
1303 case XK_dead_abovedot
:
1304 return 0xff; /* '. */
1306 #ifdef XK_dead_abovering
1307 case XK_dead_abovering
:
1308 return '0'; /* '0 isn't defined on iso-8859-x */
1310 #ifdef XK_dead_doubleacute
1311 case XK_dead_doubleacute
:
1312 return 0xbd; /* '" */
1314 #ifdef XK_dead_caron
1315 case XK_dead_caron
:
1316 return 0xb7; /* '< */
1318 #ifdef XK_dead_ogonek
1319 case XK_dead_ogonek
:
1320 return 0xb2; /* '; */
1322 /* FIXME: I don't know this three.
1325 case XK_dead_voiced_sound :
1327 case XK_dead_semivoiced_sound :
1331 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
1335 /***********************************************************************
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:
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
)
1359 static XComposeStatus cs
;
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");
1369 if (scanCode
& 0x8000)
1371 TRACE("Key UP, doing nothing\n" );
1374 e
.display
= display
;
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
;
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
);
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
);
1423 ((char*)lpChar
)[1] = '\0';
1424 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
1427 *(char*)lpChar
= dead_char
;
1434 ksname
= TSXKeysymToString(keysym
);
1437 if ((keysym
>> 8) != 0xff)
1439 ERR("Please report: no char for keysym %04lX (%s) :\n",
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
))
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
)
1466 TRACE_(key
)("ToAscii about to return %d with char %x\n",
1467 ret
, *(char*)lpChar
);
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
;
1491 keyboard_value
.bell_percent
= -1;
1493 keyboard_value
.bell_percent
= 0;
1495 TSXChangeKeyboardControl(display
, KBBellPercent
, &keyboard_value
);
1498 /***********************************************************************
1503 TSXBell(display
, 0);
1506 /***********************************************************************
1509 BOOL
X11DRV_GetDIState(DWORD len
, LPVOID ptr
)
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;
1527 WARN("whoops, got len %ld?\n", len
);
1531 /***********************************************************************
1534 BOOL
X11DRV_GetDIData(
1536 DWORD dodsize
, LPDIDEVICEOBJECTDATA dod
,
1537 LPDWORD entries
, DWORD flags
)
1539 int keyc
,n
,vkey
,xentries
;
1544 xentries
= *entries
;
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))
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 */
1564 if (!(flags
& DIGDD_PEEK
))
1565 keystate
[vkey
] = InputKeyStateTable
[vkey
]&0x80;
1569 if (n
) TRACE_(dinput
)("%d entries\n",n
);
1575 /***********************************************************************
1576 * X11DRV_GetKeyboardConfig
1578 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG
*cfg
) {
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
;
1598 TSXChangeKeyboardControl(display
, X_mask
, &xkc
);