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
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
32 #include "ts_xresource.h"
35 #include <X11/XKBlib.h>
43 #include "wine/winuser16.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 */
60 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
63 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
65 /* Keyboard translation tables */
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",",;",".:","-_",
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",",<",".>","/?",
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",",?",";.",":/","!§",
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",",;",".:","þÞ",
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
\80","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µ",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",'-",".","éÉ",
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", ",;", ".:", "-_",
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µ",",;",".:·","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",?",";.",":/","=+~",
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",",?;",".:·","-_*",
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",",<",".>","/?",
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",",<",".>","/?",
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§",",;",".:","-_/",
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",",<",".>","/?",
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",",<",".>","/?",
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",",?<",".:>","-_*",
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åÅ",",<",".>","/?",
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",",?<",".:>","-_*",
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",",;",".:","-_",
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 /*** VNC keyboard layout */
535 static const WORD main_key_scan_vnc[MAIN_LEN] =
537 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
538 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,
542 static const WORD main_key_vkey_vnc[MAIN_LEN] =
544 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,
545 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,
549 static const char main_key_vnc[MAIN_LEN][4] =
551 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
552 "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"
555 /*** Layout table. Add your keyboard mappings to this list */
556 static const struct {
558 const UINT layout_cp; /* Code page for this layout */
559 const char (*key)[MAIN_LEN][4];
560 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
561 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
563 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
564 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
565 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
566 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
567 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
568 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
569 {"German keyboard layout for logitech desktop pro", 28591, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
570 {"German keyboard layout without dead keys 105", 28591, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
571 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
572 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
573 {"Estonian keyboard layout", 28591, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
574 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
575 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
576 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
577 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
578 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
579 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
580 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
581 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
582 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
583 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
584 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
585 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
586 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
587 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
588 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
589 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
590 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
591 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
592 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
593 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
594 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
595 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
596 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
597 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
598 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
599 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
600 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
601 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
602 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
603 {"VNC keyboard layout", 28591, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
605 {NULL, 0, NULL, NULL, NULL} /* sentinel */
607 static unsigned kbd_layout=0; /* index into above table of layouts */
609 /* maybe more of these scancodes should be extended? */
610 /* extended must be set for ALT_R, CTRL_R,
611 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
612 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
613 /* FIXME should we set extended bit for NumLock ? My
614 * Windows does ... DF */
615 /* Yes, to distinguish based on scan codes, also
616 for PrtScn key ... GA */
618 static const WORD nonchar_key_vkey[256] =
621 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
623 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
624 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
625 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
627 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
628 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
629 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
630 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
631 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
632 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
634 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
635 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
636 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
638 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
639 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
640 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
642 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
643 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
644 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
645 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
646 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
647 VK_END, 0, VK_INSERT, VK_DELETE,
648 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
649 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
650 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
651 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
652 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
653 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
656 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
657 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
658 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
659 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
661 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
662 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
663 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
664 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
665 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
668 static const WORD nonchar_key_scan[256] =
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
673 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
674 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
675 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
684 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
687 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
688 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
693 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
694 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
695 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
697 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
698 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
699 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
702 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
703 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
707 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
708 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
714 /* Returns the Windows virtual key code associated with the X event <e> */
715 static WORD EVENT_event_to_vkey( XKeyEvent *e)
719 TSXLookupString(e, NULL, 0, &keysym, NULL);
721 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
722 && (e->state & NumLockMask))
723 /* Only the Keypad keys 0-9 and . send different keysyms
724 * depending on the NumLock state */
725 return nonchar_key_vkey[keysym & 0xFF];
727 return keyc2vkey[e->keycode];
730 static BOOL NumState=FALSE, CapsState=FALSE;
733 /***********************************************************************
734 * send_keyboard_input
736 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
740 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
741 input.u.ki.wVk = wVk;
742 input.u.ki.wScan = wScan;
743 input.u.ki.dwFlags = dwFlags;
744 input.u.ki.time = time;
745 input.u.ki.dwExtraInfo = 0;
746 SendInput( 1, &input, sizeof(input) );
750 /**********************************************************************
751 * KEYBOARD_GenerateMsg
753 * Generate Down+Up messages when NumLock or CapsLock is pressed.
755 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
758 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
760 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
764 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
765 don't treat it. It's from the same key press. Then the state goes to ON.
766 And from there, a 'release' event will switch off the toggle key. */
768 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
771 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
772 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
773 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
775 if (Evtype!=KeyPress)
777 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
778 send_keyboard_input( vkey, scan, down, event_time );
779 send_keyboard_input( vkey, scan, up, event_time );
781 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
784 else /* it was OFF */
785 if (Evtype==KeyPress)
787 TRACE("OFF + Keypress => 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=TRUE; /* Goes to intermediary state before going to ON */
791 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
796 /***********************************************************************
797 * KEYBOARD_UpdateOneState
799 * Updates internal state for <vkey>, depending on key <state> under X
802 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
804 /* Do something if internal table state != X state for keycode */
805 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
807 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
808 vkey, pKeyStateTable[vkey]);
810 /* Fake key being pressed inside wine */
811 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
813 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
817 /***********************************************************************
818 * X11DRV_KeymapNotify
820 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
822 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
823 * from wine to another application and back.
824 * Toggle keys are handled in HandleEvent.
826 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
828 int i, j, alt, control, shift;
829 DWORD time = GetCurrentTime();
831 alt = control = shift = 0;
832 for (i = 0; i < 32; i++)
834 if (!event->key_vector[i]) continue;
835 for (j = 0; j < 8; j++)
837 if (!(event->key_vector[i] & (1<<j))) continue;
838 switch(keyc2vkey[(i * 8) + j] & 0xff)
840 case VK_MENU: alt = 1; break;
841 case VK_CONTROL: control = 1; break;
842 case VK_SHIFT: shift = 1; break;
846 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
847 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
848 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
851 /***********************************************************************
854 * Handle a X key event
856 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
860 WORD vkey = 0, bScan;
864 DWORD event_time = event->time - X11DRV_server_startticks;
866 /* this allows support for dead keys */
867 if ((event->keycode >> 8) == 0x10)
868 event->keycode=(event->keycode & 0xff);
870 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
872 /* Ignore some unwanted events */
873 if (keysym == XK_ISO_Prev_Group ||
874 keysym == XK_ISO_Next_Group ||
875 keysym == XK_Mode_switch)
877 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
881 TRACE_(key)("state = %X\n", event->state);
883 /* If XKB extensions is used, the state mask for AltGr will used the group
884 index instead of the modifier mask. The group index is set in bits
885 13-14 of the state field in the XKeyEvent structure. So if AltGr is
886 pressed, look if the group index is diferent than 0. From XKB
887 extension documentation, the group index should for AltGr should
888 be 2 (event->state = 0x2000). It's probably better to not assume a
889 predefined group index and find it dynamically
891 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
892 AltGrMask = event->state & 0x6000;
894 Str[ascii_chars] = '\0';
898 ksname = TSXKeysymToString(keysym);
901 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
902 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
903 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
906 vkey = EVENT_event_to_vkey(event);
908 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
909 event->keycode, vkey);
916 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
919 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
920 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
921 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
924 /* Adjust the NUMLOCK state if it has been changed outside wine */
925 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
927 TRACE("Adjusting NumLock state. \n");
928 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
929 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
931 /* Adjust the CAPSLOCK state if it has been changed outside wine */
932 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
934 TRACE("Adjusting Caps Lock state.\n");
935 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
936 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
938 /* Not Num nor Caps : end of intermediary states for both. */
942 bScan = keyc2scan[event->keycode] & 0xFF;
943 TRACE_(key)("bScan = 0x%02x.\n", bScan);
946 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
947 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
949 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
954 /**********************************************************************
955 * X11DRV_KEYBOARD_DetectLayout
957 * Called from X11DRV_InitKeyboard
958 * This routine walks through the defined keyboard layouts and selects
959 * whichever matches most closely.
962 X11DRV_KEYBOARD_DetectLayout (void)
964 Display *display = thread_display();
965 unsigned current, match, mismatch, seq;
966 int score, keyc, i, key, pkey, ok, syms;
968 const char (*lkey)[MAIN_LEN][4];
969 unsigned max_seq = 0;
970 int max_score = 0, ismatch = 0;
974 syms = keysyms_per_keycode;
976 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
979 for (current = 0; main_key_tab[current].comment; current++) {
980 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
985 lkey = main_key_tab[current].key;
987 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
988 /* get data for keycode from X server */
989 for (i = 0; i < syms; i++) {
990 keysym = TSXKeycodeToKeysym (display, keyc, i);
991 /* Allow both one-byte and two-byte national keysyms */
992 if ((keysym < 0x800) && (keysym != ' '))
993 ckey[i] = keysym & 0xFF;
995 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
999 /* search for a match in layout table */
1000 /* right now, we just find an absolute match for defined positions */
1001 /* (undefined positions are ignored, so if it's defined as "3#" in */
1002 /* the table, it's okay that the X server has "3#£", for example) */
1003 /* however, the score will be higher for longer matches */
1004 for (key = 0; key < MAIN_LEN; key++) {
1005 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1006 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1008 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1016 /* count the matches and mismatches */
1019 /* and how much the keycode order matches */
1020 if (key > pkey) seq++;
1023 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
1030 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1031 match, mismatch, seq, score);
1032 if ((score > max_score) ||
1033 ((score == max_score) && (seq > max_seq))) {
1034 /* best match so far */
1035 kbd_layout = current;
1038 ismatch = !mismatch;
1041 /* we're done, report results if necessary */
1044 "Your keyboard layout was not found!\n"
1045 "Using closest match instead (%s) for scancode mapping.\n"
1046 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1047 "to us for inclusion into future Wine releases.\n"
1048 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1049 main_key_tab[kbd_layout].comment);
1052 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1055 /**********************************************************************
1056 * InitKeyboard (X11DRV.@)
1058 void X11DRV_InitKeyboard( BYTE *key_state_table )
1061 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1063 Display *display = thread_display();
1065 XModifierKeymap *mmp;
1069 WORD scan, vkey, OEMvkey;
1070 int keyc, i, keyn, syms;
1071 char ckey[4]={0,0,0,0};
1072 const char (*lkey)[MAIN_LEN][4];
1074 pKeyStateTable = key_state_table;
1078 is_xkb = XkbQueryExtension(display,
1079 &xkb_opcode, &xkb_event, &xkb_error,
1080 &xkb_major, &xkb_minor);
1082 /* we have XKB, approximate Windows behaviour */
1083 XkbSetDetectableAutoRepeat(display, True, NULL);
1085 wine_tsx11_unlock();
1087 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
1088 ksp = TSXGetKeyboardMapping(display, min_keycode,
1089 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1090 /* We are only interested in keysyms_per_keycode.
1091 There is no need to hold a local copy of the keysyms table */
1093 mmp = TSXGetModifierMapping(display);
1094 kcp = mmp->modifiermap;
1095 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1099 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1104 for (k = 0; k < keysyms_per_keycode; k += 1)
1105 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1107 NumLockMask = 1 << i;
1108 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1112 TSXFreeModifiermap(mmp);
1114 /* Detect the keyboard layout */
1115 X11DRV_KEYBOARD_DetectLayout();
1116 lkey = main_key_tab[kbd_layout].key;
1117 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1119 /* Now build two conversion arrays :
1120 * keycode -> vkey + scancode + extended
1121 * vkey + extended -> keycode */
1123 e2.display = display;
1126 OEMvkey = VK_OEM_7; /* next is available. */
1127 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1129 e2.keycode = (KeyCode)keyc;
1130 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1132 if (keysym) /* otherwise, keycode not used */
1134 if ((keysym >> 8) == 0xFF) /* non-character key */
1136 vkey = nonchar_key_vkey[keysym & 0xff];
1137 scan = nonchar_key_scan[keysym & 0xff];
1138 /* set extended bit when necessary */
1139 if (scan & 0x100) vkey |= 0x100;
1140 } else if (keysym == 0x20) { /* Spacebar */
1144 /* we seem to need to search the layout-dependent scancodes */
1145 int maxlen=0,maxval=-1,ok;
1146 for (i=0; i<syms; i++) {
1147 keysym = TSXKeycodeToKeysym(display, keyc, i);
1148 if ((keysym<0x800) && (keysym!=' ')) {
1149 ckey[i] = keysym & 0xFF;
1151 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1154 /* find key with longest match streak */
1155 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1156 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1157 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1158 if (ok||(i>maxlen)) {
1159 maxlen=i; maxval=keyn;
1165 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1166 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1167 scan = (*lscan)[maxval];
1168 vkey = (*lvkey)[maxval];
1172 /* find a suitable layout-dependent VK code */
1173 /* (most Winelib apps ought to be able to work without layout tables!) */
1174 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1176 keysym = TSXLookupKeysym(&e2, i);
1177 if ((keysym >= VK_0 && keysym <= VK_9)
1178 || (keysym >= VK_A && keysym <= VK_Z)) {
1183 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1185 keysym = TSXLookupKeysym(&e2, i);
1188 case ';': vkey = VK_OEM_1; break;
1189 case '/': vkey = VK_OEM_2; break;
1190 case '`': vkey = VK_OEM_3; break;
1191 case '[': vkey = VK_OEM_4; break;
1192 case '\\': vkey = VK_OEM_5; break;
1193 case ']': vkey = VK_OEM_6; break;
1194 case '\'': vkey = VK_OEM_7; break;
1195 case ',': vkey = VK_OEM_COMMA; break;
1196 case '.': vkey = VK_OEM_PERIOD; break;
1197 case '-': vkey = VK_OEM_MINUS; break;
1198 case '+': vkey = VK_OEM_PLUS; break;
1204 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1205 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1208 case 0xc1 : OEMvkey=0xdb; break;
1209 case 0xe5 : OEMvkey=0xe9; break;
1210 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1215 if (TRACE_ON(keyboard))
1217 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1218 OEMvkey, e2.keycode);
1220 for (i = 0; i < keysyms_per_keycode; i += 1)
1224 keysym = TSXLookupKeysym(&e2, i);
1225 ksname = TSXKeysymToString(keysym);
1227 ksname = "NoSymbol";
1228 DPRINTF( "%lX (%s) ", keysym, ksname);
1234 keyc2vkey[e2.keycode] = vkey;
1235 keyc2scan[e2.keycode] = scan;
1238 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1239 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1240 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1242 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1243 ksname = TSXKeysymToString(keysym);
1244 if (!ksname) ksname = "NoSymbol";
1246 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1248 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1249 keyc2scan[keyc]=scan++;
1252 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1253 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1254 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1255 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1256 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1257 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1258 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1262 /***********************************************************************
1263 * X11DRV_MappingNotify
1265 void X11DRV_MappingNotify( XMappingEvent *event )
1267 TSXRefreshKeyboardMapping(event);
1268 X11DRV_InitKeyboard( pKeyStateTable );
1272 /***********************************************************************
1273 * VkKeyScan (X11DRV.@)
1275 WORD X11DRV_VkKeyScan(CHAR cChar)
1277 Display *display = thread_display();
1283 /* char->keysym (same for ANSI chars) */
1284 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1285 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1287 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1289 { /* It didn't work ... let's try with deadchar code. */
1290 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1293 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1294 cChar,keysym,keysym,keycode);
1298 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1299 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1302 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1304 case 1 : highbyte = 0x0100; break;
1305 case 2 : highbyte = 0x0600; break;
1306 case 3 : highbyte = 0x0700; break;
1307 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1310 index : 0 adds 0x0000
1311 index : 1 adds 0x0100 (shift)
1312 index : ? adds 0x0200 (ctrl)
1313 index : 2 adds 0x0600 (ctrl+alt)
1314 index : 3 adds 0x0700 (ctrl+alt+shift)
1317 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1318 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1321 /***********************************************************************
1322 * MapVirtualKey (X11DRV.@)
1324 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1326 Display *display = thread_display();
1328 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1330 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1332 case 0: { /* vkey-code to scan-code */
1333 /* let's do vkey -> keycode -> scan */
1335 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1336 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1337 returnMVK (keyc2scan[keyc] & 0xFF);
1338 TRACE("returning no scan-code.\n");
1341 case 1: { /* scan-code to vkey-code */
1342 /* let's do scan -> keycode -> vkey */
1344 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1345 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1346 returnMVK (keyc2vkey[keyc] & 0xFF);
1347 TRACE("returning no vkey-code.\n");
1350 case 2: { /* vkey-code to unshifted ANSI code */
1351 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1352 /* My Windows returns 'A'. */
1353 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1358 e.display = display;
1359 e.state = 0; /* unshifted */
1362 /* We exit on the first keycode found, to speed up the thing. */
1363 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1364 { /* Find a keycode that could have generated this virtual key */
1365 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1366 { /* We filter the extended bit, we don't know it */
1367 e.keycode = keyc; /* Store it temporarily */
1368 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1369 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1370 state), so set it to 0, we'll find another one */
1375 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1376 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1378 if (wCode==VK_DECIMAL)
1379 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1383 WARN("Unknown virtual key %X !!! \n", wCode);
1384 return 0; /* whatever */
1386 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1388 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1391 TRACE("returning no ANSI.\n");
1395 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1396 /* left and right */
1397 FIXME(" stub for NT\n");
1400 default: /* reserved */
1401 WARN("Unknown wMapType %d !\n", wMapType);
1407 /***********************************************************************
1408 * GetKeyNameText (X11DRV.@)
1410 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1412 int vkey, ansi, scanCode;
1418 scanCode = lParam >> 16;
1419 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1421 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1422 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1424 /* handle "don't care" bit (0x02000000) */
1425 if (!(lParam & 0x02000000)) {
1444 ansi = X11DRV_MapVirtualKey(vkey, 2);
1445 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1447 /* first get the name of the "regular" keys which is the Upper case
1448 value of the keycap imprint. */
1449 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1450 (scanCode != 0x137) && /* PrtScn */
1451 (scanCode != 0x135) && /* numpad / */
1452 (scanCode != 0x37 ) && /* numpad * */
1453 (scanCode != 0x4a ) && /* numpad - */
1454 (scanCode != 0x4e ) ) /* numpad + */
1456 if ((nSize >= 2) && lpBuffer)
1458 *lpBuffer = toupper((char)ansi);
1466 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1467 without "extended-key" flag. However Wine generates scancode
1468 *with* "extended-key" flag. Seems to occur *only* for the
1469 function keys. Soooo.. We will leave the table alone and
1470 fudge the lookup here till the other part is found and fixed!!! */
1472 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1473 (scanCode == 0x157) || (scanCode == 0x158))
1474 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1476 /* let's do scancode -> keycode -> keysym -> String */
1478 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1479 if ((keyc2scan[keyi]) == scanCode)
1481 if (keyi <= max_keycode)
1483 keyc = (KeyCode) keyi;
1484 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1485 name = TSXKeysymToString(keys);
1486 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1487 scanCode, keyc, (int)keys, name);
1488 if (lpBuffer && nSize && name)
1490 lstrcpynA(lpBuffer, name, nSize);
1495 /* Finally issue FIXME for unknown keys */
1497 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1498 if (lpBuffer && nSize)
1503 /***********************************************************************
1504 * X11DRV_KEYBOARD_MapDeadKeysym
1506 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1510 /* symbolic ASCII is the same as defined in rfc1345 */
1511 #ifdef XK_dead_tilde
1512 case XK_dead_tilde :
1514 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1515 return '~'; /* '? */
1516 #ifdef XK_dead_acute
1517 case XK_dead_acute :
1519 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1520 return 0xb4; /* '' */
1521 #ifdef XK_dead_circumflex
1522 case XK_dead_circumflex:
1524 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1525 return '^'; /* '> */
1526 #ifdef XK_dead_grave
1527 case XK_dead_grave :
1529 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1530 return '`'; /* '! */
1531 #ifdef XK_dead_diaeresis
1532 case XK_dead_diaeresis :
1534 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1535 return 0xa8; /* ': */
1536 #ifdef XK_dead_cedilla
1537 case XK_dead_cedilla :
1538 return 0xb8; /* ', */
1540 #ifdef XK_dead_macron
1541 case XK_dead_macron :
1542 return '-'; /* 'm isn't defined on iso-8859-x */
1544 #ifdef XK_dead_breve
1545 case XK_dead_breve :
1546 return 0xa2; /* '( */
1548 #ifdef XK_dead_abovedot
1549 case XK_dead_abovedot :
1550 return 0xff; /* '. */
1552 #ifdef XK_dead_abovering
1553 case XK_dead_abovering :
1554 return '0'; /* '0 isn't defined on iso-8859-x */
1556 #ifdef XK_dead_doubleacute
1557 case XK_dead_doubleacute :
1558 return 0xbd; /* '" */
1560 #ifdef XK_dead_caron
1561 case XK_dead_caron :
1562 return 0xb7; /* '< */
1564 #ifdef XK_dead_ogonek
1565 case XK_dead_ogonek :
1566 return 0xb2; /* '; */
1568 /* FIXME: I don't know this three.
1571 case XK_dead_voiced_sound :
1573 case XK_dead_semivoiced_sound :
1577 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1581 /***********************************************************************
1582 * ToUnicode (X11DRV.@)
1584 * The ToUnicode function translates the specified virtual-key code and keyboard
1585 * state to the corresponding Windows character or characters.
1587 * If the specified key is a dead key, the return value is negative. Otherwise,
1588 * it is one of the following values:
1590 * 0 The specified virtual key has no translation for the current state of the keyboard.
1591 * 1 One Windows character was copied to the buffer.
1592 * 2 Two characters were copied to the buffer. This usually happens when a
1593 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1594 * be composed with the specified virtual key to form a single character.
1596 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1599 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1600 LPWSTR bufW, int bufW_size, UINT flags)
1602 Display *display = thread_display();
1609 if (scanCode & 0x8000)
1611 TRACE("Key UP, doing nothing\n" );
1614 e.display = display;
1617 if (lpKeyState[VK_SHIFT] & 0x80)
1619 TRACE("ShiftMask = %04x\n", ShiftMask);
1620 e.state |= ShiftMask;
1622 if (lpKeyState[VK_CAPITAL] & 0x01)
1624 TRACE("LockMask = %04x\n", LockMask);
1625 e.state |= LockMask;
1627 if (lpKeyState[VK_CONTROL] & 0x80)
1629 TRACE("ControlMask = %04x\n", ControlMask);
1630 e.state |= ControlMask;
1632 if (lpKeyState[VK_NUMLOCK] & 0x01)
1634 TRACE("NumLockMask = %04x\n", NumLockMask);
1635 e.state |= NumLockMask;
1638 /* Restore saved AltGr state */
1639 TRACE("AltGrMask = %04x\n", AltGrMask);
1640 e.state |= AltGrMask;
1642 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1643 virtKey, scanCode, e.state);
1644 /* We exit on the first keycode found, to speed up the thing. */
1645 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1646 { /* Find a keycode that could have generated this virtual key */
1647 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1648 { /* We filter the extended bit, we don't know it */
1649 e.keycode = keyc; /* Store it temporarily */
1650 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1651 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1652 state), so set it to 0, we'll find another one */
1657 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1658 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1660 if (virtKey==VK_DECIMAL)
1661 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1665 WARN("Unknown virtual key %X !!! \n",virtKey);
1666 return virtKey; /* whatever */
1668 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1670 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1675 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1678 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1685 ksname = TSXKeysymToString(keysym);
1688 if ((keysym >> 8) != 0xff)
1690 ERR("Please report: no char for keysym %04lX (%s) :\n",
1692 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1693 virtKey, scanCode, e.keycode, e.state);
1697 else { /* ret != 0 */
1698 /* We have a special case to handle : Shift + arrow, shift + home, ...
1699 X returns a char for it, but Windows doesn't. Let's eat it. */
1700 if (!(e.state & NumLockMask) /* NumLock is off */
1701 && (e.state & ShiftMask) /* Shift is pressed */
1702 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1708 /* more areas where X returns characters but Windows does not
1709 CTRL + number or CTRL + symbol*/
1710 if (e.state & ControlMask)
1712 if (((keysym>=33) && (keysym < 'A')) ||
1713 ((keysym > 'Z') && (keysym < 'a')))
1720 /* We have another special case for delete key (XK_Delete) on an
1721 extended keyboard. X returns a char for it, but Windows doesn't */
1722 if (keysym == XK_Delete)
1727 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1728 && (keysym == XK_KP_Decimal))
1734 /* perform translation to unicode */
1737 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1738 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1739 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1743 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1744 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1748 /***********************************************************************
1751 void X11DRV_Beep(void)
1753 TSXBell(thread_display(), 0);