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 <X11/Xresource.h>
33 #include <X11/Xutil.h>
35 #include <X11/XKBlib.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
45 #include "wine/winuser16.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(keyboard
);
52 WINE_DECLARE_DEBUG_CHANNEL(key
);
53 WINE_DECLARE_DEBUG_CHANNEL(dinput
);
55 int min_keycode
, max_keycode
, keysyms_per_keycode
;
56 WORD keyc2vkey
[256], keyc2scan
[256];
58 static LPBYTE pKeyStateTable
;
59 static int NumLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
60 static int kcControl
, kcAlt
, kcShift
, kcNumLock
, kcCapsLock
; /* keycodes */
62 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
64 /* Keyboard translation tables */
66 static const WORD main_key_scan_qwerty
[MAIN_LEN
] =
68 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
69 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
70 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
71 /* q w e r t y u i o p [ ] */
72 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
73 /* a s d f g h j k l ; ' \ */
74 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
75 /* z x c v b n m , . / */
76 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
77 0x56 /* the 102nd key (actually to the right of l-shift) */
80 static const WORD main_key_scan_abnt_qwerty
[MAIN_LEN
] =
82 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
83 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
84 /* q w e r t y u i o p [ ] */
85 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
86 /* a s d f g h j k l ; ' \ */
87 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
88 /* \ z x c v b n m , . / */
89 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
90 0x56, /* the 102nd key (actually to the right of l-shift) */
93 static const WORD main_key_scan_dvorak
[MAIN_LEN
] =
95 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
96 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
97 /* ' , . p y f g c r l / = */
98 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
99 /* a o e u i d h t n s - \ */
100 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
101 /* ; q j k x b m w v z */
102 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
103 0x56 /* the 102nd key (actually to the right of l-shift) */
106 static const WORD main_key_vkey_qwerty
[MAIN_LEN
] =
108 /* NOTE: this layout must concur with the scan codes layout above */
109 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
,
110 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
,
111 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
,
112 VK_Z
,VK_X
,VK_C
,VK_V
,VK_B
,VK_N
,VK_M
,VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
113 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
116 static const WORD main_key_vkey_abnt_qwerty
[MAIN_LEN
] =
118 /* NOTE: this layout must concur with the scan codes layout above */
119 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
,
120 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
,
121 VK_A
,VK_S
,VK_D
,VK_F
,VK_G
,VK_H
,VK_J
,VK_K
,VK_L
,VK_OEM_1
,VK_OEM_8
,VK_OEM_5
,
122 VK_OEM_7
,VK_Z
,VK_X
,VK_C
,VK_V
,VK_B
,VK_N
,VK_M
,VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,
123 VK_OEM_102
, /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_vkey_azerty
[MAIN_LEN
] =
128 /* NOTE: this layout must concur with the scan codes layout above */
129 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
,
130 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
,
131 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
,
132 VK_W
,VK_X
,VK_C
,VK_V
,VK_B
,VK_N
,VK_OEM_COMMA
,VK_OEM_PERIOD
,VK_OEM_2
,VK_OEM_8
,
133 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
136 static const WORD main_key_vkey_dvorak
[MAIN_LEN
] =
138 /* NOTE: this layout must concur with the scan codes layout above */
139 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
,
140 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
,
141 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
,
142 VK_OEM_1
,VK_Q
,VK_J
,VK_K
,VK_X
,VK_B
,VK_M
,VK_W
,VK_V
,VK_Z
,
143 VK_OEM_102
/* the 102nd key (actually to the right of l-shift) */
146 /* FIXME: add other layouts, such as German QWERTZ */
148 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
150 /* the VK mappings for the main keyboard will be auto-assigned as before,
151 so what we have here is just the character tables */
152 /* order: Normal, Shift, AltGr, Shift-AltGr */
153 /* We recommend you write just what is guaranteed to be correct (i.e. what's
154 written on the keycaps), not the bunch of special characters behind AltGr
155 and Shift-AltGr if it can vary among different X servers */
156 /* Remember that your 102nd key (to the right of l-shift) should be on a
157 separate line, see existing tables */
158 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
159 /* Remember to also add your new table to the layout index table far below! */
161 /*** German Logitech Desktop Pro keyboard layout */
162 static const char main_key_DE_logitech
[MAIN_LEN
][4] =
164 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
165 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
166 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
167 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
171 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
172 static const char main_key_US
[MAIN_LEN
][4] =
174 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
175 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
176 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
177 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
180 /*** United States keyboard layout (phantom key version) */
181 /* (XFree86 reports the <> key even if it's not physically there) */
182 static const char main_key_US_phantom
[MAIN_LEN
][4] =
184 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
185 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
186 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
187 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
188 "<>" /* the phantom key */
191 /*** United States keyboard layout (dvorak version) */
192 static const char main_key_US_dvorak
[MAIN_LEN
][4] =
194 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
195 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
196 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
197 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
200 /*** British keyboard layout */
201 static const char main_key_UK
[MAIN_LEN
][4] =
203 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
204 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
205 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
206 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
210 /*** French keyboard layout (contributed by Eric Pouech) */
211 static const char main_key_FR
[MAIN_LEN
][4] =
213 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
214 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
215 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
216 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
220 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
221 static const char main_key_IS
[MAIN_LEN
][4] =
223 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
224 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
225 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
226 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
230 /*** German keyboard layout (contributed by Ulrich Weigand) */
231 static const char main_key_DE
[MAIN_LEN
][4] =
233 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
234 "qQ@","wW","eE€","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
235 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
236 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
240 /*** German keyboard layout without dead keys */
241 static const char main_key_DE_nodead
[MAIN_LEN
][4] =
243 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
244 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
245 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
246 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
250 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
251 static const char main_key_DE_nodead_105
[MAIN_LEN
][4] =
253 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
254 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
255 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
256 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
259 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
260 static const char main_key_SG
[MAIN_LEN
][4] =
262 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
263 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
264 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
265 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
269 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
270 static const char main_key_SF
[MAIN_LEN
][4] =
272 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
273 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
274 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
275 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
279 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
280 static const char main_key_NO
[MAIN_LEN
][4] =
282 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
283 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
284 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
285 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
289 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
290 static const char main_key_DA
[MAIN_LEN
][4] =
292 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
293 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
294 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
295 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
299 /*** Swedish keyboard layout (contributed by Peter Bortas) */
300 static const char main_key_SE
[MAIN_LEN
][4] =
302 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
303 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
304 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
305 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
309 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
310 static const char main_key_ET
[MAIN_LEN
][4] =
312 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
313 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
314 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
315 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
319 /*** Canadian French keyboard layout */
320 static const char main_key_CF
[MAIN_LEN
][4] =
322 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
323 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
325 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
329 /*** Portuguese keyboard layout */
330 static const char main_key_PT
[MAIN_LEN
][4] =
332 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
333 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
334 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
335 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
339 /*** Italian keyboard layout */
340 static const char main_key_IT
[MAIN_LEN
][4] =
342 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
343 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
344 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
345 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
349 /*** Finnish keyboard layout */
350 static const char main_key_FI
[MAIN_LEN
][4] =
352 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
353 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
354 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
355 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
359 /*** Bulgarian bds keyboard layout */
360 static const char main_key_BG_bds
[MAIN_LEN
][4] =
362 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
363 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
364 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
365 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
366 "<>" /* the phantom key */
369 /*** Bulgarian phonetic keyboard layout */
370 static const char main_key_BG_phonetic
[MAIN_LEN
][4] =
372 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
373 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
374 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
375 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
376 "<>" /* the phantom key */
379 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
380 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
381 static const char main_key_BY
[MAIN_LEN
][4] =
383 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
384 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
385 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
386 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
390 /*** Russian keyboard layout (contributed by Pavel Roskin) */
391 static const char main_key_RU
[MAIN_LEN
][4] =
393 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
394 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
395 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
396 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
399 /*** Russian keyboard layout (phantom key version) */
400 static const char main_key_RU_phantom
[MAIN_LEN
][4] =
402 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
403 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
404 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
405 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
406 "<>" /* the phantom key */
409 /*** Russian keyboard layout KOI8-R */
410 static const char main_key_RU_koi8r
[MAIN_LEN
][4] =
412 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
413 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
414 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
415 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
416 "<>" /* the phantom key */
419 /*** Ukrainian keyboard layout KOI8-U */
420 static const char main_key_UA
[MAIN_LEN
][4] =
422 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
423 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
424 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
425 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
426 "<>" /* the phantom key */
429 /*** Spanish keyboard layout (contributed by José Marcos López) */
430 static const char main_key_ES
[MAIN_LEN
][4] =
432 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
433 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
434 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
435 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
439 /*** Belgian keyboard layout ***/
440 static const char main_key_BE
[MAIN_LEN
][4] =
442 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
443 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
444 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
445 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
449 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
450 static const char main_key_HU
[MAIN_LEN
][4] =
452 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
453 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
454 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
455 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
459 /*** Polish (programmer's) keyboard layout ***/
460 static const char main_key_PL
[MAIN_LEN
][4] =
462 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
463 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
464 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
465 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
469 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
470 static const char main_key_SI
[MAIN_LEN
][4] =
472 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
473 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
474 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
475 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
479 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
480 static const char main_key_HR_jelly
[MAIN_LEN
][4] =
482 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
483 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
484 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
485 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
489 /*** Croatian keyboard layout ***/
490 static const char main_key_HR
[MAIN_LEN
][4] =
492 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
493 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
494 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
495 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
499 /*** Japanese 106 keyboard layout ***/
500 static const char main_key_JA_jp106
[MAIN_LEN
][4] =
502 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
503 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
504 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
505 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
509 /*** Japanese pc98x1 keyboard layout ***/
510 static const char main_key_JA_pc98x1
[MAIN_LEN
][4] =
512 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
513 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
514 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
515 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
519 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
520 static const char main_key_PT_br
[MAIN_LEN
][4] =
522 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
523 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
524 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
525 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
529 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
530 static const char main_key_PT_br_alt_gr
[MAIN_LEN
][4] =
532 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
533 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
534 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
535 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
539 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
540 static const char main_key_US_intl
[MAIN_LEN
][4] =
542 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
543 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
544 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
545 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
548 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
549 - dead_abovering replaced with degree - no symbol in iso8859-2
550 - brokenbar replaced with bar */
551 static const char main_key_SK
[MAIN_LEN
][4] =
553 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
554 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
555 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ô\"","§!","ò)",
556 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
560 /*** Czech keyboard layout (setxkbmap cz) */
561 static const char main_key_CZ
[MAIN_LEN
][4] =
563 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
564 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
565 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
566 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
570 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
571 static const char main_key_CZ_qwerty
[MAIN_LEN
][4] =
573 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
574 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
575 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ù\"","§!","¨'",
576 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
580 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
581 static const char main_key_SK_prog
[MAIN_LEN
][4] =
583 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
584 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
585 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
586 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
590 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
591 static const char main_key_CS
[MAIN_LEN
][4] =
593 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
594 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
595 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
596 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
600 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
601 static const char main_key_LA
[MAIN_LEN
][4] =
603 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¿¡",
604 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
605 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
606 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
610 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
611 static const char main_key_LT_B
[MAIN_LEN
][4] =
613 "`~","1àÀ","2èÈ","3æÆ","4ëË","5áÁ","6ðÐ","7øØ","8ûÛ","9¥(","0´)","-_","=þÞ","\\|",
614 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
615 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
616 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
619 /*** Turkish keyboard Layout */
620 static const char main_key_TK
[MAIN_LEN
][4] =
622 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
623 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
624 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
625 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
628 /*** Israeli keyboard layout */
629 static const char main_key_IL
[MAIN_LEN
][4] =
631 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
632 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
633 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
634 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
637 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
638 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
639 message since they have different characters in gr and el XFree86 layouts. */
640 static const char main_key_EL
[MAIN_LEN
][4] =
642 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
643 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
644 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
645 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
649 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
650 static const char main_key_th
[MAIN_LEN
][4] =
652 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
653 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pPÂ","[{º°","]}Å,",
654 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
655 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
658 /*** VNC keyboard layout */
659 static const WORD main_key_scan_vnc
[MAIN_LEN
] =
661 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
662 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,
666 static const WORD main_key_vkey_vnc
[MAIN_LEN
] =
668 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
,
669 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
,
673 static const char main_key_vnc
[MAIN_LEN
][4] =
675 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
676 "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"
679 /*** Layout table. Add your keyboard mappings to this list */
680 static const struct {
682 const char (*key
)[MAIN_LEN
][4];
683 const WORD (*scan
)[MAIN_LEN
]; /* scan codes mapping */
684 const WORD (*vkey
)[MAIN_LEN
]; /* virtual key codes mapping */
686 {"United States keyboard layout", &main_key_US
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
687 {"United States keyboard layout (phantom key version)", &main_key_US_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
688 {"United States keyboard layout (dvorak)", &main_key_US_dvorak
, &main_key_scan_dvorak
, &main_key_vkey_dvorak
},
689 {"British keyboard layout", &main_key_UK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
690 {"German keyboard layout", &main_key_DE
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
691 {"German keyboard layout without dead keys", &main_key_DE_nodead
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
692 {"German keyboard layout for logitech desktop pro", &main_key_DE_logitech
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
693 {"German keyboard layout without dead keys 105", &main_key_DE_nodead_105
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
694 {"Swiss German keyboard layout", &main_key_SG
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
695 {"Swedish keyboard layout", &main_key_SE
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
696 {"Estonian keyboard layout", &main_key_ET
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
697 {"Norwegian keyboard layout", &main_key_NO
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
698 {"Danish keyboard layout", &main_key_DA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
699 {"French keyboard layout", &main_key_FR
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
700 {"Canadian French keyboard layout", &main_key_CF
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
701 {"Belgian keyboard layout", &main_key_BE
, &main_key_scan_qwerty
, &main_key_vkey_azerty
},
702 {"Swiss French keyboard layout", &main_key_SF
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
703 {"Portuguese keyboard layout", &main_key_PT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
704 {"Brazilian ABNT-2 keyboard layout", &main_key_PT_br
, &main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
705 {"Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr
,&main_key_scan_abnt_qwerty
, &main_key_vkey_abnt_qwerty
},
706 {"United States International keyboard layout", &main_key_US_intl
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
707 {"Finnish keyboard layout", &main_key_FI
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
708 {"Bulgarian bds keyboard layout", &main_key_BG_bds
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
709 {"Bulgarian phonetic keyboard layout", &main_key_BG_phonetic
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
710 {"Belarusian keyboard layout", &main_key_BY
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
711 {"Russian keyboard layout", &main_key_RU
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
712 {"Russian keyboard layout (phantom key version)", &main_key_RU_phantom
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
713 {"Russian keyboard layout KOI8-R", &main_key_RU_koi8r
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
714 {"Ukrainian keyboard layout KOI8-U", &main_key_UA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
715 {"Spanish keyboard layout", &main_key_ES
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
716 {"Italian keyboard layout", &main_key_IT
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
717 {"Icelandic keyboard layout", &main_key_IS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
718 {"Hungarian keyboard layout", &main_key_HU
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
719 {"Polish (programmer's) keyboard layout", &main_key_PL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
720 {"Slovenian keyboard layout", &main_key_SI
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
721 {"Croatian keyboard layout", &main_key_HR
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
722 {"Croatian keyboard layout (specific)", &main_key_HR_jelly
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
723 {"Japanese 106 keyboard layout", &main_key_JA_jp106
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
724 {"Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
725 {"Slovak keyboard layout", &main_key_SK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
726 {"Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
727 {"Czech keyboard layout", &main_key_CS
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
728 {"Czech keyboard layout cz", &main_key_CZ
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
729 {"Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
730 {"Latin American keyboard layout", &main_key_LA
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
731 {"Lithuanian (Baltic) keyboard layout", &main_key_LT_B
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
732 {"Turkish keyboard layout", &main_key_TK
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
733 {"Israeli keyboard layout", &main_key_IL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
734 {"VNC keyboard layout", &main_key_vnc
, &main_key_scan_vnc
, &main_key_vkey_vnc
},
735 {"Greek keyboard layout", &main_key_EL
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
736 {"Thai (Kedmanee) keyboard layout", &main_key_th
, &main_key_scan_qwerty
, &main_key_vkey_qwerty
},
738 {NULL
, NULL
, NULL
, NULL
} /* sentinel */
740 static unsigned kbd_layout
=0; /* index into above table of layouts */
742 /* maybe more of these scancodes should be extended? */
743 /* extended must be set for ALT_R, CTRL_R,
744 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
745 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
746 /* FIXME should we set extended bit for NumLock ? My
747 * Windows does ... DF */
748 /* Yes, to distinguish based on scan codes, also
749 for PrtScn key ... GA */
751 static const WORD nonchar_key_vkey
[256] =
754 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
756 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
757 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
758 0, 0, 0, VK_ESCAPE
, 0, 0, 0, 0, /* FF18 */
760 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
761 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
762 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
763 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
764 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
765 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
767 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, /* FF50 */
768 VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
,
769 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
771 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0, 0, 0, 0, /* FF60 */
772 VK_CANCEL
, VK_HELP
, VK_CANCEL
, VK_CANCEL
, 0, 0, 0, 0, /* FF68 */
773 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
775 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK
, /* FF78 */
776 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
777 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
778 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
779 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, /* FF98 */
780 VK_END
, 0, VK_INSERT
, VK_DELETE
,
781 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
782 0, 0, VK_MULTIPLY
, VK_ADD
, /* FFA8 */
783 VK_SEPARATOR
, VK_SUBTRACT
, VK_DECIMAL
, VK_DIVIDE
,
784 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, /* FFB0 */
785 VK_NUMPAD4
, VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
,
786 VK_NUMPAD8
, VK_NUMPAD9
, 0, 0, 0, 0, /* FFB8 */
789 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
790 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
, 0, 0, /* FFC8 */
791 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
792 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
794 0, VK_SHIFT
, VK_SHIFT
, VK_CONTROL
, /* FFE0 */
795 VK_CONTROL
, VK_CAPITAL
, 0, VK_MENU
,
796 VK_MENU
, VK_MENU
, VK_MENU
, 0, 0, 0, 0, 0, /* FFE8 */
797 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
798 0, 0, 0, 0, 0, 0, 0, VK_DELETE
/* FFF8 */
801 static const WORD nonchar_key_scan
[256] =
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
806 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
807 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
808 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
817 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
820 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
821 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
828 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
830 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
831 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
832 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
835 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
836 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
840 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
841 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
847 /* Returns the Windows virtual key code associated with the X event <e> */
848 /* x11 lock must be held */
849 static WORD
EVENT_event_to_vkey( XIC xic
, XKeyEvent
*e
)
854 XmbLookupString(xic
, e
, NULL
, 0, &keysym
, NULL
);
856 XLookupString(e
, NULL
, 0, &keysym
, NULL
);
858 if ((keysym
>= 0xFFAE) && (keysym
<= 0xFFB9) && (keysym
!= 0xFFAF)
859 && (e
->state
& NumLockMask
))
860 /* Only the Keypad keys 0-9 and . send different keysyms
861 * depending on the NumLock state */
862 return nonchar_key_vkey
[keysym
& 0xFF];
864 return keyc2vkey
[e
->keycode
];
867 static BOOL NumState
=FALSE
, CapsState
=FALSE
;
870 /***********************************************************************
871 * send_keyboard_input
873 static void send_keyboard_input( WORD wVk
, WORD wScan
, DWORD dwFlags
, DWORD time
)
877 input
.type
= WINE_INTERNAL_INPUT_KEYBOARD
;
878 input
.u
.ki
.wVk
= wVk
;
879 input
.u
.ki
.wScan
= wScan
;
880 input
.u
.ki
.dwFlags
= dwFlags
;
881 input
.u
.ki
.time
= time
;
882 input
.u
.ki
.dwExtraInfo
= 0;
883 SendInput( 1, &input
, sizeof(input
) );
887 /**********************************************************************
888 * KEYBOARD_GenerateMsg
890 * Generate Down+Up messages when NumLock or CapsLock is pressed.
892 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
895 static void KEYBOARD_GenerateMsg( WORD vkey
, WORD scan
, int Evtype
, DWORD event_time
)
897 BOOL
* State
= (vkey
==VK_NUMLOCK
? &NumState
: &CapsState
);
901 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
902 don't treat it. It's from the same key press. Then the state goes to ON.
903 And from there, a 'release' event will switch off the toggle key. */
905 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey
,pKeyStateTable
[vkey
]);
908 down
= (vkey
==VK_NUMLOCK
? KEYEVENTF_EXTENDEDKEY
: 0);
909 up
= (vkey
==VK_NUMLOCK
? KEYEVENTF_EXTENDEDKEY
: 0) | KEYEVENTF_KEYUP
;
910 if ( pKeyStateTable
[vkey
] & 0x1 ) /* it was ON */
912 if (Evtype
!=KeyPress
)
914 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
915 send_keyboard_input( vkey
, scan
, down
, event_time
);
916 send_keyboard_input( vkey
, scan
, up
, event_time
);
918 pKeyStateTable
[vkey
] &= ~0x01; /* Toggle state to off. */
921 else /* it was OFF */
922 if (Evtype
==KeyPress
)
924 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
925 send_keyboard_input( vkey
, scan
, down
, event_time
);
926 send_keyboard_input( vkey
, scan
, up
, event_time
);
927 *State
=TRUE
; /* Goes to intermediary state before going to ON */
928 pKeyStateTable
[vkey
] |= 0x01; /* Toggle state to on. */
933 /***********************************************************************
934 * KEYBOARD_UpdateOneState
936 * Updates internal state for <vkey>, depending on key <state> under X
939 inline static void KEYBOARD_UpdateOneState ( int vkey
, int state
, DWORD time
)
941 /* Do something if internal table state != X state for keycode */
942 if (((pKeyStateTable
[vkey
] & 0x80)!=0) != state
)
944 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
945 vkey
, pKeyStateTable
[vkey
]);
947 /* Fake key being pressed inside wine */
948 send_keyboard_input( vkey
, 0, state
? 0 : KEYEVENTF_KEYUP
, time
);
950 TRACE("State after %#.2x\n",pKeyStateTable
[vkey
]);
954 /***********************************************************************
955 * X11DRV_KeymapNotify
957 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
959 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
960 * from wine to another application and back.
961 * Toggle keys are handled in HandleEvent.
963 void X11DRV_KeymapNotify( HWND hwnd
, XKeymapEvent
*event
)
965 int i
, j
, alt
, control
, shift
;
966 DWORD time
= GetCurrentTime();
968 alt
= control
= shift
= 0;
969 for (i
= 0; i
< 32; i
++)
971 if (!event
->key_vector
[i
]) continue;
972 for (j
= 0; j
< 8; j
++)
974 if (!(event
->key_vector
[i
] & (1<<j
))) continue;
975 switch(keyc2vkey
[(i
* 8) + j
] & 0xff)
977 case VK_MENU
: alt
= 1; break;
978 case VK_CONTROL
: control
= 1; break;
979 case VK_SHIFT
: shift
= 1; break;
983 KEYBOARD_UpdateOneState( VK_MENU
, alt
, time
);
984 KEYBOARD_UpdateOneState( VK_CONTROL
, control
, time
);
985 KEYBOARD_UpdateOneState( VK_SHIFT
, shift
, time
);
988 /***********************************************************************
991 * Handle a X key event
993 void X11DRV_KeyEvent( HWND hwnd
, XKeyEvent
*event
)
997 WORD vkey
= 0, bScan
;
1000 XIC xic
= X11DRV_get_ic( hwnd
);
1001 DWORD event_time
= event
->time
- X11DRV_server_startticks
;
1005 ascii_chars
= XmbLookupString(xic
, event
, Str
, sizeof(Str
), &keysym
, NULL
);
1007 ascii_chars
= XLookupString(event
, Str
, sizeof(Str
), &keysym
, NULL
);
1008 wine_tsx11_unlock();
1010 TRACE_(key
)("state = %X\n", event
->state
);
1012 /* If XKB extensions are used, the state mask for AltGr will use the group
1013 index instead of the modifier mask. The group index is set in bits
1014 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1015 pressed, look if the group index is different than 0. From XKB
1016 extension documentation, the group index for AltGr should be 2
1017 (event->state = 0x2000). It's probably better to not assume a
1018 predefined group index and find it dynamically
1020 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1021 /* Save also all possible modifier states. */
1022 AltGrMask
= event
->state
& (0x6000 | Mod1Mask
| Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
);
1024 Str
[ascii_chars
] = '\0';
1028 ksname
= TSXKeysymToString(keysym
);
1031 TRACE_(key
)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1032 (event
->type
== KeyPress
) ? "KeyPress" : "KeyRelease",
1033 keysym
, ksname
, ascii_chars
, Str
[0] & 0xff, Str
);
1037 vkey
= EVENT_event_to_vkey(xic
,event
);
1038 /* X returns keycode 0 for composed characters */
1039 if (!vkey
&& ascii_chars
) vkey
= VK_NONAME
;
1040 wine_tsx11_unlock();
1042 TRACE_(key
)("keycode 0x%x converted to vkey 0x%x\n",
1043 event
->keycode
, vkey
);
1047 switch (vkey
& 0xff)
1050 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, event
->type
, event_time
);
1053 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event
->type
,pKeyStateTable
[vkey
]);
1054 KEYBOARD_GenerateMsg( VK_CAPITAL
, 0x3A, event
->type
, event_time
);
1055 TRACE("State after : %#.2x\n",pKeyStateTable
[vkey
]);
1058 /* Adjust the NUMLOCK state if it has been changed outside wine */
1059 if (!(pKeyStateTable
[VK_NUMLOCK
] & 0x01) != !(event
->state
& NumLockMask
))
1061 TRACE("Adjusting NumLock state.\n");
1062 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, KeyPress
, event_time
);
1063 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, KeyRelease
, event_time
);
1065 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1066 if (!(pKeyStateTable
[VK_CAPITAL
] & 0x01) != !(event
->state
& LockMask
))
1068 TRACE("Adjusting Caps Lock state.\n");
1069 KEYBOARD_GenerateMsg( VK_CAPITAL
, 0x3A, KeyPress
, event_time
);
1070 KEYBOARD_GenerateMsg( VK_CAPITAL
, 0x3A, KeyRelease
, event_time
);
1072 /* Not Num nor Caps : end of intermediary states for both. */
1076 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
1077 TRACE_(key
)("bScan = 0x%02x.\n", bScan
);
1080 if ( event
->type
== KeyRelease
) dwFlags
|= KEYEVENTF_KEYUP
;
1081 if ( vkey
& 0x100 ) dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
1083 send_keyboard_input( vkey
& 0xff, bScan
, dwFlags
, event_time
);
1088 /**********************************************************************
1089 * X11DRV_KEYBOARD_DetectLayout
1091 * Called from X11DRV_InitKeyboard
1092 * This routine walks through the defined keyboard layouts and selects
1093 * whichever matches most closely.
1094 * X11 lock must be held.
1097 X11DRV_KEYBOARD_DetectLayout (void)
1099 Display
*display
= thread_display();
1100 unsigned current
, match
, mismatch
, seq
;
1101 int score
, keyc
, i
, key
, pkey
, ok
, syms
;
1103 const char (*lkey
)[MAIN_LEN
][4];
1104 unsigned max_seq
= 0;
1105 int max_score
= 0, ismatch
= 0;
1109 syms
= keysyms_per_keycode
;
1111 WARN("%d keysyms per keycode not supported, set to 4\n", syms
);
1114 for (current
= 0; main_key_tab
[current
].comment
; current
++) {
1115 TRACE("Attempting to match against \"%s\"\n", main_key_tab
[current
].comment
);
1120 lkey
= main_key_tab
[current
].key
;
1122 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++) {
1123 /* get data for keycode from X server */
1124 for (i
= 0; i
< syms
; i
++) {
1125 keysym
= XKeycodeToKeysym (display
, keyc
, i
);
1126 /* Allow both one-byte and two-byte national keysyms */
1127 if ((keysym
< 0x8000) && (keysym
!= ' '))
1130 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[i
], 1, NULL
))
1133 TRACE("XKB could not translate keysym %ld\n", keysym
);
1134 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1135 * with appropriate ShiftMask and Mode_switch, use XLookupString
1136 * to get character in the local encoding.
1138 ckey
[i
] = keysym
& 0xFF;
1142 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
1146 /* search for a match in layout table */
1147 /* right now, we just find an absolute match for defined positions */
1148 /* (undefined positions are ignored, so if it's defined as "3#" in */
1149 /* the table, it's okay that the X server has "3#£", for example) */
1150 /* however, the score will be higher for longer matches */
1151 for (key
= 0; key
< MAIN_LEN
; key
++) {
1152 for (ok
= 0, i
= 0; (ok
>= 0) && (i
< syms
); i
++) {
1153 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] == ckey
[i
]))
1155 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[i
]))
1163 /* count the matches and mismatches */
1166 /* and how much the keycode order matches */
1167 if (key
> pkey
) seq
++;
1170 TRACE_(key
)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc
, ckey
[0], ckey
[0], ckey
[1], ckey
[2], ckey
[3]);
1176 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1177 match
, mismatch
, seq
, score
);
1178 if ((score
> max_score
) ||
1179 ((score
== max_score
) && (seq
> max_seq
))) {
1180 /* best match so far */
1181 kbd_layout
= current
;
1184 ismatch
= !mismatch
;
1187 /* we're done, report results if necessary */
1190 "Your keyboard layout was not found!\n"
1191 "Using closest match instead (%s) for scancode mapping.\n"
1192 "Please define your layout in dlls/x11drv/keyboard.c and submit them\n"
1193 "to us for inclusion into future Wine releases.\n"
1194 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1195 main_key_tab
[kbd_layout
].comment
);
1198 TRACE("detected layout is \"%s\"\n", main_key_tab
[kbd_layout
].comment
);
1201 /**********************************************************************
1202 * InitKeyboard (X11DRV.@)
1204 void X11DRV_InitKeyboard( BYTE
*key_state_table
)
1206 Display
*display
= thread_display();
1208 XModifierKeymap
*mmp
;
1212 WORD scan
, vkey
, OEMvkey
;
1213 int keyc
, i
, keyn
, syms
;
1214 char ckey
[4]={0,0,0,0};
1215 const char (*lkey
)[MAIN_LEN
][4];
1217 pKeyStateTable
= key_state_table
;
1220 XDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
1221 ksp
= XGetKeyboardMapping(display
, min_keycode
,
1222 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
1223 /* We are only interested in keysyms_per_keycode.
1224 There is no need to hold a local copy of the keysyms table */
1227 mmp
= XGetModifierMapping(display
);
1228 kcp
= mmp
->modifiermap
;
1229 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
1233 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
1238 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
1239 if (XKeycodeToKeysym(display
, *kcp
, k
) == XK_Num_Lock
)
1241 NumLockMask
= 1 << i
;
1242 TRACE_(key
)("NumLockMask is %x\n", NumLockMask
);
1246 XFreeModifiermap(mmp
);
1248 /* Detect the keyboard layout */
1249 X11DRV_KEYBOARD_DetectLayout();
1250 lkey
= main_key_tab
[kbd_layout
].key
;
1251 syms
= (keysyms_per_keycode
> 4) ? 4 : keysyms_per_keycode
;
1253 /* Now build two conversion arrays :
1254 * keycode -> vkey + scancode + extended
1255 * vkey + extended -> keycode */
1257 e2
.display
= display
;
1260 OEMvkey
= VK_OEM_7
; /* next is available. */
1261 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1263 e2
.keycode
= (KeyCode
)keyc
;
1264 XLookupString(&e2
, NULL
, 0, &keysym
, NULL
);
1266 if (keysym
) /* otherwise, keycode not used */
1268 if ((keysym
>> 8) == 0xFF) /* non-character key */
1270 vkey
= nonchar_key_vkey
[keysym
& 0xff];
1271 scan
= nonchar_key_scan
[keysym
& 0xff];
1272 /* set extended bit when necessary */
1273 if (scan
& 0x100) vkey
|= 0x100;
1274 } else if (keysym
== 0x20) { /* Spacebar */
1278 /* we seem to need to search the layout-dependent scancodes */
1279 int maxlen
=0,maxval
=-1,ok
;
1280 for (i
=0; i
<syms
; i
++) {
1281 keysym
= XKeycodeToKeysym(display
, keyc
, i
);
1282 if ((keysym
<0x8000) && (keysym
!=' '))
1285 if (!use_xkb
|| !XkbTranslateKeySym(display
, &keysym
, 0, &ckey
[i
], 1, NULL
))
1288 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1289 * with appropriate ShiftMask and Mode_switch, use XLookupString
1290 * to get character in the local encoding.
1292 ckey
[i
] = keysym
& 0xFF;
1295 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
1298 /* find key with longest match streak */
1299 for (keyn
=0; keyn
<MAIN_LEN
; keyn
++) {
1300 for (ok
=(*lkey
)[keyn
][i
=0]; ok
&&(i
<4); i
++)
1301 if ((*lkey
)[keyn
][i
] && (*lkey
)[keyn
][i
]!=ckey
[i
]) ok
=0;
1302 if (ok
||(i
>maxlen
)) {
1303 maxlen
=i
; maxval
=keyn
;
1309 const WORD (*lscan
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].scan
;
1310 const WORD (*lvkey
)[MAIN_LEN
] = main_key_tab
[kbd_layout
].vkey
;
1311 scan
= (*lscan
)[maxval
];
1312 vkey
= (*lvkey
)[maxval
];
1316 /* find a suitable layout-dependent VK code */
1317 /* (most Winelib apps ought to be able to work without layout tables!) */
1318 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1320 keysym
= XLookupKeysym(&e2
, i
);
1321 if ((keysym
>= VK_0
&& keysym
<= VK_9
)
1322 || (keysym
>= VK_A
&& keysym
<= VK_Z
)) {
1327 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1329 keysym
= XLookupKeysym(&e2
, i
);
1332 case ';': vkey
= VK_OEM_1
; break;
1333 case '/': vkey
= VK_OEM_2
; break;
1334 case '`': vkey
= VK_OEM_3
; break;
1335 case '[': vkey
= VK_OEM_4
; break;
1336 case '\\': vkey
= VK_OEM_5
; break;
1337 case ']': vkey
= VK_OEM_6
; break;
1338 case '\'': vkey
= VK_OEM_7
; break;
1339 case ',': vkey
= VK_OEM_COMMA
; break;
1340 case '.': vkey
= VK_OEM_PERIOD
; break;
1341 case '-': vkey
= VK_OEM_MINUS
; break;
1342 case '+': vkey
= VK_OEM_PLUS
; break;
1348 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1349 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1352 case 0xc1 : OEMvkey
=0xdb; break;
1353 case 0xe5 : OEMvkey
=0xe9; break;
1354 case 0xf6 : OEMvkey
=0xf5; WARN("No more OEM vkey available!\n");
1359 if (TRACE_ON(keyboard
))
1361 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1362 OEMvkey
, e2
.keycode
);
1364 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
1368 keysym
= XLookupKeysym(&e2
, i
);
1369 ksname
= XKeysymToString(keysym
);
1371 ksname
= "NoSymbol";
1372 TRACE( "%lX (%s) ", keysym
, ksname
);
1378 keyc2vkey
[e2
.keycode
] = vkey
;
1379 keyc2scan
[e2
.keycode
] = scan
;
1382 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1383 for (scan
= 0x60, keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
1384 if (keyc2vkey
[keyc
]&&!keyc2scan
[keyc
]) {
1386 keysym
= XKeycodeToKeysym(display
, keyc
, 0);
1387 ksname
= XKeysymToString(keysym
);
1388 if (!ksname
) ksname
= "NoSymbol";
1390 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1392 TRACE_(key
)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan
,keyc
,ksname
);
1393 keyc2scan
[keyc
]=scan
++;
1396 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1397 kcControl
= XKeysymToKeycode(display
, XK_Control_L
);
1398 kcAlt
= XKeysymToKeycode(display
, XK_Alt_L
);
1399 if (!kcAlt
) kcAlt
= XKeysymToKeycode(display
, XK_Meta_L
);
1400 kcShift
= XKeysymToKeycode(display
, XK_Shift_L
);
1401 kcNumLock
= XKeysymToKeycode(display
, XK_Num_Lock
);
1402 kcCapsLock
= XKeysymToKeycode(display
, XK_Caps_Lock
);
1403 wine_tsx11_unlock();
1407 /***********************************************************************
1408 * X11DRV_MappingNotify
1410 void X11DRV_MappingNotify( XMappingEvent
*event
)
1412 TSXRefreshKeyboardMapping(event
);
1413 X11DRV_InitKeyboard( pKeyStateTable
);
1417 /***********************************************************************
1418 * VkKeyScan (X11DRV.@)
1420 WORD
X11DRV_VkKeyScan(CHAR cChar
)
1422 Display
*display
= thread_display();
1428 /* char->keysym (same for ANSI chars) */
1429 keysym
=(unsigned char) cChar
;/* (!) cChar is signed */
1430 if (keysym
<=27) keysym
+=0xFF00;/*special chars : return, backspace...*/
1432 keycode
= TSXKeysymToKeycode(display
, keysym
); /* keysym -> keycode */
1434 { /* It didn't work ... let's try with deadchar code. */
1435 keycode
= TSXKeysymToKeycode(display
, keysym
| 0xFE00);
1438 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1439 cChar
,keysym
,keysym
,keycode
);
1443 for (index
=-1, i
=0; (i
<8) && (index
<0); i
++) /* find shift state */
1444 if (TSXKeycodeToKeysym(display
,keycode
,i
)==keysym
) index
=i
;
1447 WARN("Keysym %lx not found while parsing the keycode table\n",keysym
); break;
1449 case 1 : highbyte
= 0x0100; break;
1450 case 2 : highbyte
= 0x0600; break;
1451 case 3 : highbyte
= 0x0700; break;
1452 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index
);
1455 index : 0 adds 0x0000
1456 index : 1 adds 0x0100 (shift)
1457 index : ? adds 0x0200 (ctrl)
1458 index : 2 adds 0x0600 (ctrl+alt)
1459 index : 3 adds 0x0700 (ctrl+alt+shift)
1462 TRACE(" ... returning %#.2x\n", keyc2vkey
[keycode
]+highbyte
);
1463 return keyc2vkey
[keycode
]+highbyte
; /* keycode -> (keyc2vkey) vkey */
1466 /***********************************************************************
1467 * MapVirtualKey (X11DRV.@)
1469 UINT
X11DRV_MapVirtualKey(UINT wCode
, UINT wMapType
)
1471 Display
*display
= thread_display();
1473 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1475 TRACE("wCode=0x%x wMapType=%d ...\n", wCode
,wMapType
);
1477 case 0: { /* vkey-code to scan-code */
1478 /* let's do vkey -> keycode -> scan */
1480 for (keyc
=min_keycode
; keyc
<=max_keycode
; keyc
++)
1481 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
1482 returnMVK (keyc2scan
[keyc
] & 0xFF);
1483 TRACE("returning no scan-code.\n");
1486 case 1: { /* scan-code to vkey-code */
1487 /* let's do scan -> keycode -> vkey */
1489 for (keyc
=min_keycode
; keyc
<=max_keycode
; keyc
++)
1490 if ((keyc2scan
[keyc
] & 0xFF) == (wCode
& 0xFF))
1491 returnMVK (keyc2vkey
[keyc
] & 0xFF);
1492 TRACE("returning no vkey-code.\n");
1495 case 2: { /* vkey-code to unshifted ANSI code */
1496 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1497 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1498 * key.. Looks like something is wrong with the MS docs?
1499 * This is only true for letters, for example VK_0 returns '0' not ')'.
1500 * - hence we use the lock mask to ensure this happens.
1502 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1507 e
.display
= display
;
1510 /* LockMask should behave exactly like caps lock - upercase
1511 * the letter keys and thats about it. */
1516 /* We exit on the first keycode found, to speed up the thing. */
1517 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
1518 { /* Find a keycode that could have generated this virtual key */
1519 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
1520 { /* We filter the extended bit, we don't know it */
1521 e
.keycode
= keyc
; /* Store it temporarily */
1522 if ((EVENT_event_to_vkey(0,&e
) & 0xFF) != wCode
) {
1523 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
1524 state), so set it to 0, we'll find another one */
1529 if ((wCode
>=VK_NUMPAD0
) && (wCode
<=VK_NUMPAD9
))
1530 e
.keycode
= XKeysymToKeycode(e
.display
, wCode
-VK_NUMPAD0
+XK_KP_0
);
1532 if (wCode
==VK_DECIMAL
)
1533 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
1537 WARN("Unknown virtual key %X !!! \n", wCode
);
1538 wine_tsx11_unlock();
1539 return 0; /* whatever */
1541 TRACE("Found keycode %d (0x%2X)\n",e
.keycode
,e
.keycode
);
1543 if (XLookupString(&e
, s
, 2, &keysym
, NULL
))
1545 wine_tsx11_unlock();
1549 TRACE("returning no ANSI.\n");
1550 wine_tsx11_unlock();
1554 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1555 /* left and right */
1556 FIXME(" stub for NT\n");
1559 default: /* reserved */
1560 WARN("Unknown wMapType %d !\n", wMapType
);
1566 /***********************************************************************
1567 * GetKeyNameText (X11DRV.@)
1569 INT
X11DRV_GetKeyNameText(LONG lParam
, LPSTR lpBuffer
, INT nSize
)
1571 int vkey
, ansi
, scanCode
;
1577 scanCode
= lParam
>> 16;
1578 scanCode
&= 0x1ff; /* keep "extended-key" flag with code */
1580 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1581 vkey
= X11DRV_MapVirtualKey(scanCode
, 1);
1583 /* handle "don't care" bit (0x02000000) */
1584 if (!(lParam
& 0x02000000)) {
1603 ansi
= X11DRV_MapVirtualKey(vkey
, 2);
1604 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode
, vkey
, ansi
);
1606 /* first get the name of the "regular" keys which is the Upper case
1607 value of the keycap imprint. */
1608 if ( ((ansi
>= 0x21) && (ansi
<= 0x7e)) &&
1609 (scanCode
!= 0x137) && /* PrtScn */
1610 (scanCode
!= 0x135) && /* numpad / */
1611 (scanCode
!= 0x37 ) && /* numpad * */
1612 (scanCode
!= 0x4a ) && /* numpad - */
1613 (scanCode
!= 0x4e ) ) /* numpad + */
1615 if ((nSize
>= 2) && lpBuffer
)
1617 *lpBuffer
= toupper((char)ansi
);
1625 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1626 without "extended-key" flag. However Wine generates scancode
1627 *with* "extended-key" flag. Seems to occur *only* for the
1628 function keys. Soooo.. We will leave the table alone and
1629 fudge the lookup here till the other part is found and fixed!!! */
1631 if ( ((scanCode
>= 0x13b) && (scanCode
<= 0x144)) ||
1632 (scanCode
== 0x157) || (scanCode
== 0x158))
1633 scanCode
&= 0xff; /* remove "extended-key" flag for Fx keys */
1635 /* let's do scancode -> keycode -> keysym -> String */
1637 for (keyi
=min_keycode
; keyi
<=max_keycode
; keyi
++)
1638 if ((keyc2scan
[keyi
]) == scanCode
)
1640 if (keyi
<= max_keycode
)
1642 keyc
= (KeyCode
) keyi
;
1643 keys
= TSXKeycodeToKeysym(thread_display(), keyc
, 0);
1644 name
= TSXKeysymToString(keys
);
1645 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1646 scanCode
, keyc
, (int)keys
, name
);
1647 if (lpBuffer
&& nSize
&& name
)
1649 lstrcpynA(lpBuffer
, name
, nSize
);
1654 /* Finally issue FIXME for unknown keys */
1656 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam
,lpBuffer
,nSize
,vkey
,ansi
);
1657 if (lpBuffer
&& nSize
)
1662 /***********************************************************************
1663 * X11DRV_KEYBOARD_MapDeadKeysym
1665 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
1669 /* symbolic ASCII is the same as defined in rfc1345 */
1670 #ifdef XK_dead_tilde
1671 case XK_dead_tilde
:
1673 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1674 return '~'; /* '? */
1675 #ifdef XK_dead_acute
1676 case XK_dead_acute
:
1678 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1679 return 0xb4; /* '' */
1680 #ifdef XK_dead_circumflex
1681 case XK_dead_circumflex
:
1683 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1684 return '^'; /* '> */
1685 #ifdef XK_dead_grave
1686 case XK_dead_grave
:
1688 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1689 return '`'; /* '! */
1690 #ifdef XK_dead_diaeresis
1691 case XK_dead_diaeresis
:
1693 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1694 return 0xa8; /* ': */
1695 #ifdef XK_dead_cedilla
1696 case XK_dead_cedilla
:
1697 return 0xb8; /* ', */
1699 #ifdef XK_dead_macron
1700 case XK_dead_macron
:
1701 return '-'; /* 'm isn't defined on iso-8859-x */
1703 #ifdef XK_dead_breve
1704 case XK_dead_breve
:
1705 return 0xa2; /* '( */
1707 #ifdef XK_dead_abovedot
1708 case XK_dead_abovedot
:
1709 return 0xff; /* '. */
1711 #ifdef XK_dead_abovering
1712 case XK_dead_abovering
:
1713 return '0'; /* '0 isn't defined on iso-8859-x */
1715 #ifdef XK_dead_doubleacute
1716 case XK_dead_doubleacute
:
1717 return 0xbd; /* '" */
1719 #ifdef XK_dead_caron
1720 case XK_dead_caron
:
1721 return 0xb7; /* '< */
1723 #ifdef XK_dead_ogonek
1724 case XK_dead_ogonek
:
1725 return 0xb2; /* '; */
1727 /* FIXME: I don't know this three.
1730 case XK_dead_voiced_sound :
1732 case XK_dead_semivoiced_sound :
1736 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
1740 /***********************************************************************
1741 * ToUnicode (X11DRV.@)
1743 * The ToUnicode function translates the specified virtual-key code and keyboard
1744 * state to the corresponding Windows character or characters.
1746 * If the specified key is a dead key, the return value is negative. Otherwise,
1747 * it is one of the following values:
1749 * 0 The specified virtual key has no translation for the current state of the keyboard.
1750 * 1 One Windows character was copied to the buffer.
1751 * 2 Two characters were copied to the buffer. This usually happens when a
1752 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1753 * be composed with the specified virtual key to form a single character.
1755 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1758 INT
X11DRV_ToUnicode(UINT virtKey
, UINT scanCode
, LPBYTE lpKeyState
,
1759 LPWSTR bufW
, int bufW_size
, UINT flags
)
1761 Display
*display
= thread_display();
1770 if (scanCode
& 0x8000)
1772 TRACE("Key UP, doing nothing\n" );
1776 e
.display
= display
;
1782 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
1783 if (!focus
) focus
= GetActiveWindow();
1784 e
.window
= X11DRV_get_whole_window( focus
);
1785 xic
= X11DRV_get_ic( focus
);
1787 if (lpKeyState
[VK_SHIFT
] & 0x80)
1789 TRACE("ShiftMask = %04x\n", ShiftMask
);
1790 e
.state
|= ShiftMask
;
1792 if (lpKeyState
[VK_CAPITAL
] & 0x01)
1794 TRACE("LockMask = %04x\n", LockMask
);
1795 e
.state
|= LockMask
;
1797 if (lpKeyState
[VK_CONTROL
] & 0x80)
1799 TRACE("ControlMask = %04x\n", ControlMask
);
1800 e
.state
|= ControlMask
;
1802 if (lpKeyState
[VK_NUMLOCK
] & 0x01)
1804 TRACE("NumLockMask = %04x\n", NumLockMask
);
1805 e
.state
|= NumLockMask
;
1808 /* Restore saved AltGr state */
1809 TRACE("AltGrMask = %04x\n", AltGrMask
);
1810 e
.state
|= AltGrMask
;
1812 TRACE_(key
)("(%04X, %04X) : faked state = %X\n",
1813 virtKey
, scanCode
, e
.state
);
1815 /* We exit on the first keycode found, to speed up the thing. */
1816 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
1817 { /* Find a keycode that could have generated this virtual key */
1818 if ((keyc2vkey
[keyc
] & 0xFF) == virtKey
)
1819 { /* We filter the extended bit, we don't know it */
1820 e
.keycode
= keyc
; /* Store it temporarily */
1821 if ((EVENT_event_to_vkey(xic
,&e
) & 0xFF) != virtKey
) {
1822 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
1823 state), so set it to 0, we'll find another one */
1828 if ((virtKey
>=VK_NUMPAD0
) && (virtKey
<=VK_NUMPAD9
))
1829 e
.keycode
= XKeysymToKeycode(e
.display
, virtKey
-VK_NUMPAD0
+XK_KP_0
);
1831 if (virtKey
==VK_DECIMAL
)
1832 e
.keycode
= XKeysymToKeycode(e
.display
, XK_KP_Decimal
);
1834 if (!e
.keycode
&& virtKey
!= VK_NONAME
)
1836 WARN("Unknown virtual key %X !!! \n",virtKey
);
1837 wine_tsx11_unlock();
1838 return virtKey
; /* whatever */
1840 else TRACE("Found keycode %d (0x%2X)\n",e
.keycode
,e
.keycode
);
1843 ret
= XmbLookupString(xic
, &e
, lpChar
, sizeof(lpChar
), &keysym
, NULL
);
1845 ret
= XLookupString(&e
, lpChar
, sizeof(lpChar
), &keysym
, NULL
);
1846 wine_tsx11_unlock();
1852 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
1855 MultiByteToWideChar(CP_UNIXCP
, 0, &dead_char
, 1, bufW
, bufW_size
);
1862 ksname
= TSXKeysymToString(keysym
);
1865 if ((keysym
>> 8) != 0xff)
1867 ERR("Please report: no char for keysym %04lX (%s) :\n",
1869 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1870 virtKey
, scanCode
, e
.keycode
, e
.state
);
1874 else { /* ret != 0 */
1875 /* We have a special case to handle : Shift + arrow, shift + home, ...
1876 X returns a char for it, but Windows doesn't. Let's eat it. */
1877 if (!(e
.state
& NumLockMask
) /* NumLock is off */
1878 && (e
.state
& ShiftMask
) /* Shift is pressed */
1879 && (keysym
>=XK_KP_0
) && (keysym
<=XK_KP_9
))
1885 /* more areas where X returns characters but Windows does not
1886 CTRL + number or CTRL + symbol */
1887 if (e
.state
& ControlMask
)
1889 if (((keysym
>=33) && (keysym
< 'A')) ||
1890 ((keysym
> 'Z') && (keysym
< 'a')))
1897 /* We have another special case for delete key (XK_Delete) on an
1898 extended keyboard. X returns a char for it, but Windows doesn't */
1899 if (keysym
== XK_Delete
)
1904 else if((lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
1905 && (keysym
== XK_KP_Decimal
))
1911 /* perform translation to unicode */
1914 TRACE_(key
)("Translating char 0x%02x to unicode\n", *(BYTE
*)lpChar
);
1915 ret
= MultiByteToWideChar(CP_UNIXCP
, 0, lpChar
, ret
, bufW
, bufW_size
);
1919 TRACE_(key
)("ToUnicode about to return %d with char %x %s\n",
1920 ret
, bufW
? bufW
[0] : 0, bufW
? "" : "(no buffer)");
1924 /***********************************************************************
1927 void X11DRV_Beep(void)
1929 TSXBell(thread_display(), 0);