2 * USER Input processing
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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "win32u_private.h"
30 #include "wine/server.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(win
);
34 WINE_DECLARE_DEBUG_CHANNEL(keyboard
);
36 static const WCHAR keyboard_layouts_keyW
[] =
38 '\\','R','e','g','i','s','t','r','y',
39 '\\','M','a','c','h','i','n','e',
40 '\\','S','y','s','t','e','m',
41 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
42 '\\','C','o','n','t','r','o','l',
43 '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s'
47 /**********************************************************************
48 * NtUserAttachThreadInput (win32u.@)
50 BOOL WINAPI
NtUserAttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
54 SERVER_START_REQ( attach_thread_input
)
59 ret
= !wine_server_call_err( req
);
65 /***********************************************************************
66 * get_locale_kbd_layout
68 static HKL
get_locale_kbd_layout(void)
75 * layout = main_key_tab[kbd_layout].lcid;
77 * Winword uses return value of GetKeyboardLayout as a codepage
78 * to translate ANSI keyboard messages to unicode. But we have
79 * a problem with it: for instance Polish keyboard layout is
80 * identical to the US one, and therefore instead of the Polish
81 * locale id we return the US one.
84 NtQueryDefaultLocale( TRUE
, &layout
);
87 * Microsoft Office expects this value to be something specific
88 * for Japanese and Korean Windows with an IME the value is 0xe001
89 * We should probably check to see if an IME exists and if so then
90 * set this word properly.
92 langid
= PRIMARYLANGID( LANGIDFROMLCID( layout
) );
93 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
94 layout
= MAKELONG( layout
, 0xe001 ); /* IME */
96 layout
= MAKELONG( layout
, layout
);
98 return ULongToHandle( layout
);
101 /***********************************************************************
102 * NtUserGetKeyboardLayout (win32u.@)
104 * Device handle for keyboard layout defaulted to
105 * the language id. This is the way Windows default works.
107 HKL WINAPI
NtUserGetKeyboardLayout( DWORD thread_id
)
109 struct user_thread_info
*thread
= get_user_thread_info();
110 HKL layout
= thread
->kbd_layout
;
112 if (thread_id
&& thread_id
!= GetCurrentThreadId())
113 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id
);
115 if (!layout
) return get_locale_kbd_layout();
119 /**********************************************************************
120 * NtUserGetKeyState (win32u.@)
122 * An application calls the GetKeyState function in response to a
123 * keyboard-input message. This function retrieves the state of the key
124 * at the time the input message was generated.
126 SHORT WINAPI
NtUserGetKeyState( INT vkey
)
130 SERVER_START_REQ( get_key_state
)
133 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
136 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
140 /**********************************************************************
141 * NtUserGetKeyboardState (win32u.@)
143 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
148 TRACE("(%p)\n", state
);
150 memset( state
, 0, 256 );
151 SERVER_START_REQ( get_key_state
)
154 wine_server_set_reply( req
, state
, 256 );
155 ret
= !wine_server_call_err( req
);
156 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
162 /**********************************************************************
163 * NtUserSetKeyboardState (win32u.@)
165 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
169 SERVER_START_REQ( set_key_state
)
171 wine_server_add_data( req
, state
, 256 );
172 ret
= !wine_server_call_err( req
);
178 /******************************************************************************
179 * NtUserVkKeyScanEx (win32u.@)
181 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
183 WORD shift
= 0x100, ctrl
= 0x200;
186 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
188 if ((ret
= user_driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
190 /* FIXME: English keyboard layout specific */
192 if (chr
== VK_CANCEL
|| chr
== VK_BACK
|| chr
== VK_TAB
|| chr
== VK_RETURN
||
193 chr
== VK_ESCAPE
|| chr
== VK_SPACE
) ret
= chr
;
194 else if (chr
>= '0' && chr
<= '9') ret
= chr
;
195 else if (chr
== ')') ret
= shift
+ '0';
196 else if (chr
== '!') ret
= shift
+ '1';
197 else if (chr
== '@') ret
= shift
+ '2';
198 else if (chr
== '#') ret
= shift
+ '3';
199 else if (chr
== '$') ret
= shift
+ '4';
200 else if (chr
== '%') ret
= shift
+ '5';
201 else if (chr
== '^') ret
= shift
+ '6';
202 else if (chr
== '&') ret
= shift
+ '7';
203 else if (chr
== '*') ret
= shift
+ '8';
204 else if (chr
== '(') ret
= shift
+ '9';
205 else if (chr
>= 'a' && chr
<= 'z') ret
= chr
- 'a' + 'A';
206 else if (chr
>= 'A' && chr
<= 'Z') ret
= shift
+ chr
;
207 else if (chr
== ';') ret
= VK_OEM_1
;
208 else if (chr
== '=') ret
= VK_OEM_PLUS
;
209 else if (chr
== ',') ret
= VK_OEM_COMMA
;
210 else if (chr
== '-') ret
= VK_OEM_MINUS
;
211 else if (chr
== '.') ret
= VK_OEM_PERIOD
;
212 else if (chr
== '/') ret
= VK_OEM_2
;
213 else if (chr
== '`') ret
= VK_OEM_3
;
214 else if (chr
== '[') ret
= VK_OEM_4
;
215 else if (chr
== '\\') ret
= VK_OEM_5
;
216 else if (chr
== ']') ret
= VK_OEM_6
;
217 else if (chr
== '\'') ret
= VK_OEM_7
;
218 else if (chr
== ':') ret
= shift
+ VK_OEM_1
;
219 else if (chr
== '+') ret
= shift
+ VK_OEM_PLUS
;
220 else if (chr
== '<') ret
= shift
+ VK_OEM_COMMA
;
221 else if (chr
== '_') ret
= shift
+ VK_OEM_MINUS
;
222 else if (chr
== '>') ret
= shift
+ VK_OEM_PERIOD
;
223 else if (chr
== '?') ret
= shift
+ VK_OEM_2
;
224 else if (chr
== '~') ret
= shift
+ VK_OEM_3
;
225 else if (chr
== '{') ret
= shift
+ VK_OEM_4
;
226 else if (chr
== '|') ret
= shift
+ VK_OEM_5
;
227 else if (chr
== '}') ret
= shift
+ VK_OEM_6
;
228 else if (chr
== '\"') ret
= shift
+ VK_OEM_7
;
229 else if (chr
== 0x7f) ret
= ctrl
+ VK_BACK
;
230 else if (chr
== '\n') ret
= ctrl
+ VK_RETURN
;
231 else if (chr
== 0xf000) ret
= ctrl
+ '2';
232 else if (chr
== 0x0000) ret
= ctrl
+ shift
+ '2';
233 else if (chr
>= 0x0001 && chr
<= 0x001a) ret
= ctrl
+ 'A' + chr
- 1;
234 else if (chr
>= 0x001c && chr
<= 0x001d) ret
= ctrl
+ VK_OEM_3
+ chr
;
235 else if (chr
== 0x001e) ret
= ctrl
+ shift
+ '6';
236 else if (chr
== 0x001f) ret
= ctrl
+ shift
+ VK_OEM_MINUS
;
239 TRACE_(keyboard
)( "ret %04x\n", ret
);
243 /* English keyboard layout (0x0409) */
244 static const UINT kbd_en_vsc2vk
[] =
246 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
247 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
248 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
249 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
250 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
251 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
252 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
253 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
265 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
266 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
268 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 static const UINT kbd_en_vk2char
[] =
300 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
302 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
305 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
306 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/',
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/',
312 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
314 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 static const char *kbd_en_vscname
[] =
320 0, "Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", "Tab",
321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Enter", "Ctrl", 0, 0,
322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Shift", 0, 0, 0, 0, 0,
323 0, 0, 0, 0, 0, 0, "Right Shift", "Num *", "Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5",
324 "F6", "F7", "F8", "F9", "F10", "Pause", "Scroll Lock", "Num 7", "Num 8", "Num 9", "Num -", "Num 4", "Num 5", "Num 6", "Num +", "Num 1",
325 "Num 2", "Num 3", "Num 0", "Num Del", "Sys Req", 0, 0, "F11", "F12", 0, 0, 0, 0, 0, 0, 0,
326 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
327 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "F13", "F14", "F15", "F16",
328 "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", 0, 0, 0, 0, 0, 0, 0, 0,
329 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
332 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
333 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
338 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Num Enter", "Right Ctrl", 0, 0,
339 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
340 0, 0, 0, 0, 0, "Num /", 0, "Prnt Scrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0,
341 0, 0, 0, 0, 0, "Num Lock", "Break", "Home", "Up", "Page Up", 0, "Left", 0, "Right", 0, "End",
342 "Down", "Page Down", "Insert", "Delete", "<00>", 0, "Help", 0, 0, 0, 0, "Left Windows", "Right Windows", "Application", 0, 0,
343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
355 /******************************************************************************
356 * NtUserMapVirtualKeyEx (win32u.@)
358 UINT WINAPI
NtUserMapVirtualKeyEx( UINT code
, UINT type
, HKL layout
)
360 const UINT
*vsc2vk
, *vk2char
;
361 UINT vsc2vk_size
, vk2char_size
;
364 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
366 if ((ret
= user_driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
368 /* FIXME: English keyboard layout specific */
370 vsc2vk
= kbd_en_vsc2vk
;
371 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
372 vk2char
= kbd_en_vk2char
;
373 vk2char_size
= ARRAYSIZE(kbd_en_vk2char
);
377 case MAPVK_VK_TO_VSC_EX
:
378 case MAPVK_VK_TO_VSC
:
381 case VK_SHIFT
: code
= VK_LSHIFT
; break;
382 case VK_CONTROL
: code
= VK_LCONTROL
; break;
383 case VK_MENU
: code
= VK_LMENU
; break;
384 case VK_NUMPAD0
: code
= VK_INSERT
; break;
385 case VK_NUMPAD1
: code
= VK_END
; break;
386 case VK_NUMPAD2
: code
= VK_DOWN
; break;
387 case VK_NUMPAD3
: code
= VK_NEXT
; break;
388 case VK_NUMPAD4
: code
= VK_LEFT
; break;
389 case VK_NUMPAD5
: code
= VK_CLEAR
; break;
390 case VK_NUMPAD6
: code
= VK_RIGHT
; break;
391 case VK_NUMPAD7
: code
= VK_HOME
; break;
392 case VK_NUMPAD8
: code
= VK_UP
; break;
393 case VK_NUMPAD9
: code
= VK_PRIOR
; break;
394 case VK_DECIMAL
: code
= VK_DELETE
; break;
397 for (ret
= 0; ret
< vsc2vk_size
; ++ret
) if (vsc2vk
[ret
] == code
) break;
398 if (ret
>= vsc2vk_size
) ret
= 0;
400 if (type
== MAPVK_VK_TO_VSC
)
402 if (ret
>= 0x200) ret
= 0;
405 else if (ret
>= 0x100) ret
+= 0xdf00;
407 case MAPVK_VSC_TO_VK
:
408 case MAPVK_VSC_TO_VK_EX
:
409 if (code
& 0xe000) code
-= 0xdf00;
410 if (code
>= vsc2vk_size
) ret
= 0;
411 else ret
= vsc2vk
[code
];
413 if (type
== MAPVK_VSC_TO_VK
)
417 case VK_LSHIFT
: case VK_RSHIFT
: ret
= VK_SHIFT
; break;
418 case VK_LCONTROL
: case VK_RCONTROL
: ret
= VK_CONTROL
; break;
419 case VK_LMENU
: case VK_RMENU
: ret
= VK_MENU
; break;
423 case MAPVK_VK_TO_CHAR
:
424 if (code
>= vk2char_size
) ret
= 0;
425 else ret
= vk2char
[code
];
428 FIXME_(keyboard
)( "unknown type %d\n", type
);
432 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
436 /****************************************************************************
437 * NtUserGetKeyNameText (win32u.@)
439 INT WINAPI
NtUserGetKeyNameText( LONG lparam
, WCHAR
*buffer
, INT size
)
441 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
442 UINT vsc2vk_size
, vscname_size
;
443 const char *const *vscname
;
446 TRACE_(keyboard
)( "lparam %d, buffer %p, size %d.\n", lparam
, buffer
, size
);
448 if (!buffer
|| !size
) return 0;
449 if ((len
= user_driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
451 /* FIXME: English keyboard layout specific */
453 vsc2vk
= kbd_en_vsc2vk
;
454 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
455 vscname
= kbd_en_vscname
;
456 vscname_size
= ARRAYSIZE(kbd_en_vscname
);
458 if (lparam
& 0x2000000)
460 switch ((vkey
= vsc2vk
[code
]))
465 for (code
= 0; code
< vsc2vk_size
; ++code
)
466 if (vsc2vk
[code
] == (vkey
- 1)) break;
471 if (code
< vscname_size
)
475 len
= min( size
- 1, strlen(vscname
[code
]) );
476 ascii_to_unicode( buffer
, vscname
[code
], len
);
480 HKL hkl
= NtUserGetKeyboardLayout( 0 );
481 vkey
= NtUserMapVirtualKeyEx( code
& 0xff, MAPVK_VSC_TO_VK
, hkl
);
482 buffer
[0] = NtUserMapVirtualKeyEx( vkey
, MAPVK_VK_TO_CHAR
, hkl
);
488 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
492 /****************************************************************************
493 * NtUserToUnicodeEx (win32u.@)
495 INT WINAPI
NtUserToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
496 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
498 BOOL shift
, ctrl
, alt
, numlock
;
502 TRACE_(keyboard
)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
503 virt
, scan
, state
, str
, size
, flags
, layout
);
505 if (!state
) return 0;
506 if ((len
= user_driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1)
509 alt
= state
[VK_MENU
] & 0x80;
510 shift
= state
[VK_SHIFT
] & 0x80;
511 ctrl
= state
[VK_CONTROL
] & 0x80;
512 numlock
= state
[VK_NUMLOCK
] & 0x01;
514 /* FIXME: English keyboard layout specific */
516 if (scan
& 0x8000) buffer
[0] = 0; /* key up */
517 else if (virt
== VK_ESCAPE
) buffer
[0] = VK_ESCAPE
;
522 case VK_BACK
: buffer
[0] = '\b'; break;
523 case VK_OEM_1
: buffer
[0] = shift
? ':' : ';'; break;
524 case VK_OEM_2
: buffer
[0] = shift
? '?' : '/'; break;
525 case VK_OEM_3
: buffer
[0] = shift
? '~' : '`'; break;
526 case VK_OEM_4
: buffer
[0] = shift
? '{' : '['; break;
527 case VK_OEM_5
: buffer
[0] = shift
? '|' : '\\'; break;
528 case VK_OEM_6
: buffer
[0] = shift
? '}' : ']'; break;
529 case VK_OEM_7
: buffer
[0] = shift
? '"' : '\''; break;
530 case VK_OEM_COMMA
: buffer
[0] = shift
? '<' : ','; break;
531 case VK_OEM_MINUS
: buffer
[0] = shift
? '_' : '-'; break;
532 case VK_OEM_PERIOD
: buffer
[0] = shift
? '>' : '.'; break;
533 case VK_OEM_PLUS
: buffer
[0] = shift
? '+' : '='; break;
534 case VK_RETURN
: buffer
[0] = '\r'; break;
535 case VK_SPACE
: buffer
[0] = ' '; break;
536 case VK_TAB
: buffer
[0] = '\t'; break;
537 case VK_MULTIPLY
: buffer
[0] = '*'; break;
538 case VK_ADD
: buffer
[0] = '+'; break;
539 case VK_SUBTRACT
: buffer
[0] = '-'; break;
540 case VK_DIVIDE
: buffer
[0] = '/'; break;
542 if (virt
>= '0' && virt
<= '9')
543 buffer
[0] = shift
? ")!@#$%^&*("[virt
- '0'] : virt
;
544 else if (virt
>= 'A' && virt
<= 'Z')
545 buffer
[0] = shift
|| (state
[VK_CAPITAL
] & 0x01) ? virt
: virt
+ 'a' - 'A';
546 else if (virt
>= VK_NUMPAD0
&& virt
<= VK_NUMPAD9
&& numlock
&& !shift
)
547 buffer
[0] = '0' + virt
- VK_NUMPAD0
;
548 else if (virt
== VK_DECIMAL
&& numlock
&& !shift
)
555 else if (!alt
) /* Control codes */
559 case VK_OEM_4
: buffer
[0] = 0x1b; break;
560 case VK_OEM_5
: buffer
[0] = 0x1c; break;
561 case VK_OEM_6
: buffer
[0] = 0x1d; break;
562 case '6': buffer
[0] = shift
? 0x1e : 0; break;
563 case VK_OEM_MINUS
: buffer
[0] = shift
? 0x1f : 0; break;
564 case VK_BACK
: buffer
[0] = 0x7f; break;
565 case VK_RETURN
: buffer
[0] = shift
? 0 : '\n'; break;
566 case '2': buffer
[0] = shift
? 0xffff : 0xf000; break;
567 case VK_SPACE
: buffer
[0] = ' '; break;
569 if (virt
>= 'A' && virt
<= 'Z') buffer
[0] = virt
- 'A' + 1;
576 len
= lstrlenW( buffer
);
577 if (buffer
[0] == 0xffff) buffer
[0] = 0;
578 lstrcpynW( str
, buffer
, size
);
580 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(str
) );
584 /**********************************************************************
585 * NtUserActivateKeyboardLayout (win32u.@)
587 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
589 struct user_thread_info
*info
= get_user_thread_info();
592 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
594 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
596 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
598 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
599 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
603 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
606 old_layout
= info
->kbd_layout
;
607 info
->kbd_layout
= layout
;
608 if (old_layout
!= layout
) info
->kbd_layout_id
= 0;
610 if (!old_layout
) return get_locale_kbd_layout();
616 /***********************************************************************
617 * NtUserGetKeyboardLayoutList (win32u.@)
619 * Return number of values available if either input parm is
620 * 0, per MS documentation.
622 UINT WINAPI
NtUserGetKeyboardLayoutList( INT size
, HKL
*layouts
)
625 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
626 KEY_VALUE_PARTIAL_INFORMATION
*value_info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
627 DWORD count
, tmp
, i
= 0;
631 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
633 if ((count
= user_driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
635 layout
= get_locale_kbd_layout();
641 layouts
[count
- 1] = layout
;
642 if (count
== size
) return count
;
645 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
647 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key_info
,
648 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
650 if (!(subkey
= reg_open_key( hkey
, key_info
->Name
, key_info
->NameLength
))) continue;
651 key_info
->Name
[key_info
->NameLength
/ sizeof(WCHAR
)] = 0;
652 tmp
= wcstoul( key_info
->Name
, NULL
, 16 );
653 if (query_reg_ascii_value( subkey
, "Layout Id", value_info
, sizeof(buffer
) ) &&
654 value_info
->Type
== REG_SZ
)
655 tmp
= MAKELONG( LOWORD( tmp
),
656 0xf000 | (wcstoul( (const WCHAR
*)value_info
->Data
, NULL
, 16 ) & 0xfff) );
659 if (layout
== UlongToHandle( tmp
)) continue;
664 layouts
[count
- 1] = UlongToHandle( tmp
);
665 if (count
== size
) break;
674 /****************************************************************************
675 * NtUserGetKeyboardLayoutName (win32u.@)
677 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
679 struct user_thread_info
*info
= get_user_thread_info();
681 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
682 KEY_VALUE_PARTIAL_INFORMATION
*value
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
683 WCHAR klid
[KL_NAMELENGTH
];
688 TRACE_(keyboard
)( "name %p\n", name
);
692 SetLastError( ERROR_NOACCESS
);
696 if (info
->kbd_layout_id
)
698 sprintf( buffer
, "%08X", info
->kbd_layout_id
);
699 asciiz_to_unicode( name
, buffer
);
703 layout
= NtUserGetKeyboardLayout( 0 );
704 tmp
= HandleToUlong( layout
);
705 if (HIWORD( tmp
) == LOWORD( tmp
)) tmp
= LOWORD( tmp
);
706 sprintf( buffer
, "%08X", tmp
);
707 asciiz_to_unicode( name
, buffer
);
709 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
711 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
,
712 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
714 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
715 memcpy( klid
, key
->Name
, key
->NameLength
);
716 klid
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
717 if (query_reg_ascii_value( subkey
, "Layout Id", value
, sizeof(buffer
) ) &&
718 value
->Type
== REG_SZ
)
719 tmp
= 0xf000 | (wcstoul( (const WCHAR
*)value
->Data
, NULL
, 16 ) & 0xfff);
721 tmp
= wcstoul( klid
, NULL
, 16 );
724 if (HIWORD( layout
) == tmp
)
726 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
733 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
735 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
739 /***********************************************************************
740 * NtUserUnregisterHotKey (win32u.@)
742 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
747 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
749 SERVER_START_REQ( unregister_hotkey
)
751 req
->window
= wine_server_user_handle( hwnd
);
753 if ((ret
= !wine_server_call_err( req
)))
755 modifiers
= reply
->flags
;
762 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
767 /***********************************************************************
768 * NtUserGetMouseMovePointsEx (win32u.@)
770 int WINAPI
NtUserGetMouseMovePointsEx( UINT size
, MOUSEMOVEPOINT
*ptin
, MOUSEMOVEPOINT
*ptout
,
771 int count
, DWORD resolution
)
773 cursor_pos_t
*pos
, positions
[64];
778 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, resolution
);
780 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
782 SetLastError( ERROR_INVALID_PARAMETER
);
786 if (!ptin
|| (!ptout
&& count
))
788 SetLastError( ERROR_NOACCESS
);
792 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
794 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
795 SetLastError( ERROR_POINT_NOT_FOUND
);
799 SERVER_START_REQ( get_cursor_history
)
801 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
802 if (wine_server_call_err( req
)) return -1;
806 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
809 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
813 if (i
== ARRAY_SIZE( positions
))
815 SetLastError( ERROR_POINT_NOT_FOUND
);
819 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
822 ptout
[copied
].x
= pos
->x
;
823 ptout
[copied
].y
= pos
->y
;
824 ptout
[copied
].time
= pos
->time
;
825 ptout
[copied
].dwExtraInfo
= pos
->info
;