VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/linux/keyboard.c@ 5238

Last change on this file since 5238 was 5238, checked in by vboxsync, 17 years ago

Linux host keyboard: ignore more than two keyboard symbols, as using three or more causes problems in many setups

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 113.4 KB
Line 
1/*
2 * X11 keyboard driver
3 *
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
10 *
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.
15 *
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.
20 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26/* our master define to make this module usable outside of Wine */
27#define OUTOFWINE
28
29#ifdef OUTOFWINE
30#include "keyboard_outofwine.h"
31/* I don't see any advantage for us of using Xkb here. The only effect of it in
32 the code is to cause the keyboard symbols we are looking up to be translated
33 according to the locale, so that we potentially need additional look-up tables
34 for ambiguous situations (or the translation can fail if the combination of
35 locale and keyboard does not match). */
36int use_xkb = 0;
37#endif /* OUTOFWINE defined */
38
39#ifndef OUTOFWINE
40#include "config.h"
41#endif /* OUTOFWINE not defined */
42
43#include <X11/Xatom.h>
44#include <X11/keysym.h>
45#include <X11/Xlib.h>
46#include <X11/Xresource.h>
47#include <X11/Xutil.h>
48#ifdef HAVE_X11_XKBLIB_H
49#include <X11/XKBlib.h>
50#endif
51
52#include <ctype.h>
53#include <stdarg.h>
54#include <string.h>
55
56#ifndef OUTOFWINE
57#define NONAMELESSUNION
58#define NONAMELESSSTRUCT
59#include "windef.h"
60#include "winbase.h"
61#include "wingdi.h"
62#include "winuser.h"
63#include "wine/winuser16.h"
64#include "winnls.h"
65#include "win.h"
66#include "x11drv.h"
67#include "wine/server.h"
68#include "wine/unicode.h"
69#include "wine/debug.h"
70
71WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
72WINE_DECLARE_DEBUG_CHANNEL(key);
73
74typedef union
75{
76 struct
77 {
78#ifndef BITFIELDS_BIGENDIAN
79 unsigned long count : 16;
80#endif
81 unsigned long code : 8;
82 unsigned long extended : 1;
83 unsigned long unused : 2;
84 unsigned long win_internal : 2;
85 unsigned long context : 1;
86 unsigned long previous : 1;
87 unsigned long transition : 1;
88#ifdef BITFIELDS_BIGENDIAN
89 unsigned long count : 16;
90#endif
91 } lp1;
92 unsigned long lp2;
93} KEYLP;
94
95/* key state table bits:
96 0x80 -> key is pressed
97 0x40 -> key got pressed since last time
98 0x01 -> key is toggled
99*/
100BYTE key_state_table[256];
101
102static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
103 or a WM_KEYUP message */
104#endif
105
106static int min_keycode, max_keycode, keysyms_per_keycode;
107
108#ifndef OUTOFWINE
109static WORD keyc2vkey[256], keyc2scan[256];
110
111static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
112static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
113#else
114static WORD keyc2scan[256];
115#endif
116
117static char KEYBOARD_MapDeadKeysym(KeySym keysym);
118
119/* Keyboard translation tables */
120#define MAIN_LEN 49
121static const WORD main_key_scan_qwerty[MAIN_LEN] =
122{
123/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
124 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
125 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
126 /* q w e r t y u i o p [ ] */
127 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
128 /* a s d f g h j k l ; ' \ */
129 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
130 /* z x c v b n m , . / */
131 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
132 0x56 /* the 102nd key (actually to the right of l-shift) */
133};
134
135static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
136{
137 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
138 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
139 /* q w e r t y u i o p [ ] */
140 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
141 /* a s d f g h j k l ; ' \ */
142 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
143#ifndef OUTOFWINE
144 /* \ z x c v b n m , . / */
145 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
146 0x56, /* the 102nd key (actually to the right of l-shift) */
147#else
148/* innotek FIX */
149 /* \ z x c v b n m , . / */
150 0x56,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
151 0x73, /* the extra key on the Brazilian keyboard. */
152#endif
153};
154
155#ifndef OUTOFWINE
156/* innotek FIX - a dvorak keyboard uses standard scan codes. */
157static const WORD main_key_scan_dvorak[MAIN_LEN] =
158{
159 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
160 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
161 /* ' , . p y f g c r l / = */
162 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
163 /* a o e u i d h t n s - \ */
164 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
165 /* ; q j k x b m w v z */
166 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
167 0x56 /* the 102nd key (actually to the right of l-shift) */
168};
169#endif
170
171#ifdef OUTOFWINE
172/* Not FIXed as it should still work, even though it is completely unnecessary. */
173/* What is this supposed to be? This is just the same as the qwerty layout, with one key
174 in a different place. */
175#endif
176static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
177{
178 /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
179 /* 1 2 3 4 5 6 7 8 9 0 - ^ \ */
180 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
181 /* q w e r t y u i o p @ [ */
182 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
183 /* a s d f g h j k l ; : ] */
184 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
185 /* z x c v b n m , . / */
186 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
187 0x56 /* the 102nd key (actually to the right of l-shift) */
188};
189
190
191static const WORD main_key_vkey_qwerty[MAIN_LEN] =
192{
193/* NOTE: this layout must concur with the scan codes layout above */
194 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
195 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
196 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
197 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
198 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
199};
200
201static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
202{
203/* NOTE: this layout must concur with the scan codes layout above */
204 '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
205 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
206 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
207 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
208 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
209};
210
211static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
212{
213/* NOTE: this layout must concur with the scan codes layout above */
214 VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
215 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
216 'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
217 'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
218 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
219};
220
221static const WORD main_key_vkey_qwertz[MAIN_LEN] =
222{
223/* NOTE: this layout must concur with the scan codes layout above */
224 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
225 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
226 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
227 'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
228 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
229};
230
231static const WORD main_key_vkey_qwertz_105[MAIN_LEN] =
232{
233/* NOTE: this layout must concur with the scan codes layout above */
234 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
235 'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
236 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
237 VK_OEM_102,'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2
238};
239
240static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
241{
242/* NOTE: this layout must concur with the scan codes layout above */
243 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
244 'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
245 'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
246 VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
247 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
248};
249
250static const WORD main_key_vkey_azerty[MAIN_LEN] =
251{
252/* NOTE: this layout must concur with the scan codes layout above */
253 VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
254 'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
255 'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
256 'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
257 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
258};
259
260static const WORD main_key_vkey_dvorak[MAIN_LEN] =
261{
262/* NOTE: this layout must concur with the scan codes layout above */
263 VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
264 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
265 'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
266 VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
267 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
268};
269
270/*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
271
272/* the VK mappings for the main keyboard will be auto-assigned as before,
273 so what we have here is just the character tables */
274/* order: Normal, Shift, AltGr, Shift-AltGr */
275/* We recommend you write just what is guaranteed to be correct (i.e. what's
276 written on the keycaps), not the bunch of special characters behind AltGr
277 and Shift-AltGr if it can vary among different X servers */
278/* Remember that your 102nd key (to the right of l-shift) should be on a
279 separate line, see existing tables */
280/* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
281/* Remember to also add your new table to the layout index table far below! */
282
283#ifndef OUTOFWINE
284/*** German Logitech Desktop Pro keyboard layout */
285static const char main_key_DE_logitech[MAIN_LEN][4] =
286{
287 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
288 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
290 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
291 "<>|"
292};
293#endif
294
295/*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
296static const char main_key_US[MAIN_LEN][4] =
297{
298 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
299 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
300 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
301 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
302};
303
304/*** United States keyboard layout (phantom key version) */
305/* (XFree86 reports the <> key even if it's not physically there) */
306static const char main_key_US_phantom[MAIN_LEN][4] =
307{
308 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
309 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
310 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
311 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
312 "<>" /* the phantom key */
313};
314
315/*** United States keyboard layout (dvorak version) */
316static const char main_key_US_dvorak[MAIN_LEN][4] =
317{
318 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
319 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
320 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
321 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
322};
323
324#ifdef OUTOFWINE
325/* innotek FIX */
326/*** United States keyboard layout (dvorak version with phantom key) */
327static const char main_key_US_dvorak_phantom[MAIN_LEN][4] =
328{
329 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
330 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
331 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
332 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ",
333 "<>" /* the phantom key */
334};
335#endif
336
337/*** British keyboard layout */
338static const char main_key_UK[MAIN_LEN][4] =
339{
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",",<",".>","/?",
344 "\\|"
345};
346
347#ifdef OUTOFWINE
348
349/*** British international keyboard layout */
350static const char main_key_UK_intl[MAIN_LEN][4] =
351{
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",",<",".>","/?",
356 "\\|"
357};
358
359#endif
360
361/*** French keyboard layout (setxkbmap fr) */
362static const char main_key_FR[MAIN_LEN][4] =
363{
364 "²","&1","é2","\"3","'4","(5","-6","è7","_8","ç9","à0",")°","=+",
365 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£",
366 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
367 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
368 "<>"
369};
370
371/*** Icelandic keyboard layout (setxkbmap is) */
372static const char main_key_IS[MAIN_LEN][4] =
373{
374 "°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","öÖ","-_",
375 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?",
376 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´Ä","+*",
377 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
378 "<>"
379};
380
381/*** German keyboard layout (setxkbmap de) */
382static const char main_key_DE[MAIN_LEN][4] =
383{
384 "^°","1!","2\"","3§","4$","5%","6&","7/","8(","9)","0=","ß?","´`",
385 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*",
386 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
387 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
388#ifndef OUTOFWINE
389 "<>|"
390#else
391 "<>"
392#endif
393};
394
395#ifndef OUTOFWINE
396/*** German keyboard layout without dead keys */
397static const char main_key_DE_nodead[MAIN_LEN][4] =
398{
399 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
400 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
401 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
402 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
403 "<>"
404};
405#endif
406
407/*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
408static const char main_key_DE_nodead_105[MAIN_LEN][4] =
409{
410 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
411 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
412 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
413 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_", "<>|"
414};
415
416/*** Swiss German keyboard layout (setxkbmap ch -variant de) */
417static const char main_key_SG[MAIN_LEN][4] =
418{
419 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
420 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè","¨!",
421 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà","$£",
422 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
423 "<>"
424};
425
426/*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
427static const char main_key_SF[MAIN_LEN][4] =
428{
429 "§°","1+","2\"","3*","4ç","5%","6&","7/","8(","9)","0=","'?","^`",
430 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü","¨!",
431 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä","$£",
432 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
433 "<>"
434};
435
436#ifndef OUTOFWINE
437/*** Norwegian keyboard layout (contributed by Ove Kåven) */
438static const char main_key_NO[MAIN_LEN][4] =
439{
440 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
441 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
442 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
443 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
444 "<>"
445};
446#else
447/* innotek FIX */
448/*** Norwegian keyboard layout (contributed by Ove Kåven) */
449static const char main_key_NO[MAIN_LEN][4] =
450{
451 "|§","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","\\`",
452 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
453 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'",
454 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
455 "<>"
456};
457#endif
458
459/*** Danish keyboard layout (setxkbmap dk) */
460static const char main_key_DA[MAIN_LEN][4] =
461{
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",",;",".:","-_",
466 "<>"
467};
468
469/*** Swedish keyboard layout (setxkbmap se) */
470static const char main_key_SE[MAIN_LEN][4] =
471{
472 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
473 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
474 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
475 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
476 "<>"
477};
478
479/*** Estonian keyboard layout (setxkbmap ee) */
480static const char main_key_ET[MAIN_LEN][4] =
481{
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",",;",".:","-_",
486 "<>"
487};
488
489#ifndef OUTOFWINE
490/*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
491static const char main_key_CF[MAIN_LEN][4] =
492{
493 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
494 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
495 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
496 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
497 "«»°"
498};
499#endif
500
501/*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
502static const char main_key_CA_fr[MAIN_LEN][4] =
503{
504 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
505 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","¸¨",
506 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
507 "zZ","xX","cC","vV","bB","nN","mM",",'",".","éÉ",
508 "«»"
509};
510
511#ifndef OUTOFWINE
512/*** Canadian keyboard layout (setxkbmap ca) */
513static const char main_key_CA[MAIN_LEN][4] =
514{
515 "/\\","1!¹¡","2@²","3#³£","4$¼¤","5%½","6?¾","7&","8*","9(","0)","-_","=+",
516 "qQ","wW","eE","rR","tT","yY","uU","iI","oOøØ","pPþÞ","^¨¨","çÇ~",
517 "aAæÆ","sSߧ","dDðÐ","fF","gG","hH","jJ","kK","lL",";:´","èÈ","àÀ",
518 "zZ","xX","cC¢©","vV","bB","nN","mMµº",",'",".\"·÷","éÉ",
519 "ùÙ"
520};
521#else
522/*** Canadian keyboard layout (setxkbmap ca) */
523static const char main_key_CA[MAIN_LEN][4] =
524{
525 "/\\","1!","2@","3#","4$","5%","6?","7&","8*","9(","0)","-_","=+",
526 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^¨","çÇ",
527 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","èÈ","àÀ",
528 "zZ","xX","cC","vV","bB","nN","mM",",'",".\"","éÉ",
529 "ùÙ"
530};
531#endif
532
533/*** Portuguese keyboard layout (setxkbmap pt) */
534static const char main_key_PT[MAIN_LEN][4] =
535{
536 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","«»",
537 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","´`",
538 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","ºª","~^",
539 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
540 "<>"
541};
542
543/*** Italian keyboard layout (setxkbmap it) */
544static const char main_key_IT[MAIN_LEN][4] =
545{
546 "\\|","1!","2\"","3£","4$","5%","6&","7/","8(","9)","0=","'?","ì^",
547 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","èé","+*",
548 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","òç","à°","ù§",
549 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
550 "<>"
551};
552
553/*** Finnish keyboard layout (setxkbmap fi) */
554static const char main_key_FI[MAIN_LEN][4] =
555{
556 "§½","1!","2\"","3#","4¤","5%","6&","7/","8(","9)","0=","+?","´`",
557 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^",
558 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
559 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
560 "<>"
561};
562
563#ifndef OUTOFWINE
564/*** Bulgarian bds keyboard layout */
565static const char main_key_BG_bds[MAIN_LEN][4] =
566{
567 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
568 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
569 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
570 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
571 "<>" /* the phantom key */
572};
573
574/*** Bulgarian phonetic keyboard layout */
575static const char main_key_BG_phonetic[MAIN_LEN][4] =
576{
577 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
578 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
579 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
580 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
581 "<>" /* the phantom key */
582};
583
584/*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
585/*** It matches belarusian layout for XKB from Alexander Mikhailian */
586static const char main_key_BY[MAIN_LEN][4] =
587{
588 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
589 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
590 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
591 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
592};
593#else
594/*** Bulgarian bds keyboard layout */
595static const char main_key_BG_bds[MAIN_LEN][4] =
596{
597 "()","1!","2?","3+","4\"","5%","6=","7:","8/","9\xa9","0\xb0","-I",".V",
598 ",\xd9","\xd5\xf5","\xc5\xe5","\xc9\xe9","\xdb\xfb","\xdd\xfd","\xcb\xeb","\xd3\xf3","\xc4\xe4","\xda\xfa","\xc3\xe3",";\xa7",
599 "\xd8\xf8","\xd1\xf1","\xc1\xe1","\xcf\xef","\xd6\xf6","\xc7\xe7","\xd4\xf4","\xce\xee","\xd7\xf7","\xcd\xed","\xde\xfe","'\xf9",
600 "\xc0\xe0","\xca\xea","\xdf\xff","\xdc\xfc","\xc6\xe6","\xc8\xe8","\xd0\xf0","\xd2\xf2","\xcc\xec","\xc2\xe2",
601 "<>" /* the phantom key */
602};
603
604/*** Bulgarian phonetic keyboard layout */
605static const char main_key_BG_phonetic[MAIN_LEN][4] =
606{
607 "\xde\xfe","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
608 "\xd1\xf1","\xd7\xf7","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xdf\xff","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","\xdd\xfd",
609 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xca\xea","\xcb\xeb","\xcc\xec",";:","'\"","\xc0\xe0",
610 "\xda\xfa","\xd8\xf8","\xc3\xe3","\xd6\xf6","\xc2\xe2","\xce\xee","\xcd\xed",",<",".>","/?",
611 "<>" /* the phantom key */
612};
613
614/*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
615/*** It matches belarusian layout for XKB from Alexander Mikhailian */
616static const char main_key_BY[MAIN_LEN][4] =
617{
618 "£³","1!","2\"","3#","4;","5%","6:","7?","8*","9(","0)","-_","=+",
619 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","®¾","Úú","Èè","''",
620 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","/|",
621 "Ññ","Þþ","Óó","Íí","¦¶","Ôô","Øø","Ââ","Àà",".,", "|¦",
622};
623#endif
624
625
626#ifndef OUTOFWINE
627/*** Russian keyboard layout (contributed by Pavel Roskin) */
628static const char main_key_RU[MAIN_LEN][4] =
629{
630 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
631 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
632 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
633 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
634};
635
636/*** Russian keyboard layout (phantom key version) */
637static const char main_key_RU_phantom[MAIN_LEN][4] =
638{
639 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
640 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
641 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
642 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
643 "<>" /* the phantom key */
644};
645
646/*** Russian keyboard layout KOI8-R */
647static const char main_key_RU_koi8r[MAIN_LEN][4] =
648{
649 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
650 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
651 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
652 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
653 "<>" /* the phantom key */
654};
655#else
656/*** Russian keyboard layout KOI8-R */
657static const char main_key_RU_koi8r[MAIN_LEN][4] =
658{
659 "£³","1!","2\"","3#","4*","5:","6,","7.","8;","9(","0)","-_","=+",
660 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
661 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
662 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
663 "/|" /* the phantom key */
664};
665#endif
666
667#ifndef OUTOFWINE
668/*** Russian keyboard layout cp1251 */
669static const char main_key_RU_cp1251[MAIN_LEN][4] =
670{
671 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
672 "qQéÉ","wWöÖ","eEóÓ","rRêÊ","tTåÅ","yYíÍ","uUãÃ","iIøØ","oOùÙ","pPçÇ","[{õÕ","]}úÚ",
673 "aAôÔ","sSûÛ","dDâÂ","fFàÀ","gGïÏ","hHðÐ","jJîÎ","kKëË","lLäÄ",";:æÆ","'\"ýÝ","\\|",
674 "zZÿß","xX÷×","cCñÑ","vVìÌ","bBèÈ","nNòÒ","mMüÜ",",<áÁ",".>þÞ","/?",
675 "<>" /* the phantom key */
676};
677
678/*** Russian phonetic keyboard layout */
679static const char main_key_RU_phonetic[MAIN_LEN][4] =
680{
681 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
682 "qQÑñ","wW×÷","eEÅå","rRÒò","tTÔô","yYÙù","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}Ýý",
683 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJÊê","kKËë","lLÌì",";:","'\"","\\|",
684 "zZÚú","xXØø","cCÃã","vVÖö","bBÂâ","nNÎî","mMÍí",",<",".>","/?",
685 "<>" /* the phantom key */
686};
687#else
688/*** Russian phonetic keyboard layout */
689static const char main_key_RU_phonetic[MAIN_LEN][4] =
690{
691 "Àà","1!","2@","3£","4³","5ß","6ÿ","7&","8*","9(","0)","-_","Þþ",
692 "Ññ","×÷","Åå","Òò","Ôô","Ùù","Õõ","Éé","Ïï","Ðð","Ûû","Ýý",
693 "Áá","Óó","Ää","Ææ","Çç","Èè","Êê","Ëë","Ìì",";:","'\"","Üü",
694 "Úú","Øø","Ãã","Öö","Ââ","Îî","Íí",",<",".>","/?",
695 "|¦" /* the phantom key */
696};
697#endif
698
699#ifndef OUTOFWINE
700/*** Ukrainian keyboard layout KOI8-U */
701static const char main_key_UA[MAIN_LEN][4] =
702{
703 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
704 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
705 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
706 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
707 "<>" /* the phantom key */
708};
709#else
710/*** Ukrainian keyboard layout KOI8-U */
711static const char main_key_UA[MAIN_LEN][4] =
712{
713 "­½","1!","2\"","3#","4*","5:","6,","7.","8;","9(","0)","-_","=+",
714 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
715 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\|",
716 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
717 "<>" /* the phantom key */
718};
719#endif
720
721/*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
722/*** (as it appears on most of keyboards sold today) */
723static const char main_key_UA_std[MAIN_LEN][4] =
724{
725 "­½","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
726 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","§·",
727 "Ææ","¦¶","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","¤´","\\/",
728 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
729 "<>" /* the phantom key */
730};
731
732/*** Russian keyboard layout KOI8-R (pair to the previous) */
733static const char main_key_RU_std[MAIN_LEN][4] =
734{
735 "£³","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
736 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
737 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\/",
738 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà",".,",
739 "<>" /* the phantom key */
740};
741
742/*** Spanish keyboard layout (setxkbmap es) */
743static const char main_key_ES[MAIN_LEN][4] =
744{
745 "ºª","1!","2\"","3·","4$","5%","6&","7/","8(","9)","0=","'?","¡¿",
746 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
747 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨","çÇ",
748 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
749 "<>"
750};
751
752/*** Belgian keyboard layout ***/
753static const char main_key_BE[MAIN_LEN][4] =
754{
755#ifndef OUTOFWINE
756 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
757 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
758 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
759 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
760 "<>\\"
761#else
762/* innotek FIX */
763/* I wonder how much of this Wine code has been properly tested? There are many
764 seemingly duplicate layouts, and while many specify three or four keysyms per
765 key, the code choked on all keys in this layout containing more than two
766 keysyms. I suspect that many of these maps only work by luck. */
767 "²³","&1","é2","\"3","'4","(5","§6","è7","!8","ç9","à0",")°","-_",
768 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$*",
769 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","µ£",
770 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+",
771 "<>"
772#endif
773};
774
775/*** Hungarian keyboard layout (setxkbmap hu) */
776static const char main_key_HU[MAIN_LEN][4] =
777{
778 "0§","1'","2\"","3+","4!","5%","6/","7=","8(","9)","öÖ","üÜ","óÓ",
779 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","õÕ","úÚ",
780 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éÉ","áÁ","ûÛ",
781 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
782 "íÍ"
783};
784
785/*** Polish (programmer's) keyboard layout ***/
786static const char main_key_PL[MAIN_LEN][4] =
787{
788 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
789 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
790 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
791 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
792 "<>|"
793};
794
795/*** Slovenian keyboard layout (setxkbmap si) ***/
796static const char main_key_SI[MAIN_LEN][4] =
797{
798 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
799 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
800 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
801 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
802 "<>"
803};
804
805/*** Serbian keyboard layout (setxkbmap sr) ***/
806static const char main_key_SR[MAIN_LEN][4] =
807{
808 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
809 "©¹","ªº","Åå","Òò","Ôô","Úú","Õõ","Éé","Ïï","Ðð","Ûû","[]",
810 "Áá","Óó","Ää","Ææ","Çç","Èè","¨¸","Ëë","Ìì","Þþ","«»","-_",
811 "¡±","¯¿","Ãã","×÷","Ââ","Îî","Íí",",;",".:","Öö",
812 "<>" /* the phantom key */
813};
814
815/*** Serbian keyboard layout (setxkbmap us,sr) ***/
816static const char main_key_US_SR[MAIN_LEN][4] =
817{
818 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
819 "qQ©¹","wWªº","eEÅå","rRÒò","tTÔô","yYÚú","uUÕõ","iIÉé","oOÏï","pPÐð","[{Ûû","]}[]",
820 "aAÁá","sSÓó","dDÄä","fFÆæ","gGÇç","hHÈè","jJ¨¸","kKËë","lLÌì",";:Þþ","'\"«»","\\|-_",
821 "zZ¡±","xX¯¿","cCÃã","vV×÷","bBÂâ","nNÎî","mMÍí",",<,;",".>.:","/?Öö",
822 "<>" /* the phantom key */
823};
824
825/*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
826static const char main_key_HR_jelly[MAIN_LEN][4] =
827{
828 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
829 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
830 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
831 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
832 "<>|"
833};
834
835/*** Croatian keyboard layout (setxkbmap hr) ***/
836static const char main_key_HR[MAIN_LEN][4] =
837{
838 "¸¨","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
839 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","¹©","ðÐ",
840 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","èÈ","æÆ","¾®",
841 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
842 "<>"
843};
844
845/*** Japanese 106 keyboard layout ***/
846static const char main_key_JA_jp106[MAIN_LEN][4] =
847{
848 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
849 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
850 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
851 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
852 "\\_",
853};
854
855/*** Japanese pc98x1 keyboard layout ***/
856static const char main_key_JA_pc98x1[MAIN_LEN][4] =
857{
858 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
859 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
860 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
861 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
862 "\\_",
863};
864
865/*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
866static const char main_key_PT_br[MAIN_LEN][4] =
867{
868 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
869 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
870 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
871 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
872};
873
874/*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
875static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
876{
877 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
878 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
879 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
880 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
881};
882
883#ifndef OUTOFWINE
884/*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
885static const char main_key_US_intl[MAIN_LEN][4] =
886{
887 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
888 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
889 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
890 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
891};
892#else
893/* innotek FIX */
894/*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
895static const char main_key_US_intl[MAIN_LEN][4] =
896{
897 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+",
898 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
899 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "´¨",
900 "\\|", "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
901};
902
903/*** US international keyboard layout with phantom key (contributed by Gustavo Noronha (kov@debian.org)) */
904static const char main_key_US_intl_phantom[MAIN_LEN][4] =
905{
906 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+",
907 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
908 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "´¨",
909 "\\|", "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?",
910 "<>" /* the phantom key */
911};
912#endif
913
914/*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
915 - dead_abovering replaced with degree - no symbol in iso8859-2
916 - brokenbar replaced with bar */
917static const char main_key_SK[MAIN_LEN][4] =
918{
919 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
920 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
921 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
922 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
923 "<>"
924};
925
926/*** Czech keyboard layout (setxkbmap cz) */
927static const char main_key_CZ[MAIN_LEN][4] =
928{
929 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
930 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
931 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
932 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
933 "\\"
934};
935
936/*** Czech keyboard layout (setxkbmap cz_qwerty) */
937static const char main_key_CZ_qwerty[MAIN_LEN][4] =
938{
939 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
940 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
941 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
942 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
943 "\\"
944};
945
946/*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
947static const char main_key_SK_prog[MAIN_LEN][4] =
948{
949 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
950 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
951 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
952 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
953 "<>"
954};
955
956/*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
957static const char main_key_CS[MAIN_LEN][4] =
958{
959 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
960 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
961 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
962 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
963 "<>\\|"
964};
965
966/*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
967static const char main_key_LA[MAIN_LEN][4] =
968{
969 "|°","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","¿¡",
970 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*",
971 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]",
972 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
973 "<>"
974};
975
976/*** Lithuanian keyboard layout (setxkbmap lt) */
977static const char main_key_LT_B[MAIN_LEN][4] =
978{
979 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
980 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
981 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
982 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
983 "ª¬"
984};
985
986/*** Turkish keyboard Layout */
987static const char main_key_TK[MAIN_LEN][4] =
988{
989"\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
990"qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
991"aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
992"zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
993};
994
995/*** Turkish keyboard layout (setxkbmap tr) */
996static const char main_key_TR[MAIN_LEN][4] =
997{
998"\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
999"qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","üÜ",
1000"aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
1001"zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:",
1002"<>"
1003};
1004
1005/*** Turkish F keyboard layout (setxkbmap trf) */
1006static const char main_key_TR_F[MAIN_LEN][4] =
1007{
1008"+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
1009"fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
1010"uU","i\0","eE","aA","üÜ","tT","kK","mM","lL","yY","\xba\xaa","xX",
1011"jJ","öÖ","vV","cC","çÇ","zZ","sS","bB",".:",",;",
1012"<>"
1013};
1014
1015/*** Israelian keyboard layout (setxkbmap us,il) */
1016static const char main_key_IL[MAIN_LEN][4] =
1017{
1018 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
1019 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{","]}",
1020 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|",
1021 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?.",
1022 "<>"
1023};
1024
1025/*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
1026static const char main_key_IL_phonetic[MAIN_LEN][4] =
1027{
1028 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
1029 "qQ÷","wWå","eEà","rRø","tTú","yYò","uUå","iIé","oOñ","pPô","[{","]}",
1030 "aAà","sSù","dDã","fFô","gGâ","hHä","jJé","kKë","lLì",";:","'\"","\\|",
1031 "zZæ","xXç","cCö","vVå","bBá","nNð","mMî",",<",".>","/?",
1032 "<>"
1033};
1034
1035/*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
1036static const char main_key_IL_saharon[MAIN_LEN][4] =
1037{
1038 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
1039 "qQ÷","wWñ","eE","rRø","tTè","yYã","uU","iI","oO","pPô","[{","]}",
1040 "aAà","sSå","dDì","fFú","gGâ","hHä","jJù","kKë","lLé",";:","'\"","\\|",
1041 "zZæ","xXç","cCö","vVò","bBá","nNð","mMî",",<",".>","/?",
1042 "<>"
1043};
1044
1045/*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
1046 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
1047 message since they have different characters in gr and el XFree86 layouts. */
1048static const char main_key_EL[MAIN_LEN][4] =
1049{
1050 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
1051 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
1052 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
1053 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
1054 "<>"
1055};
1056
1057#ifndef OUTOFWINE
1058/*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
1059static const char main_key_th[MAIN_LEN][4] =
1060{
1061 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
1062 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
1063 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
1064 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
1065};
1066#else
1067/*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
1068static const char main_key_th[MAIN_LEN][4] =
1069{
1070 "_%","å+","/ñ","-ò","Àó","¶ô","ØÙ","Öß","¤õ","µö","¨÷","¢ø","ªù",
1071 "æð",\"","Ó®","¾±","и","Ñí","Õê","ó","¹Ï","­","º°","Å,",
1072 "¿Ä","˦","¡¯","´â","à¬","éç","èë","ÒÉ","ÊÈ","Ç«","§.","£¥",
1073 "¼(","»)","á©","ÍÎ","\xd4\xda","×ì","·?","Á²","ãÌ","½Æ",
1074 "<>" /* The phantom key. */
1075};
1076#endif
1077
1078/*** VNC keyboard layout */
1079static const WORD main_key_scan_vnc[MAIN_LEN] =
1080{
1081 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
1082 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,
1083 0x56
1084};
1085
1086static const WORD main_key_vkey_vnc[MAIN_LEN] =
1087{
1088 '1','2','3','4','5','6','7','8','9','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,
1089 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
1090 VK_OEM_102
1091};
1092
1093static const char main_key_vnc[MAIN_LEN][4] =
1094{
1095 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
1096 "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"
1097};
1098
1099/*** Dutch keyboard layout (setxkbmap nl) ***/
1100static const char main_key_NL[MAIN_LEN][4] =
1101{
1102 "@§","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","°~",
1103 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","¨~","*|",
1104 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+±","'`","<>",
1105 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
1106 "[]"
1107};
1108
1109
1110
1111/*** Layout table. Add your keyboard mappings to this list */
1112static const struct {
1113 LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
1114 in the appropriate dlls/kernel/nls/.nls file */
1115 const char *comment;
1116 const char (*key)[MAIN_LEN][4];
1117 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
1118 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
1119} main_key_tab[]={
1120 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1121 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1122#ifndef OUTOFWINE
1123 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
1124 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1125#else
1126/* innotek FIX */
1127 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_qwerty, &main_key_vkey_dvorak},
1128 {0x0409, "United States keyboard layout (dvorak, phantom key version)", &main_key_US_dvorak_phantom, &main_key_scan_qwerty, &main_key_vkey_dvorak},
1129 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1130 {0x0409, "United States International keyboard layout (phantom key version)", &main_key_US_intl_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1131#endif
1132 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1133#ifdef OUTOFWINE
1134 {0x0809, "British international keyboard layout", &main_key_UK_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1135#endif
1136 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1137#ifndef OUTOFWINE
1138 {0x0407, "German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1139 {0x0407, "German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1140#endif
1141 {0x0407, "German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwertz_105},
1142 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1143 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1144 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
1145 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1146 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1147 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1148 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
1149#ifndef OUTOFWINE
1150 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1151#endif
1152 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1153 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1154 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
1155 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1156 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
1157 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
1158 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1159 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1160 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1161 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1162#ifndef OUTOFWINE
1163 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1164 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1165#endif
1166 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1167#ifndef OUTOFWINE
1168 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1169#endif
1170 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1171 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1172 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1173 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1174 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1175 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1176 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1177 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1178 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1179 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1180 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
1181 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
1182 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1183 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1184 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
1185 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1186 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1187 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1188 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1189 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
1190 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1191 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1192 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1193 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1194 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1195 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1196 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1197 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1198 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1199 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
1200 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1201 {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1202 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
1203
1204 {0, NULL, NULL, NULL, NULL} /* sentinel */
1205};
1206static unsigned kbd_layout=0; /* index into above table of layouts */
1207
1208/* maybe more of these scancodes should be extended? */
1209 /* extended must be set for ALT_R, CTRL_R,
1210 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
1211 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
1212 /* FIXME should we set extended bit for NumLock ? My
1213 * Windows does ... DF */
1214 /* Yes, to distinguish based on scan codes, also
1215 for PrtScn key ... GA */
1216
1217#ifndef OUTOFWINE
1218static const WORD nonchar_key_vkey[256] =
1219{
1220 /* unused */
1221 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
1222 /* special keys */
1223 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
1224 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
1225 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
1226 /* unused */
1227 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
1228 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
1229 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
1230 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
1231 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
1232 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
1233 /* cursor keys */
1234 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
1235 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
1236 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
1237 /* misc keys */
1238 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
1239 0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
1240 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
1241 /* keypad keys */
1242 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
1243 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
1244 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
1245 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
1246 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
1247 VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1248 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
1249 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
1250 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1251 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
1252 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1253 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL, /* FFB8 */
1254 /* function keys */
1255 VK_F1, VK_F2,
1256 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
1257 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
1258 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
1259 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
1260 /* modifier keys */
1261 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
1262 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
1263 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
1264 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
1265 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
1266};
1267#endif /* OUTOFWINE not defined */
1268
1269static const WORD nonchar_key_scan[256] =
1270{
1271 /* unused */
1272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
1273 /* special keys */
1274 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
1275 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
1276 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
1277 /* unused */
1278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
1279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
1280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
1281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
1282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
1283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
1284 /* cursor keys */
1285 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
1286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
1287 /* misc keys */
1288#ifdef OUTOFWINE
1289/* innotek FIX */
1290 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */
1291#else
1292 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
1293#endif
1294 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
1295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
1296 /* keypad keys */
1297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
1298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
1299 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
1300 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
1301 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
1302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
1303#ifdef OUTOFWINE
1304/* innotek FIX */
1305 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x7e, 0x135, /* FFA8 */
1306#else
1307 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */
1308#endif
1309 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
1310 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
1311 /* function keys */
1312 0x3B, 0x3C,
1313 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
1314 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
1315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
1316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
1317 /* modifier keys */
1318 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
1319#ifdef OUTOFWINE
1320/* innotek FIX */
1321 0x138, 0x38, 0x138, 0x15B, 0x15C, 0x00, 0x00, 0x00, /* FFE8 */
1322#else
1323 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
1324#endif
1325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
1326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
1327};
1328
1329#ifndef OUTOFWINE
1330static const WORD xfree86_vendor_key_vkey[256] =
1331{
1332 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1333 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1334 0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP, /* 1008FF10 */
1335 VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
1336 VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
1337 0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH, /* 1008FF18 */
1338 0, 0, 0, VK_BROWSER_HOME,
1339 0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD, /* 1008FF20 */
1340 VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0, /* 1008FF28 */
1341 VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0, /* 1008FF30 */
1342 0, 0, 0, 0,
1343 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1344 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1345 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1346 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF50 */
1347 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF58 */
1348 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1349 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF68 */
1350 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF70 */
1351 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF78 */
1352 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1353 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1354 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF90 */
1355 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1356 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1357 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1358 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1359 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1360 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1361 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1362 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1363 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1364 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1365 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1366 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1367 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1368};
1369#else /* OUTOFWINE defined */
1370/* innotek FIX */
1371/* This list was put together using /usr/include/X11/XF86keysym.h and
1372 http://www.win.tue.nl/~aeb/linux/kbd/scancodes-6.html. It has not yet
1373 been extensively tested. The scancodes are those used by MicroSoft
1374 keyboards. */
1375static const WORD xfree86_vendor_key_scan[256] =
1376{
1377 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */
1378 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF08 */
1379 /* Vol- Mute Vol+ Play Stop Track- Track+ */
1380 0, 0x12e, 0x120, 0x130, 0x122, 0x124, 0x110, 0x119, /* 1008FF10 */
1381 /* Home E-mail Search */
1382 0x132, 0x16c, 0, 0x165, 0, 0, 0, 0, /* 1008FF18 */
1383 /* Calndr PwrDown Back Forward */
1384 0x115, 0x15e, 0, 0, 0, 0, 0x16a, 0x169, /* 1008FF20 */
1385 /* Stop Refresh Power Wake Sleep */
1386 0x168, 0x167, 0x15e, 0x163, 0, 0, 0, 0x15f, /* 1008FF28 */
1387 /* Favrts Pause Media MyComp */
1388 0x166, 0x122, 0x16d, 0x16b, 0, 0, 0, 0, /* 1008FF30 */
1389 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF38 */
1390 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF40 */
1391 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF48 */
1392 /* AppL AppR Calc Close Copy */
1393 0x109, 0x11e, 0, 0, 0x121, 0, 0x140, 0x118, /* 1008FF50 */
1394 /* Cut Docmnts Excel */
1395 0x117, 0, 0, 0x105, 0x114, 0, 0, 0, /* 1008FF58 */
1396 /* LogOff */
1397 0, 0x116, 0, 0, 0, 0, 0, 0, /* 1008FF60 */
1398 /* OffcHm Open Paste */
1399 0, 0, 0x13c, 0x13f, 0, 0x10a, 0, 0, /* 1008FF68 */
1400 /* Reply Refresh Save */
1401 0, 0, 0x141, 0x167, 0, 0, 0, 0x157, /* 1008FF70 */
1402 /* ScrlUp ScrlDn Send Spell TaskPane */
1403 0x10b, 0x18b, 0, 0x143, 0x123, 0, 0, 0x13d, /* 1008FF78 */
1404 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF80 */
1405 /* Word */
1406 0, 0x113, 0, 0, 0, 0, 0, 0, /* 1008FF88 */
1407 /* MailFwd MyPics MyMusic*/
1408 0x142, 0x164, 0x13c, 0, 0, 0, 0, 0, /* 1008FF90 */
1409 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF98 */
1410 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA0 */
1411 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFA8 */
1412 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB0 */
1413 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFB8 */
1414 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC0 */
1415 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFC8 */
1416 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD0 */
1417 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFD8 */
1418 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE0 */
1419 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFE8 */
1420 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FFF0 */
1421 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */
1422};
1423#endif /* OUTOFWINE defined */
1424
1425#ifndef OUTOFWINE
1426/* Returns the Windows virtual key code associated with the X event <e> */
1427/* x11 lock must be held */
1428static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1429{
1430 KeySym keysym = 0;
1431 Status status;
1432 char buf[24];
1433
1434 /* Clients should pass only KeyPress events to XmbLookupString */
1435 if (xic && e->type == KeyPress)
1436 XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1437 else
1438 XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1439
1440 if ((e->state & NumLockMask) &&
1441 (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
1442 (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1443 /* Only the Keypad keys 0-9 and . send different keysyms
1444 * depending on the NumLock state */
1445 return nonchar_key_vkey[keysym & 0xFF];
1446
1447 TRACE_(key)("e->keycode = %x\n", e->keycode);
1448
1449 return keyc2vkey[e->keycode];
1450}
1451
1452static BOOL NumState=FALSE, CapsState=FALSE;
1453
1454
1455/***********************************************************************
1456 * X11DRV_send_keyboard_input
1457 */
1458void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time,
1459 DWORD dwExtraInfo, UINT injected_flags )
1460{
1461 UINT message;
1462 KEYLP keylp;
1463 KBDLLHOOKSTRUCT hook;
1464 WORD wVkStripped;
1465
1466 wVk = LOBYTE(wVk);
1467
1468 /* strip left/right for menu, control, shift */
1469 if (wVk == VK_LMENU || wVk == VK_RMENU)
1470 wVkStripped = VK_MENU;
1471 else if (wVk == VK_LCONTROL || wVk == VK_RCONTROL)
1472 wVkStripped = VK_CONTROL;
1473 else if (wVk == VK_LSHIFT || wVk == VK_RSHIFT)
1474 wVkStripped = VK_SHIFT;
1475 else
1476 wVkStripped = wVk;
1477
1478 keylp.lp2 = 0;
1479 keylp.lp1.count = 1;
1480 keylp.lp1.code = wScan;
1481 keylp.lp1.extended = (dwFlags & KEYEVENTF_EXTENDEDKEY) != 0;
1482 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
1483 * don't remember where I read it - AK */
1484 /* it's '1' under windows, when a dialog box appears
1485 * and you press one of the underlined keys - DF*/
1486
1487 /* note that there is a test for all this */
1488 if (dwFlags & KEYEVENTF_KEYUP )
1489 {
1490 message = WM_KEYUP;
1491 if ((key_state_table[VK_MENU] & 0x80) &&
1492 ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
1493 || !(key_state_table[VK_CONTROL] & 0x80)))
1494 {
1495 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
1496 (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
1497 message = WM_SYSKEYUP;
1498 TrackSysKey = 0;
1499 }
1500 key_state_table[wVk] &= ~0x80;
1501 key_state_table[wVkStripped] &= ~0x80;
1502 keylp.lp1.previous = 1;
1503 keylp.lp1.transition = 1;
1504 }
1505 else
1506 {
1507 keylp.lp1.previous = (key_state_table[wVk] & 0x80) != 0;
1508 keylp.lp1.transition = 0;
1509 if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01;
1510 key_state_table[wVk] |= 0xc0;
1511 key_state_table[wVkStripped] |= 0xc0;
1512
1513 message = WM_KEYDOWN;
1514 if ((key_state_table[VK_MENU] & 0x80) && !(key_state_table[VK_CONTROL] & 0x80))
1515 {
1516 message = WM_SYSKEYDOWN;
1517 TrackSysKey = wVkStripped;
1518 }
1519 }
1520
1521 keylp.lp1.context = (key_state_table[VK_MENU] & 0x80) != 0; /* 1 if alt */
1522
1523 TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
1524 wVk, keylp.lp2, key_state_table[wVk] );
1525
1526 hook.vkCode = wVk;
1527 hook.scanCode = wScan;
1528 hook.flags = (keylp.lp2 >> 24) | injected_flags;
1529 hook.time = time;
1530 hook.dwExtraInfo = dwExtraInfo;
1531 if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return;
1532
1533 SERVER_START_REQ( send_hardware_message )
1534 {
1535 req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId();
1536 req->win = 0;
1537 req->msg = message;
1538 req->wparam = wVk;
1539 req->lparam = keylp.lp2;
1540 req->x = cursor_pos.x;
1541 req->y = cursor_pos.y;
1542 req->time = time;
1543 req->info = dwExtraInfo;
1544 wine_server_call( req );
1545 }
1546 SERVER_END_REQ;
1547}
1548
1549
1550/**********************************************************************
1551 * KEYBOARD_GenerateMsg
1552 *
1553 * Generate Down+Up messages when NumLock or CapsLock is pressed.
1554 *
1555 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
1556 *
1557 */
1558static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
1559{
1560 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
1561 DWORD up, down;
1562
1563 if (*State) {
1564 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
1565 don't treat it. It's from the same key press. Then the state goes to ON.
1566 And from there, a 'release' event will switch off the toggle key. */
1567 *State=FALSE;
1568 TRACE("INTERM : don't treat release of toggle key. key_state_table[%#x] = %#x\n",
1569 vkey,key_state_table[vkey]);
1570 } else
1571 {
1572 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
1573 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
1574 if ( key_state_table[vkey] & 0x1 ) /* it was ON */
1575 {
1576 if (Evtype!=KeyPress)
1577 {
1578 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
1579 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1580 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1581 *State=FALSE;
1582 key_state_table[vkey] &= ~0x01; /* Toggle state to off. */
1583 }
1584 }
1585 else /* it was OFF */
1586 if (Evtype==KeyPress)
1587 {
1588 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
1589 X11DRV_send_keyboard_input( vkey, scan, down, event_time, 0, 0 );
1590 X11DRV_send_keyboard_input( vkey, scan, up, event_time, 0, 0 );
1591 *State=TRUE; /* Goes to intermediary state before going to ON */
1592 key_state_table[vkey] |= 0x01; /* Toggle state to on. */
1593 }
1594 }
1595}
1596
1597/***********************************************************************
1598 * KEYBOARD_UpdateOneState
1599 *
1600 * Updates internal state for <vkey>, depending on key <state> under X
1601 *
1602 */
1603inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
1604{
1605 /* Do something if internal table state != X state for keycode */
1606 if (((key_state_table[vkey] & 0x80)!=0) != state)
1607 {
1608 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
1609 vkey, key_state_table[vkey]);
1610
1611 /* Fake key being pressed inside wine */
1612 X11DRV_send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time, 0, 0 );
1613
1614 TRACE("State after %#.2x\n",key_state_table[vkey]);
1615 }
1616}
1617
1618/***********************************************************************
1619 * X11DRV_KeymapNotify
1620 *
1621 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1622 *
1623 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
1624 * from wine to another application and back.
1625 * Toggle keys are handled in HandleEvent.
1626 */
1627void X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1628{
1629 int i, j, alt, control, shift;
1630 DWORD time = GetCurrentTime();
1631
1632 alt = control = shift = 0;
1633 /* the minimum keycode is always greater or equal to 8, so we can
1634 * skip the first 8 values, hence start at 1
1635 */
1636 for (i = 1; i < 32; i++)
1637 {
1638 if (!event->xkeymap.key_vector[i]) continue;
1639 for (j = 0; j < 8; j++)
1640 {
1641 if (!(event->xkeymap.key_vector[i] & (1<<j))) continue;
1642 switch(keyc2vkey[(i * 8) + j] & 0xff)
1643 {
1644 case VK_MENU: alt = 1; break;
1645 case VK_CONTROL: control = 1; break;
1646 case VK_SHIFT: shift = 1; break;
1647 }
1648 }
1649 }
1650 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
1651 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
1652 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
1653}
1654
1655/***********************************************************************
1656 * X11DRV_KeyEvent
1657 *
1658 * Handle a X key event
1659 */
1660void X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1661{
1662 XKeyEvent *event = &xev->xkey;
1663 char Str[24];
1664 KeySym keysym = 0;
1665 WORD vkey = 0, bScan;
1666 DWORD dwFlags;
1667 int ascii_chars;
1668 XIC xic = X11DRV_get_ic( hwnd );
1669 DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1670 Status status = 0;
1671
1672 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
1673 event->type, event->window, event->state, event->keycode);
1674
1675 wine_tsx11_lock();
1676 /* Clients should pass only KeyPress events to XmbLookupString */
1677 if (xic && event->type == KeyPress)
1678 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
1679 else
1680 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1681 wine_tsx11_unlock();
1682
1683 TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status);
1684
1685 if (status == XBufferOverflow)
1686 ERR("Buffer Overflow need %i!\n",ascii_chars);
1687
1688 if (status == XLookupChars)
1689 {
1690 X11DRV_XIMLookupChars( Str, ascii_chars );
1691 return;
1692 }
1693
1694 /* If XKB extensions are used, the state mask for AltGr will use the group
1695 index instead of the modifier mask. The group index is set in bits
1696 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1697 pressed, look if the group index is different than 0. From XKB
1698 extension documentation, the group index for AltGr should be 2
1699 (event->state = 0x2000). It's probably better to not assume a
1700 predefined group index and find it dynamically
1701
1702 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1703 /* Save also all possible modifier states. */
1704 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1705
1706 Str[ascii_chars] = '\0';
1707 if (TRACE_ON(key)){
1708 const char *ksname;
1709
1710 wine_tsx11_lock();
1711 ksname = XKeysymToString(keysym);
1712 wine_tsx11_unlock();
1713 if (!ksname)
1714 ksname = "No Name";
1715 TRACE_(key)("%s : keysym=%lX (%s), # of chars=%d / 0x%02x / '%s'\n",
1716 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1717 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1718 }
1719
1720 wine_tsx11_lock();
1721 vkey = EVENT_event_to_vkey(xic,event);
1722 /* X returns keycode 0 for composed characters */
1723 if (!vkey && ascii_chars) vkey = VK_NONAME;
1724 wine_tsx11_unlock();
1725
1726 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1727 event->keycode, vkey);
1728
1729 if (vkey)
1730 {
1731 switch (vkey & 0xff)
1732 {
1733 case VK_NUMLOCK:
1734 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1735 break;
1736 case VK_CAPITAL:
1737 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,key_state_table[vkey]);
1738 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1739 TRACE("State after : %#.2x\n",key_state_table[vkey]);
1740 break;
1741 default:
1742 /* Adjust the NUMLOCK state if it has been changed outside wine */
1743 if (!(key_state_table[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1744 {
1745 TRACE("Adjusting NumLock state.\n");
1746 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1747 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1748 }
1749 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1750 if (!(key_state_table[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1751 {
1752 TRACE("Adjusting Caps Lock state.\n");
1753 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1754 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1755 }
1756 /* Not Num nor Caps : end of intermediary states for both. */
1757 NumState = FALSE;
1758 CapsState = FALSE;
1759
1760 bScan = keyc2scan[event->keycode] & 0xFF;
1761 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1762
1763 dwFlags = 0;
1764 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1765 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1766
1767 X11DRV_send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time, 0, 0 );
1768 }
1769 }
1770}
1771
1772#else /* OUTOFWINE defined */
1773
1774void X11DRV_KeyEvent(Display *dpy, XEvent *xev, WINEKEYBOARDINFO *wKbInfo)
1775{
1776 XKeyEvent *event = &xev->xkey;
1777 wKbInfo->wScan = keyc2scan[event->keycode] & 0xFF;
1778 wKbInfo->dwFlags = keyc2scan[event->keycode] >> 8;
1779}
1780
1781#endif /* OUTOFWINE defined */
1782
1783/**********************************************************************
1784 * X11DRV_KEYBOARD_DetectLayout
1785 *
1786 * Called from X11DRV_InitKeyboard
1787 * This routine walks through the defined keyboard layouts and selects
1788 * whichever matches most closely.
1789 * X11 lock must be held.
1790 */
1791#ifndef OUTOFWINE
1792static void
1793X11DRV_KEYBOARD_DetectLayout (void)
1794#else
1795static void
1796X11DRV_KEYBOARD_DetectLayout (Display *display)
1797#endif
1798{
1799#ifndef OUTOFWINE
1800 Display *display = thread_display();
1801#endif
1802 unsigned current, match, mismatch, seq, i, syms;
1803 int score, keyc, key, pkey, ok;
1804 KeySym keysym = 0;
1805 const char (*lkey)[MAIN_LEN][4];
1806 unsigned max_seq = 0;
1807 int max_score = 0, ismatch = 0;
1808 char ckey[256][4];
1809#ifdef OUTOFWINE
1810/* innotek FIX */
1811 /* The Wine algorithm is incapable of distinguishing the dvorak and the querty layout,
1812 which have the same keys in a different sequence. Based on the assumption that
1813 scan codes are laid out more or less sequentially, we keep a track of how many
1814 of our detected scan codes are out of order as an additional matching criterium. */
1815 int misorder, last_match, least_misorder = 256;
1816#endif
1817
1818#ifndef OUTOFWINE
1819 syms = keysyms_per_keycode;
1820 if (syms > 4) {
1821 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1822 syms = 4;
1823 }
1824#else
1825/* innotek FIX */
1826 /* Not all setups really produce all four keysyms, and two are enough
1827 for identification anyway. */
1828 syms = keysyms_per_keycode;
1829 if (syms > 2) {
1830 WARN("%d keysyms per keycode not supported, set to 2\n", syms);
1831 syms = 2;
1832 }
1833#endif
1834
1835 memset( ckey, 0, sizeof(ckey) );
1836 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1837 /* get data for keycode from X server */
1838 for (i = 0; i < syms; i++) {
1839 if (!(keysym = XKeycodeToKeysym (display, keyc, i))) continue;
1840 /* Allow both one-byte and two-byte national keysyms */
1841 if ((keysym < 0x8000) && (keysym != ' '))
1842 {
1843#ifdef HAVE_XKB
1844 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1845#endif
1846 {
1847#ifndef OUTOFWINE
1848 TRACE("XKB could not translate keysym %ld\n", keysym);
1849#endif
1850 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1851 * with appropriate ShiftMask and Mode_switch, use XLookupString
1852 * to get character in the local encoding.
1853 */
1854 ckey[keyc][i] = keysym & 0xFF;
1855 }
1856 }
1857 else {
1858 ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1859 }
1860 }
1861 }
1862
1863 for (current = 0; main_key_tab[current].comment; current++) {
1864 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1865 match = 0;
1866 mismatch = 0;
1867 score = 0;
1868 seq = 0;
1869 lkey = main_key_tab[current].key;
1870 pkey = -1;
1871#ifdef OUTOFWINE
1872/* innotek FIX - dvorak layout */
1873 last_match = 0;
1874 misorder = 0;
1875#endif
1876 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1877 if (ckey[keyc][0]) {
1878 /* search for a match in layout table */
1879 /* right now, we just find an absolute match for defined positions */
1880 /* (undefined positions are ignored, so if it's defined as "3#" in */
1881 /* the table, it's okay that the X server has "3#£", for example) */
1882 /* however, the score will be higher for longer matches */
1883 for (key = 0; key < MAIN_LEN; key++) {
1884 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1885 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1886 ok++;
1887 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1888 ok = -1;
1889 }
1890 if (ok > 0) {
1891 score += ok;
1892#ifdef OUTOFWINE
1893/* innotek FIX - dvorak layout */
1894 if (key < last_match)
1895 {
1896 ++misorder;
1897 }
1898 last_match = key;
1899#endif
1900 break;
1901 }
1902 }
1903 /* count the matches and mismatches */
1904 if (ok > 0) {
1905 match++;
1906 /* and how much the keycode order matches */
1907 if (key > pkey) seq++;
1908 pkey = key;
1909 } else {
1910 /* print spaces instead of \0's */
1911 char str[5];
1912 for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
1913 str[4] = 0;
1914#ifndef OUTOFWINE
1915 TRACE_(key)("mismatch for keysym 0x%04lX, keycode %d, got %s\n", keysym, keyc, str );
1916#else
1917 TRACE_(key)("mismatch for keycode %d, got %s (0x%.2hx 0x%.2hx)\n",
1918 keyc, str, str[0], str[1]);
1919#endif
1920 mismatch++;
1921 score -= syms;
1922 }
1923 }
1924 }
1925#ifndef OUTOFWINE
1926 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1927 match, mismatch, seq, score);
1928 if ((score > max_score) ||
1929 ((score == max_score) && (seq > max_seq))) {
1930#else
1931/* innotek FIX - dvorak layout */
1932 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d, misorder = %d\n",
1933 match, mismatch, seq, score, misorder);
1934 if ((score > max_score) ||
1935 ((score == max_score) && (seq > max_seq)) ||
1936 ((score == max_score) && (seq == max_seq) &&
1937 (misorder < least_misorder))) {
1938#endif
1939 /* best match so far */
1940 kbd_layout = current;
1941 max_score = score;
1942 max_seq = seq;
1943 ismatch = !mismatch;
1944#ifdef OUTOFWINE
1945/* innotek FIX - dvorak layout */
1946 least_misorder = misorder;
1947#endif
1948 }
1949 }
1950 /* we're done, report results if necessary */
1951 if (!ismatch)
1952 WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
1953 main_key_tab[kbd_layout].comment);
1954
1955 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1956}
1957
1958/**********************************************************************
1959 * X11DRV_InitKeyboard
1960 */
1961#ifndef OUTOFWINE
1962void X11DRV_InitKeyboard(void)
1963#else
1964void X11DRV_InitKeyboard(Display *display)
1965#endif
1966{
1967#ifndef OUTOFWINE
1968 Display *display = thread_display();
1969 KeySym *ksp;
1970 XModifierKeymap *mmp;
1971 KeySym keysym;
1972 KeyCode *kcp;
1973 XKeyEvent e2;
1974 WORD scan, vkey, OEMvkey;
1975#else
1976 KeySym *ksp;
1977 KeySym keysym;
1978 XKeyEvent e2;
1979 WORD scan;
1980#endif
1981 int keyc, i, keyn, syms;
1982 char ckey[4]={0,0,0,0};
1983 const char (*lkey)[MAIN_LEN][4];
1984#ifndef OUTOFWINE
1985 char vkey_used[256] = { 0 };
1986#endif
1987
1988 wine_tsx11_lock();
1989 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1990 ksp = XGetKeyboardMapping(display, min_keycode,
1991 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1992 /* We are only interested in keysyms_per_keycode.
1993 There is no need to hold a local copy of the keysyms table */
1994 XFree(ksp);
1995
1996#ifndef OUTOFWINE
1997 mmp = XGetModifierMapping(display);
1998 kcp = mmp->modifiermap;
1999 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
2000 {
2001 int j;
2002
2003 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
2004 if (*kcp)
2005 {
2006 int k;
2007
2008 for (k = 0; k < keysyms_per_keycode; k += 1)
2009 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
2010 {
2011 NumLockMask = 1 << i;
2012 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
2013 }
2014 }
2015 }
2016 XFreeModifiermap(mmp);
2017
2018 /* Detect the keyboard layout */
2019 X11DRV_KEYBOARD_DetectLayout();
2020#else
2021 /* Detect the keyboard layout */
2022 X11DRV_KEYBOARD_DetectLayout(display);
2023#endif
2024 lkey = main_key_tab[kbd_layout].key;
2025#ifndef OUTOFWINE
2026 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
2027#else
2028/* innotek FIX */
2029 /* Not all setups really produce all four keysyms, and two are enough
2030 for identification anyway. */
2031 syms = (keysyms_per_keycode > 2) ? 2 : keysyms_per_keycode;
2032#endif
2033
2034 /* Now build two conversion arrays :
2035 * keycode -> vkey + scancode + extended
2036 * vkey + extended -> keycode */
2037
2038 e2.display = display;
2039 e2.state = 0;
2040
2041#ifndef OUTOFWINE
2042 OEMvkey = VK_OEM_8; /* next is available. */
2043 memset(keyc2vkey, 0, sizeof(keyc2vkey));
2044#endif
2045 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2046 {
2047 char buf[30];
2048 int have_chars;
2049
2050 keysym = 0;
2051 e2.keycode = (KeyCode)keyc;
2052 have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
2053#ifndef OUTOFWINE
2054 vkey = 0; scan = 0;
2055#else
2056 scan = 0;
2057#endif
2058 if (keysym) /* otherwise, keycode not used */
2059 {
2060 if ((keysym >> 8) == 0xFF) /* non-character key */
2061 {
2062#ifndef OUTOFWINE
2063 vkey = nonchar_key_vkey[keysym & 0xff];
2064#endif
2065 scan = nonchar_key_scan[keysym & 0xff];
2066 /* set extended bit when necessary */
2067#ifndef OUTOFWINE
2068 if (scan & 0x100) vkey |= 0x100;
2069#endif
2070 } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
2071#ifndef OUTOFWINE
2072 vkey = xfree86_vendor_key_vkey[keysym & 0xff];
2073 /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
2074 scan = 0x100;
2075 vkey |= 0x100;
2076#else
2077/* innotek FIX - multimedia/internet keys */
2078 /* @michael: this needs to be tested and completed some day. */
2079 scan = xfree86_vendor_key_scan[keysym & 0xff];
2080#endif
2081 } else if (keysym == 0x20) { /* Spacebar */
2082#ifndef OUTOFWINE
2083 vkey = VK_SPACE;
2084#endif
2085 scan = 0x39;
2086#ifdef OUTOFWINE
2087/* innotek FIX - AltGr support */
2088 } else if (keysym == 0xFE03) { /* ISO level3 shift, aka AltGr */
2089 scan = 0x138;
2090#endif /* OUTOFWINE defined */
2091 } else if (have_chars) {
2092 /* we seem to need to search the layout-dependent scancodes */
2093 int maxlen=0,maxval=-1,ok;
2094 for (i=0; i<syms; i++) {
2095 keysym = XKeycodeToKeysym(display, keyc, i);
2096 if ((keysym<0x8000) && (keysym!=' '))
2097 {
2098#ifdef HAVE_XKB
2099 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
2100#endif
2101 {
2102 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
2103 * with appropriate ShiftMask and Mode_switch, use XLookupString
2104 * to get character in the local encoding.
2105 */
2106 ckey[i] = keysym & 0xFF;
2107 }
2108 } else {
2109 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
2110 }
2111 }
2112 /* find key with longest match streak */
2113 for (keyn=0; keyn<MAIN_LEN; keyn++) {
2114 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
2115 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
2116 if (!ok) i--; /* we overshot */
2117 if (ok||(i>maxlen)) {
2118 maxlen=i; maxval=keyn;
2119 }
2120 if (ok) break;
2121 }
2122 if (maxval>=0) {
2123 /* got it */
2124#ifndef OUTOFWINE
2125 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
2126 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
2127 scan = (*lscan)[maxval];
2128 vkey = (*lvkey)[maxval];
2129#else
2130 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
2131 scan = (*lscan)[maxval];
2132#endif
2133 }
2134 }
2135 }
2136#ifndef OUTOFWINE
2137 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
2138 keyc2vkey[e2.keycode] = vkey;
2139 keyc2scan[e2.keycode] = scan;
2140 if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
2141 WARN("vkey %04x is being used by more than one keycode\n", vkey);
2142 vkey_used[(vkey & 0xff)] = 1;
2143#else
2144 keyc2scan[e2.keycode] = scan;
2145#endif
2146 } /* for */
2147
2148#ifndef OUTOFWINE
2149#define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
2150 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2151 {
2152 vkey = keyc2vkey[keyc] & 0xff;
2153 if (vkey)
2154 continue;
2155
2156 e2.keycode = (KeyCode)keyc;
2157 keysym = XLookupKeysym(&e2, 0);
2158 if (!keysym)
2159 continue;
2160
2161 /* find a suitable layout-dependent VK code */
2162 /* (most Winelib apps ought to be able to work without layout tables!) */
2163 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
2164 {
2165 keysym = XLookupKeysym(&e2, i);
2166 if ((keysym >= XK_0 && keysym <= XK_9)
2167 || (keysym >= XK_A && keysym <= XK_Z)) {
2168 vkey = VKEY_IF_NOT_USED(keysym);
2169 }
2170 }
2171
2172 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
2173 {
2174 keysym = XLookupKeysym(&e2, i);
2175 switch (keysym)
2176 {
2177 case ';': vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
2178 case '/': vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
2179 case '`': vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
2180 case '[': vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
2181 case '\\': vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
2182 case ']': vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
2183 case '\'': vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
2184 case ',': vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
2185 case '.': vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
2186 case '-': vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
2187 case '+': vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
2188 }
2189 }
2190
2191 if (!vkey)
2192 {
2193 /* Others keys: let's assign OEM virtual key codes in the allowed range,
2194 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
2195 do
2196 {
2197 switch (++OEMvkey)
2198 {
2199 case 0xc1 : OEMvkey=0xdb; break;
2200 case 0xe5 : OEMvkey=0xe9; break;
2201 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
2202 }
2203 } while (OEMvkey < 0xf5 && vkey_used[OEMvkey]);
2204
2205 vkey = VKEY_IF_NOT_USED(OEMvkey);
2206
2207 if (TRACE_ON(keyboard))
2208 {
2209 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
2210 OEMvkey, e2.keycode);
2211 TRACE("(");
2212 for (i = 0; i < keysyms_per_keycode; i += 1)
2213 {
2214 const char *ksname;
2215
2216 keysym = XLookupKeysym(&e2, i);
2217 ksname = XKeysymToString(keysym);
2218 if (!ksname)
2219 ksname = "NoSymbol";
2220 TRACE( "%lX (%s) ", keysym, ksname);
2221 }
2222 TRACE(")\n");
2223 }
2224 }
2225
2226 if (vkey)
2227 {
2228 TRACE("keycode %04x => vkey %04x\n", e2.keycode, vkey);
2229 keyc2vkey[e2.keycode] = vkey;
2230 }
2231 } /* for */
2232#undef VKEY_IF_NOT_USED
2233
2234 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
2235 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
2236 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
2237 const char *ksname;
2238 keysym = XKeycodeToKeysym(display, keyc, 0);
2239 ksname = XKeysymToString(keysym);
2240 if (!ksname) ksname = "NoSymbol";
2241
2242 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
2243
2244 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
2245 keyc2scan[keyc]=scan++;
2246 }
2247
2248 /* Now store one keycode for each modifier. Used to simulate keypresses. */
2249 kcControl = XKeysymToKeycode(display, XK_Control_L);
2250 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
2251 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
2252 kcShift = XKeysymToKeycode(display, XK_Shift_L);
2253 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
2254 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
2255#endif /* OUTOFWINE not defined */
2256 wine_tsx11_unlock();
2257}
2258
2259#ifndef OUTOFWINE
2260/**********************************************************************
2261 * GetAsyncKeyState (X11DRV.@)
2262 */
2263SHORT X11DRV_GetAsyncKeyState(INT key)
2264{
2265 SHORT retval;
2266
2267 X11DRV_MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_KEY, 0 );
2268
2269 retval = ((key_state_table[key] & 0x40) ? 0x0001 : 0) |
2270 ((key_state_table[key] & 0x80) ? 0x8000 : 0);
2271 key_state_table[key] &= ~0x40;
2272 TRACE_(key)("(%x) -> %x\n", key, retval);
2273 return retval;
2274}
2275
2276
2277/***********************************************************************
2278 * GetKeyboardLayoutList (X11DRV.@)
2279 */
2280UINT X11DRV_GetKeyboardLayoutList(INT size, HKL *hkl)
2281{
2282 INT i;
2283
2284 TRACE("%d, %p\n", size, hkl);
2285
2286 if (!size)
2287 {
2288 size = 4096; /* hope we will never have that many */
2289 hkl = NULL;
2290 }
2291
2292 for (i = 0; main_key_tab[i].comment && (i < size); i++)
2293 {
2294 if (hkl)
2295 {
2296 ULONG_PTR layout = main_key_tab[i].lcid;
2297 LANGID langid;
2298
2299 /* see comment for GetKeyboardLayout */
2300 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
2301 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
2302 layout |= 0xe001 << 16; /* FIXME */
2303 else
2304 layout |= layout << 16;
2305
2306 hkl[i] = (HKL)layout;
2307 }
2308 }
2309 return i;
2310}
2311
2312
2313/***********************************************************************
2314 * GetKeyboardLayout (X11DRV.@)
2315 */
2316HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
2317{
2318 ULONG_PTR layout;
2319 LANGID langid;
2320
2321 if (dwThreadid && dwThreadid != GetCurrentThreadId())
2322 FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
2323
2324#if 0
2325 layout = main_key_tab[kbd_layout].lcid;
2326#else
2327 /* FIXME:
2328 * Winword uses return value of GetKeyboardLayout as a codepage
2329 * to translate ANSI keyboard messages to unicode. But we have
2330 * a problem with it: for instance Polish keyboard layout is
2331 * identical to the US one, and therefore instead of the Polish
2332 * locale id we return the US one.
2333 */
2334 layout = GetUserDefaultLCID();
2335#endif
2336 /*
2337 * Microsoft Office expects this value to be something specific
2338 * for Japanese and Korean Windows with an IME the value is 0xe001
2339 * We should probably check to see if an IME exists and if so then
2340 * set this word properly.
2341 */
2342 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
2343 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
2344 layout |= 0xe001 << 16; /* FIXME */
2345 else
2346 layout |= layout << 16;
2347
2348 return (HKL)layout;
2349}
2350
2351
2352/***********************************************************************
2353 * GetKeyboardLayoutName (X11DRV.@)
2354 */
2355BOOL X11DRV_GetKeyboardLayoutName(LPWSTR name)
2356{
2357 static const WCHAR formatW[] = {'%','0','8','l','x',0};
2358 DWORD layout;
2359 LANGID langid;
2360
2361 layout = main_key_tab[kbd_layout].lcid;
2362 /* see comment for GetKeyboardLayout */
2363 langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
2364 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
2365 layout |= 0xe001 << 16; /* FIXME */
2366 else
2367 layout |= layout << 16;
2368
2369 sprintfW(name, formatW, layout);
2370 TRACE("returning %s\n", debugstr_w(name));
2371 return TRUE;
2372}
2373
2374
2375/***********************************************************************
2376 * LoadKeyboardLayout (X11DRV.@)
2377 */
2378HKL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
2379{
2380 FIXME("%s, %04x: stub!\n", debugstr_w(name), flags);
2381 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2382 return 0;
2383}
2384
2385
2386/***********************************************************************
2387 * UnloadKeyboardLayout (X11DRV.@)
2388 */
2389BOOL X11DRV_UnloadKeyboardLayout(HKL hkl)
2390{
2391 FIXME("%p: stub!\n", hkl);
2392 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2393 return FALSE;
2394}
2395
2396
2397/***********************************************************************
2398 * ActivateKeyboardLayout (X11DRV.@)
2399 */
2400HKL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
2401{
2402 FIXME("%p, %04x: stub!\n", hkl, flags);
2403 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2404 return 0;
2405}
2406
2407
2408/***********************************************************************
2409 * X11DRV_MappingNotify
2410 */
2411void X11DRV_MappingNotify( HWND dummy, XEvent *event )
2412{
2413 HWND hwnd;
2414
2415 wine_tsx11_lock();
2416 XRefreshKeyboardMapping(&event->xmapping);
2417 wine_tsx11_unlock();
2418 X11DRV_InitKeyboard();
2419
2420 hwnd = GetFocus();
2421 if (!hwnd) hwnd = GetActiveWindow();
2422 PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
2423 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2424}
2425
2426
2427/***********************************************************************
2428 * VkKeyScanEx (X11DRV.@)
2429 *
2430 * Note: Windows ignores HKL parameter and uses current active layout instead
2431 */
2432SHORT X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2433{
2434 Display *display = thread_display();
2435 KeyCode keycode;
2436 KeySym keysym;
2437 int i, index;
2438 CHAR cChar;
2439 SHORT ret;
2440
2441 /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
2442 * is UTF-8 (multibyte encoding)?
2443 */
2444 if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
2445 {
2446 WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
2447 return -1;
2448 }
2449
2450 TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);
2451
2452 /* char->keysym (same for ANSI chars) */
2453 keysym = (unsigned char)cChar; /* (!) cChar is signed */
2454 if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */
2455
2456 wine_tsx11_lock();
2457 keycode = XKeysymToKeycode(display, keysym); /* keysym -> keycode */
2458 if (!keycode)
2459 {
2460 if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
2461 {
2462 ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
2463 TRACE(" ... returning ctrl char %#.2x\n", ret);
2464 wine_tsx11_unlock();
2465 return ret;
2466 }
2467 /* It didn't work ... let's try with deadchar code. */
2468 TRACE("retrying with | 0xFE00\n");
2469 keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2470 }
2471 wine_tsx11_unlock();
2472
2473 TRACE("'%c'(%#lx, %lu): got keycode %#.2x (%d)\n",
2474 cChar, keysym, keysym, keycode, keycode);
2475
2476 /* keycode -> (keyc2vkey) vkey */
2477 ret = keyc2vkey[keycode];
2478
2479 if (!keycode || !ret)
2480 {
2481 TRACE("keycode for '%c' not found, returning -1\n", cChar);
2482 return -1;
2483 }
2484
2485 index = -1;
2486 wine_tsx11_lock();
2487 for (i = 0; i < 4; i++) /* find shift state */
2488 {
2489 if (XKeycodeToKeysym(display, keycode, i) == keysym)
2490 {
2491 index = i;
2492 break;
2493 }
2494 }
2495 wine_tsx11_unlock();
2496
2497 switch (index)
2498 {
2499 default:
2500 case -1:
2501 WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
2502 return -1;
2503
2504 case 0: break;
2505 case 1: ret += 0x0100; break;
2506 case 2: ret += 0x0600; break;
2507 case 3: ret += 0x0700; break;
2508 }
2509 /*
2510 index : 0 adds 0x0000
2511 index : 1 adds 0x0100 (shift)
2512 index : ? adds 0x0200 (ctrl)
2513 index : 2 adds 0x0600 (ctrl+alt)
2514 index : 3 adds 0x0700 (ctrl+alt+shift)
2515 */
2516
2517 TRACE(" ... returning %#.2x\n", ret);
2518 return ret;
2519}
2520
2521/***********************************************************************
2522 * MapVirtualKeyEx (X11DRV.@)
2523 */
2524UINT X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2525{
2526 Display *display = thread_display();
2527
2528#define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
2529
2530 TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2531 if (hkl != X11DRV_GetKeyboardLayout(0))
2532 FIXME("keyboard layout %p is not supported\n", hkl);
2533
2534 switch(wMapType) {
2535 case 0: { /* vkey-code to scan-code */
2536 /* let's do vkey -> keycode -> scan */
2537 int keyc;
2538 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
2539 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2540 returnMVK (keyc2scan[keyc] & 0xFF);
2541 TRACE("returning no scan-code.\n");
2542 return 0; }
2543
2544 case 1: { /* scan-code to vkey-code */
2545 /* let's do scan -> keycode -> vkey */
2546 int keyc;
2547 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
2548 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
2549 returnMVK (keyc2vkey[keyc] & 0xFF);
2550 TRACE("returning no vkey-code.\n");
2551 return 0; }
2552
2553 case 2: { /* vkey-code to unshifted ANSI code */
2554 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
2555 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
2556 * key.. Looks like something is wrong with the MS docs?
2557 * This is only true for letters, for example VK_0 returns '0' not ')'.
2558 * - hence we use the lock mask to ensure this happens.
2559 */
2560 /* let's do vkey -> keycode -> (XLookupString) ansi char */
2561 XKeyEvent e;
2562 KeySym keysym;
2563 int keyc;
2564 char s[2];
2565 e.display = display;
2566
2567 e.state = LockMask;
2568 /* LockMask should behave exactly like caps lock - upercase
2569 * the letter keys and thats about it. */
2570
2571 wine_tsx11_lock();
2572
2573 e.keycode = 0;
2574 /* We exit on the first keycode found, to speed up the thing. */
2575 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2576 { /* Find a keycode that could have generated this virtual key */
2577 if ((keyc2vkey[keyc] & 0xFF) == wCode)
2578 { /* We filter the extended bit, we don't know it */
2579 e.keycode = keyc; /* Store it temporarily */
2580 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
2581 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2582 state), so set it to 0, we'll find another one */
2583 }
2584 }
2585 }
2586
2587 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
2588 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
2589
2590 if (wCode==VK_DECIMAL)
2591 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2592
2593 if (!e.keycode)
2594 {
2595 WARN("Unknown virtual key %X !!!\n", wCode);
2596 wine_tsx11_unlock();
2597 return 0; /* whatever */
2598 }
2599 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2600
2601 if (XLookupString(&e, s, 2, &keysym, NULL))
2602 {
2603 wine_tsx11_unlock();
2604 returnMVK (*s);
2605 }
2606
2607 TRACE("returning no ANSI.\n");
2608 wine_tsx11_unlock();
2609 return 0;
2610 }
2611
2612 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
2613 /* left and right */
2614 FIXME(" stub for NT\n");
2615 return 0;
2616
2617 default: /* reserved */
2618 WARN("Unknown wMapType %d !\n", wMapType);
2619 return 0;
2620 }
2621 return 0;
2622}
2623
2624/***********************************************************************
2625 * GetKeyNameText (X11DRV.@)
2626 */
2627INT X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2628{
2629 int vkey, ansi, scanCode;
2630 KeyCode keyc;
2631 int keyi;
2632 KeySym keys;
2633 char *name;
2634
2635 scanCode = lParam >> 16;
2636 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
2637
2638 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
2639 vkey = X11DRV_MapVirtualKeyEx(scanCode, 1, X11DRV_GetKeyboardLayout(0));
2640
2641 /* handle "don't care" bit (0x02000000) */
2642 if (!(lParam & 0x02000000)) {
2643 switch (vkey) {
2644 case VK_LSHIFT:
2645 case VK_RSHIFT:
2646 vkey = VK_SHIFT;
2647 break;
2648 case VK_LCONTROL:
2649 case VK_RCONTROL:
2650 vkey = VK_CONTROL;
2651 break;
2652 case VK_LMENU:
2653 case VK_RMENU:
2654 vkey = VK_MENU;
2655 break;
2656 default:
2657 break;
2658 }
2659 }
2660
2661 ansi = X11DRV_MapVirtualKeyEx(vkey, 2, X11DRV_GetKeyboardLayout(0));
2662 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
2663
2664 /* first get the name of the "regular" keys which is the Upper case
2665 value of the keycap imprint. */
2666 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
2667 (scanCode != 0x137) && /* PrtScn */
2668 (scanCode != 0x135) && /* numpad / */
2669 (scanCode != 0x37 ) && /* numpad * */
2670 (scanCode != 0x4a ) && /* numpad - */
2671 (scanCode != 0x4e ) ) /* numpad + */
2672 {
2673 if ((nSize >= 2) && lpBuffer)
2674 {
2675 *lpBuffer = toupperW((WCHAR)ansi);
2676 *(lpBuffer+1) = 0;
2677 return 1;
2678 }
2679 else
2680 return 0;
2681 }
2682
2683 /* FIXME: horrible hack to fix function keys. Windows reports scancode
2684 without "extended-key" flag. However Wine generates scancode
2685 *with* "extended-key" flag. Seems to occur *only* for the
2686 function keys. Soooo.. We will leave the table alone and
2687 fudge the lookup here till the other part is found and fixed!!! */
2688
2689 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
2690 (scanCode == 0x157) || (scanCode == 0x158))
2691 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
2692
2693 /* let's do scancode -> keycode -> keysym -> String */
2694
2695 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
2696 if ((keyc2scan[keyi]) == scanCode)
2697 break;
2698 if (keyi <= max_keycode)
2699 {
2700 wine_tsx11_lock();
2701 keyc = (KeyCode) keyi;
2702 keys = XKeycodeToKeysym(thread_display(), keyc, 0);
2703 name = XKeysymToString(keys);
2704 wine_tsx11_unlock();
2705 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
2706 scanCode, keyc, (int)keys, name);
2707 if (lpBuffer && nSize && name)
2708 {
2709 MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
2710 lpBuffer[nSize - 1] = 0;
2711 return 1;
2712 }
2713 }
2714
2715 /* Finally issue WARN for unknown keys */
2716
2717 WARN("(%08x,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2718 if (lpBuffer && nSize)
2719 *lpBuffer = 0;
2720 return 0;
2721}
2722#endif /* OUTOFWINE not defined */
2723
2724/***********************************************************************
2725 * X11DRV_KEYBOARD_MapDeadKeysym
2726 */
2727static char KEYBOARD_MapDeadKeysym(KeySym keysym)
2728{
2729 switch (keysym)
2730 {
2731 /* symbolic ASCII is the same as defined in rfc1345 */
2732#ifdef XK_dead_tilde
2733 case XK_dead_tilde :
2734#endif
2735 case 0x1000FE7E : /* Xfree's XK_Dtilde */
2736 return '~'; /* '? */
2737#ifdef XK_dead_acute
2738 case XK_dead_acute :
2739#endif
2740 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
2741 return (char)0xb4; /* '' */
2742#ifdef XK_dead_circumflex
2743 case XK_dead_circumflex:
2744#endif
2745 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
2746 return '^'; /* '> */
2747#ifdef XK_dead_grave
2748 case XK_dead_grave :
2749#endif
2750 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
2751 return '`'; /* '! */
2752#ifdef XK_dead_diaeresis
2753 case XK_dead_diaeresis :
2754#endif
2755 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
2756 return (char)0xa8; /* ': */
2757#ifdef XK_dead_cedilla
2758 case XK_dead_cedilla :
2759 return (char)0xb8; /* ', */
2760#endif
2761#ifdef XK_dead_macron
2762 case XK_dead_macron :
2763 return '-'; /* 'm isn't defined on iso-8859-x */
2764#endif
2765#ifdef XK_dead_breve
2766 case XK_dead_breve :
2767 return (char)0xa2; /* '( */
2768#endif
2769#ifdef XK_dead_abovedot
2770 case XK_dead_abovedot :
2771 return (char)0xff; /* '. */
2772#endif
2773#ifdef XK_dead_abovering
2774 case XK_dead_abovering :
2775 return '0'; /* '0 isn't defined on iso-8859-x */
2776#endif
2777#ifdef XK_dead_doubleacute
2778 case XK_dead_doubleacute :
2779 return (char)0xbd; /* '" */
2780#endif
2781#ifdef XK_dead_caron
2782 case XK_dead_caron :
2783 return (char)0xb7; /* '< */
2784#endif
2785#ifdef XK_dead_ogonek
2786 case XK_dead_ogonek :
2787 return (char)0xb2; /* '; */
2788#endif
2789/* FIXME: I don't know this three.
2790 case XK_dead_iota :
2791 return 'i';
2792 case XK_dead_voiced_sound :
2793 return 'v';
2794 case XK_dead_semivoiced_sound :
2795 return 's';
2796*/
2797 }
2798 TRACE("no character for dead keysym 0x%08lx\n",keysym);
2799 return 0;
2800}
2801
2802#ifndef OUTOFWINE
2803/***********************************************************************
2804 * ToUnicodeEx (X11DRV.@)
2805 *
2806 * The ToUnicode function translates the specified virtual-key code and keyboard
2807 * state to the corresponding Windows character or characters.
2808 *
2809 * If the specified key is a dead key, the return value is negative. Otherwise,
2810 * it is one of the following values:
2811 * Value Meaning
2812 * 0 The specified virtual key has no translation for the current state of the keyboard.
2813 * 1 One Windows character was copied to the buffer.
2814 * 2 Two characters were copied to the buffer. This usually happens when a
2815 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
2816 * be composed with the specified virtual key to form a single character.
2817 *
2818 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
2819 *
2820 */
2821INT X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
2822 LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2823{
2824 Display *display = thread_display();
2825 XKeyEvent e;
2826 KeySym keysym = 0;
2827 INT ret;
2828 int keyc;
2829 char lpChar[10];
2830 HWND focus;
2831 XIC xic;
2832 Status status;
2833
2834 if (scanCode & 0x8000)
2835 {
2836 TRACE("Key UP, doing nothing\n" );
2837 return 0;
2838 }
2839
2840 if (hkl != X11DRV_GetKeyboardLayout(0))
2841 FIXME("keyboard layout %p is not supported\n", hkl);
2842
2843 if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
2844 {
2845 TRACE("Ctrl+Alt+[key] won't generate a character\n");
2846 return 0;
2847 }
2848
2849 e.display = display;
2850 e.keycode = 0;
2851 e.state = 0;
2852 e.type = KeyPress;
2853
2854 focus = GetFocus();
2855 if (focus) focus = GetAncestor( focus, GA_ROOT );
2856 if (!focus) focus = GetActiveWindow();
2857 e.window = X11DRV_get_whole_window( focus );
2858 xic = X11DRV_get_ic( focus );
2859
2860 if (lpKeyState[VK_SHIFT] & 0x80)
2861 {
2862 TRACE("ShiftMask = %04x\n", ShiftMask);
2863 e.state |= ShiftMask;
2864 }
2865 if (lpKeyState[VK_CAPITAL] & 0x01)
2866 {
2867 TRACE("LockMask = %04x\n", LockMask);
2868 e.state |= LockMask;
2869 }
2870 if (lpKeyState[VK_CONTROL] & 0x80)
2871 {
2872 TRACE("ControlMask = %04x\n", ControlMask);
2873 e.state |= ControlMask;
2874 }
2875 if (lpKeyState[VK_NUMLOCK] & 0x01)
2876 {
2877 TRACE("NumLockMask = %04x\n", NumLockMask);
2878 e.state |= NumLockMask;
2879 }
2880
2881 /* Restore saved AltGr state */
2882 TRACE("AltGrMask = %04x\n", AltGrMask);
2883 e.state |= AltGrMask;
2884
2885 TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2886 virtKey, scanCode, e.state);
2887 wine_tsx11_lock();
2888 /* We exit on the first keycode found, to speed up the thing. */
2889 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
2890 { /* Find a keycode that could have generated this virtual key */
2891 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
2892 { /* We filter the extended bit, we don't know it */
2893 e.keycode = keyc; /* Store it temporarily */
2894 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2895 e.keycode = 0; /* Wrong one (ex: because of the NumLock
2896 state), so set it to 0, we'll find another one */
2897 }
2898 }
2899 }
2900
2901 if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
2902 e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);
2903
2904 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2905 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2906
2907 if (virtKey==VK_DECIMAL)
2908 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
2909
2910 if (virtKey==VK_SEPARATOR)
2911 e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2912
2913 if (!e.keycode && virtKey != VK_NONAME)
2914 {
2915 WARN("Unknown virtual key %X !!!\n", virtKey);
2916 wine_tsx11_unlock();
2917 return 0;
2918 }
2919 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
2920
2921 TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
2922 e.type, e.window, e.state, e.keycode);
2923
2924 /* Clients should pass only KeyPress events to XmbLookupString,
2925 * e.type was set to KeyPress above.
2926 */
2927 if (xic)
2928 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, &status);
2929 else
2930 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
2931 wine_tsx11_unlock();
2932
2933 if (ret == 0)
2934 {
2935 char dead_char;
2936
2937#ifdef XK_EuroSign
2938 /* An ugly hack for EuroSign: X can't translate it to a character
2939 for some locales. */
2940 if (keysym == XK_EuroSign)
2941 {
2942 bufW[0] = 0x20AC;
2943 ret = 1;
2944 goto found;
2945 }
2946#endif
2947 /* Special case: X turns shift-tab into ISO_Left_Tab. */
2948 /* Here we change it back. */
2949 if (keysym == XK_ISO_Left_Tab)
2950 {
2951 bufW[0] = 0x09;
2952 ret = 1;
2953 goto found;
2954 }
2955
2956 dead_char = KEYBOARD_MapDeadKeysym(keysym);
2957 if (dead_char)
2958 {
2959 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2960 ret = -1;
2961 goto found;
2962 }
2963
2964 if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
2965 {
2966 /* Unicode direct mapping */
2967 bufW[0] = keysym & 0xffff;
2968 ret = 1;
2969 goto found;
2970 }
2971 else if ((keysym >> 8) == 0x1008FF) {
2972 bufW[0] = 0;
2973 ret = 0;
2974 goto found;
2975 }
2976 else
2977 {
2978 const char *ksname;
2979
2980 wine_tsx11_lock();
2981 ksname = XKeysymToString(keysym);
2982 wine_tsx11_unlock();
2983 if (!ksname)
2984 ksname = "No Name";
2985 if ((keysym >> 8) != 0xff)
2986 {
2987 WARN("no char for keysym %04lX (%s) :\n",
2988 keysym, ksname);
2989 WARN("virtKey=%X, scanCode=%X, keycode=%X, state=%X\n",
2990 virtKey, scanCode, e.keycode, e.state);
2991 }
2992 }
2993 }
2994 else { /* ret != 0 */
2995 /* We have a special case to handle : Shift + arrow, shift + home, ...
2996 X returns a char for it, but Windows doesn't. Let's eat it. */
2997 if (!(e.state & NumLockMask) /* NumLock is off */
2998 && (e.state & ShiftMask) /* Shift is pressed */
2999 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
3000 {
3001 lpChar[0] = 0;
3002 ret = 0;
3003 }
3004
3005 /* more areas where X returns characters but Windows does not
3006 CTRL + number or CTRL + symbol */
3007 if (e.state & ControlMask)
3008 {
3009 if (((keysym>=33) && (keysym < 'A')) ||
3010 ((keysym > 'Z') && (keysym < 'a')))
3011 {
3012 lpChar[0] = 0;
3013 ret = 0;
3014 }
3015 }
3016
3017 /* We have another special case for delete key (XK_Delete) on an
3018 extended keyboard. X returns a char for it, but Windows doesn't */
3019 if (keysym == XK_Delete)
3020 {
3021 lpChar[0] = 0;
3022 ret = 0;
3023 }
3024 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
3025 && (keysym == XK_KP_Decimal))
3026 {
3027 lpChar[0] = 0;
3028 ret = 0;
3029 }
3030
3031 /* Hack to detect an XLookupString hard-coded to Latin1 */
3032 if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
3033 {
3034 bufW[0] = (BYTE)lpChar[0];
3035 goto found;
3036 }
3037
3038 /* perform translation to unicode */
3039 if(ret)
3040 {
3041 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
3042 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
3043 }
3044 }
3045
3046found:
3047 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
3048 ret, (ret && bufW) ? bufW[0] : 0, bufW ? "" : "(no buffer)");
3049 return ret;
3050}
3051
3052/***********************************************************************
3053 * Beep (X11DRV.@)
3054 */
3055void X11DRV_Beep(void)
3056{
3057 wine_tsx11_lock();
3058 XBell(thread_display(), 0);
3059 wine_tsx11_unlock();
3060}
3061#else /* OUTOFWINE defined */
3062int X11DRV_GetKeysymsPerKeycode()
3063{
3064 return keysyms_per_keycode;
3065}
3066#endif /* OUTOFWINE defined */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use