Fixed a number of dll separation issues.
[wine/hacks.git] / dlls / x11drv / keyboard.c
blob71b16cf8c464ccf40e75ca62a243addc3fd02dd0
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 /*** Bulgarian bds keyboard layout */
338 static const char main_key_BG_bds[MAIN_LEN][4] =
340 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
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ïÏ",",<ðÐ",".>ëË","/?áÁ",
344 "<>" /* the phantom key */
347 /*** Bulgarian phonetic keyboard layout */
348 static const char main_key_BG_phonetic[MAIN_LEN][4] =
350 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
351 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
352 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
353 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
354 "<>" /* the phantom key */
357 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
358 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
359 static const char main_key_BY[MAIN_LEN][4] =
361 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
362 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
363 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
364 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
368 /*** Russian keyboard layout (contributed by Pavel Roskin) */
369 static const char main_key_RU[MAIN_LEN][4] =
371 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
372 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
373 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
374 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
377 /*** Russian keyboard layout (phantom key version) */
378 static const char main_key_RU_phantom[MAIN_LEN][4] =
380 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
381 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
382 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
383 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
384 "<>" /* the phantom key */
387 /*** Russian keyboard layout KOI8-R */
388 static const char main_key_RU_koi8r[MAIN_LEN][4] =
390 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
391 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
392 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
393 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
394 "<>" /* the phantom key */
397 /*** Ukrainian keyboard layout KOI8-U */
398 static const char main_key_UA[MAIN_LEN][4] =
400 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
401 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
402 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
403 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
404 "<>" /* the phantom key */
407 /*** Spanish keyboard layout (contributed by José Marcos López) */
408 static const char main_key_ES[MAIN_LEN][4] =
410 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
411 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
412 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
413 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
414 "<>"
417 /*** Belgian keyboard layout ***/
418 static const char main_key_BE[MAIN_LEN][4] =
420 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
421 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
422 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
423 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
424 "<>\\"
427 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
428 static const char main_key_HU[MAIN_LEN][4] =
430 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
431 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
432 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
433 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
434 "íÍ<"
437 /*** Polish (programmer's) keyboard layout ***/
438 static const char main_key_PL[MAIN_LEN][4] =
440 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
441 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
442 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
443 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
444 "<>|"
447 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
448 static const char main_key_SI[MAIN_LEN][4] =
450 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
451 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
452 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
453 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
454 "<>"
457 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
458 static const char main_key_HR_jelly[MAIN_LEN][4] =
460 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
461 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
462 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
463 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
464 "<>|"
467 /*** Croatian keyboard layout ***/
468 static const char main_key_HR[MAIN_LEN][4] =
470 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
471 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
472 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
473 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
474 "<>"
477 /*** Japanese 106 keyboard layout ***/
478 static const char main_key_JA_jp106[MAIN_LEN][4] =
480 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
481 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
482 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
483 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
484 "\\_",
487 /*** Japanese pc98x1 keyboard layout ***/
488 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
490 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
491 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
492 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
493 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
494 "\\_",
497 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
498 static const char main_key_PT_br[MAIN_LEN][4] =
500 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
501 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
502 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
503 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?"
506 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
507 static const char main_key_US_intl[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", ",<", ".>", "/?"
515 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
516 - dead_abovering replaced with degree - no symbol in iso8859-2
517 - brokenbar replaced with bar */
518 static const char main_key_SK[MAIN_LEN][4] =
520 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
521 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
522 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
523 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
524 "<>"
527 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
528 static const char main_key_SK_prog[MAIN_LEN][4] =
530 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
531 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
532 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
533 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
534 "<>"
537 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
538 static const char main_key_CS[MAIN_LEN][4] =
540 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
541 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
542 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
543 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
544 "<>\\|"
547 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
548 static const char main_key_LA[MAIN_LEN][4] =
550 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
551 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
552 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
553 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
554 "<>"
557 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
558 static const char main_key_LT_B[MAIN_LEN][4] =
560 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
561 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
562 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
563 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
566 /*** Turkish keyboard Layout */
567 static const char main_key_TK[MAIN_LEN][4] =
569 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
570 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
571 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
572 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
575 /*** Israeli keyboard layout */
576 static const char main_key_IL[MAIN_LEN][4] =
578 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
579 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
580 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
581 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
584 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
585 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
586 message since they have different characters in gr and el XFree86 layouts. */
587 static const char main_key_EL[MAIN_LEN][4] =
589 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
590 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
591 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
592 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
593 "<>"
596 /*** VNC keyboard layout */
597 static const WORD main_key_scan_vnc[MAIN_LEN] =
599 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
600 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,
601 0x56
604 static const WORD main_key_vkey_vnc[MAIN_LEN] =
606 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,
607 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,
608 VK_OEM_102
611 static const char main_key_vnc[MAIN_LEN][4] =
613 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
614 "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"
617 /*** Layout table. Add your keyboard mappings to this list */
618 static const struct {
619 const char *comment;
620 const UINT layout_cp; /* Code page for this layout */
621 const char (*key)[MAIN_LEN][4];
622 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
623 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
624 } main_key_tab[]={
625 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
626 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
627 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
628 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
629 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
630 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
631 {"German keyboard layout for logitech desktop pro", 28591, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
632 {"German keyboard layout without dead keys 105", 28591, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
633 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
634 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
635 {"Estonian keyboard layout", 28591, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
636 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
637 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
638 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
639 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
640 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
641 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
642 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
643 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
644 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
645 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
646 {"Bulgarian bds keyboard layout", 1251, &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
647 {"Bulgarian phonetic keyboard layout", 1251, &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
648 {"Belarusian keyboard layout", 1251, &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
649 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
650 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
651 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
652 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
653 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
654 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
655 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
656 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
657 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
658 {"Slovenian keyboard layout", 28592, &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
659 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
660 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
661 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
662 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
663 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
664 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
665 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
666 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
667 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
668 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
669 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
670 {"VNC keyboard layout", 28591, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
671 {"Greek keyboard layout", 28597, &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
673 {NULL, 0, NULL, NULL, NULL} /* sentinel */
675 static unsigned kbd_layout=0; /* index into above table of layouts */
677 /* maybe more of these scancodes should be extended? */
678 /* extended must be set for ALT_R, CTRL_R,
679 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
680 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
681 /* FIXME should we set extended bit for NumLock ? My
682 * Windows does ... DF */
683 /* Yes, to distinguish based on scan codes, also
684 for PrtScn key ... GA */
686 static const WORD nonchar_key_vkey[256] =
688 /* unused */
689 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
690 /* special keys */
691 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
692 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
693 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
694 /* unused */
695 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
696 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
697 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
698 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
699 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
700 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
701 /* cursor keys */
702 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
703 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
704 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
705 /* misc keys */
706 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
707 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
708 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
709 /* keypad keys */
710 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
711 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
712 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
713 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
714 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
715 VK_END, 0, VK_INSERT, VK_DELETE,
716 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
717 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
718 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
719 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
720 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
721 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
722 /* function keys */
723 VK_F1, VK_F2,
724 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
725 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
726 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
727 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
728 /* modifier keys */
729 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
730 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
731 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
732 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
733 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
736 static const WORD nonchar_key_scan[256] =
738 /* unused */
739 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
740 /* special keys */
741 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
742 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
743 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
744 /* unused */
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
751 /* cursor keys */
752 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
754 /* misc keys */
755 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
756 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
758 /* keypad keys */
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
763 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
765 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
766 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
767 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
768 /* function keys */
769 0x3B, 0x3C,
770 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
771 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
774 /* modifier keys */
775 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
776 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
782 /* Returns the Windows virtual key code associated with the X event <e> */
783 static WORD EVENT_event_to_vkey( XKeyEvent *e)
785 KeySym keysym;
787 TSXLookupString(e, NULL, 0, &keysym, NULL);
789 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
790 && (e->state & NumLockMask))
791 /* Only the Keypad keys 0-9 and . send different keysyms
792 * depending on the NumLock state */
793 return nonchar_key_vkey[keysym & 0xFF];
795 return keyc2vkey[e->keycode];
798 static BOOL NumState=FALSE, CapsState=FALSE;
801 /***********************************************************************
802 * send_keyboard_input
804 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
806 INPUT input;
808 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
809 input.u.ki.wVk = wVk;
810 input.u.ki.wScan = wScan;
811 input.u.ki.dwFlags = dwFlags;
812 input.u.ki.time = time;
813 input.u.ki.dwExtraInfo = 0;
814 SendInput( 1, &input, sizeof(input) );
818 /**********************************************************************
819 * KEYBOARD_GenerateMsg
821 * Generate Down+Up messages when NumLock or CapsLock is pressed.
823 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
826 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
828 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
829 DWORD up, down;
831 if (*State) {
832 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
833 don't treat it. It's from the same key press. Then the state goes to ON.
834 And from there, a 'release' event will switch off the toggle key. */
835 *State=FALSE;
836 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
837 } else
839 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
840 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
841 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
843 if (Evtype!=KeyPress)
845 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
846 send_keyboard_input( vkey, scan, down, event_time );
847 send_keyboard_input( vkey, scan, up, event_time );
848 *State=FALSE;
849 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
852 else /* it was OFF */
853 if (Evtype==KeyPress)
855 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
856 send_keyboard_input( vkey, scan, down, event_time );
857 send_keyboard_input( vkey, scan, up, event_time );
858 *State=TRUE; /* Goes to intermediary state before going to ON */
859 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
864 /***********************************************************************
865 * KEYBOARD_UpdateOneState
867 * Updates internal state for <vkey>, depending on key <state> under X
870 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
872 /* Do something if internal table state != X state for keycode */
873 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
875 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
876 vkey, pKeyStateTable[vkey]);
878 /* Fake key being pressed inside wine */
879 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
881 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
885 /***********************************************************************
886 * X11DRV_KeymapNotify
888 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
890 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
891 * from wine to another application and back.
892 * Toggle keys are handled in HandleEvent.
894 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
896 int i, j, alt, control, shift;
897 DWORD time = GetCurrentTime();
899 alt = control = shift = 0;
900 for (i = 0; i < 32; i++)
902 if (!event->key_vector[i]) continue;
903 for (j = 0; j < 8; j++)
905 if (!(event->key_vector[i] & (1<<j))) continue;
906 switch(keyc2vkey[(i * 8) + j] & 0xff)
908 case VK_MENU: alt = 1; break;
909 case VK_CONTROL: control = 1; break;
910 case VK_SHIFT: shift = 1; break;
914 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
915 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
916 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
919 /***********************************************************************
920 * X11DRV_KeyEvent
922 * Handle a X key event
924 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
926 char Str[24];
927 KeySym keysym;
928 WORD vkey = 0, bScan;
929 DWORD dwFlags;
930 int ascii_chars;
932 DWORD event_time = event->time - X11DRV_server_startticks;
934 /* this allows support for dead keys */
935 if ((event->keycode >> 8) == 0x10)
936 event->keycode=(event->keycode & 0xff);
938 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
940 /* Ignore some unwanted events */
941 if (keysym == XK_ISO_Prev_Group ||
942 keysym == XK_ISO_Next_Group ||
943 keysym == XK_Mode_switch)
945 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
946 return;
949 TRACE_(key)("state = %X\n", event->state);
951 /* If XKB extensions is used, the state mask for AltGr will used the group
952 index instead of the modifier mask. The group index is set in bits
953 13-14 of the state field in the XKeyEvent structure. So if AltGr is
954 pressed, look if the group index is diferent than 0. From XKB
955 extension documentation, the group index should for AltGr should
956 be 2 (event->state = 0x2000). It's probably better to not assume a
957 predefined group index and find it dynamically
959 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
960 AltGrMask = event->state & 0x6000;
962 Str[ascii_chars] = '\0';
963 if (TRACE_ON(key)){
964 char *ksname;
966 ksname = TSXKeysymToString(keysym);
967 if (!ksname)
968 ksname = "No Name";
969 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
970 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
971 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
974 vkey = EVENT_event_to_vkey(event);
976 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
977 event->keycode, vkey);
979 if (vkey)
981 switch (vkey & 0xff)
983 case VK_NUMLOCK:
984 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
985 break;
986 case VK_CAPITAL:
987 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
988 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
989 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
990 break;
991 default:
992 /* Adjust the NUMLOCK state if it has been changed outside wine */
993 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
995 TRACE("Adjusting NumLock state. \n");
996 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
997 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
999 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1000 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1002 TRACE("Adjusting Caps Lock state.\n");
1003 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1004 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1006 /* Not Num nor Caps : end of intermediary states for both. */
1007 NumState = FALSE;
1008 CapsState = FALSE;
1010 bScan = keyc2scan[event->keycode] & 0xFF;
1011 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1013 dwFlags = 0;
1014 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1015 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1017 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1022 /**********************************************************************
1023 * X11DRV_KEYBOARD_DetectLayout
1025 * Called from X11DRV_InitKeyboard
1026 * This routine walks through the defined keyboard layouts and selects
1027 * whichever matches most closely.
1029 static void
1030 X11DRV_KEYBOARD_DetectLayout (void)
1032 Display *display = thread_display();
1033 unsigned current, match, mismatch, seq;
1034 int score, keyc, i, key, pkey, ok, syms;
1035 KeySym keysym;
1036 const char (*lkey)[MAIN_LEN][4];
1037 unsigned max_seq = 0;
1038 int max_score = 0, ismatch = 0;
1039 char ckey[4] =
1040 {0, 0, 0, 0};
1042 syms = keysyms_per_keycode;
1043 if (syms > 4) {
1044 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1045 syms = 4;
1047 for (current = 0; main_key_tab[current].comment; current++) {
1048 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1049 match = 0;
1050 mismatch = 0;
1051 score = 0;
1052 seq = 0;
1053 lkey = main_key_tab[current].key;
1054 pkey = -1;
1055 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1056 /* get data for keycode from X server */
1057 for (i = 0; i < syms; i++) {
1058 keysym = TSXKeycodeToKeysym (display, keyc, i);
1059 /* Allow both one-byte and two-byte national keysyms */
1060 if ((keysym < 0x8000) && (keysym != ' '))
1061 ckey[i] = keysym & 0xFF;
1062 else {
1063 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1066 if (ckey[0]) {
1067 /* search for a match in layout table */
1068 /* right now, we just find an absolute match for defined positions */
1069 /* (undefined positions are ignored, so if it's defined as "3#" in */
1070 /* the table, it's okay that the X server has "3#£", for example) */
1071 /* however, the score will be higher for longer matches */
1072 for (key = 0; key < MAIN_LEN; key++) {
1073 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1074 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1075 ok++;
1076 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1077 ok = -1;
1079 if (ok > 0) {
1080 score += ok;
1081 break;
1084 /* count the matches and mismatches */
1085 if (ok > 0) {
1086 match++;
1087 /* and how much the keycode order matches */
1088 if (key > pkey) seq++;
1089 pkey = key;
1090 } else {
1091 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
1092 ckey[0]);
1093 mismatch++;
1094 score -= syms;
1098 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1099 match, mismatch, seq, score);
1100 if ((score > max_score) ||
1101 ((score == max_score) && (seq > max_seq))) {
1102 /* best match so far */
1103 kbd_layout = current;
1104 max_score = score;
1105 max_seq = seq;
1106 ismatch = !mismatch;
1109 /* we're done, report results if necessary */
1110 if (!ismatch) {
1111 FIXME(
1112 "Your keyboard layout was not found!\n"
1113 "Using closest match instead (%s) for scancode mapping.\n"
1114 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1115 "to us for inclusion into future Wine releases.\n"
1116 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1117 main_key_tab[kbd_layout].comment);
1120 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1123 /**********************************************************************
1124 * InitKeyboard (X11DRV.@)
1126 void X11DRV_InitKeyboard( BYTE *key_state_table )
1128 #ifdef HAVE_XKB
1129 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1130 #endif
1131 Display *display = thread_display();
1132 KeySym *ksp;
1133 XModifierKeymap *mmp;
1134 KeySym keysym;
1135 KeyCode *kcp;
1136 XKeyEvent e2;
1137 WORD scan, vkey, OEMvkey;
1138 int keyc, i, keyn, syms;
1139 char ckey[4]={0,0,0,0};
1140 const char (*lkey)[MAIN_LEN][4];
1142 pKeyStateTable = key_state_table;
1144 #ifdef HAVE_XKB
1145 wine_tsx11_lock();
1146 is_xkb = XkbQueryExtension(display,
1147 &xkb_opcode, &xkb_event, &xkb_error,
1148 &xkb_major, &xkb_minor);
1149 if (is_xkb) {
1150 /* we have XKB, approximate Windows behaviour */
1151 XkbSetDetectableAutoRepeat(display, True, NULL);
1153 wine_tsx11_unlock();
1154 #endif
1155 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
1156 ksp = TSXGetKeyboardMapping(display, min_keycode,
1157 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1158 /* We are only interested in keysyms_per_keycode.
1159 There is no need to hold a local copy of the keysyms table */
1160 TSXFree(ksp);
1161 mmp = TSXGetModifierMapping(display);
1162 kcp = mmp->modifiermap;
1163 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1165 int j;
1167 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1168 if (*kcp)
1170 int k;
1172 for (k = 0; k < keysyms_per_keycode; k += 1)
1173 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1175 NumLockMask = 1 << i;
1176 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1180 TSXFreeModifiermap(mmp);
1182 /* Detect the keyboard layout */
1183 X11DRV_KEYBOARD_DetectLayout();
1184 lkey = main_key_tab[kbd_layout].key;
1185 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1187 /* Now build two conversion arrays :
1188 * keycode -> vkey + scancode + extended
1189 * vkey + extended -> keycode */
1191 e2.display = display;
1192 e2.state = 0;
1194 OEMvkey = VK_OEM_7; /* next is available. */
1195 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1197 e2.keycode = (KeyCode)keyc;
1198 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1199 vkey = 0; scan = 0;
1200 if (keysym) /* otherwise, keycode not used */
1202 if ((keysym >> 8) == 0xFF) /* non-character key */
1204 vkey = nonchar_key_vkey[keysym & 0xff];
1205 scan = nonchar_key_scan[keysym & 0xff];
1206 /* set extended bit when necessary */
1207 if (scan & 0x100) vkey |= 0x100;
1208 } else if (keysym == 0x20) { /* Spacebar */
1209 vkey = VK_SPACE;
1210 scan = 0x39;
1211 } else {
1212 /* we seem to need to search the layout-dependent scancodes */
1213 int maxlen=0,maxval=-1,ok;
1214 for (i=0; i<syms; i++) {
1215 keysym = TSXKeycodeToKeysym(display, keyc, i);
1216 if ((keysym<0x800) && (keysym!=' ')) {
1217 ckey[i] = keysym & 0xFF;
1218 } else {
1219 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1222 /* find key with longest match streak */
1223 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1224 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1225 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1226 if (ok||(i>maxlen)) {
1227 maxlen=i; maxval=keyn;
1229 if (ok) break;
1231 if (maxval>=0) {
1232 /* got it */
1233 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1234 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1235 scan = (*lscan)[maxval];
1236 vkey = (*lvkey)[maxval];
1240 /* find a suitable layout-dependent VK code */
1241 /* (most Winelib apps ought to be able to work without layout tables!) */
1242 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1244 keysym = TSXLookupKeysym(&e2, i);
1245 if ((keysym >= VK_0 && keysym <= VK_9)
1246 || (keysym >= VK_A && keysym <= VK_Z)) {
1247 vkey = keysym;
1251 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1253 keysym = TSXLookupKeysym(&e2, i);
1254 switch (keysym)
1256 case ';': vkey = VK_OEM_1; break;
1257 case '/': vkey = VK_OEM_2; break;
1258 case '`': vkey = VK_OEM_3; break;
1259 case '[': vkey = VK_OEM_4; break;
1260 case '\\': vkey = VK_OEM_5; break;
1261 case ']': vkey = VK_OEM_6; break;
1262 case '\'': vkey = VK_OEM_7; break;
1263 case ',': vkey = VK_OEM_COMMA; break;
1264 case '.': vkey = VK_OEM_PERIOD; break;
1265 case '-': vkey = VK_OEM_MINUS; break;
1266 case '+': vkey = VK_OEM_PLUS; break;
1270 if (!vkey)
1272 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1273 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1274 switch (++OEMvkey)
1276 case 0xc1 : OEMvkey=0xdb; break;
1277 case 0xe5 : OEMvkey=0xe9; break;
1278 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1281 vkey = OEMvkey;
1283 if (TRACE_ON(keyboard))
1285 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1286 OEMvkey, e2.keycode);
1287 TRACE("(");
1288 for (i = 0; i < keysyms_per_keycode; i += 1)
1290 char *ksname;
1292 keysym = TSXLookupKeysym(&e2, i);
1293 ksname = TSXKeysymToString(keysym);
1294 if (!ksname)
1295 ksname = "NoSymbol";
1296 DPRINTF( "%lX (%s) ", keysym, ksname);
1298 DPRINTF(")\n");
1302 keyc2vkey[e2.keycode] = vkey;
1303 keyc2scan[e2.keycode] = scan;
1304 } /* for */
1306 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1307 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1308 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1309 char *ksname;
1310 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1311 ksname = TSXKeysymToString(keysym);
1312 if (!ksname) ksname = "NoSymbol";
1314 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1316 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1317 keyc2scan[keyc]=scan++;
1320 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1321 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1322 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1323 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1324 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1325 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1326 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1330 /***********************************************************************
1331 * X11DRV_MappingNotify
1333 void X11DRV_MappingNotify( XMappingEvent *event )
1335 TSXRefreshKeyboardMapping(event);
1336 X11DRV_InitKeyboard( pKeyStateTable );
1340 /***********************************************************************
1341 * VkKeyScan (X11DRV.@)
1343 WORD X11DRV_VkKeyScan(CHAR cChar)
1345 Display *display = thread_display();
1346 KeyCode keycode;
1347 KeySym keysym;
1348 int i,index;
1349 int highbyte=0;
1351 /* char->keysym (same for ANSI chars) */
1352 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1353 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1355 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1356 if (!keycode)
1357 { /* It didn't work ... let's try with deadchar code. */
1358 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1361 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1362 cChar,keysym,keysym,keycode);
1364 if (keycode)
1366 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1367 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1368 switch (index) {
1369 case -1 :
1370 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1371 case 0 : break;
1372 case 1 : highbyte = 0x0100; break;
1373 case 2 : highbyte = 0x0600; break;
1374 case 3 : highbyte = 0x0700; break;
1375 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1378 index : 0 adds 0x0000
1379 index : 1 adds 0x0100 (shift)
1380 index : ? adds 0x0200 (ctrl)
1381 index : 2 adds 0x0600 (ctrl+alt)
1382 index : 3 adds 0x0700 (ctrl+alt+shift)
1385 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1386 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1389 /***********************************************************************
1390 * MapVirtualKey (X11DRV.@)
1392 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1394 Display *display = thread_display();
1396 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1398 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1399 switch(wMapType) {
1400 case 0: { /* vkey-code to scan-code */
1401 /* let's do vkey -> keycode -> scan */
1402 int keyc;
1403 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1404 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1405 returnMVK (keyc2scan[keyc] & 0xFF);
1406 TRACE("returning no scan-code.\n");
1407 return 0; }
1409 case 1: { /* scan-code to vkey-code */
1410 /* let's do scan -> keycode -> vkey */
1411 int keyc;
1412 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1413 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1414 returnMVK (keyc2vkey[keyc] & 0xFF);
1415 TRACE("returning no vkey-code.\n");
1416 return 0; }
1418 case 2: { /* vkey-code to unshifted ANSI code */
1419 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1420 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1421 * key.. Looks like something is wrong with the MS docs?
1422 * This is only true for letters, for example VK_0 returns '0' not ')'.
1423 * - hence we use the lock mask to ensure this happens.
1425 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1426 XKeyEvent e;
1427 KeySym keysym;
1428 int keyc;
1429 char s[2];
1430 e.display = display;
1432 e.state = LockMask;
1433 /* LockMask should behave exactly like caps lock - upercase
1434 * the letter keys and thats about it. */
1436 e.keycode = 0;
1437 /* We exit on the first keycode found, to speed up the thing. */
1438 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1439 { /* Find a keycode that could have generated this virtual key */
1440 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1441 { /* We filter the extended bit, we don't know it */
1442 e.keycode = keyc; /* Store it temporarily */
1443 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1444 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1445 state), so set it to 0, we'll find another one */
1450 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1451 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1453 if (wCode==VK_DECIMAL)
1454 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1456 if (!e.keycode)
1458 WARN("Unknown virtual key %X !!! \n", wCode);
1459 return 0; /* whatever */
1461 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1463 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1464 returnMVK (*s);
1466 TRACE("returning no ANSI.\n");
1467 return 0;
1470 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1471 /* left and right */
1472 FIXME(" stub for NT\n");
1473 return 0;
1475 default: /* reserved */
1476 WARN("Unknown wMapType %d !\n", wMapType);
1477 return 0;
1479 return 0;
1482 /***********************************************************************
1483 * GetKeyNameText (X11DRV.@)
1485 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1487 int vkey, ansi, scanCode;
1488 KeyCode keyc;
1489 int keyi;
1490 KeySym keys;
1491 char *name;
1493 scanCode = lParam >> 16;
1494 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1496 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1497 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1499 /* handle "don't care" bit (0x02000000) */
1500 if (!(lParam & 0x02000000)) {
1501 switch (vkey) {
1502 case VK_LSHIFT:
1503 case VK_RSHIFT:
1504 vkey = VK_SHIFT;
1505 break;
1506 case VK_LCONTROL:
1507 case VK_RCONTROL:
1508 vkey = VK_CONTROL;
1509 break;
1510 case VK_LMENU:
1511 case VK_RMENU:
1512 vkey = VK_MENU;
1513 break;
1514 default:
1515 break;
1519 ansi = X11DRV_MapVirtualKey(vkey, 2);
1520 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1522 /* first get the name of the "regular" keys which is the Upper case
1523 value of the keycap imprint. */
1524 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1525 (scanCode != 0x137) && /* PrtScn */
1526 (scanCode != 0x135) && /* numpad / */
1527 (scanCode != 0x37 ) && /* numpad * */
1528 (scanCode != 0x4a ) && /* numpad - */
1529 (scanCode != 0x4e ) ) /* numpad + */
1531 if ((nSize >= 2) && lpBuffer)
1533 *lpBuffer = toupper((char)ansi);
1534 *(lpBuffer+1) = 0;
1535 return 1;
1537 else
1538 return 0;
1541 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1542 without "extended-key" flag. However Wine generates scancode
1543 *with* "extended-key" flag. Seems to occur *only* for the
1544 function keys. Soooo.. We will leave the table alone and
1545 fudge the lookup here till the other part is found and fixed!!! */
1547 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1548 (scanCode == 0x157) || (scanCode == 0x158))
1549 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1551 /* let's do scancode -> keycode -> keysym -> String */
1553 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1554 if ((keyc2scan[keyi]) == scanCode)
1555 break;
1556 if (keyi <= max_keycode)
1558 keyc = (KeyCode) keyi;
1559 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1560 name = TSXKeysymToString(keys);
1561 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1562 scanCode, keyc, (int)keys, name);
1563 if (lpBuffer && nSize && name)
1565 lstrcpynA(lpBuffer, name, nSize);
1566 return 1;
1570 /* Finally issue FIXME for unknown keys */
1572 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1573 if (lpBuffer && nSize)
1574 *lpBuffer = 0;
1575 return 0;
1578 /***********************************************************************
1579 * X11DRV_KEYBOARD_MapDeadKeysym
1581 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1583 switch (keysym)
1585 /* symbolic ASCII is the same as defined in rfc1345 */
1586 #ifdef XK_dead_tilde
1587 case XK_dead_tilde :
1588 #endif
1589 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1590 return '~'; /* '? */
1591 #ifdef XK_dead_acute
1592 case XK_dead_acute :
1593 #endif
1594 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1595 return 0xb4; /* '' */
1596 #ifdef XK_dead_circumflex
1597 case XK_dead_circumflex:
1598 #endif
1599 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1600 return '^'; /* '> */
1601 #ifdef XK_dead_grave
1602 case XK_dead_grave :
1603 #endif
1604 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1605 return '`'; /* '! */
1606 #ifdef XK_dead_diaeresis
1607 case XK_dead_diaeresis :
1608 #endif
1609 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1610 return 0xa8; /* ': */
1611 #ifdef XK_dead_cedilla
1612 case XK_dead_cedilla :
1613 return 0xb8; /* ', */
1614 #endif
1615 #ifdef XK_dead_macron
1616 case XK_dead_macron :
1617 return '-'; /* 'm isn't defined on iso-8859-x */
1618 #endif
1619 #ifdef XK_dead_breve
1620 case XK_dead_breve :
1621 return 0xa2; /* '( */
1622 #endif
1623 #ifdef XK_dead_abovedot
1624 case XK_dead_abovedot :
1625 return 0xff; /* '. */
1626 #endif
1627 #ifdef XK_dead_abovering
1628 case XK_dead_abovering :
1629 return '0'; /* '0 isn't defined on iso-8859-x */
1630 #endif
1631 #ifdef XK_dead_doubleacute
1632 case XK_dead_doubleacute :
1633 return 0xbd; /* '" */
1634 #endif
1635 #ifdef XK_dead_caron
1636 case XK_dead_caron :
1637 return 0xb7; /* '< */
1638 #endif
1639 #ifdef XK_dead_ogonek
1640 case XK_dead_ogonek :
1641 return 0xb2; /* '; */
1642 #endif
1643 /* FIXME: I don't know this three.
1644 case XK_dead_iota :
1645 return 'i';
1646 case XK_dead_voiced_sound :
1647 return 'v';
1648 case XK_dead_semivoiced_sound :
1649 return 's';
1652 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1653 return 0;
1656 /***********************************************************************
1657 * ToUnicode (X11DRV.@)
1659 * The ToUnicode function translates the specified virtual-key code and keyboard
1660 * state to the corresponding Windows character or characters.
1662 * If the specified key is a dead key, the return value is negative. Otherwise,
1663 * it is one of the following values:
1664 * Value Meaning
1665 * 0 The specified virtual key has no translation for the current state of the keyboard.
1666 * 1 One Windows character was copied to the buffer.
1667 * 2 Two characters were copied to the buffer. This usually happens when a
1668 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1669 * be composed with the specified virtual key to form a single character.
1671 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1674 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1675 LPWSTR bufW, int bufW_size, UINT flags)
1677 Display *display = thread_display();
1678 XKeyEvent e;
1679 KeySym keysym;
1680 INT ret;
1681 int keyc;
1682 BYTE lpChar[2];
1684 if (scanCode & 0x8000)
1686 TRACE("Key UP, doing nothing\n" );
1687 return 0;
1689 e.display = display;
1690 e.keycode = 0;
1691 e.state = 0;
1692 if (lpKeyState[VK_SHIFT] & 0x80)
1694 TRACE("ShiftMask = %04x\n", ShiftMask);
1695 e.state |= ShiftMask;
1697 if (lpKeyState[VK_CAPITAL] & 0x01)
1699 TRACE("LockMask = %04x\n", LockMask);
1700 e.state |= LockMask;
1702 if (lpKeyState[VK_CONTROL] & 0x80)
1704 TRACE("ControlMask = %04x\n", ControlMask);
1705 e.state |= ControlMask;
1707 if (lpKeyState[VK_NUMLOCK] & 0x01)
1709 TRACE("NumLockMask = %04x\n", NumLockMask);
1710 e.state |= NumLockMask;
1713 /* Restore saved AltGr state */
1714 TRACE("AltGrMask = %04x\n", AltGrMask);
1715 e.state |= AltGrMask;
1717 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1718 virtKey, scanCode, e.state);
1719 /* We exit on the first keycode found, to speed up the thing. */
1720 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1721 { /* Find a keycode that could have generated this virtual key */
1722 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1723 { /* We filter the extended bit, we don't know it */
1724 e.keycode = keyc; /* Store it temporarily */
1725 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1726 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1727 state), so set it to 0, we'll find another one */
1732 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1733 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1735 if (virtKey==VK_DECIMAL)
1736 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1738 if (!e.keycode)
1740 WARN("Unknown virtual key %X !!! \n",virtKey);
1741 return virtKey; /* whatever */
1743 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1745 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1746 if (ret == 0)
1748 BYTE dead_char;
1750 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1751 if (dead_char)
1753 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1754 ret = -1;
1756 else
1758 char *ksname;
1760 ksname = TSXKeysymToString(keysym);
1761 if (!ksname)
1762 ksname = "No Name";
1763 if ((keysym >> 8) != 0xff)
1765 ERR("Please report: no char for keysym %04lX (%s) :\n",
1766 keysym, ksname);
1767 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1768 virtKey, scanCode, e.keycode, e.state);
1772 else { /* ret != 0 */
1773 /* We have a special case to handle : Shift + arrow, shift + home, ...
1774 X returns a char for it, but Windows doesn't. Let's eat it. */
1775 if (!(e.state & NumLockMask) /* NumLock is off */
1776 && (e.state & ShiftMask) /* Shift is pressed */
1777 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1779 *(char*)lpChar = 0;
1780 ret = 0;
1783 /* more areas where X returns characters but Windows does not
1784 CTRL + number or CTRL + symbol*/
1785 if (e.state & ControlMask)
1787 if (((keysym>=33) && (keysym < 'A')) ||
1788 ((keysym > 'Z') && (keysym < 'a')))
1790 *(char*)lpChar = 0;
1791 ret = 0;
1795 /* We have another special case for delete key (XK_Delete) on an
1796 extended keyboard. X returns a char for it, but Windows doesn't */
1797 if (keysym == XK_Delete)
1799 *(char*)lpChar = 0;
1800 ret = 0;
1802 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1803 && (keysym == XK_KP_Decimal))
1805 *(char*)lpChar = 0;
1806 ret = 0;
1809 /* perform translation to unicode */
1810 if(ret)
1812 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1813 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1814 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1818 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1819 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1820 return ret;
1823 /***********************************************************************
1824 * Beep (X11DRV.@)
1826 void X11DRV_Beep(void)
1828 TSXBell(thread_display(), 0);