MapVirtualKey actually returns uppercase keys in Windows.
[wine.git] / dlls / x11drv / keyboard.c
blobec3af57a452d6c247eb5777f5101cead1893feee
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config.h"
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include "ts_xlib.h"
32 #include "ts_xresource.h"
33 #include "ts_xutil.h"
34 #ifdef HAVE_XKB
35 #include <X11/XKBlib.h>
36 #endif
38 #include <ctype.h>
39 #include <string.h>
41 #include "windef.h"
42 #include "wingdi.h"
43 #include "wine/winuser16.h"
44 #include "winnls.h"
45 #include "win.h"
46 #include "x11drv.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
50 WINE_DECLARE_DEBUG_CHANNEL(key);
51 WINE_DECLARE_DEBUG_CHANNEL(dinput);
53 int min_keycode, max_keycode, keysyms_per_keycode;
54 WORD keyc2vkey[256], keyc2scan[256];
56 static LPBYTE pKeyStateTable;
57 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
58 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
59 #ifdef HAVE_XKB
60 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
61 #endif
63 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
65 /* Keyboard translation tables */
66 #define MAIN_LEN 48
67 static const WORD main_key_scan_qwerty[MAIN_LEN] =
69 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
70 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
71 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
72 /* q w e r t y u i o p [ ] */
73 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
74 /* a s d f g h j k l ; ' \ */
75 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
76 /* z x c v b n m , . / */
77 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
78 0x56 /* the 102nd key (actually to the right of l-shift) */
81 static const WORD main_key_scan_dvorak[MAIN_LEN] =
83 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
84 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
85 /* ' , . p y f g c r l / = */
86 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
87 /* a o e u i d h t n s - \ */
88 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
89 /* ; q j k x b m w v z */
90 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
91 0x56 /* the 102nd key (actually to the right of l-shift) */
94 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
96 /* NOTE: this layout must concur with the scan codes layout above */
97 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
98 VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
99 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_7,VK_OEM_5,
100 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
101 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
104 static const WORD main_key_vkey_azerty[MAIN_LEN] =
106 /* NOTE: this layout must concur with the scan codes layout above */
107 VK_OEM_7,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_PLUS,
108 VK_A,VK_Z,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_6,VK_OEM_1,
109 VK_Q,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_M,VK_OEM_3,VK_OEM_5,
110 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
111 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
114 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
116 /* NOTE: this layout must concur with the scan codes layout above */
117 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_6,
118 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,VK_P,VK_Y,VK_F,VK_G,VK_C,VK_R,VK_L,VK_OEM_2,VK_OEM_PLUS,
119 VK_A,VK_O,VK_E,VK_U,VK_I,VK_D,VK_H,VK_T,VK_N,VK_S,VK_OEM_MINUS,VK_OEM_5,
120 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
121 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
124 /* FIXME: add other layouts, such as German QWERTZ */
126 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
128 /* the VK mappings for the main keyboard will be auto-assigned as before,
129 so what we have here is just the character tables */
130 /* order: Normal, Shift, AltGr, Shift-AltGr */
131 /* We recommend you write just what is guaranteed to be correct (i.e. what's
132 written on the keycaps), not the bunch of special characters behind AltGr
133 and Shift-AltGr if it can vary among different X servers */
134 /* Remember that your 102nd key (to the right of l-shift) should be on a
135 separate line, see existing tables */
136 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
137 /* Remember to also add your new table to the layout index table far below! */
139 /*** German Logitech Desktop Pro keyboard layout */
140 static const char main_key_DE_logitech[MAIN_LEN][4] =
142 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
143 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
144 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
145 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
146 "<>|"
149 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
150 static const char main_key_US[MAIN_LEN][4] =
152 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
153 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
154 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
155 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
158 /*** United States keyboard layout (phantom key version) */
159 /* (XFree86 reports the <> key even if it's not physically there) */
160 static const char main_key_US_phantom[MAIN_LEN][4] =
162 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
163 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
164 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
165 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
166 "<>" /* the phantom key */
169 /*** United States keyboard layout (dvorak version) */
170 static const char main_key_US_dvorak[MAIN_LEN][4] =
172 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
173 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
174 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
175 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
178 /*** British keyboard layout */
179 static const char main_key_UK[MAIN_LEN][4] =
181 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
182 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
183 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
184 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
185 "\\|"
188 /*** French keyboard layout (contributed by Eric Pouech) */
189 static const char main_key_FR[MAIN_LEN][4] =
191 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
192 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
193 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
194 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
195 "<>"
198 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
199 static const char main_key_IS[MAIN_LEN][4] =
201 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
202 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
203 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
204 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
205 "<>|"
208 /*** German keyboard layout (contributed by Ulrich Weigand) */
209 static const char main_key_DE[MAIN_LEN][4] =
211 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
212 "qQ@","wW","eE€","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
213 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
214 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
215 "<>|"
218 /*** German keyboard layout without dead keys */
219 static const char main_key_DE_nodead[MAIN_LEN][4] =
221 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
222 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
223 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
224 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
225 "<>"
228 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
229 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
231 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
232 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
233 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
234 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
237 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
238 static const char main_key_SG[MAIN_LEN][4] =
240 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
241 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
242 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
243 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
244 "<>\\"
247 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
248 static const char main_key_SF[MAIN_LEN][4] =
250 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
251 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
252 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
253 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
254 "<>\\"
257 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
258 static const char main_key_NO[MAIN_LEN][4] =
260 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
261 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
262 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
263 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
264 "<>"
267 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
268 static const char main_key_DA[MAIN_LEN][4] =
270 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
271 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
272 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
273 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
274 "<>\\"
277 /*** Swedish keyboard layout (contributed by Peter Bortas) */
278 static const char main_key_SE[MAIN_LEN][4] =
280 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
281 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
282 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
283 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
284 "<>|"
287 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
288 static const char main_key_ET[MAIN_LEN][4] =
290 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
291 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
292 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
293 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
294 "<>|"
297 /*** Canadian French keyboard layout */
298 static const char main_key_CF[MAIN_LEN][4] =
300 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
301 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
302 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
303 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
304 "«»°"
307 /*** Portuguese keyboard layout */
308 static const char main_key_PT[MAIN_LEN][4] =
310 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
311 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
312 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
313 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
314 "<>"
317 /*** Italian keyboard layout */
318 static const char main_key_IT[MAIN_LEN][4] =
320 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
321 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
322 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
323 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
324 "<>|"
327 /*** Finnish keyboard layout */
328 static const char main_key_FI[MAIN_LEN][4] =
330 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
331 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
332 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
333 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
334 "<>|"
337 /*** Russian keyboard layout (contributed by Pavel Roskin) */
338 static const char main_key_RU[MAIN_LEN][4] =
340 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
341 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
342 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
343 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
346 /*** Russian keyboard layout (phantom key version) */
347 static const char main_key_RU_phantom[MAIN_LEN][4] =
349 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
350 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
351 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
352 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
353 "<>" /* the phantom key */
356 /*** Russian keyboard layout KOI8-R */
357 static const char main_key_RU_koi8r[MAIN_LEN][4] =
359 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
360 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
361 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
362 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
363 "<>" /* the phantom key */
366 /*** Ukrainian keyboard layout KOI8-U */
367 static const char main_key_UA[MAIN_LEN][4] =
369 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
370 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
371 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
372 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
373 "<>" /* the phantom key */
376 /*** Spanish keyboard layout (contributed by José Marcos López) */
377 static const char main_key_ES[MAIN_LEN][4] =
379 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
380 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
381 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
382 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
383 "<>"
386 /*** Belgian keyboard layout ***/
387 static const char main_key_BE[MAIN_LEN][4] =
389 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
390 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
391 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
392 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
393 "<>\\"
396 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
397 static const char main_key_HU[MAIN_LEN][4] =
399 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
400 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
401 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
402 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
403 "íÍ<"
406 /*** Polish (programmer's) keyboard layout ***/
407 static const char main_key_PL[MAIN_LEN][4] =
409 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
410 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
411 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
412 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
413 "<>|"
416 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
417 static const char main_key_HR_jelly[MAIN_LEN][4] =
419 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
420 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
421 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
422 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
423 "<>|"
426 /*** Croatian keyboard layout ***/
427 static const char main_key_HR[MAIN_LEN][4] =
429 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
430 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
431 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
432 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
433 "<>"
436 /*** Japanese 106 keyboard layout ***/
437 static const char main_key_JA_jp106[MAIN_LEN][4] =
439 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
440 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
441 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
442 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
443 "\\_",
446 /*** Japanese pc98x1 keyboard layout ***/
447 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
449 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
450 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
451 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
452 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
453 "\\_",
456 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
457 static const char main_key_PT_br[MAIN_LEN][4] =
459 "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
460 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
461 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
462 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
465 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
466 static const char main_key_US_intl[MAIN_LEN][4] =
468 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
469 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
470 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
471 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
474 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
475 - dead_abovering replaced with degree - no symbol in iso8859-2
476 - brokenbar replaced with bar */
477 static const char main_key_SK[MAIN_LEN][4] =
479 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0)","=%","",
480 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/÷","ä(×",
481 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","ò)¤",
482 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
483 "<>\\|"
486 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
487 static const char main_key_SK_prog[MAIN_LEN][4] =
489 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
490 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
491 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
492 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
493 "<>"
496 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
497 static const char main_key_CS[MAIN_LEN][4] =
499 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
500 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
501 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
502 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
503 "<>\\|"
506 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
507 static const char main_key_LA[MAIN_LEN][4] =
509 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
510 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
511 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
512 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
513 "<>"
516 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
517 static const char main_key_LT_B[MAIN_LEN][4] =
519 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
520 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
521 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
522 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
525 /*** Turkish keyboard Layout */
526 static const char main_key_TK[MAIN_LEN][4] =
528 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
529 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
530 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
531 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
534 /*** Israeli keyboard layout */
535 static const char main_key_IL[MAIN_LEN][4] =
537 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
538 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
539 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
540 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
543 /*** VNC keyboard layout */
544 static const WORD main_key_scan_vnc[MAIN_LEN] =
546 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
547 0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C,
548 0x56
551 static const WORD main_key_vkey_vnc[MAIN_LEN] =
553 VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_4,VK_OEM_6,VK_OEM_1,VK_OEM_7,VK_OEM_3,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_5,
554 VK_A,VK_B,VK_C,VK_D,VK_E,VK_F,VK_G,VK_H,VK_I,VK_J,VK_K,VK_L,VK_M,VK_N,VK_O,VK_P,VK_Q,VK_R,VK_S,VK_T,VK_U,VK_V,VK_W,VK_X,VK_Y,VK_Z,
555 VK_OEM_102
558 static const char main_key_vnc[MAIN_LEN][4] =
560 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
561 "aA","bB","cC","dD","eE","fF","gG","hH","iI","jJ","kK","lL","mM","nN","oO","pP","qQ","rR","sS","tT","uU","vV","wW","xX","yY","zZ"
564 /*** Layout table. Add your keyboard mappings to this list */
565 static const struct {
566 const char *comment;
567 const UINT layout_cp; /* Code page for this layout */
568 const char (*key)[MAIN_LEN][4];
569 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
570 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
571 } main_key_tab[]={
572 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
573 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
574 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
575 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
576 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
577 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
578 {"German keyboard layout for logitech desktop pro", 28591, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
579 {"German keyboard layout without dead keys 105", 28591, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
580 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
581 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
582 {"Estonian keyboard layout", 28591, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
583 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
584 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
585 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
586 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
587 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
588 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
589 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
590 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
591 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
592 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
593 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
594 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
595 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
596 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
597 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
598 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
599 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
600 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
601 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
602 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
603 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
604 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
605 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
606 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
607 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
608 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
609 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
610 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
611 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
612 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
613 {"VNC keyboard layout", 28591, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
615 {NULL, 0, NULL, NULL, NULL} /* sentinel */
617 static unsigned kbd_layout=0; /* index into above table of layouts */
619 /* maybe more of these scancodes should be extended? */
620 /* extended must be set for ALT_R, CTRL_R,
621 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
622 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
623 /* FIXME should we set extended bit for NumLock ? My
624 * Windows does ... DF */
625 /* Yes, to distinguish based on scan codes, also
626 for PrtScn key ... GA */
628 static const WORD nonchar_key_vkey[256] =
630 /* unused */
631 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
632 /* special keys */
633 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
634 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
635 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
636 /* unused */
637 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
638 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
639 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
640 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
641 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
642 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
643 /* cursor keys */
644 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
645 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
646 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
647 /* misc keys */
648 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
649 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
650 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
651 /* keypad keys */
652 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
653 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
654 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
655 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
656 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
657 VK_END, 0, VK_INSERT, VK_DELETE,
658 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
659 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
660 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
661 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
662 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
663 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
664 /* function keys */
665 VK_F1, VK_F2,
666 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
667 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
668 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
669 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
670 /* modifier keys */
671 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
672 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
673 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
674 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
675 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
678 static const WORD nonchar_key_scan[256] =
680 /* unused */
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
682 /* special keys */
683 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
684 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
685 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
686 /* unused */
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
693 /* cursor keys */
694 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
695 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
696 /* misc keys */
697 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
698 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
700 /* keypad keys */
701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
703 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
704 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
705 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
707 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
708 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
709 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
710 /* function keys */
711 0x3B, 0x3C,
712 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
713 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
716 /* modifier keys */
717 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
718 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
724 /* Returns the Windows virtual key code associated with the X event <e> */
725 static WORD EVENT_event_to_vkey( XKeyEvent *e)
727 KeySym keysym;
729 TSXLookupString(e, NULL, 0, &keysym, NULL);
731 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
732 && (e->state & NumLockMask))
733 /* Only the Keypad keys 0-9 and . send different keysyms
734 * depending on the NumLock state */
735 return nonchar_key_vkey[keysym & 0xFF];
737 return keyc2vkey[e->keycode];
740 static BOOL NumState=FALSE, CapsState=FALSE;
743 /***********************************************************************
744 * send_keyboard_input
746 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
748 INPUT input;
750 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
751 input.u.ki.wVk = wVk;
752 input.u.ki.wScan = wScan;
753 input.u.ki.dwFlags = dwFlags;
754 input.u.ki.time = time;
755 input.u.ki.dwExtraInfo = 0;
756 SendInput( 1, &input, sizeof(input) );
760 /**********************************************************************
761 * KEYBOARD_GenerateMsg
763 * Generate Down+Up messages when NumLock or CapsLock is pressed.
765 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
768 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
770 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
771 DWORD up, down;
773 if (*State) {
774 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
775 don't treat it. It's from the same key press. Then the state goes to ON.
776 And from there, a 'release' event will switch off the toggle key. */
777 *State=FALSE;
778 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
779 } else
781 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
782 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
783 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
785 if (Evtype!=KeyPress)
787 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
788 send_keyboard_input( vkey, scan, down, event_time );
789 send_keyboard_input( vkey, scan, up, event_time );
790 *State=FALSE;
791 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
794 else /* it was OFF */
795 if (Evtype==KeyPress)
797 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
798 send_keyboard_input( vkey, scan, down, event_time );
799 send_keyboard_input( vkey, scan, up, event_time );
800 *State=TRUE; /* Goes to intermediary state before going to ON */
801 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
806 /***********************************************************************
807 * KEYBOARD_UpdateOneState
809 * Updates internal state for <vkey>, depending on key <state> under X
812 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
814 /* Do something if internal table state != X state for keycode */
815 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
817 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
818 vkey, pKeyStateTable[vkey]);
820 /* Fake key being pressed inside wine */
821 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
823 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
827 /***********************************************************************
828 * X11DRV_KeymapNotify
830 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
832 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
833 * from wine to another application and back.
834 * Toggle keys are handled in HandleEvent.
836 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
838 int i, j, alt, control, shift;
839 DWORD time = GetCurrentTime();
841 alt = control = shift = 0;
842 for (i = 0; i < 32; i++)
844 if (!event->key_vector[i]) continue;
845 for (j = 0; j < 8; j++)
847 if (!(event->key_vector[i] & (1<<j))) continue;
848 switch(keyc2vkey[(i * 8) + j] & 0xff)
850 case VK_MENU: alt = 1; break;
851 case VK_CONTROL: control = 1; break;
852 case VK_SHIFT: shift = 1; break;
856 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
857 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
858 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
861 /***********************************************************************
862 * X11DRV_KeyEvent
864 * Handle a X key event
866 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
868 char Str[24];
869 KeySym keysym;
870 WORD vkey = 0, bScan;
871 DWORD dwFlags;
872 int ascii_chars;
874 DWORD event_time = event->time - X11DRV_server_startticks;
876 /* this allows support for dead keys */
877 if ((event->keycode >> 8) == 0x10)
878 event->keycode=(event->keycode & 0xff);
880 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
882 /* Ignore some unwanted events */
883 if (keysym == XK_ISO_Prev_Group ||
884 keysym == XK_ISO_Next_Group ||
885 keysym == XK_Mode_switch)
887 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
888 return;
891 TRACE_(key)("state = %X\n", event->state);
893 /* If XKB extensions is used, the state mask for AltGr will used the group
894 index instead of the modifier mask. The group index is set in bits
895 13-14 of the state field in the XKeyEvent structure. So if AltGr is
896 pressed, look if the group index is diferent than 0. From XKB
897 extension documentation, the group index should for AltGr should
898 be 2 (event->state = 0x2000). It's probably better to not assume a
899 predefined group index and find it dynamically
901 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
902 AltGrMask = event->state & 0x6000;
904 Str[ascii_chars] = '\0';
905 if (TRACE_ON(key)){
906 char *ksname;
908 ksname = TSXKeysymToString(keysym);
909 if (!ksname)
910 ksname = "No Name";
911 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
912 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
913 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
916 vkey = EVENT_event_to_vkey(event);
918 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
919 event->keycode, vkey);
921 if (vkey)
923 switch (vkey & 0xff)
925 case VK_NUMLOCK:
926 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
927 break;
928 case VK_CAPITAL:
929 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
930 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
931 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
932 break;
933 default:
934 /* Adjust the NUMLOCK state if it has been changed outside wine */
935 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
937 TRACE("Adjusting NumLock state. \n");
938 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
939 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
941 /* Adjust the CAPSLOCK state if it has been changed outside wine */
942 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
944 TRACE("Adjusting Caps Lock state.\n");
945 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
946 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
948 /* Not Num nor Caps : end of intermediary states for both. */
949 NumState = FALSE;
950 CapsState = FALSE;
952 bScan = keyc2scan[event->keycode] & 0xFF;
953 TRACE_(key)("bScan = 0x%02x.\n", bScan);
955 dwFlags = 0;
956 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
957 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
959 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
964 /**********************************************************************
965 * X11DRV_KEYBOARD_DetectLayout
967 * Called from X11DRV_InitKeyboard
968 * This routine walks through the defined keyboard layouts and selects
969 * whichever matches most closely.
971 static void
972 X11DRV_KEYBOARD_DetectLayout (void)
974 Display *display = thread_display();
975 unsigned current, match, mismatch, seq;
976 int score, keyc, i, key, pkey, ok, syms;
977 KeySym keysym;
978 const char (*lkey)[MAIN_LEN][4];
979 unsigned max_seq = 0;
980 int max_score = 0, ismatch = 0;
981 char ckey[4] =
982 {0, 0, 0, 0};
984 syms = keysyms_per_keycode;
985 if (syms > 4) {
986 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
987 syms = 4;
989 for (current = 0; main_key_tab[current].comment; current++) {
990 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
991 match = 0;
992 mismatch = 0;
993 score = 0;
994 seq = 0;
995 lkey = main_key_tab[current].key;
996 pkey = -1;
997 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
998 /* get data for keycode from X server */
999 for (i = 0; i < syms; i++) {
1000 keysym = TSXKeycodeToKeysym (display, keyc, i);
1001 /* Allow both one-byte and two-byte national keysyms */
1002 if ((keysym < 0x8000) && (keysym != ' '))
1003 ckey[i] = keysym & 0xFF;
1004 else {
1005 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1008 if (ckey[0]) {
1009 /* search for a match in layout table */
1010 /* right now, we just find an absolute match for defined positions */
1011 /* (undefined positions are ignored, so if it's defined as "3#" in */
1012 /* the table, it's okay that the X server has "3#£", for example) */
1013 /* however, the score will be higher for longer matches */
1014 for (key = 0; key < MAIN_LEN; key++) {
1015 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1016 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1017 ok++;
1018 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1019 ok = -1;
1021 if (ok > 0) {
1022 score += ok;
1023 break;
1026 /* count the matches and mismatches */
1027 if (ok > 0) {
1028 match++;
1029 /* and how much the keycode order matches */
1030 if (key > pkey) seq++;
1031 pkey = key;
1032 } else {
1033 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
1034 ckey[0]);
1035 mismatch++;
1036 score -= syms;
1040 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1041 match, mismatch, seq, score);
1042 if ((score > max_score) ||
1043 ((score == max_score) && (seq > max_seq))) {
1044 /* best match so far */
1045 kbd_layout = current;
1046 max_score = score;
1047 max_seq = seq;
1048 ismatch = !mismatch;
1051 /* we're done, report results if necessary */
1052 if (!ismatch) {
1053 FIXME(
1054 "Your keyboard layout was not found!\n"
1055 "Using closest match instead (%s) for scancode mapping.\n"
1056 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1057 "to us for inclusion into future Wine releases.\n"
1058 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1059 main_key_tab[kbd_layout].comment);
1062 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1065 /**********************************************************************
1066 * InitKeyboard (X11DRV.@)
1068 void X11DRV_InitKeyboard( BYTE *key_state_table )
1070 #ifdef HAVE_XKB
1071 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1072 #endif
1073 Display *display = thread_display();
1074 KeySym *ksp;
1075 XModifierKeymap *mmp;
1076 KeySym keysym;
1077 KeyCode *kcp;
1078 XKeyEvent e2;
1079 WORD scan, vkey, OEMvkey;
1080 int keyc, i, keyn, syms;
1081 char ckey[4]={0,0,0,0};
1082 const char (*lkey)[MAIN_LEN][4];
1084 pKeyStateTable = key_state_table;
1086 #ifdef HAVE_XKB
1087 wine_tsx11_lock();
1088 is_xkb = XkbQueryExtension(display,
1089 &xkb_opcode, &xkb_event, &xkb_error,
1090 &xkb_major, &xkb_minor);
1091 if (is_xkb) {
1092 /* we have XKB, approximate Windows behaviour */
1093 XkbSetDetectableAutoRepeat(display, True, NULL);
1095 wine_tsx11_unlock();
1096 #endif
1097 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
1098 ksp = TSXGetKeyboardMapping(display, min_keycode,
1099 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1100 /* We are only interested in keysyms_per_keycode.
1101 There is no need to hold a local copy of the keysyms table */
1102 TSXFree(ksp);
1103 mmp = TSXGetModifierMapping(display);
1104 kcp = mmp->modifiermap;
1105 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1107 int j;
1109 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1110 if (*kcp)
1112 int k;
1114 for (k = 0; k < keysyms_per_keycode; k += 1)
1115 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1117 NumLockMask = 1 << i;
1118 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1122 TSXFreeModifiermap(mmp);
1124 /* Detect the keyboard layout */
1125 X11DRV_KEYBOARD_DetectLayout();
1126 lkey = main_key_tab[kbd_layout].key;
1127 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1129 /* Now build two conversion arrays :
1130 * keycode -> vkey + scancode + extended
1131 * vkey + extended -> keycode */
1133 e2.display = display;
1134 e2.state = 0;
1136 OEMvkey = VK_OEM_7; /* next is available. */
1137 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1139 e2.keycode = (KeyCode)keyc;
1140 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1141 vkey = 0; scan = 0;
1142 if (keysym) /* otherwise, keycode not used */
1144 if ((keysym >> 8) == 0xFF) /* non-character key */
1146 vkey = nonchar_key_vkey[keysym & 0xff];
1147 scan = nonchar_key_scan[keysym & 0xff];
1148 /* set extended bit when necessary */
1149 if (scan & 0x100) vkey |= 0x100;
1150 } else if (keysym == 0x20) { /* Spacebar */
1151 vkey = VK_SPACE;
1152 scan = 0x39;
1153 } else {
1154 /* we seem to need to search the layout-dependent scancodes */
1155 int maxlen=0,maxval=-1,ok;
1156 for (i=0; i<syms; i++) {
1157 keysym = TSXKeycodeToKeysym(display, keyc, i);
1158 if ((keysym<0x800) && (keysym!=' ')) {
1159 ckey[i] = keysym & 0xFF;
1160 } else {
1161 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1164 /* find key with longest match streak */
1165 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1166 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1167 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1168 if (ok||(i>maxlen)) {
1169 maxlen=i; maxval=keyn;
1171 if (ok) break;
1173 if (maxval>=0) {
1174 /* got it */
1175 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1176 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1177 scan = (*lscan)[maxval];
1178 vkey = (*lvkey)[maxval];
1182 /* find a suitable layout-dependent VK code */
1183 /* (most Winelib apps ought to be able to work without layout tables!) */
1184 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1186 keysym = TSXLookupKeysym(&e2, i);
1187 if ((keysym >= VK_0 && keysym <= VK_9)
1188 || (keysym >= VK_A && keysym <= VK_Z)) {
1189 vkey = keysym;
1193 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1195 keysym = TSXLookupKeysym(&e2, i);
1196 switch (keysym)
1198 case ';': vkey = VK_OEM_1; break;
1199 case '/': vkey = VK_OEM_2; break;
1200 case '`': vkey = VK_OEM_3; break;
1201 case '[': vkey = VK_OEM_4; break;
1202 case '\\': vkey = VK_OEM_5; break;
1203 case ']': vkey = VK_OEM_6; break;
1204 case '\'': vkey = VK_OEM_7; break;
1205 case ',': vkey = VK_OEM_COMMA; break;
1206 case '.': vkey = VK_OEM_PERIOD; break;
1207 case '-': vkey = VK_OEM_MINUS; break;
1208 case '+': vkey = VK_OEM_PLUS; break;
1212 if (!vkey)
1214 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1215 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1216 switch (++OEMvkey)
1218 case 0xc1 : OEMvkey=0xdb; break;
1219 case 0xe5 : OEMvkey=0xe9; break;
1220 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1223 vkey = OEMvkey;
1225 if (TRACE_ON(keyboard))
1227 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1228 OEMvkey, e2.keycode);
1229 TRACE("(");
1230 for (i = 0; i < keysyms_per_keycode; i += 1)
1232 char *ksname;
1234 keysym = TSXLookupKeysym(&e2, i);
1235 ksname = TSXKeysymToString(keysym);
1236 if (!ksname)
1237 ksname = "NoSymbol";
1238 DPRINTF( "%lX (%s) ", keysym, ksname);
1240 DPRINTF(")\n");
1244 keyc2vkey[e2.keycode] = vkey;
1245 keyc2scan[e2.keycode] = scan;
1246 } /* for */
1248 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1249 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1250 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1251 char *ksname;
1252 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1253 ksname = TSXKeysymToString(keysym);
1254 if (!ksname) ksname = "NoSymbol";
1256 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1258 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1259 keyc2scan[keyc]=scan++;
1262 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1263 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1264 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1265 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1266 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1267 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1268 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1272 /***********************************************************************
1273 * X11DRV_MappingNotify
1275 void X11DRV_MappingNotify( XMappingEvent *event )
1277 TSXRefreshKeyboardMapping(event);
1278 X11DRV_InitKeyboard( pKeyStateTable );
1282 /***********************************************************************
1283 * VkKeyScan (X11DRV.@)
1285 WORD X11DRV_VkKeyScan(CHAR cChar)
1287 Display *display = thread_display();
1288 KeyCode keycode;
1289 KeySym keysym;
1290 int i,index;
1291 int highbyte=0;
1293 /* char->keysym (same for ANSI chars) */
1294 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1295 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1297 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1298 if (!keycode)
1299 { /* It didn't work ... let's try with deadchar code. */
1300 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1303 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1304 cChar,keysym,keysym,keycode);
1306 if (keycode)
1308 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1309 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1310 switch (index) {
1311 case -1 :
1312 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1313 case 0 : break;
1314 case 1 : highbyte = 0x0100; break;
1315 case 2 : highbyte = 0x0600; break;
1316 case 3 : highbyte = 0x0700; break;
1317 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1320 index : 0 adds 0x0000
1321 index : 1 adds 0x0100 (shift)
1322 index : ? adds 0x0200 (ctrl)
1323 index : 2 adds 0x0600 (ctrl+alt)
1324 index : 3 adds 0x0700 (ctrl+alt+shift)
1327 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1328 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1331 /***********************************************************************
1332 * MapVirtualKey (X11DRV.@)
1334 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1336 Display *display = thread_display();
1338 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1340 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1341 switch(wMapType) {
1342 case 0: { /* vkey-code to scan-code */
1343 /* let's do vkey -> keycode -> scan */
1344 int keyc;
1345 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1346 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1347 returnMVK (keyc2scan[keyc] & 0xFF);
1348 TRACE("returning no scan-code.\n");
1349 return 0; }
1351 case 1: { /* scan-code to vkey-code */
1352 /* let's do scan -> keycode -> vkey */
1353 int keyc;
1354 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1355 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1356 returnMVK (keyc2vkey[keyc] & 0xFF);
1357 TRACE("returning no vkey-code.\n");
1358 return 0; }
1360 case 2: { /* vkey-code to unshifted ANSI code */
1361 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1362 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1363 * key.. Looks like something is wrong with the MS docs?
1364 * This is only true for letters, for example VK_0 returns '0' not ')'.
1365 * - hence we use the lock mask to ensure this happens.
1367 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1368 XKeyEvent e;
1369 KeySym keysym;
1370 int keyc;
1371 char s[2];
1372 e.display = display;
1374 e.state = LockMask;
1375 /* LockMask should behave exactly like caps lock - upercase
1376 * the letter keys and thats about it. */
1378 e.keycode = 0;
1379 /* We exit on the first keycode found, to speed up the thing. */
1380 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1381 { /* Find a keycode that could have generated this virtual key */
1382 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1383 { /* We filter the extended bit, we don't know it */
1384 e.keycode = keyc; /* Store it temporarily */
1385 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1386 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1387 state), so set it to 0, we'll find another one */
1392 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1393 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1395 if (wCode==VK_DECIMAL)
1396 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1398 if (!e.keycode)
1400 WARN("Unknown virtual key %X !!! \n", wCode);
1401 return 0; /* whatever */
1403 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1405 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1406 returnMVK (*s);
1408 TRACE("returning no ANSI.\n");
1409 return 0;
1412 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1413 /* left and right */
1414 FIXME(" stub for NT\n");
1415 return 0;
1417 default: /* reserved */
1418 WARN("Unknown wMapType %d !\n", wMapType);
1419 return 0;
1421 return 0;
1424 /***********************************************************************
1425 * GetKeyNameText (X11DRV.@)
1427 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1429 int vkey, ansi, scanCode;
1430 KeyCode keyc;
1431 int keyi;
1432 KeySym keys;
1433 char *name;
1435 scanCode = lParam >> 16;
1436 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1438 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1439 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1441 /* handle "don't care" bit (0x02000000) */
1442 if (!(lParam & 0x02000000)) {
1443 switch (vkey) {
1444 case VK_LSHIFT:
1445 case VK_RSHIFT:
1446 vkey = VK_SHIFT;
1447 break;
1448 case VK_LCONTROL:
1449 case VK_RCONTROL:
1450 vkey = VK_CONTROL;
1451 break;
1452 case VK_LMENU:
1453 case VK_RMENU:
1454 vkey = VK_MENU;
1455 break;
1456 default:
1457 break;
1461 ansi = X11DRV_MapVirtualKey(vkey, 2);
1462 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1464 /* first get the name of the "regular" keys which is the Upper case
1465 value of the keycap imprint. */
1466 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1467 (scanCode != 0x137) && /* PrtScn */
1468 (scanCode != 0x135) && /* numpad / */
1469 (scanCode != 0x37 ) && /* numpad * */
1470 (scanCode != 0x4a ) && /* numpad - */
1471 (scanCode != 0x4e ) ) /* numpad + */
1473 if ((nSize >= 2) && lpBuffer)
1475 *lpBuffer = toupper((char)ansi);
1476 *(lpBuffer+1) = 0;
1477 return 1;
1479 else
1480 return 0;
1483 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1484 without "extended-key" flag. However Wine generates scancode
1485 *with* "extended-key" flag. Seems to occur *only* for the
1486 function keys. Soooo.. We will leave the table alone and
1487 fudge the lookup here till the other part is found and fixed!!! */
1489 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1490 (scanCode == 0x157) || (scanCode == 0x158))
1491 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1493 /* let's do scancode -> keycode -> keysym -> String */
1495 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1496 if ((keyc2scan[keyi]) == scanCode)
1497 break;
1498 if (keyi <= max_keycode)
1500 keyc = (KeyCode) keyi;
1501 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1502 name = TSXKeysymToString(keys);
1503 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1504 scanCode, keyc, (int)keys, name);
1505 if (lpBuffer && nSize && name)
1507 lstrcpynA(lpBuffer, name, nSize);
1508 return 1;
1512 /* Finally issue FIXME for unknown keys */
1514 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1515 if (lpBuffer && nSize)
1516 *lpBuffer = 0;
1517 return 0;
1520 /***********************************************************************
1521 * X11DRV_KEYBOARD_MapDeadKeysym
1523 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1525 switch (keysym)
1527 /* symbolic ASCII is the same as defined in rfc1345 */
1528 #ifdef XK_dead_tilde
1529 case XK_dead_tilde :
1530 #endif
1531 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1532 return '~'; /* '? */
1533 #ifdef XK_dead_acute
1534 case XK_dead_acute :
1535 #endif
1536 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1537 return 0xb4; /* '' */
1538 #ifdef XK_dead_circumflex
1539 case XK_dead_circumflex:
1540 #endif
1541 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1542 return '^'; /* '> */
1543 #ifdef XK_dead_grave
1544 case XK_dead_grave :
1545 #endif
1546 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1547 return '`'; /* '! */
1548 #ifdef XK_dead_diaeresis
1549 case XK_dead_diaeresis :
1550 #endif
1551 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1552 return 0xa8; /* ': */
1553 #ifdef XK_dead_cedilla
1554 case XK_dead_cedilla :
1555 return 0xb8; /* ', */
1556 #endif
1557 #ifdef XK_dead_macron
1558 case XK_dead_macron :
1559 return '-'; /* 'm isn't defined on iso-8859-x */
1560 #endif
1561 #ifdef XK_dead_breve
1562 case XK_dead_breve :
1563 return 0xa2; /* '( */
1564 #endif
1565 #ifdef XK_dead_abovedot
1566 case XK_dead_abovedot :
1567 return 0xff; /* '. */
1568 #endif
1569 #ifdef XK_dead_abovering
1570 case XK_dead_abovering :
1571 return '0'; /* '0 isn't defined on iso-8859-x */
1572 #endif
1573 #ifdef XK_dead_doubleacute
1574 case XK_dead_doubleacute :
1575 return 0xbd; /* '" */
1576 #endif
1577 #ifdef XK_dead_caron
1578 case XK_dead_caron :
1579 return 0xb7; /* '< */
1580 #endif
1581 #ifdef XK_dead_ogonek
1582 case XK_dead_ogonek :
1583 return 0xb2; /* '; */
1584 #endif
1585 /* FIXME: I don't know this three.
1586 case XK_dead_iota :
1587 return 'i';
1588 case XK_dead_voiced_sound :
1589 return 'v';
1590 case XK_dead_semivoiced_sound :
1591 return 's';
1594 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1595 return 0;
1598 /***********************************************************************
1599 * ToUnicode (X11DRV.@)
1601 * The ToUnicode function translates the specified virtual-key code and keyboard
1602 * state to the corresponding Windows character or characters.
1604 * If the specified key is a dead key, the return value is negative. Otherwise,
1605 * it is one of the following values:
1606 * Value Meaning
1607 * 0 The specified virtual key has no translation for the current state of the keyboard.
1608 * 1 One Windows character was copied to the buffer.
1609 * 2 Two characters were copied to the buffer. This usually happens when a
1610 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1611 * be composed with the specified virtual key to form a single character.
1613 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1616 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1617 LPWSTR bufW, int bufW_size, UINT flags)
1619 Display *display = thread_display();
1620 XKeyEvent e;
1621 KeySym keysym;
1622 INT ret;
1623 int keyc;
1624 BYTE lpChar[2];
1626 if (scanCode & 0x8000)
1628 TRACE("Key UP, doing nothing\n" );
1629 return 0;
1631 e.display = display;
1632 e.keycode = 0;
1633 e.state = 0;
1634 if (lpKeyState[VK_SHIFT] & 0x80)
1636 TRACE("ShiftMask = %04x\n", ShiftMask);
1637 e.state |= ShiftMask;
1639 if (lpKeyState[VK_CAPITAL] & 0x01)
1641 TRACE("LockMask = %04x\n", LockMask);
1642 e.state |= LockMask;
1644 if (lpKeyState[VK_CONTROL] & 0x80)
1646 TRACE("ControlMask = %04x\n", ControlMask);
1647 e.state |= ControlMask;
1649 if (lpKeyState[VK_NUMLOCK] & 0x01)
1651 TRACE("NumLockMask = %04x\n", NumLockMask);
1652 e.state |= NumLockMask;
1655 /* Restore saved AltGr state */
1656 TRACE("AltGrMask = %04x\n", AltGrMask);
1657 e.state |= AltGrMask;
1659 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1660 virtKey, scanCode, e.state);
1661 /* We exit on the first keycode found, to speed up the thing. */
1662 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1663 { /* Find a keycode that could have generated this virtual key */
1664 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1665 { /* We filter the extended bit, we don't know it */
1666 e.keycode = keyc; /* Store it temporarily */
1667 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1668 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1669 state), so set it to 0, we'll find another one */
1674 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1675 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1677 if (virtKey==VK_DECIMAL)
1678 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1680 if (!e.keycode)
1682 WARN("Unknown virtual key %X !!! \n",virtKey);
1683 return virtKey; /* whatever */
1685 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1687 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1688 if (ret == 0)
1690 BYTE dead_char;
1692 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1693 if (dead_char)
1695 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1696 ret = -1;
1698 else
1700 char *ksname;
1702 ksname = TSXKeysymToString(keysym);
1703 if (!ksname)
1704 ksname = "No Name";
1705 if ((keysym >> 8) != 0xff)
1707 ERR("Please report: no char for keysym %04lX (%s) :\n",
1708 keysym, ksname);
1709 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1710 virtKey, scanCode, e.keycode, e.state);
1714 else { /* ret != 0 */
1715 /* We have a special case to handle : Shift + arrow, shift + home, ...
1716 X returns a char for it, but Windows doesn't. Let's eat it. */
1717 if (!(e.state & NumLockMask) /* NumLock is off */
1718 && (e.state & ShiftMask) /* Shift is pressed */
1719 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1721 *(char*)lpChar = 0;
1722 ret = 0;
1725 /* more areas where X returns characters but Windows does not
1726 CTRL + number or CTRL + symbol*/
1727 if (e.state & ControlMask)
1729 if (((keysym>=33) && (keysym < 'A')) ||
1730 ((keysym > 'Z') && (keysym < 'a')))
1732 *(char*)lpChar = 0;
1733 ret = 0;
1737 /* We have another special case for delete key (XK_Delete) on an
1738 extended keyboard. X returns a char for it, but Windows doesn't */
1739 if (keysym == XK_Delete)
1741 *(char*)lpChar = 0;
1742 ret = 0;
1744 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1745 && (keysym == XK_KP_Decimal))
1747 *(char*)lpChar = 0;
1748 ret = 0;
1751 /* perform translation to unicode */
1752 if(ret)
1754 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1755 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1756 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1760 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1761 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1762 return ret;
1765 /***********************************************************************
1766 * Beep (X11DRV.@)
1768 void X11DRV_Beep(void)
1770 TSXBell(thread_display(), 0);