blob: f2cd64124338489f1d41dc4c3babfbc82c332de0 [file] [log] [blame]
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001/*
Ove Kaaven7173e1c1999-03-14 14:00:57 +00002 * X11 keyboard driver
Patrik Stridvalle35d6361998-12-07 09:13:40 +00003 *
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
Ove Kaaven7173e1c1999-03-14 14:00:57 +00009 * Copyright 1999 Ove Kåven
Patrik Stridvalle35d6361998-12-07 09:13:40 +000010 */
11
12#include "config.h"
13
Patrik Stridvalle35d6361998-12-07 09:13:40 +000014#include <X11/Xatom.h>
15#include <X11/keysym.h>
Patrik Stridvall3d511612000-04-25 19:55:35 +000016
Patrik Stridvalle35d6361998-12-07 09:13:40 +000017#include "ts_xlib.h"
18#include "ts_xresource.h"
19#include "ts_xutil.h"
20
Patrik Stridvall3d511612000-04-25 19:55:35 +000021#include <ctype.h>
22#include <string.h>
23
Jeremy Whited3e22d92000-02-10 19:03:02 +000024#include "windef.h"
25#include "wingdi.h"
Veksler Michaele94e3541999-03-22 12:41:26 +000026#include "wine/winuser16.h"
Patrik Stridvalld96e1f11999-07-04 13:31:03 +000027#include "dinput.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000028#include "debugtools.h"
Alexandre Julliard28c3a1b2000-03-20 18:21:19 +000029#include "user.h"
Patrik Stridvallab121e71999-02-04 11:11:01 +000030#include "keyboard.h"
Patrik Stridvalle35d6361998-12-07 09:13:40 +000031#include "message.h"
Ove Kaaven7173e1c1999-03-14 14:00:57 +000032#include "winnls.h"
Patrik Stridvall6cc47d42000-03-08 18:26:56 +000033#include "win.h"
Patrik Stridvalld96e1f11999-07-04 13:31:03 +000034#include "x11drv.h"
Patrik Stridvalle35d6361998-12-07 09:13:40 +000035
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +000036DEFAULT_DEBUG_CHANNEL(keyboard)
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000037DECLARE_DEBUG_CHANNEL(key)
Lionel Ulmerc9713e51999-12-05 02:20:46 +000038DECLARE_DEBUG_CHANNEL(dinput)
Patrik Stridvalld96e1f11999-07-04 13:31:03 +000039
40extern BYTE InputKeyStateTable[256];
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000041
Patrik Stridvalle35d6361998-12-07 09:13:40 +000042extern LPBYTE pKeyStateTable;
43
44int min_keycode, max_keycode, keysyms_per_keycode;
Ove Kaaven7173e1c1999-03-14 14:00:57 +000045WORD keyc2vkey[256], keyc2scan[256];
Patrik Stridvalle35d6361998-12-07 09:13:40 +000046
47static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
48static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
49
Marcus Meissner2199f6e1999-04-01 12:05:44 +000050static char KEYBOARD_MapDeadKeysym(KeySym keysym);
51
Patrik Stridvalle35d6361998-12-07 09:13:40 +000052/* Keyboard translation tables */
Ove Kaaven7173e1c1999-03-14 14:00:57 +000053#define MAIN_LEN 48
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +000054static const WORD main_key_scan_qwerty[MAIN_LEN] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +000055{
56/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
57 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
58 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
59 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
60 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
Ove Kaaven44b71781999-03-15 15:24:32 +000061 0x56 /* the 102nd key (actually to the right of l-shift) */
Ove Kaaven7173e1c1999-03-14 14:00:57 +000062};
63
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +000064static const WORD main_key_vkey_qwerty[MAIN_LEN] =
65{
Dmitry Timoshkovff81f932000-10-19 22:25:35 +000066/* NOTE: this layout must concur with the scan codes layout above */
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +000067 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
68 VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
69 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_7,VK_OEM_5,
70 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
71 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
72};
73
Dmitry Timoshkovff81f932000-10-19 22:25:35 +000074static const WORD main_key_vkey_azerty[MAIN_LEN] =
75{
76/* NOTE: this layout must concur with the scan codes layout above */
77 VK_OEM_7,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_PLUS,
78 VK_A,VK_Z,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_6,VK_OEM_1,
79 VK_Q,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_M,VK_OEM_3,VK_OEM_5,
80 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
81 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
82};
83
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +000084/* FIXME: add other layouts, such as DVORAK and German QWERTZ */
85
Ove Kaaven7173e1c1999-03-14 14:00:57 +000086/*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
87
Ove Kaaven44b71781999-03-15 15:24:32 +000088/* the VK mappings for the main keyboard will be auto-assigned as before,
89 so what we have here is just the character tables */
Ove Kaaven7173e1c1999-03-14 14:00:57 +000090/* order: Normal, Shift, AltGr, Shift-AltGr */
Ove Kaaven44b71781999-03-15 15:24:32 +000091/* We recommend you write just what is guaranteed to be correct (i.e. what's
92 written on the keycaps), not the bunch of special characters behind AltGr
93 and Shift-AltGr if it can vary among different X servers */
94/* Remember that your 102nd key (to the right of l-shift) should be on a
95 separate line, see existing tables */
96/* If Wine fails to match your new table, use -debugmsg +key to find out why */
97/* Remember to also add your new table to the layout index table far below! */
Ove Kaaven7173e1c1999-03-14 14:00:57 +000098
Ove Kaaven44b71781999-03-15 15:24:32 +000099/*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000100static const char main_key_US[MAIN_LEN][4] =
101{
Ove Kaaven44b71781999-03-15 15:24:32 +0000102 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
103 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
104 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
105 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000106};
107
Ove Kaavenfc091b22000-01-04 00:28:31 +0000108/*** United States keyboard layout (phantom key version) */
109/* (XFree86 reports the <> key even if it's not physically there) */
110static const char main_key_US_phantom[MAIN_LEN][4] =
111{
112 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
113 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
114 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
Mike McCormack88c5bc62000-09-04 20:19:27 +0000115 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
Ove Kaavenfc091b22000-01-04 00:28:31 +0000116 "<>" /* the phantom key */
117};
118
Huw D M Davies12eb5fd1999-03-17 15:29:35 +0000119/*** British keyboard layout */
120static const char main_key_UK[MAIN_LEN][4] =
121{
122 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
123 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
124 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
125 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
126 "\\|"
127};
128
Ove Kaaven44b71781999-03-15 15:24:32 +0000129/*** French keyboard layout (contributed by Eric Pouech) */
130static const char main_key_FR[MAIN_LEN][4] =
131{
132 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
Eric Pouech24f5ffc1999-04-03 13:50:58 +0000133 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
Ove Kaaven44b71781999-03-15 15:24:32 +0000134 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
135 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
136 "<>"
137};
138
Rikhardur Egilsson365c54e1999-05-29 11:04:09 +0000139/*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
140static const char main_key_IS[MAIN_LEN][4] =
141{
142 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
143 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
144 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
145 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
146 "<>|"
147};
148
Ove Kaaven44b71781999-03-15 15:24:32 +0000149/*** German keyboard layout (contributed by Ulrich Weigand) */
150static const char main_key_DE[MAIN_LEN][4] =
151{
152 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
153 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
154 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
155 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
156 "<>"
157};
158
Marcus Meissnere14deff1999-10-13 12:18:03 +0000159/*** German keyboard layout without dead keys */
160static const char main_key_DE_nodead[MAIN_LEN][4] =
161{
162 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
163 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
164 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
165 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
166 "<>"
167};
168
Jonathan Naylora5a02271999-03-28 12:36:27 +0000169/*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
170static const char main_key_SG[MAIN_LEN][4] =
171{
172 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
173 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
174 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
175 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
176 "<>\\"
177};
178
Philippe Froidevauxc778d9b1999-06-22 19:01:14 +0000179/*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
180static const char main_key_SF[MAIN_LEN][4] =
181{
182 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
183 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
184 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
185 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
186 "<>\\"
187};
188
Ove Kaaven44b71781999-03-15 15:24:32 +0000189/*** Norwegian keyboard layout (contributed by Ove Kåven) */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000190static const char main_key_NO[MAIN_LEN][4] =
191{
192 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
193 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
194 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
195 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
196 "<>"
197};
198
Ove Kaaven44b71781999-03-15 15:24:32 +0000199/*** Danish keyboard layout (contributed by Bertho Stultiens) */
200static const char main_key_DA[MAIN_LEN][4] =
201{
Bertho Stultiensff2b3691999-03-19 16:42:52 +0000202 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
Ove Kaaven44b71781999-03-15 15:24:32 +0000203 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
204 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
205 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
206 "<>\\"
207};
208
Peter Bortas1e24a081999-04-25 10:53:22 +0000209/*** Swedish keyboard layout (contributed by Peter Bortas) */
210static const char main_key_SE[MAIN_LEN][4] =
211{
212 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
213 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
214 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
215 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
216 "<>|"
217};
218
Robert Pouliot5574c991999-03-17 15:39:36 +0000219/*** Canadian French keyboard layout */
220static const char main_key_CF[MAIN_LEN][4] =
221{
Ivan De Saedeleer0e65a491999-08-04 14:28:03 +0000222 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
223 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
Robert Pouliot5574c991999-03-17 15:39:36 +0000224 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
Ivan De Saedeleer0e65a491999-08-04 14:28:03 +0000225 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
Robert Pouliot4f278bd1999-03-21 15:46:34 +0000226 "«»°"
Robert Pouliot5574c991999-03-17 15:39:36 +0000227};
228
Bruno Afonsoe70b1831999-03-17 15:54:44 +0000229/*** Portuguese keyboard layout */
230static const char main_key_PT[MAIN_LEN][4] =
231{
232 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
233 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
234 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
235 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
236 "<>"
237};
238
75793af1999-05-13 18:49:47 +0000239/*** Italian keyboard layout */
240static const char main_key_IT[MAIN_LEN][4] =
241{
Giovanni Pancottif708f542000-09-07 21:04:06 +0000242 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
243 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
244 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
245 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
246 "<>|"
75793af1999-05-13 18:49:47 +0000247};
248
Kalevi J Hautaniemicc5d9241999-03-22 14:46:08 +0000249/*** Finnish keyboard layout */
250static const char main_key_FI[MAIN_LEN][4] =
251{
252 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
253 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
254 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
255 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
256 "<>|"
257};
258
Pavel Roskindbfdca81999-03-28 13:44:56 +0000259/*** Russian keyboard layout (contributed by Pavel Roskin) */
260static const char main_key_RU[MAIN_LEN][4] =
261{
262 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
263 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
264 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
265 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
266};
267
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000268/*** Russian keyboard layout KOI8-R */
269static const char main_key_RU_koi8r[MAIN_LEN][4] =
270{
271 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
272 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
273 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
274 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
275 "<>" /* the phantom key */
276};
277
José Marcos López05eb8b51999-04-04 12:44:42 +0000278/*** Spanish keyboard layout (contributed by José Marcos López) */
279static const char main_key_ES[MAIN_LEN][4] =
280{
281 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
282 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
283 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
284 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
285 "<>"
286};
287
Pablo Saratxaga002106a1999-04-16 09:06:58 +0000288/*** Belgian keyboard layout ***/
289static const char main_key_BE[MAIN_LEN][4] =
290{
291 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
292 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
293 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
294 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
295 "<>\\"
296};
297
Zoltan Kovacs3d4cabf1999-10-13 13:54:39 +0000298/*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
299static const char main_key_HU[MAIN_LEN][4] =
300{
301 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
302 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
303 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
304 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
305 "íÍ<"
306};
307
Jaroslaw Piotr Sobieszek384a10d1999-11-04 02:02:05 +0000308/*** Polish (programmer's) keyboard layout ***/
309static const char main_key_PL[MAIN_LEN][4] =
310{
311 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
312 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
313 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
314 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
315 "<>|"
316};
317
Zoran Dzelajlija846880b2000-05-30 20:50:45 +0000318/*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
319static const char main_key_HR_jelly[MAIN_LEN][4] =
320{
321 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
322 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
323 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
324 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
325 "<>|"
326};
327
328/*** Croatian keyboard layout ***/
329static const char main_key_HR[MAIN_LEN][4] =
330{
331 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
332 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
333 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
334 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
335 "<>"
336};
337
Hidenori Takeshima8097a262000-02-20 13:43:29 +0000338/*** Japanese 106 keyboard layout ***/
339static const char main_key_JA_jp106[MAIN_LEN][4] =
340{
341 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
342 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
343 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
344 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
345 "\\_",
346};
347
348/*** Japanese pc98x1 keyboard layout ***/
349static const char main_key_JA_pc98x1[MAIN_LEN][4] =
350{
351 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
352 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
353 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
354 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
355 "\\_",
356};
357
Raul Fernandes9ed48c62000-07-16 15:40:29 +0000358/*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
359static const char main_key_PT_br[MAIN_LEN][4] =
360{
361 "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
362 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
363 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
364 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
365};
Hidenori Takeshima8097a262000-02-20 13:43:29 +0000366
Peter Ivanyi1da3bef2000-10-31 01:19:11 +0000367/*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
368 - dead_abovering replaced with degree - no symbol in iso8859-2
369 - brokenbar replaced with bar */
370static const char main_key_SK[MAIN_LEN][4] =
371{
372 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0)","=%","",
373 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/÷","ä(×",
374 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ô\"$","§!ß","ò)¤",
375 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
376 "<>\\|"
377};
378
379/*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
380static const char main_key_SK_prog[MAIN_LEN][4] =
381{
382 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
383 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
384 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
385 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
386 "<>"
387};
388
389/*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
390static const char main_key_CS[MAIN_LEN][4] =
391{
392 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
393 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
394 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
395 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
396 "<>\\|"
397};
398
Gabriel Garciaa9774be2000-11-01 01:47:39 +0000399/*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
400static const char main_key_LA[MAIN_LEN][4] =
401{
402 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
403 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
404 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
405 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
406 "<>"
407};
Hidenori Takeshima8097a262000-02-20 13:43:29 +0000408
Nerijus Baliunasc4b8b262000-11-11 00:34:32 +0000409/*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
410static const char main_key_LT_B[MAIN_LEN][4] =
411{
412 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
413 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
414 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
415 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
416};
417
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000418/*** Layout table. Add your keyboard mappings to this list */
Raul Fernandes9ed48c62000-07-16 15:40:29 +0000419static const struct {
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000420 const char *comment;
421 const UINT layout_cp; /* Code page for this layout */
422 const char (*key)[MAIN_LEN][4];
423 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
424 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000425} main_key_tab[]={
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000426 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
427 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
428 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
429 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
430 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
431 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
432 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
433 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
434 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Dmitry Timoshkovff81f932000-10-19 22:25:35 +0000435 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000436 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Dmitry Timoshkovff81f932000-10-19 22:25:35 +0000437 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000438 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
439 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
440 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
441 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
442 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
443 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
444 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
445 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
446 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
447 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
448 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
449 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
450 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
451 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
452 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Peter Ivanyi1da3bef2000-10-31 01:19:11 +0000453 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
454 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
455 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Gabriel Garciaa9774be2000-11-01 01:47:39 +0000456 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Nerijus Baliunasc4b8b262000-11-11 00:34:32 +0000457 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000458
Joerg Mayer959d73e2000-10-22 23:56:32 +0000459 {NULL, 0, NULL, NULL, NULL} /* sentinel */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000460};
461static unsigned kbd_layout=0; /* index into above table of layouts */
462
463/* maybe more of these scancodes should be extended? */
464 /* extended must be set for ALT_R, CTRL_R,
465 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
466 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
467 /* FIXME should we set extended bit for NumLock ? My
468 * Windows does ... DF */
Guy Albertelli5bd55171999-09-03 12:39:29 +0000469 /* Yes, to distinguish based on scan codes, also
470 for PrtScn key ... GA */
471
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000472static const WORD special_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000473{
474 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
475 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
476 0, 0, 0, VK_ESCAPE /* FF18 */
477};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000478static const WORD special_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000479{
480 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
481 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
482 0, 0, 0, 0x01 /* FF18 */
483};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000484
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000485static const WORD cursor_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000486{
487 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
488 VK_NEXT, VK_END /* FF50 */
489};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000490static const WORD cursor_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000491{
492 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
493};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000494
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000495static const WORD misc_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000496{
497 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
Pierre Mageauf2d99ee1999-10-24 17:21:32 +0000498 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000499};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000500static const WORD misc_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000501{
Guy Albertelli5bd55171999-09-03 12:39:29 +0000502 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
Pierre Mageauf2d99ee1999-10-24 17:21:32 +0000503 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000504};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000505
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000506static const WORD keypad_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000507{
508 0, VK_NUMLOCK, /* FF7E */
509 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
510 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
511 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
512 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
513 VK_INSERT, VK_DELETE, /* FF98 */
514 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
515 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
516 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
517 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
518 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
519 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
520};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000521static const WORD keypad_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000522{
Guy Albertelli5bd55171999-09-03 12:39:29 +0000523 0x138, 0x145, /* FF7E */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000524 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
525 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
526 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
527 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
528 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
529 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
530 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
531 0x48, 0x49 /* FFB8 */
532};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000533
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000534static const WORD function_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000535{
536 VK_F1, VK_F2, /* FFBE */
537 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
538 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
539};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000540static const WORD function_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000541{
542 0x3B, 0x3C, /* FFBE */
543 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
544 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
545};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000546
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000547static const WORD modifier_key_vkey[] =
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000548{
549 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
550 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
551};
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000552static const WORD modifier_key_scan[] =
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000553{
554 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
555 0x38, 0x138, 0x38, 0x138 /* FFE7 */
556};
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000557
558/* Returns the Windows virtual key code associated with the X event <e> */
559static WORD EVENT_event_to_vkey( XKeyEvent *e)
560{
561 KeySym keysym;
562
563 TSXLookupString(e, NULL, 0, &keysym, NULL);
564
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000565 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
566 && (e->state & NumLockMask))
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000567 /* Only the Keypad keys 0-9 and . send different keysyms
568 * depending on the NumLock state */
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000569 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000570
571 return keyc2vkey[e->keycode];
572}
573
Stephane Lussier0debf422000-04-13 16:00:08 +0000574static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000575
576/**********************************************************************
577 * KEYBOARD_GenerateMsg
578 *
579 * Generate Down+Up messages when NumLock or CapsLock is pressed.
580 *
581 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
582 *
583 */
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000584static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000585 DWORD event_time )
586{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000587 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000588 DWORD up, down;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000589
590 if (*State) {
591 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
592 don't treat it. It's from the same key press. Then the state goes to ON.
593 And from there, a 'release' event will switch off the toggle key. */
594 *State=FALSE;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000595 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000596 } else
597 {
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000598 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
599 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000600 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
601 {
602 if (Evtype!=KeyPress)
603 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000604 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000605 KEYBOARD_SendEvent( vkey, scan, down,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000606 event_x, event_y, event_time );
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000607 KEYBOARD_SendEvent( vkey, scan, up,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000608 event_x, event_y, event_time );
609 *State=FALSE;
610 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
611 }
612 }
613 else /* it was OFF */
614 if (Evtype==KeyPress)
615 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000616 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000617 KEYBOARD_SendEvent( vkey, scan, down,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000618 event_x, event_y, event_time );
Guy Albertelli76d8abe1999-04-15 15:14:44 +0000619 KEYBOARD_SendEvent( vkey, scan, up,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000620 event_x, event_y, event_time );
621 *State=TRUE; /* Goes to intermediary state before going to ON */
622 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
623 }
624 }
625}
626
627/***********************************************************************
628 * KEYBOARD_UpdateOneState
629 *
630 * Updates internal state for <vkey>, depending on key <state> under X
631 *
632 */
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000633static void KEYBOARD_UpdateOneState ( int vkey, int state )
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000634{
635 /* Do something if internal table state != X state for keycode */
636 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
637 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000638 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000639 vkey, pKeyStateTable[vkey]);
640
641 /* Fake key being pressed inside wine */
642 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
643 0, 0, GetTickCount() );
644
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000645 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000646 }
647}
648
649/***********************************************************************
Patrik Stridvallab121e71999-02-04 11:11:01 +0000650 * X11DRV_KEYBOARD_UpdateState
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000651 *
652 * Update modifiers state (Ctrl, Alt, Shift)
653 * when window is activated (called by EVENT_FocusIn in event.c)
654 *
655 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
656 * from wine to another application and back.
657 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
658 * about them)
659 */
Patrik Stridvallab121e71999-02-04 11:11:01 +0000660void X11DRV_KEYBOARD_UpdateState ( void )
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000661{
662/* extract a bit from the char[32] bit suite */
663#define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
664
665 char keys_return[32];
666
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000667 TRACE("called\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000668 if (!TSXQueryKeymap(display, keys_return)) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000669 ERR("Error getting keymap !");
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000670 return;
671 }
672
673 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
674 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
675 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
676 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
677#undef KeyState
678}
679
680/***********************************************************************
Patrik Stridvallab121e71999-02-04 11:11:01 +0000681 * X11DRV_KEYBOARD_HandleEvent
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000682 *
683 * Handle a X key event
684 */
Patrik Stridvallab121e71999-02-04 11:11:01 +0000685void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000686{
687 char Str[24];
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000688 KeySym keysym;
689 WORD vkey = 0, bScan;
690 DWORD dwFlags;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000691 static BOOL force_extended = FALSE; /* hack for AltGr translation */
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000692 int ascii_chars;
693
Alexandre Julliarda3960291999-02-26 11:11:13 +0000694 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
695 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
Andreas Mohrc941eff2000-09-22 22:37:56 +0000696 DWORD event_time = event->time - X11DRV_server_startticks;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000697
698 /* this allows support for dead keys */
699 if ((event->keycode >> 8) == 0x10)
700 event->keycode=(event->keycode & 0xff);
701
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000702 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000703
Andreas Mohrc941eff2000-09-22 22:37:56 +0000704 TRACE_(key)("state = %X\n", event->state);
Stephane Lussier0debf422000-04-13 16:00:08 +0000705
Stephane Lussier3e731da2000-04-14 14:09:20 +0000706 /* If XKB extensions is used, the state mask for AltGr will used the group
707 index instead of the modifier mask. The group index is set in bits
708 13-14 of the state field in the XKeyEvent structure. So if AltGr is
709 pressed, look if the group index is diferent than 0. From XKB
710 extension documentation, the group index should for AltGr should
711 be 2 (event->state = 0x2000). It's probably better to not assume a
712 predefined group index and find it dynamically
Stephane Lussier0debf422000-04-13 16:00:08 +0000713
714 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
Stephane Lussier3e731da2000-04-14 14:09:20 +0000715 if ( AltGrState && (event->state & 0x6000) )
Stephane Lussier0debf422000-04-13 16:00:08 +0000716 AltGrMask = event->state & 0x6000;
717
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000718 if (keysym == XK_Mode_switch)
719 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000720 TRACE_(key)("Alt Gr key event received\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000721 event->keycode = kcControl; /* Simulate Control */
Patrik Stridvallab121e71999-02-04 11:11:01 +0000722 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000723
724 event->keycode = kcAlt; /* Simulate Alt */
725 force_extended = TRUE;
Patrik Stridvallab121e71999-02-04 11:11:01 +0000726 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000727 force_extended = FALSE;
Stephane Lussier0debf422000-04-13 16:00:08 +0000728
729 /* Here we save the pressed/released state of the AltGr key, to be able to
730 identify the group index associated with AltGr on the next key pressed *
731 see comment above. */
732 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
733
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000734 return;
735 }
736
737 Str[ascii_chars] = '\0';
738 if (TRACE_ON(key)){
739 char *ksname;
740
741 ksname = TSXKeysymToString(keysym);
742 if (!ksname)
743 ksname = "No Name";
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000744 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000745 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
746 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000747 }
748
749 vkey = EVENT_event_to_vkey(event);
750 if (force_extended) vkey |= 0x100;
751
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000752 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000753 event->keycode, vkey);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000754
755 if (vkey)
756 {
757 switch (vkey & 0xff)
758 {
759 case VK_NUMLOCK:
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000760 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000761 event_time );
762 break;
763 case VK_CAPITAL:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000764 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000765 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000766 event_time );
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000767 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000768 break;
769 default:
770 /* Adjust the NUMLOCK state if it has been changed outside wine */
771 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
772 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000773 TRACE("Adjusting NumLock state. \n");
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000774 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000775 event_time );
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000776 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000777 event_time );
778 }
779 /* Adjust the CAPSLOCK state if it has been changed outside wine */
780 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
781 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000782 TRACE("Adjusting Caps Lock state.\n");
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000783 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000784 event_time );
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000785 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000786 event_time );
787 }
788 /* Not Num nor Caps : end of intermediary states for both. */
789 NumState = FALSE;
790 CapsState = FALSE;
791
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000792 bScan = keyc2scan[event->keycode] & 0xFF;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000793 TRACE_(key)("bScan = 0x%02x.\n", bScan);
Brian Gerst97847011998-12-07 15:44:54 +0000794
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000795 dwFlags = 0;
796 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
797 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
798 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
799
800 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
801 event_x, event_y, event_time );
802 }
803 }
804}
805
806/**********************************************************************
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000807 * X11DRV_KEYBOARD_DetectLayout
808 *
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000809 * Called from X11DRV_InitKeyboard
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000810 * This routine walks through the defined keyboard layouts and selects
811 * whichever matches most closely.
812 */
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000813static void
Pavel Roskinf15d1801999-03-28 13:39:55 +0000814X11DRV_KEYBOARD_DetectLayout (void)
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000815{
Ove Kaaven787cf101999-04-03 11:18:58 +0000816 unsigned current, match, mismatch, seq;
817 int score, keyc, i, key, pkey, ok, syms;
Pavel Roskinf15d1801999-03-28 13:39:55 +0000818 KeySym keysym;
819 const char (*lkey)[MAIN_LEN][4];
Ove Kaaven787cf101999-04-03 11:18:58 +0000820 unsigned max_seq = 0;
Pavel Roskinf15d1801999-03-28 13:39:55 +0000821 int max_score = 0, ismatch = 0;
822 char ckey[4] =
823 {0, 0, 0, 0};
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000824
Pavel Roskinf15d1801999-03-28 13:39:55 +0000825 syms = keysyms_per_keycode;
826 if (syms > 4) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000827 WARN("%d keysyms per keycode not supported, set to 4", syms);
Pavel Roskinf15d1801999-03-28 13:39:55 +0000828 syms = 4;
829 }
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000830 for (current = 0; main_key_tab[current].comment; current++) {
831 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
Pavel Roskinf15d1801999-03-28 13:39:55 +0000832 match = 0;
833 mismatch = 0;
834 score = 0;
Ove Kaaven787cf101999-04-03 11:18:58 +0000835 seq = 0;
Pavel Roskinf15d1801999-03-28 13:39:55 +0000836 lkey = main_key_tab[current].key;
Ove Kaaven787cf101999-04-03 11:18:58 +0000837 pkey = -1;
Pavel Roskinf15d1801999-03-28 13:39:55 +0000838 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
839 /* get data for keycode from X server */
840 for (i = 0; i < syms; i++) {
841 keysym = TSXKeycodeToKeysym (display, keyc, i);
842 /* Allow both one-byte and two-byte national keysyms */
843 if ((keysym < 0x800) && (keysym != ' '))
844 ckey[i] = keysym & 0xFF;
Marcus Meissner2199f6e1999-04-01 12:05:44 +0000845 else {
846 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
847 }
Pavel Roskinf15d1801999-03-28 13:39:55 +0000848 }
849 if (ckey[0]) {
850 /* search for a match in layout table */
851 /* right now, we just find an absolute match for defined positions */
852 /* (undefined positions are ignored, so if it's defined as "3#" in */
853 /* the table, it's okay that the X server has "3#£", for example) */
854 /* however, the score will be higher for longer matches */
855 for (key = 0; key < MAIN_LEN; key++) {
856 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
857 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
858 ok++;
859 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
860 ok = -1;
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000861 }
Pavel Roskinf15d1801999-03-28 13:39:55 +0000862 if (ok > 0) {
863 score += ok;
864 break;
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000865 }
866 }
Pavel Roskinf15d1801999-03-28 13:39:55 +0000867 /* count the matches and mismatches */
Ove Kaaven787cf101999-04-03 11:18:58 +0000868 if (ok > 0) {
Pavel Roskinf15d1801999-03-28 13:39:55 +0000869 match++;
Ove Kaaven787cf101999-04-03 11:18:58 +0000870 /* and how much the keycode order matches */
871 if (key > pkey) seq++;
872 pkey = key;
873 } else {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000874 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
Pavel Roskinf15d1801999-03-28 13:39:55 +0000875 ckey[0]);
876 mismatch++;
877 score -= syms;
878 }
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000879 }
880 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000881 TRACE("matches=%d, mismatches=%d, score=%d\n",
Pavel Roskinf15d1801999-03-28 13:39:55 +0000882 match, mismatch, score);
Ove Kaaven787cf101999-04-03 11:18:58 +0000883 if ((score > max_score) ||
884 ((score == max_score) && (seq > max_seq))) {
Pavel Roskinf15d1801999-03-28 13:39:55 +0000885 /* best match so far */
886 kbd_layout = current;
887 max_score = score;
Ove Kaaven787cf101999-04-03 11:18:58 +0000888 max_seq = seq;
Pavel Roskinf15d1801999-03-28 13:39:55 +0000889 ismatch = !mismatch;
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000890 }
Pavel Roskinf15d1801999-03-28 13:39:55 +0000891 }
892 /* we're done, report results if necessary */
893 if (!ismatch) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000894 FIXME(
Ove Kaaven787cf101999-04-03 11:18:58 +0000895 "Your keyboard layout was not found!\n"
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000896 "Instead of using closest match (%s) for scancode mapping.\n"
Ove Kaaven787cf101999-04-03 11:18:58 +0000897 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
Pavel Roskinf15d1801999-03-28 13:39:55 +0000898 "to us for inclusion into future Wine releases.\n"
899 "See documentation/keyboard for more information.\n",
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000900 main_key_tab[kbd_layout].comment);
Pavel Roskinf15d1801999-03-28 13:39:55 +0000901 }
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +0000902
903 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000904}
905
906/**********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000907 * X11DRV_InitKeyboard
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000908 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000909void X11DRV_InitKeyboard(void)
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000910{
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000911 KeySym *ksp;
912 XModifierKeymap *mmp;
913 KeySym keysym;
914 KeyCode *kcp;
915 XKeyEvent e2;
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000916 WORD scan, vkey, OEMvkey;
917 int keyc, i, keyn, syms;
918 char ckey[4]={0,0,0,0};
919 const char (*lkey)[MAIN_LEN][4];
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000920
921 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
922 ksp = TSXGetKeyboardMapping(display, min_keycode,
923 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
924 /* We are only interested in keysyms_per_keycode.
925 There is no need to hold a local copy of the keysyms table */
926 TSXFree(ksp);
927 mmp = TSXGetModifierMapping(display);
928 kcp = mmp->modifiermap;
929 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
930 {
931 int j;
932
933 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
934 if (*kcp)
935 {
936 int k;
937
938 for (k = 0; k < keysyms_per_keycode; k += 1)
939 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
940 {
941 AltGrMask = 1 << i;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000942 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000943 }
944 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
945 {
946 NumLockMask = 1 << i;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000947 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000948 }
949 }
950 }
951 TSXFreeModifiermap(mmp);
952
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000953 /* Detect the keyboard layout */
954 X11DRV_KEYBOARD_DetectLayout();
955 lkey = main_key_tab[kbd_layout].key;
956 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
957
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000958 /* Now build two conversion arrays :
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000959 * keycode -> vkey + scancode + extended
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000960 * vkey + extended -> keycode */
961
962 e2.display = display;
963 e2.state = 0;
964
965 OEMvkey = VK_OEM_7; /* next is available. */
966 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
967 {
968 e2.keycode = (KeyCode)keyc;
969 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000970 vkey = 0; scan = 0;
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000971 if (keysym) /* otherwise, keycode not used */
972 {
973 if ((keysym >> 8) == 0xFF) /* non-character key */
974 {
975 int key = keysym & 0xff;
976
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000977 if (key >= 0x08 && key <= 0x1B) { /* special key */
978 vkey = special_key_vkey[key - 0x08];
979 scan = special_key_scan[key - 0x08];
980 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
981 vkey = cursor_key_vkey[key - 0x50];
982 scan = cursor_key_scan[key - 0x50];
983 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
984 vkey = misc_key_vkey[key - 0x60];
985 scan = misc_key_scan[key - 0x60];
986 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
987 vkey = keypad_key_vkey[key - 0x7E];
988 scan = keypad_key_scan[key - 0x7E];
989 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
990 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
991 scan = function_key_scan[key - 0xBE];
992 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
993 vkey = modifier_key_vkey[key - 0xE1];
994 scan = modifier_key_scan[key - 0xE1];
995 } else if (key == 0xFF) { /* DEL key */
Patrik Stridvalle35d6361998-12-07 09:13:40 +0000996 vkey = VK_DELETE;
Ove Kaaven7173e1c1999-03-14 14:00:57 +0000997 scan = 0x153;
998 }
999 /* set extended bit when necessary */
1000 if (scan & 0x100) vkey |= 0x100;
1001 } else if (keysym == 0x20) { /* Spacebar */
1002 vkey = VK_SPACE;
1003 scan = 0x39;
1004 } else {
1005 /* we seem to need to search the layout-dependent scancodes */
1006 int maxlen=0,maxval=-1,ok;
1007 for (i=0; i<syms; i++) {
1008 keysym = TSXKeycodeToKeysym(display, keyc, i);
Ove Kaaven787cf101999-04-03 11:18:58 +00001009 if ((keysym<0x800) && (keysym!=' ')) {
1010 ckey[i] = keysym & 0xFF;
1011 } else {
1012 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1013 }
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001014 }
1015 /* find key with longest match streak */
1016 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1017 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1018 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1019 if (ok||(i>maxlen)) {
1020 maxlen=i; maxval=keyn;
1021 }
1022 if (ok) break;
1023 }
1024 if (maxval>=0) {
1025 /* got it */
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +00001026 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1027 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1028 scan = (*lscan)[maxval];
1029 vkey = (*lvkey)[maxval];
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001030 }
1031 }
1032
1033 /* find a suitable layout-dependent VK code */
1034 /* (most Winelib apps ought to be able to work without layout tables!) */
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001035 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1036 {
1037 keysym = TSXLookupKeysym(&e2, i);
1038 if ((keysym >= VK_0 && keysym <= VK_9)
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001039 || (keysym >= VK_A && keysym <= VK_Z)) {
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001040 vkey = keysym;
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001041 }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001042 }
1043
1044 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1045 {
1046 keysym = TSXLookupKeysym(&e2, i);
1047 switch (keysym)
1048 {
1049 case ';': vkey = VK_OEM_1; break;
1050 case '/': vkey = VK_OEM_2; break;
1051 case '`': vkey = VK_OEM_3; break;
1052 case '[': vkey = VK_OEM_4; break;
1053 case '\\': vkey = VK_OEM_5; break;
1054 case ']': vkey = VK_OEM_6; break;
1055 case '\'': vkey = VK_OEM_7; break;
1056 case ',': vkey = VK_OEM_COMMA; break;
1057 case '.': vkey = VK_OEM_PERIOD; break;
1058 case '-': vkey = VK_OEM_MINUS; break;
1059 case '+': vkey = VK_OEM_PLUS; break;
1060 }
1061 }
1062
1063 if (!vkey)
1064 {
1065 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1066 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1067 switch (++OEMvkey)
1068 {
1069 case 0xc1 : OEMvkey=0xdb; break;
1070 case 0xe5 : OEMvkey=0xe9; break;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001071 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001072 }
1073
1074 vkey = OEMvkey;
1075
1076 if (TRACE_ON(keyboard))
1077 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001078 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
Alexandre Julliard15de6151999-08-04 12:22:42 +00001079 OEMvkey, e2.keycode);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001080 TRACE("(");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001081 for (i = 0; i < keysyms_per_keycode; i += 1)
1082 {
1083 char *ksname;
1084
1085 keysym = TSXLookupKeysym(&e2, i);
1086 ksname = TSXKeysymToString(keysym);
1087 if (!ksname)
1088 ksname = "NoSymbol";
Alexandre Julliard15de6151999-08-04 12:22:42 +00001089 DPRINTF( "%lX (%s) ", keysym, ksname);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001090 }
Alexandre Julliard15de6151999-08-04 12:22:42 +00001091 DPRINTF(")\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001092 }
1093 }
1094 }
1095 keyc2vkey[e2.keycode] = vkey;
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001096 keyc2scan[e2.keycode] = scan;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001097 } /* for */
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001098
1099 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1100 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1101 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1102 char *ksname;
1103 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1104 ksname = TSXKeysymToString(keysym);
1105 if (!ksname) ksname = "NoSymbol";
1106
1107 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1108
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001109 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001110 keyc2scan[keyc]=scan++;
1111 }
1112
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001113 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1114 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1115 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1116 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1117 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1118 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1119 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1120}
1121
1122/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001123 * X11DRV_VkKeyScan
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001124 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001125WORD X11DRV_VkKeyScan(CHAR cChar)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001126{
1127 KeyCode keycode;
1128 KeySym keysym;
1129 int i,index;
1130 int highbyte=0;
1131
1132 /* char->keysym (same for ANSI chars) */
1133 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1134 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1135
1136 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1137 if (!keycode)
1138 { /* It didn't work ... let's try with deadchar code. */
1139 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1140 }
1141
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001142 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1143 cChar,keysym,keysym,keycode);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001144
1145 if (keycode)
1146 {
1147 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1148 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1149 switch (index) {
1150 case -1 :
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001151 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001152 case 0 : break;
1153 case 1 : highbyte = 0x0100; break;
Huw D M Davies746706b1999-04-15 16:37:16 +00001154 case 2 : highbyte = 0x0600; break;
1155 case 3 : highbyte = 0x0700; break;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001156 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001157 }
1158 /*
1159 index : 0 adds 0x0000
1160 index : 1 adds 0x0100 (shift)
1161 index : ? adds 0x0200 (ctrl)
1162 index : 2 adds 0x0600 (ctrl+alt)
Huw D M Davies746706b1999-04-15 16:37:16 +00001163 index : 3 adds 0x0700 (ctrl+alt+shift)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001164 */
1165 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001166 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001167 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1168}
1169
1170/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001171 * X11DRV_MapVirtualKey
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001172 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001173UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001174{
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001175#define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001176
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001177 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001178 switch(wMapType) {
1179 case 0: { /* vkey-code to scan-code */
1180 /* let's do vkey -> keycode -> scan */
1181 int keyc;
1182 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1183 if ((keyc2vkey[keyc] & 0xFF) == wCode)
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001184 returnMVK (keyc2scan[keyc] & 0xFF);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001185 TRACE("returning no scan-code.\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001186 return 0; }
1187
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001188 case 1: { /* scan-code to vkey-code */
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001189 /* let's do scan -> keycode -> vkey */
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001190 int keyc;
1191 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001192 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001193 returnMVK (keyc2vkey[keyc] & 0xFF);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001194 TRACE("returning no vkey-code.\n");
Ove Kaaven7173e1c1999-03-14 14:00:57 +00001195 return 0; }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001196
1197 case 2: { /* vkey-code to unshifted ANSI code */
1198 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1199 /* My Windows returns 'A'. */
1200 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1201 XKeyEvent e;
1202 KeySym keysym;
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001203 int keyc;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001204 char s[2];
1205 e.display = display;
1206 e.state = 0; /* unshifted */
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001207
1208 e.keycode = 0;
1209 /* We exit on the first keycode found, to speed up the thing. */
1210 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1211 { /* Find a keycode that could have generated this virtual key */
1212 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1213 { /* We filter the extended bit, we don't know it */
1214 e.keycode = keyc; /* Store it temporarily */
1215 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1216 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1217 state), so set it to 0, we'll find another one */
1218 }
1219 }
1220 }
1221
1222 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1223 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1224
1225 if (wCode==VK_DECIMAL)
1226 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1227
1228 if (!e.keycode)
1229 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001230 WARN("Unknown virtual key %X !!! \n", wCode);
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001231 return 0; /* whatever */
1232 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001233 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001234
1235 if (TSXLookupString(&e, s, 2, &keysym, NULL))
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001236 returnMVK (*s);
1237
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001238 TRACE("returning no ANSI.\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001239 return 0;
1240 }
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001241
1242 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1243 /* left and right */
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001244 FIXME(" stub for NT\n");
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001245 return 0;
1246
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001247 default: /* reserved */
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001248 WARN("Unknown wMapType %d !\n", wMapType);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001249 return 0;
1250 }
1251 return 0;
1252}
1253
1254/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001255 * X11DRV_GetKeyNameText
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001256 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001257INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001258{
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001259 int vkey, ansi, scanCode;
Guy Albertelli5bd55171999-09-03 12:39:29 +00001260 KeyCode keyc;
1261 KeySym keys;
1262 char *name;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001263
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001264 scanCode = lParam >> 16;
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001265 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001266
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001267 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001268 vkey = X11DRV_MapVirtualKey(scanCode, 1);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001269
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001270 /* handle "don't care" bit (0x02000000) */
1271 if (!(lParam & 0x02000000)) {
1272 switch (vkey) {
1273 case VK_LSHIFT:
1274 case VK_RSHIFT:
1275 vkey = VK_SHIFT;
1276 break;
1277 case VK_LCONTROL:
1278 case VK_RCONTROL:
1279 vkey = VK_CONTROL;
1280 break;
1281 case VK_LMENU:
1282 case VK_RMENU:
1283 vkey = VK_MENU;
1284 break;
1285 default:
1286 break;
1287 }
1288 }
1289
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001290 ansi = X11DRV_MapVirtualKey(vkey, 2);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001291 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001292
Guy Albertelli5bd55171999-09-03 12:39:29 +00001293 /* first get the name of the "regular" keys which is the Upper case
1294 value of the keycap imprint. */
1295 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1296 (scanCode != 0x137) && /* PrtScn */
1297 (scanCode != 0x135) && /* numpad / */
1298 (scanCode != 0x37 ) && /* numpad * */
1299 (scanCode != 0x4a ) && /* numpad - */
1300 (scanCode != 0x4e ) ) /* numpad + */
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001301 {
1302 if ((nSize >= 2) && lpBuffer)
1303 {
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001304 *lpBuffer = toupper((char)ansi);
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001305 *(lpBuffer+1) = 0;
1306 return 1;
1307 }
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001308 else
1309 return 0;
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001310 }
1311
Guy Albertelli5bd55171999-09-03 12:39:29 +00001312 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1313 without "extended-key" flag. However Wine generates scancode
1314 *with* "extended-key" flag. Seems to occur *only* for the
1315 function keys. Soooo.. We will leave the table alone and
1316 fudge the lookup here till the other part is found and fixed!!! */
Guy Albertelli76d8abe1999-04-15 15:14:44 +00001317
Guy Albertelli5bd55171999-09-03 12:39:29 +00001318 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1319 (scanCode == 0x157) || (scanCode == 0x158))
1320 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001321
Guy Albertelli5bd55171999-09-03 12:39:29 +00001322 /* let's do scancode -> keycode -> keysym -> String */
1323
1324 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1325 if ((keyc2scan[keyc]) == scanCode)
1326 break;
1327 if (keyc <= max_keycode)
1328 {
1329 keys = TSXKeycodeToKeysym(display, keyc, 0);
1330 name = TSXKeysymToString(keys);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001331 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1332 scanCode, keyc, (int)keys, name);
Guy Albertelli5bd55171999-09-03 12:39:29 +00001333 if (lpBuffer && nSize && name)
1334 {
Francois Gougetbaa9bf91999-12-27 05:24:06 +00001335 lstrcpynA(lpBuffer, name, nSize);
Guy Albertelli5bd55171999-09-03 12:39:29 +00001336 return 1;
1337 }
1338 }
1339
1340 /* Finally issue FIXME for unknown keys */
1341
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001342 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
Guy Albertelli2031d6c1999-04-11 14:47:41 +00001343 if (lpBuffer && nSize)
1344 *lpBuffer = 0;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001345 return 0;
1346}
1347
1348/***********************************************************************
Marcus Meissner2199f6e1999-04-01 12:05:44 +00001349 * X11DRV_KEYBOARD_MapDeadKeysym
1350 */
1351static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1352{
1353 switch (keysym)
1354 {
1355 /* symbolic ASCII is the same as defined in rfc1345 */
1356#ifdef XK_dead_tilde
1357 case XK_dead_tilde :
1358#endif
1359 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1360 return '~'; /* '? */
1361#ifdef XK_dead_acute
1362 case XK_dead_acute :
1363#endif
1364 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1365 return 0xb4; /* '' */
1366#ifdef XK_dead_circumflex
1367 case XK_dead_circumflex:
1368#endif
1369 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1370 return '^'; /* '> */
1371#ifdef XK_dead_grave
1372 case XK_dead_grave :
1373#endif
1374 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1375 return '`'; /* '! */
1376#ifdef XK_dead_diaeresis
1377 case XK_dead_diaeresis :
1378#endif
1379 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1380 return 0xa8; /* ': */
1381#ifdef XK_dead_cedilla
1382 case XK_dead_cedilla :
1383 return 0xb8; /* ', */
1384#endif
1385#ifdef XK_dead_macron
1386 case XK_dead_macron :
1387 return '-'; /* 'm isn't defined on iso-8859-x */
1388#endif
1389#ifdef XK_dead_breve
1390 case XK_dead_breve :
1391 return 0xa2; /* '( */
1392#endif
1393#ifdef XK_dead_abovedot
1394 case XK_dead_abovedot :
1395 return 0xff; /* '. */
1396#endif
1397#ifdef XK_dead_abovering
1398 case XK_dead_abovering :
1399 return '0'; /* '0 isn't defined on iso-8859-x */
1400#endif
1401#ifdef XK_dead_doubleacute
1402 case XK_dead_doubleacute :
1403 return 0xbd; /* '" */
1404#endif
1405#ifdef XK_dead_caron
1406 case XK_dead_caron :
1407 return 0xb7; /* '< */
1408#endif
1409#ifdef XK_dead_ogonek
1410 case XK_dead_ogonek :
1411 return 0xb2; /* '; */
1412#endif
1413/* FIXME: I don't know this three.
1414 case XK_dead_iota :
1415 return 'i';
1416 case XK_dead_voiced_sound :
1417 return 'v';
1418 case XK_dead_semivoiced_sound :
1419 return 's';
1420*/
1421 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001422 TRACE("no character for dead keysym 0x%08lx\n",keysym);
Marcus Meissner2199f6e1999-04-01 12:05:44 +00001423 return 0;
1424}
1425
1426/***********************************************************************
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001427 * X11DRV_ToUnicode
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001428 *
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001429 * The ToUnicode function translates the specified virtual-key code and keyboard
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001430 * state to the corresponding Windows character or characters.
1431 *
1432 * If the specified key is a dead key, the return value is negative. Otherwise,
1433 * it is one of the following values:
1434 * Value Meaning
1435 * 0 The specified virtual key has no translation for the current state of the keyboard.
1436 * 1 One Windows character was copied to the buffer.
1437 * 2 Two characters were copied to the buffer. This usually happens when a
1438 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1439 * be composed with the specified virtual key to form a single character.
1440 *
1441 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1442 *
1443 */
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001444INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1445 LPWSTR bufW, int bufW_size, UINT flags)
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001446{
1447 XKeyEvent e;
1448 KeySym keysym;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001449 INT ret;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001450 int keyc;
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001451 BYTE lpChar[2];
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001452
1453 if (scanCode==0) {
1454 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1455 event is generated by windows. Just ignore it. */
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001456 TRACE("scanCode=0, doing nothing\n");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001457 return 0;
1458 }
Ulrich Weigand175989d1999-03-10 13:28:30 +00001459 if (scanCode & 0x8000)
1460 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001461 TRACE("Key UP, doing nothing\n" );
Ulrich Weigand175989d1999-03-10 13:28:30 +00001462 return 0;
1463 }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001464 e.display = display;
1465 e.keycode = 0;
1466 e.state = 0;
1467 if (lpKeyState[VK_SHIFT] & 0x80)
1468 e.state |= ShiftMask;
1469 if (lpKeyState[VK_CAPITAL] & 0x01)
1470 e.state |= LockMask;
1471 if (lpKeyState[VK_CONTROL] & 0x80)
1472 {
1473 if (lpKeyState[VK_MENU] & 0x80)
1474 e.state |= AltGrMask;
1475 else
1476 e.state |= ControlMask;
1477 }
1478 if (lpKeyState[VK_NUMLOCK] & 0x01)
1479 e.state |= NumLockMask;
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001480 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001481 virtKey, scanCode, e.state);
1482 /* We exit on the first keycode found, to speed up the thing. */
1483 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1484 { /* Find a keycode that could have generated this virtual key */
1485 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1486 { /* We filter the extended bit, we don't know it */
1487 e.keycode = keyc; /* Store it temporarily */
1488 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1489 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1490 state), so set it to 0, we'll find another one */
1491 }
1492 }
1493 }
1494
1495 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1496 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1497
1498 if (virtKey==VK_DECIMAL)
1499 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1500
1501 if (!e.keycode)
1502 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001503 WARN("Unknown virtual key %X !!! \n",virtKey);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001504 return virtKey; /* whatever */
1505 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001506 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001507
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +00001508 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001509 if (ret == 0)
1510 {
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001511 BYTE dead_char;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001512
Marcus Meissner2199f6e1999-04-01 12:05:44 +00001513 dead_char = KEYBOARD_MapDeadKeysym(keysym);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001514 if (dead_char)
1515 {
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001516 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001517 ret = -1;
1518 }
1519 else
1520 {
1521 char *ksname;
1522
1523 ksname = TSXKeysymToString(keysym);
1524 if (!ksname)
1525 ksname = "No Name";
1526 if ((keysym >> 8) != 0xff)
1527 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001528 ERR("Please report: no char for keysym %04lX (%s) :\n",
1529 keysym, ksname);
1530 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1531 virtKey, scanCode, e.keycode, e.state);
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001532 }
1533 }
1534 }
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001535 else { /* ret != 0 */
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001536 /* We have a special case to handle : Shift + arrow, shift + home, ...
1537 X returns a char for it, but Windows doesn't. Let's eat it. */
1538 if (!(lpKeyState[VK_NUMLOCK] & 0x01) /* NumLock is off */
1539 && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1540 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1541 {
1542 *(char*)lpChar = 0;
1543 ret = 0;
1544 }
Aric Stewart7ab63982000-11-08 04:29:42 +00001545
1546 /* more areas where X returns characters but Windows does not
1547 CTRL + number */
1548 if ((lpKeyState[VK_CONTROL] & 0x80)&&(keysym>=48)&&
1549 (keysym<=57))
1550 {
1551 *(char*)lpChar = 0;
1552 ret = 0;
1553 }
Stephane Lussier540a2271999-09-10 13:57:59 +00001554
1555 /* We have another special case for delete key (XK_Delete) on an
1556 extended keyboard. X returns a char for it, but Windows doesn't */
1557 if (keysym == XK_Delete)
1558 {
1559 *(char*)lpChar = 0;
1560 ret = 0;
1561 }
Dmitry Timoshkovb5f8b922000-10-25 21:58:48 +00001562 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1563 && (keysym == XK_KP_Decimal))
1564 {
1565 *(char*)lpChar = 0;
1566 ret = 0;
1567 }
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +00001568
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001569 /* perform translation to unicode */
1570 if(ret)
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +00001571 {
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001572 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1573 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1574 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
Dmitry Timoshkov7b0bf0f2000-10-17 00:31:53 +00001575 }
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001576 }
1577
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001578 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
Dmitry Timoshkovc8ac4a22000-11-25 02:12:49 +00001579 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001580 return ret;
1581}
1582
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001583/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001584 * X11DRV_GetBeepActive
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001585 */
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001586BOOL X11DRV_GetBeepActive(void)
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001587{
1588 XKeyboardState keyboard_state;
Patrik Stridvalle35d6361998-12-07 09:13:40 +00001589
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001590 TSXGetKeyboardControl(display, &keyboard_state);
1591
1592 return keyboard_state.bell_percent != 0;
1593}
1594
1595/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001596 * X11DRV_SetBeepActive
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001597 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001598void X11DRV_SetBeepActive(BOOL bActivate)
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001599{
1600 XKeyboardControl keyboard_value;
1601
1602 if(bActivate)
1603 keyboard_value.bell_percent = -1;
1604 else
1605 keyboard_value.bell_percent = 0;
1606
1607 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1608}
1609
1610/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001611 * X11DRV_Beep
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001612 */
Dmitry Timoshkov8a316342000-10-25 21:34:31 +00001613void X11DRV_Beep(void)
Patrik Stridvallb87fe2e1999-04-01 08:16:08 +00001614{
1615 TSXBell(display, 0);
1616}
1617
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001618/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001619 * X11DRV_GetDIState
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001620 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001621BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001622{
1623 if (len==256) {
1624 int keyc,vkey;
1625
1626 memset(ptr,0,256);
1627 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1628 {
1629 /* X keycode to virtual key */
1630 vkey = keyc2vkey[keyc] & 0xFF;
1631 /* The windows scancode is keyc-min_keycode */
1632 if (InputKeyStateTable[vkey]&0x80) {
1633 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1634 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1635 }
1636 }
1637 return TRUE;
1638 }
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001639 WARN("whoops, got len %ld?\n", len);
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001640 return TRUE;
1641}
1642
1643/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001644 * X11DRV_GetDIData
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001645 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001646BOOL X11DRV_GetDIData(
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001647 BYTE *keystate,
1648 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1649 LPDWORD entries, DWORD flags)
1650{
1651 int keyc,n,vkey,xentries;
1652
1653 /* FIXME !!! */
1654
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001655 if (entries)
1656 xentries = *entries;
1657 else
1658 xentries = 1;
1659
1660 n = 0;
1661
1662 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1663 {
1664 /* X keycode to virtual key */
1665 vkey = keyc2vkey[keyc] & 0xFF;
1666 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1667 continue;
1668 if (dod) {
1669 /* add an entry */
1670 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1671 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1672 dod[n].dwTimeStamp = 0; /* umm */
1673 dod[n].dwSequence = 0; /* umm */
1674 n++;
1675 }
1676 if (!(flags & DIGDD_PEEK))
1677 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1678
1679 }
1680
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001681 if (n) TRACE_(dinput)("%d entries\n",n);
Patrik Stridvalld96e1f11999-07-04 13:31:03 +00001682 *entries = n;
1683
1684 return TRUE;
1685}
1686
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001687/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001688 * X11DRV_GetKeyboardConfig
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001689 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001690void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001691 XKeyboardState xks;
1692
1693 /* For the moment, only get the auto-repeat mode */
1694 TSXGetKeyboardControl(display, &xks);
1695 cfg->auto_repeat = xks.global_auto_repeat;
1696}
1697
1698/***********************************************************************
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001699 * X11DRV_SetKeyboardConfig
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001700 */
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001701extern void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
Lionel Ulmerc9713e51999-12-05 02:20:46 +00001702 XKeyboardControl xkc;
1703 unsigned long X_mask = 0;
1704
1705 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1706 X_mask |= KBAutoRepeatMode;
1707 xkc.auto_repeat_mode = cfg->auto_repeat;
1708 }
1709 if (X_mask)
1710 TSXChangeKeyboardControl(display, X_mask, &xkc);
1711}
1712