41d93e1213fd6e061440857930e52c301ded88d0
[reactos.git] / rostests / winetests / user32 / input.c
1 /* Test Key event to Key message translation
2 *
3 * Copyright 2003 Rein Klazes
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 /* test whether the right type of messages:
21 * WM_KEYUP/DOWN vs WM_SYSKEYUP/DOWN are sent in case of combined
22 * keystrokes.
23 *
24 * For instance <ALT>-X can be accomplished by
25 * the sequence ALT-KEY-DOWN, X-KEY-DOWN, ALT-KEY-UP, X-KEY-UP
26 * but also X-KEY-DOWN, ALT-KEY-DOWN, X-KEY-UP, ALT-KEY-UP
27 * Whether a KEY or a SYSKEY message is sent is not always clear, it is
28 * also not the same in WINNT as in WIN9X */
29
30 /* NOTE that there will be test failures under WIN9X
31 * No applications are known to me that rely on this
32 * so I don't fix it */
33
34 /* TODO:
35 * 1. extend it to the wm_command and wm_syscommand notifications
36 * 2. add some more tests with special cases like dead keys or right (alt) key
37 * 3. there is some adapted code from input.c in here. Should really
38 * make that code exactly the same.
39 * 4. resolve the win9x case when there is a need or the testing frame work
40 * offers a nice way.
41 * 5. The test app creates a window, the user should not take the focus
42 * away during its short existence. I could do something to prevent that
43 * if it is a problem.
44 *
45 */
46
47 //#define _WIN32_WINNT 0x401
48 //#define _WIN32_IE 0x0500
49
50 #include <stdarg.h>
51 #include <assert.h>
52
53 #include "windef.h"
54 #include "winbase.h"
55 #include "winuser.h"
56
57 #include "wine/test.h"
58
59 /* globals */
60 static HWND hWndTest;
61 static LONG timetag = 0x10000000;
62
63 static struct {
64 LONG last_key_down;
65 LONG last_key_up;
66 LONG last_syskey_down;
67 LONG last_syskey_up;
68 LONG last_char;
69 LONG last_syschar;
70 LONG last_hook_down;
71 LONG last_hook_up;
72 LONG last_hook_syskey_down;
73 LONG last_hook_syskey_up;
74 BOOL expect_alt;
75 BOOL sendinput_broken;
76 } key_status;
77
78 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
79 static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD);
80 static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT);
81
82 #define MAXKEYEVENTS 12
83 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
84 and only one message */
85
86 /* keyboard message names, sorted as their value */
87 static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
88 "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
89
90 /* keyevents, add more as needed */
91 typedef enum KEVtag
92 { ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV;
93 /* matching VK's */
94 static const int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL};
95 /* matching scan codes */
96 static const int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
97 /* matching updown events */
98 static const int GETFLAGS[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP};
99 /* matching descriptions */
100 static const char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
101
102 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
103 typedef struct
104 {
105 DWORD type;
106 union
107 {
108 MOUSEINPUT mi;
109 KEYBDINPUT ki;
110 HARDWAREINPUT hi;
111 } u;
112 } TEST_INPUT;
113
114 #define ADDTOINPUTS(kev) \
115 inputs[evtctr].type = INPUT_KEYBOARD; \
116 ((TEST_INPUT*)inputs)[evtctr].u.ki.wVk = GETVKEY[ kev]; \
117 ((TEST_INPUT*)inputs)[evtctr].u.ki.wScan = GETSCAN[ kev]; \
118 ((TEST_INPUT*)inputs)[evtctr].u.ki.dwFlags = GETFLAGS[ kev]; \
119 ((TEST_INPUT*)inputs)[evtctr].u.ki.dwExtraInfo = 0; \
120 ((TEST_INPUT*)inputs)[evtctr].u.ki.time = ++timetag; \
121 if( kev) evtctr++;
122
123 typedef struct {
124 UINT message;
125 WPARAM wParam;
126 LPARAM lParam;
127 } KMSG;
128
129 /*******************************************
130 * add new test sets here
131 * the software will make all combinations of the
132 * keyevent defined here
133 */
134 static const struct {
135 int nrkev;
136 KEV keydwn[MAXKEYEVENTS];
137 KEV keyup[MAXKEYEVENTS];
138 } testkeyset[]= {
139 { 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}},
140 { 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}},
141 { 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}},
142 { 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}},
143 { 0 } /* mark the end */
144 };
145
146 /**********************adapted from input.c **********************************/
147
148 static BYTE InputKeyStateTable[256];
149 static BYTE AsyncKeyStateTable[256];
150 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
151 or a WM_KEYUP message */
152
153 static void init_function_pointers(void)
154 {
155 HMODULE hdll = GetModuleHandleA("user32");
156
157 #define GET_PROC(func) \
158 p ## func = (void*)GetProcAddress(hdll, #func); \
159 if(!p ## func) \
160 trace("GetProcAddress(%s) failed\n", #func);
161
162 GET_PROC(SendInput)
163 GET_PROC(GetMouseMovePointsEx)
164 GET_PROC(GetRawInputDeviceList)
165
166 #undef GET_PROC
167 }
168
169 static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam )
170 {
171 UINT message;
172 int VKey = GETVKEY[kev];
173 WORD flags;
174
175 flags = LOBYTE(GETSCAN[kev]);
176 if (GETFLAGS[kev] & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
177
178 if (GETFLAGS[kev] & KEYEVENTF_KEYUP )
179 {
180 message = WM_KEYUP;
181 if( (InputKeyStateTable[VK_MENU] & 0x80) && (
182 (VKey == VK_MENU) || (VKey == VK_CONTROL) ||
183 !(InputKeyStateTable[VK_CONTROL] & 0x80))) {
184 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
185 (VKey != VK_MENU)) /* <ALT>-down...<something else>-up */
186 message = WM_SYSKEYUP;
187 TrackSysKey = 0;
188 }
189 InputKeyStateTable[VKey] &= ~0x80;
190 flags |= KF_REPEAT | KF_UP;
191 }
192 else
193 {
194 if (InputKeyStateTable[VKey] & 0x80) flags |= KF_REPEAT;
195 if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01;
196 InputKeyStateTable[VKey] |= 0x80;
197 AsyncKeyStateTable[VKey] |= 0x80;
198
199 message = WM_KEYDOWN;
200 if( (InputKeyStateTable[VK_MENU] & 0x80) &&
201 !(InputKeyStateTable[VK_CONTROL] & 0x80)) {
202 message = WM_SYSKEYDOWN;
203 TrackSysKey = VKey;
204 }
205 }
206
207 if (InputKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
208
209 if( plParam) *plParam = MAKELPARAM( 1, flags );
210 if( pwParam) *pwParam = VKey;
211 return message;
212 }
213
214 /****************************** end copy input.c ****************************/
215
216 /*
217 * . prepare the keyevents for SendInputs
218 * . calculate the "expected" messages
219 * . Send the events to our window
220 * . retrieve the messages from the input queue
221 * . verify
222 */
223 static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] )
224 {
225 INPUT inputs[MAXKEYEVENTS];
226 KMSG expmsg[MAXKEYEVENTS];
227 MSG msg;
228 char buf[100];
229 UINT evtctr=0;
230 int kmctr, i;
231
232 buf[0]='\0';
233 TrackSysKey=0; /* see input.c */
234 for( i = 0; i < MAXKEYEVENTS; i++) {
235 ADDTOINPUTS(td[i])
236 strcat(buf, getdesc[td[i]]);
237 if(td[i])
238 expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam));
239 else
240 expmsg[i].message = 0;
241 }
242 for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++)
243 ;
244 ok( evtctr <= MAXKEYEVENTS, "evtctr is above MAXKEYEVENTS\n" );
245 if( evtctr != pSendInput(evtctr, &inputs[0], sizeof(INPUT)))
246 ok (FALSE, "SendInput failed to send some events\n");
247 i = 0;
248 if (winetest_debug > 1)
249 trace("======== key stroke sequence #%d: %s =============\n",
250 seqnr + 1, buf);
251 while( PeekMessageA(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) {
252 if (winetest_debug > 1)
253 trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i,
254 MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time);
255 if( i < kmctr ) {
256 ok( msg.message == expmsg[i].message &&
257 msg.wParam == expmsg[i].wParam &&
258 msg.lParam == expmsg[i].lParam,
259 "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n",
260 seqnr, i, msg.message, msg.wParam, msg.lParam,
261 MSGNAME[(expmsg[i]).message - WM_KEYFIRST], expmsg[i].wParam, expmsg[i].lParam );
262 }
263 i++;
264 }
265 if (winetest_debug > 1)
266 trace("%d messages retrieved\n", i);
267 if (!i && kmctr)
268 {
269 skip( "simulated keyboard input doesn't work\n" );
270 return FALSE;
271 }
272 ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr);
273 return TRUE;
274 }
275
276 /* test all combinations of the specified key events */
277 static BOOL TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] )
278 {
279 int i,j,k,l,m,n;
280 static int count=0;
281 KEV kbuf[MAXKEYEVENTS];
282 assert( nrkev==2 || nrkev==3);
283 for(i=0;i<MAXKEYEVENTS;i++) kbuf[i]=0;
284 /* two keys involved gives 4 test cases */
285 if(nrkev==2) {
286 for(i=0;i<nrkev;i++) {
287 for(j=0;j<nrkev;j++) {
288 kbuf[0] = kevdwn[i];
289 kbuf[1] = kevdwn[1-i];
290 kbuf[2] = kevup[j];
291 kbuf[3] = kevup[1-j];
292 if (!do_test( hWnd, count++, kbuf)) return FALSE;
293 }
294 }
295 }
296 /* three keys involved gives 36 test cases */
297 if(nrkev==3){
298 for(i=0;i<nrkev;i++){
299 for(j=0;j<nrkev;j++){
300 if(j==i) continue;
301 for(k=0;k<nrkev;k++){
302 if(k==i || k==j) continue;
303 for(l=0;l<nrkev;l++){
304 for(m=0;m<nrkev;m++){
305 if(m==l) continue;
306 for(n=0;n<nrkev;n++){
307 if(n==l ||n==m) continue;
308 kbuf[0] = kevdwn[i];
309 kbuf[1] = kevdwn[j];
310 kbuf[2] = kevdwn[k];
311 kbuf[3] = kevup[l];
312 kbuf[4] = kevup[m];
313 kbuf[5] = kevup[n];
314 if (!do_test( hWnd, count++, kbuf)) return FALSE;
315 }
316 }
317 }
318 }
319 }
320 }
321 }
322 return TRUE;
323 }
324
325 /* test each set specified in the global testkeyset array */
326 static void TestSysKeys( HWND hWnd)
327 {
328 int i;
329 for(i=0; testkeyset[i].nrkev;i++)
330 if (!TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn, testkeyset[i].keyup)) break;
331 }
332
333 static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam,
334 LPARAM lParam )
335 {
336 return DefWindowProcA( hWnd, msg, wParam, lParam );
337 }
338
339 static void test_Input_whitebox(void)
340 {
341 MSG msg;
342 WNDCLASSA wclass;
343 HANDLE hInstance = GetModuleHandleA( NULL );
344
345 wclass.lpszClassName = "InputSysKeyTestClass";
346 wclass.style = CS_HREDRAW | CS_VREDRAW;
347 wclass.lpfnWndProc = WndProc;
348 wclass.hInstance = hInstance;
349 wclass.hIcon = LoadIconA( 0, (LPCSTR)IDI_APPLICATION );
350 wclass.hCursor = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
351 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
352 wclass.lpszMenuName = 0;
353 wclass.cbClsExtra = 0;
354 wclass.cbWndExtra = 0;
355 RegisterClassA( &wclass );
356 /* create the test window that will receive the keystrokes */
357 hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest",
358 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
359 NULL, NULL, hInstance, NULL);
360 assert( hWndTest );
361 ShowWindow( hWndTest, SW_SHOW);
362 SetWindowPos( hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
363 SetForegroundWindow( hWndTest );
364 UpdateWindow( hWndTest);
365
366 /* flush pending messages */
367 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
368
369 SetFocus( hWndTest );
370 TestSysKeys( hWndTest );
371 DestroyWindow(hWndTest);
372 }
373
374 static inline BOOL is_keyboard_message( UINT message )
375 {
376 return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
377 }
378
379 static inline BOOL is_mouse_message( UINT message )
380 {
381 return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST);
382 }
383
384 /* try to make sure pending X events have been processed before continuing */
385 static void empty_message_queue(void)
386 {
387 MSG msg;
388 int diff = 200;
389 int min_timeout = 50;
390 DWORD time = GetTickCount() + diff;
391
392 while (diff > 0)
393 {
394 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
395 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
396 {
397 if (is_keyboard_message(msg.message) || is_mouse_message(msg.message))
398 ok(msg.time != 0, "message %#x has time set to 0\n", msg.message);
399
400 TranslateMessage(&msg);
401 DispatchMessageA(&msg);
402 }
403 diff = time - GetTickCount();
404 }
405 }
406
407 struct transition_s {
408 WORD wVk;
409 BYTE before_state;
410 BYTE optional;
411 };
412
413 typedef enum {
414 sent=0x1,
415 posted=0x2,
416 parent=0x4,
417 wparam=0x8,
418 lparam=0x10,
419 defwinproc=0x20,
420 beginpaint=0x40,
421 optional=0x80,
422 hook=0x100,
423 winevent_hook=0x200
424 } msg_flags_t;
425
426 struct message {
427 UINT message; /* the WM_* code */
428 msg_flags_t flags; /* message props */
429 WPARAM wParam; /* expected value of wParam */
430 LPARAM lParam; /* expected value of lParam */
431 };
432
433 static const struct sendinput_test_s {
434 WORD wVk;
435 DWORD dwFlags;
436 BOOL _todo_wine;
437 struct transition_s expected_transitions[MAXKEYEVENTS+1];
438 struct message expected_messages[MAXKEYMESSAGES+1];
439 } sendinput_test[] = {
440 /* test ALT+F */
441 /* 0 */
442 {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
443 {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}},
444 {'F', 0, FALSE, {{'F', 0x00}, {0}},
445 {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN},
446 {WM_SYSCHAR},
447 {WM_SYSCOMMAND}, {0}}},
448 {'F', KEYEVENTF_KEYUP, FALSE, {{'F', 0x80}, {0}},
449 {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
450 {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
451 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
452
453 /* test CTRL+O */
454 /* 4 */
455 {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
456 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
457 {'O', 0, FALSE, {{'O', 0x00}, {0}},
458 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
459 {'O', KEYEVENTF_KEYUP, FALSE, {{'O', 0x80}, {0}},
460 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
461 {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
462 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
463
464 /* test ALT+CTRL+X */
465 /* 8 */
466 {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
467 {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}},
468 {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
469 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
470 {'X', 0, FALSE, {{'X', 0x00}, {0}},
471 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
472 {'X', KEYEVENTF_KEYUP, FALSE, {{'X', 0x80}, {0}},
473 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
474 {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
475 {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
476 {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
477 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
478
479 /* test SHIFT+A */
480 /* 14 */
481 {VK_LSHIFT, 0, FALSE, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
482 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
483 {'A', 0, FALSE, {{'A', 0x00}, {0}},
484 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
485 {'A', KEYEVENTF_KEYUP, FALSE, {{'A', 0x80}, {0}},
486 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
487 {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
488 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
489 /* test L-SHIFT & R-SHIFT: */
490 /* RSHIFT == LSHIFT */
491 /* 18 */
492 {VK_RSHIFT, 0, FALSE,
493 /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
494 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}},
495 {{WM_KEYDOWN, hook|wparam, VK_RSHIFT},
496 {WM_KEYDOWN}, {0}}},
497 {VK_RSHIFT, KEYEVENTF_KEYUP, FALSE,
498 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}},
499 {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT},
500 {WM_KEYUP}, {0}}},
501
502 /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
503 /* 20 */
504 {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
505 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
506 {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED},
507 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
508 {VK_LSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
509 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
510 {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED},
511 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
512 /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
513 /* 22 */
514 {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
515 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
516 {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
517 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
518 {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
519 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
520 {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
521 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
522
523 /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
524 win2k - sends to hook whatever we generated here
525 winXP+ - Attempts to convert key to L/R key but not always correct
526 */
527 /* SHIFT == LSHIFT */
528 /* 24 */
529 {VK_SHIFT, 0, FALSE,
530 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
531 {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0},
532 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
533 {VK_SHIFT, KEYEVENTF_KEYUP, FALSE,
534 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
535 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP},
536 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
537 /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
538 /* 26 */
539 {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
540 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
541 {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED},
542 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
543 {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
544 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
545 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED},
546 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
547
548 /* test L-CONTROL & R-CONTROL: */
549 /* RCONTROL == LCONTROL */
550 /* 28 */
551 {VK_RCONTROL, 0, FALSE,
552 {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
553 {{WM_KEYDOWN, hook|wparam, VK_RCONTROL},
554 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
555 {VK_RCONTROL, KEYEVENTF_KEYUP, FALSE,
556 {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
557 {{WM_KEYUP, hook|wparam, VK_RCONTROL},
558 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
559 /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
560 /* 30 */
561 {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
562 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
563 {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED},
564 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
565 {VK_LCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
566 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
567 {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED},
568 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
569 /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
570 /* 32 */
571 {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
572 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
573 {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED},
574 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
575 {VK_RCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
576 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
577 {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED},
578 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
579 /* CONTROL == LCONTROL */
580 /* 34 */
581 {VK_CONTROL, 0, FALSE,
582 {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
583 {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/},
584 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
585 {VK_CONTROL, KEYEVENTF_KEYUP, FALSE,
586 {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
587 {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/},
588 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
589 /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
590 /* 36 */
591 {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
592 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
593 {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED},
594 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
595 {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
596 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
597 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED},
598 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
599
600 /* test L-MENU & R-MENU: */
601 /* RMENU == LMENU */
602 /* 38 */
603 {VK_RMENU, 0, FALSE,
604 {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
605 {{WM_SYSKEYDOWN, hook|wparam|optional, VK_LCONTROL},
606 {WM_SYSKEYDOWN, hook|wparam, VK_RMENU},
607 {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
608 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
609 {VK_RMENU, KEYEVENTF_KEYUP, TRUE,
610 {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
611 {{WM_KEYUP, hook|wparam|optional, VK_LCONTROL},
612 {WM_KEYUP, hook|wparam, VK_RMENU},
613 {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
614 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
615 {WM_SYSCOMMAND, optional}, {0}}},
616 /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
617 /* 40 */
618 {VK_LMENU, KEYEVENTF_EXTENDEDKEY, FALSE,
619 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
620 {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED},
621 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
622 {VK_LMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
623 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}},
624 {{WM_KEYUP, hook|wparam|lparam, VK_LMENU, LLKHF_UP|LLKHF_EXTENDED},
625 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
626 {WM_SYSCOMMAND}, {0}}},
627 /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
628 /* 42 */
629 {VK_RMENU, KEYEVENTF_EXTENDEDKEY, FALSE,
630 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
631 {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_LCONTROL, 0},
632 {WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED},
633 {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
634 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
635 {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
636 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
637 {{WM_KEYUP, hook|wparam|lparam|optional, VK_LCONTROL, LLKHF_UP},
638 {WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED},
639 {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
640 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
641 {WM_SYSCOMMAND, optional}, {0}}},
642 /* MENU == LMENU */
643 /* 44 */
644 {VK_MENU, 0, FALSE,
645 {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
646 {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/},
647 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
648 {VK_MENU, KEYEVENTF_KEYUP, TRUE,
649 {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
650 {{WM_KEYUP, hook/*|wparam, VK_MENU*/},
651 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
652 {WM_SYSCOMMAND}, {0}}},
653 /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
654 /* 46 */
655 {VK_MENU, KEYEVENTF_EXTENDEDKEY, FALSE,
656 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
657 {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_CONTROL, 0},
658 {WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED},
659 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
660 {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
661 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
662 {{WM_KEYUP, hook|wparam|lparam|optional, VK_CONTROL, LLKHF_UP},
663 {WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED},
664 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
665 {WM_SYSCOMMAND}, {0}}},
666
667 /* test LSHIFT & RSHIFT */
668 /* 48 */
669 {VK_LSHIFT, 0, FALSE,
670 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
671 {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0},
672 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
673 {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
674 {{VK_RSHIFT, 0x00}, {0}},
675 {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
676 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
677 {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
678 {{VK_RSHIFT, 0x80}, {0}},
679 {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
680 {WM_KEYUP, optional}, {0}}},
681 {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE,
682 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
683 {{WM_KEYUP, hook|wparam, VK_LSHIFT},
684 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
685
686 {0, 0, FALSE, {{0}}, {{0}}} /* end */
687 };
688
689 static struct message sent_messages[MAXKEYMESSAGES];
690 static UINT sent_messages_cnt;
691
692 /* Verify that only specified key state transitions occur */
693 static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, const struct sendinput_test_s *test)
694 {
695 int i, failcount = 0;
696 const struct transition_s *t = test->expected_transitions;
697 UINT actual_cnt = 0;
698 const struct message *expected = test->expected_messages;
699
700 while (t->wVk) {
701 BOOL matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80)
702 && (ks2[t->wVk]&0x80) == (~t->before_state&0x80));
703
704 if (!matched && !t->optional && test->_todo_wine)
705 {
706 failcount++;
707 todo_wine {
708 ok(matched, "%2d (%x/%x): %02x from %02x -> %02x "
709 "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
710 t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
711 ~t->before_state&0x80);
712 }
713 } else {
714 ok(matched || t->optional, "%2d (%x/%x): %02x from %02x -> %02x "
715 "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
716 t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
717 ~t->before_state&0x80);
718 }
719 ks2[t->wVk] = ks1[t->wVk]; /* clear the match */
720 t++;
721 }
722 for (i = 0; i < 256; i++)
723 if (ks2[i] != ks1[i] && test->_todo_wine)
724 {
725 failcount++;
726 todo_wine
727 ok(FALSE, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
728 id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
729 }
730 else
731 ok(ks2[i] == ks1[i], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
732 id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
733
734 while (expected->message && actual_cnt < sent_messages_cnt)
735 {
736 const struct message *actual = &sent_messages[actual_cnt];
737
738 if (expected->message == actual->message)
739 {
740 if (expected->flags & wparam)
741 {
742 if ((expected->flags & optional) && (expected->wParam != actual->wParam))
743 {
744 expected++;
745 continue;
746 }
747 if (expected->wParam != actual->wParam && test->_todo_wine)
748 {
749 failcount++;
750 todo_wine
751 ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
752 id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
753 }
754 else
755 ok(expected->wParam == actual->wParam,
756 "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
757 id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
758 }
759 if (expected->flags & lparam)
760 {
761 if (expected->lParam != actual->lParam && test->_todo_wine)
762 {
763 failcount++;
764 todo_wine
765 ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
766 id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
767 }
768 else
769 ok(expected->lParam == actual->lParam,
770 "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
771 id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
772 }
773 ok((expected->flags & hook) == (actual->flags & hook),
774 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
775 id, test->wVk, test->dwFlags, expected->message);
776
777 }
778 else if (expected->flags & optional)
779 {
780 expected++;
781 continue;
782 }
783 /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
784 else if ((expected->flags & hook) &&
785 (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
786 (actual->message == expected->message - 4))
787 {
788 ok((expected->flags & hook) == (actual->flags & hook),
789 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
790 id, test->wVk, test->dwFlags, expected->message);
791 }
792 /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
793 * instead of SYSKEYDOWN/UP to the WNDPROC */
794 else if (test->wVk == VK_RMENU && !(expected->flags & hook) &&
795 (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
796 (actual->message == expected->message - 4))
797 {
798 ok(expected->wParam == actual->wParam && expected->lParam == actual->lParam,
799 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
800 id, test->wVk, test->dwFlags, expected->message, actual->message);
801 }
802 else if (test->_todo_wine)
803 {
804 failcount++;
805 todo_wine
806 ok(FALSE,
807 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
808 id, test->wVk, test->dwFlags, expected->message, actual->message);
809 }
810 else
811 ok(FALSE,
812 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
813 id, test->wVk, test->dwFlags, expected->message, actual->message);
814
815 actual_cnt++;
816 expected++;
817 }
818 /* skip all optional trailing messages */
819 while (expected->message && (expected->flags & optional))
820 expected++;
821
822
823 if (expected->message || actual_cnt < sent_messages_cnt)
824 {
825 if (test->_todo_wine)
826 {
827 failcount++;
828 todo_wine
829 ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
830 id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
831 }
832 else
833 ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
834 id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
835 }
836
837 if( test->_todo_wine && !failcount) /* succeeded yet marked todo */
838 todo_wine
839 ok(TRUE, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags);
840
841 sent_messages_cnt = 0;
842 }
843
844 /* WndProc2 checks that we get at least the messages specified */
845 static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam,
846 LPARAM lParam)
847 {
848 if (winetest_debug > 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg, wParam, lParam);
849
850 if (Msg != WM_PAINT &&
851 Msg != WM_NCPAINT &&
852 Msg != WM_SYNCPAINT &&
853 Msg != WM_ERASEBKGND &&
854 Msg != WM_NCHITTEST &&
855 Msg != WM_GETTEXT &&
856 Msg != WM_GETICON &&
857 Msg != WM_IME_SELECT &&
858 Msg != WM_DEVICECHANGE &&
859 Msg != WM_TIMECHANGE)
860 {
861 ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
862 if (sent_messages_cnt < MAXKEYMESSAGES)
863 {
864 sent_messages[sent_messages_cnt].message = Msg;
865 sent_messages[sent_messages_cnt].flags = 0;
866 sent_messages[sent_messages_cnt].wParam = wParam;
867 sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED);
868 }
869 }
870 return DefWindowProcA(hWnd, Msg, wParam, lParam);
871 }
872
873 static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam)
874 {
875 KBDLLHOOKSTRUCT *hook_info = (KBDLLHOOKSTRUCT *)lparam;
876
877 if (code == HC_ACTION)
878 {
879 ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
880 if (sent_messages_cnt < MAXKEYMESSAGES)
881 {
882 sent_messages[sent_messages_cnt].message = wparam;
883 sent_messages[sent_messages_cnt].flags = hook;
884 sent_messages[sent_messages_cnt].wParam = hook_info->vkCode;
885 sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED);
886 }
887
888 if(0) /* For some reason not stable on Wine */
889 {
890 if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN)
891 ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %x should be up\n", hook_info->vkCode);
892 else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP)
893 ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %x should be down\n", hook_info->vkCode);
894 }
895
896 if (winetest_debug > 1)
897 trace("Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam,
898 hook_info->vkCode, hook_info->scanCode, hook_info->flags, hook_info->dwExtraInfo);
899 }
900 return CallNextHookEx( 0, code, wparam, lparam );
901 }
902 static void test_Input_blackbox(void)
903 {
904 TEST_INPUT i;
905 int ii;
906 BYTE ks1[256], ks2[256];
907 LONG_PTR prevWndProc;
908 HWND window;
909 HHOOK hook;
910
911 if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409)
912 {
913 skip("Skipping Input_blackbox test on non-US keyboard\n");
914 return;
915 }
916 window = CreateWindowA("Static", NULL, WS_POPUP|WS_HSCROLL|WS_VSCROLL
917 |WS_VISIBLE, 0, 0, 200, 60, NULL, NULL,
918 NULL, NULL);
919 ok(window != NULL, "error: %d\n", (int) GetLastError());
920 SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
921 SetForegroundWindow( window );
922
923 if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0)))
924 {
925 DestroyWindow(window);
926 win_skip("WH_KEYBOARD_LL is not supported\n");
927 return;
928 }
929
930 /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
931 * key state set by SendInput(). */
932 empty_message_queue();
933
934 prevWndProc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR) WndProc2);
935 ok(prevWndProc != 0 || (prevWndProc == 0 && GetLastError() == 0),
936 "error: %d\n", (int) GetLastError());
937
938 i.type = INPUT_KEYBOARD;
939 i.u.ki.time = 0;
940 i.u.ki.dwExtraInfo = 0;
941
942 for (ii = 0; ii < sizeof(sendinput_test)/sizeof(struct sendinput_test_s)-1;
943 ii++) {
944 GetKeyboardState(ks1);
945 i.u.ki.wScan = ii+1 /* useful for debugging */;
946 i.u.ki.dwFlags = sendinput_test[ii].dwFlags;
947 i.u.ki.wVk = sendinput_test[ii].wVk;
948 pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT));
949 empty_message_queue();
950 GetKeyboardState(ks2);
951 if (!ii && sent_messages_cnt <= 1 && !memcmp( ks1, ks2, sizeof(ks1) ))
952 {
953 win_skip( "window doesn't receive the queued input\n" );
954 /* release the key */
955 i.u.ki.dwFlags |= KEYEVENTF_KEYUP;
956 pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT));
957 break;
958 }
959 compare_and_check(ii, ks1, ks2, &sendinput_test[ii]);
960 }
961
962 empty_message_queue();
963 DestroyWindow(window);
964 UnhookWindowsHookEx(hook);
965 }
966
967 static void reset_key_status(void)
968 {
969 key_status.last_key_down = -1;
970 key_status.last_key_up = -1;
971 key_status.last_syskey_down = -1;
972 key_status.last_syskey_up = -1;
973 key_status.last_char = -1;
974 key_status.last_syschar = -1;
975 key_status.last_hook_down = -1;
976 key_status.last_hook_up = -1;
977 key_status.last_hook_syskey_down = -1;
978 key_status.last_hook_syskey_up = -1;
979 key_status.expect_alt = FALSE;
980 key_status.sendinput_broken = FALSE;
981 }
982
983 static void test_unicode_keys(HWND hwnd, HHOOK hook)
984 {
985 TEST_INPUT inputs[2];
986 MSG msg;
987
988 /* init input data that never changes */
989 inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
990 inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0;
991 inputs[1].u.ki.time = inputs[0].u.ki.time = 0;
992
993 /* pressing & releasing a single unicode character */
994 inputs[0].u.ki.wVk = 0;
995 inputs[0].u.ki.wScan = 0x3c0;
996 inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE;
997
998 reset_key_status();
999 pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
1000 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1001 if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
1002 TranslateMessage(&msg);
1003 }
1004 DispatchMessageW(&msg);
1005 }
1006 if(!key_status.sendinput_broken){
1007 ok(key_status.last_key_down == VK_PACKET,
1008 "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_down);
1009 ok(key_status.last_char == 0x3c0,
1010 "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status.last_char);
1011 if(hook)
1012 ok(key_status.last_hook_down == 0x3c0,
1013 "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_down);
1014 }
1015
1016 inputs[1].u.ki.wVk = 0;
1017 inputs[1].u.ki.wScan = 0x3c0;
1018 inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1019
1020 reset_key_status();
1021 pSendInput(1, (INPUT*)(inputs+1), sizeof(INPUT));
1022 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1023 if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
1024 TranslateMessage(&msg);
1025 }
1026 DispatchMessageW(&msg);
1027 }
1028 if(!key_status.sendinput_broken){
1029 ok(key_status.last_key_up == VK_PACKET,
1030 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up);
1031 if(hook)
1032 ok(key_status.last_hook_up == 0x3c0,
1033 "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_up);
1034 }
1035
1036 /* holding alt, pressing & releasing a unicode character, releasing alt */
1037 inputs[0].u.ki.wVk = VK_LMENU;
1038 inputs[0].u.ki.wScan = 0;
1039 inputs[0].u.ki.dwFlags = 0;
1040
1041 inputs[1].u.ki.wVk = 0;
1042 inputs[1].u.ki.wScan = 0x3041;
1043 inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE;
1044
1045 reset_key_status();
1046 key_status.expect_alt = TRUE;
1047 pSendInput(2, (INPUT*)inputs, sizeof(INPUT));
1048 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1049 if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1050 TranslateMessage(&msg);
1051 }
1052 DispatchMessageW(&msg);
1053 }
1054 if(!key_status.sendinput_broken){
1055 ok(key_status.last_syskey_down == VK_PACKET,
1056 "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_syskey_down);
1057 ok(key_status.last_syschar == 0x3041,
1058 "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status.last_syschar);
1059 if(hook)
1060 ok(key_status.last_hook_syskey_down == 0x3041,
1061 "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_syskey_down);
1062 }
1063
1064 inputs[1].u.ki.wVk = 0;
1065 inputs[1].u.ki.wScan = 0x3041;
1066 inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1067
1068 inputs[0].u.ki.wVk = VK_LMENU;
1069 inputs[0].u.ki.wScan = 0;
1070 inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
1071
1072 reset_key_status();
1073 key_status.expect_alt = TRUE;
1074 pSendInput(2, (INPUT*)inputs, sizeof(INPUT));
1075 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1076 if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1077 TranslateMessage(&msg);
1078 }
1079 DispatchMessageW(&msg);
1080 }
1081 if(!key_status.sendinput_broken){
1082 ok(key_status.last_key_up == VK_PACKET,
1083 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up);
1084 if(hook)
1085 ok(key_status.last_hook_up == 0x3041,
1086 "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_up);
1087 }
1088 }
1089
1090 static LRESULT CALLBACK unicode_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
1091 LPARAM lParam )
1092 {
1093 switch(msg){
1094 case WM_KEYDOWN:
1095 key_status.last_key_down = wParam;
1096 break;
1097 case WM_SYSKEYDOWN:
1098 key_status.last_syskey_down = wParam;
1099 break;
1100 case WM_KEYUP:
1101 key_status.last_key_up = wParam;
1102 break;
1103 case WM_SYSKEYUP:
1104 key_status.last_syskey_up = wParam;
1105 break;
1106 case WM_CHAR:
1107 key_status.last_char = wParam;
1108 break;
1109 case WM_SYSCHAR:
1110 key_status.last_syschar = wParam;
1111 break;
1112 }
1113 return DefWindowProcW(hWnd, msg, wParam, lParam);
1114 }
1115
1116 static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lParam)
1117 {
1118 if(nCode == HC_ACTION){
1119 LPKBDLLHOOKSTRUCT info = (LPKBDLLHOOKSTRUCT)lParam;
1120 if(!info->vkCode){
1121 key_status.sendinput_broken = TRUE;
1122 win_skip("SendInput doesn't support unicode on this platform\n");
1123 }else{
1124 if(key_status.expect_alt){
1125 ok(info->vkCode == VK_LMENU, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU, info->vkCode);
1126 key_status.expect_alt = FALSE;
1127 }else
1128 ok(info->vkCode == VK_PACKET, "vkCode should have been VK_PACKET[0x%04x], was: 0x%x\n", VK_PACKET, info->vkCode);
1129 }
1130 switch(wParam){
1131 case WM_KEYDOWN:
1132 key_status.last_hook_down = info->scanCode;
1133 break;
1134 case WM_KEYUP:
1135 key_status.last_hook_up = info->scanCode;
1136 break;
1137 case WM_SYSKEYDOWN:
1138 key_status.last_hook_syskey_down = info->scanCode;
1139 break;
1140 case WM_SYSKEYUP:
1141 key_status.last_hook_syskey_up = info->scanCode;
1142 break;
1143 }
1144 }
1145 return CallNextHookEx(NULL, nCode, wParam, lParam);
1146 }
1147
1148 static void test_Input_unicode(void)
1149 {
1150 WCHAR classNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1151 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1152 WCHAR windowNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1153 'K','e','y','T','e','s','t',0};
1154 MSG msg;
1155 WNDCLASSW wclass;
1156 HANDLE hInstance = GetModuleHandleW(NULL);
1157 HHOOK hook;
1158 HMODULE hModuleImm32;
1159 BOOL (WINAPI *pImmDisableIME)(DWORD);
1160
1161 wclass.lpszClassName = classNameW;
1162 wclass.style = CS_HREDRAW | CS_VREDRAW;
1163 wclass.lpfnWndProc = unicode_wnd_proc;
1164 wclass.hInstance = hInstance;
1165 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
1166 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
1167 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1168 wclass.lpszMenuName = 0;
1169 wclass.cbClsExtra = 0;
1170 wclass.cbWndExtra = 0;
1171 if(!RegisterClassW(&wclass)){
1172 win_skip("Unicode functions not supported\n");
1173 return;
1174 }
1175
1176 hModuleImm32 = LoadLibraryA("imm32.dll");
1177 if (hModuleImm32) {
1178 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
1179 if (pImmDisableIME)
1180 pImmDisableIME(0);
1181 }
1182 pImmDisableIME = NULL;
1183 FreeLibrary(hModuleImm32);
1184
1185 /* create the test window that will receive the keystrokes */
1186 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW,
1187 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
1188 NULL, NULL, hInstance, NULL);
1189
1190 assert(hWndTest);
1191 assert(IsWindowUnicode(hWndTest));
1192
1193 hook = SetWindowsHookExW(WH_KEYBOARD_LL, llkbd_unicode_hook, GetModuleHandleW(NULL), 0);
1194 if(!hook)
1195 win_skip("unable to set WH_KEYBOARD_LL hook\n");
1196
1197 ShowWindow(hWndTest, SW_SHOW);
1198 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1199 SetForegroundWindow(hWndTest);
1200 UpdateWindow(hWndTest);
1201
1202 /* flush pending messages */
1203 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
1204
1205 SetFocus(hWndTest);
1206
1207 test_unicode_keys(hWndTest, hook);
1208
1209 if(hook)
1210 UnhookWindowsHookEx(hook);
1211 DestroyWindow(hWndTest);
1212 }
1213
1214 static void test_keynames(void)
1215 {
1216 int i, len;
1217 char buff[256];
1218
1219 for (i = 0; i < 512; i++)
1220 {
1221 strcpy(buff, "----");
1222 len = GetKeyNameTextA(i << 16, buff, sizeof(buff));
1223 ok(len || !buff[0], "%d: Buffer is not zeroed\n", i);
1224 }
1225 }
1226
1227 static POINT pt_old, pt_new;
1228 static BOOL clipped;
1229 #define STEP 3
1230
1231 static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam )
1232 {
1233 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1234 POINT pt, pt1;
1235
1236 if (code == HC_ACTION)
1237 {
1238 /* This is our new cursor position */
1239 pt_new = hook->pt;
1240 /* Should return previous position */
1241 GetCursorPos(&pt);
1242 ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1243
1244 /* Should set new position until hook chain is finished. */
1245 pt.x = pt_old.x + STEP;
1246 pt.y = pt_old.y + STEP;
1247 SetCursorPos(pt.x, pt.y);
1248 GetCursorPos(&pt1);
1249 if (clipped)
1250 ok(pt1.x == pt_old.x && pt1.y == pt_old.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y);
1251 else
1252 ok(pt1.x == pt.x && pt1.y == pt.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y);
1253 }
1254 return CallNextHookEx( 0, code, wparam, lparam );
1255 }
1256
1257 static LRESULT CALLBACK hook_proc2( int code, WPARAM wparam, LPARAM lparam )
1258 {
1259 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1260 POINT pt;
1261
1262 if (code == HC_ACTION)
1263 {
1264 ok(hook->pt.x == pt_new.x && hook->pt.y == pt_new.y,
1265 "Wrong hook coords: (%d %d) != (%d,%d)\n", hook->pt.x, hook->pt.y, pt_new.x, pt_new.y);
1266
1267 /* Should match position set above */
1268 GetCursorPos(&pt);
1269 if (clipped)
1270 ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1271 else
1272 ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1273 }
1274 return CallNextHookEx( 0, code, wparam, lparam );
1275 }
1276
1277 static void test_mouse_ll_hook(void)
1278 {
1279 HWND hwnd;
1280 HHOOK hook1, hook2;
1281 POINT pt_org, pt;
1282 RECT rc;
1283
1284 GetCursorPos(&pt_org);
1285 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1286 10, 10, 200, 200, NULL, NULL, NULL, NULL);
1287 SetCursorPos(100, 100);
1288
1289 if (!(hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0)))
1290 {
1291 win_skip( "cannot set MOUSE_LL hook\n" );
1292 goto done;
1293 }
1294 hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0);
1295
1296 GetCursorPos(&pt_old);
1297 mouse_event(MOUSEEVENTF_MOVE, -STEP, 0, 0, 0);
1298 GetCursorPos(&pt_old);
1299 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y);
1300 mouse_event(MOUSEEVENTF_MOVE, +STEP, 0, 0, 0);
1301 GetCursorPos(&pt_old);
1302 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y);
1303 mouse_event(MOUSEEVENTF_MOVE, 0, -STEP, 0, 0);
1304 GetCursorPos(&pt_old);
1305 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y);
1306 mouse_event(MOUSEEVENTF_MOVE, 0, +STEP, 0, 0);
1307 GetCursorPos(&pt_old);
1308 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y);
1309
1310 SetRect(&rc, 50, 50, 151, 151);
1311 ClipCursor(&rc);
1312 clipped = TRUE;
1313
1314 SetCursorPos(40, 40);
1315 GetCursorPos(&pt_old);
1316 ok(pt_old.x == 50 && pt_old.y == 50, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1317 SetCursorPos(160, 160);
1318 GetCursorPos(&pt_old);
1319 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1320 mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0);
1321 GetCursorPos(&pt_old);
1322 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1323
1324 clipped = FALSE;
1325 pt_new.x = pt_new.y = 150;
1326 ClipCursor(NULL);
1327 UnhookWindowsHookEx(hook1);
1328
1329 /* Now check that mouse buttons do not change mouse position
1330 if we don't have MOUSEEVENTF_MOVE flag specified. */
1331
1332 /* We reusing the same hook callback, so make it happy */
1333 pt_old.x = pt_new.x - STEP;
1334 pt_old.y = pt_new.y - STEP;
1335 mouse_event(MOUSEEVENTF_LEFTUP, 123, 456, 0, 0);
1336 GetCursorPos(&pt);
1337 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1338 mouse_event(MOUSEEVENTF_RIGHTUP, 456, 123, 0, 0);
1339 GetCursorPos(&pt);
1340 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1341
1342 mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 123, 456, 0, 0);
1343 GetCursorPos(&pt);
1344 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1345 mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE, 456, 123, 0, 0);
1346 GetCursorPos(&pt);
1347 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1348
1349 UnhookWindowsHookEx(hook2);
1350 done:
1351 DestroyWindow(hwnd);
1352 SetCursorPos(pt_org.x, pt_org.y);
1353 }
1354
1355 static void test_GetMouseMovePointsEx(void)
1356 {
1357 #define BUFLIM 64
1358 #define MYERROR 0xdeadbeef
1359 int count, retval;
1360 MOUSEMOVEPOINT in;
1361 MOUSEMOVEPOINT out[200];
1362 POINT point;
1363
1364 /* Get a valid content for the input struct */
1365 if(!GetCursorPos(&point)) {
1366 win_skip("GetCursorPos() failed with error %u\n", GetLastError());
1367 return;
1368 }
1369 memset(&in, 0, sizeof(MOUSEMOVEPOINT));
1370 in.x = point.x;
1371 in.y = point.y;
1372
1373 /* test first parameter
1374 * everything different than sizeof(MOUSEMOVEPOINT)
1375 * is expected to fail with ERROR_INVALID_PARAMETER
1376 */
1377 SetLastError(MYERROR);
1378 retval = pGetMouseMovePointsEx(0, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1379 if (retval == ERROR_INVALID_PARAMETER)
1380 {
1381 win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1382 return;
1383 }
1384 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1385 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1386 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1387
1388 SetLastError(MYERROR);
1389 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1390 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1391 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1392 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1393
1394 SetLastError(MYERROR);
1395 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1396 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1397 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1398 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1399
1400 /* test second and third parameter
1401 */
1402 SetLastError(MYERROR);
1403 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1404 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1405 ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR,
1406 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1407
1408 SetLastError(MYERROR);
1409 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1410 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1411 ok(ERROR_NOACCESS == GetLastError(),
1412 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1413
1414 SetLastError(MYERROR);
1415 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1416 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1417 ok(ERROR_NOACCESS == GetLastError(),
1418 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1419
1420 SetLastError(MYERROR);
1421 count = 0;
1422 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, count, GMMP_USE_DISPLAY_POINTS);
1423 if (retval == -1)
1424 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1425 else
1426 ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1427
1428 /* test fourth parameter
1429 * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1430 */
1431 SetLastError(MYERROR);
1432 count = -1;
1433 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1434 ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1435 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1436 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1437
1438 SetLastError(MYERROR);
1439 count = 0;
1440 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1441 if (retval == -1)
1442 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1443 else
1444 ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1445
1446 SetLastError(MYERROR);
1447 count = BUFLIM;
1448 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1449 if (retval == -1)
1450 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1451 else
1452 ok((0 <= retval) && (retval <= count), "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1453
1454 SetLastError(MYERROR);
1455 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1456 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1457 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1458 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1459
1460 /* it was not possible to force an error with the fifth parameter on win2k */
1461
1462 /* test combinations of wrong parameters to see which error wins */
1463 SetLastError(MYERROR);
1464 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1465 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1466 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1467 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1468
1469 SetLastError(MYERROR);
1470 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1471 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1472 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1473 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1474
1475 SetLastError(MYERROR);
1476 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1477 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1478 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1479 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1480
1481 SetLastError(MYERROR);
1482 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1483 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1484 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1485 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1486
1487 #undef BUFLIM
1488 #undef MYERROR
1489 }
1490
1491 static void test_GetRawInputDeviceList(void)
1492 {
1493 RAWINPUTDEVICELIST devices[32];
1494 UINT ret, oret, devcount, odevcount;
1495 DWORD err;
1496
1497 SetLastError(0xdeadbeef);
1498 ret = pGetRawInputDeviceList(NULL, NULL, 0);
1499 err = GetLastError();
1500 ok(ret == -1, "expected -1, got %d\n", ret);
1501 ok(err == ERROR_INVALID_PARAMETER, "expected 87, got %d\n", err);
1502
1503 SetLastError(0xdeadbeef);
1504 ret = pGetRawInputDeviceList(NULL, NULL, sizeof(devices[0]));
1505 err = GetLastError();
1506 ok(ret == -1, "expected -1, got %d\n", ret);
1507 ok(err == ERROR_NOACCESS, "expected 998, got %d\n", err);
1508
1509 devcount = 0;
1510 ret = pGetRawInputDeviceList(NULL, &devcount, sizeof(devices[0]));
1511 ok(ret == 0, "expected 0, got %d\n", ret);
1512 ok(devcount > 0, "expected non-zero\n");
1513
1514 SetLastError(0xdeadbeef);
1515 devcount = 0;
1516 ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0]));
1517 err = GetLastError();
1518 ok(ret == -1, "expected -1, got %d\n", ret);
1519 ok(err == ERROR_INSUFFICIENT_BUFFER, "expected 122, got %d\n", err);
1520 ok(devcount > 0, "expected non-zero\n");
1521
1522 /* devcount contains now the correct number of devices */
1523 ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0]));
1524 ok(ret > 0, "expected non-zero\n");
1525
1526 /* check if variable changes from larger to smaller value */
1527 devcount = odevcount = sizeof(devices) / sizeof(devices[0]);
1528 oret = ret = pGetRawInputDeviceList(devices, &odevcount, sizeof(devices[0]));
1529 ok(ret > 0, "expected non-zero\n");
1530 ok(devcount == odevcount, "expected %d, got %d\n", devcount, odevcount);
1531 devcount = odevcount;
1532 odevcount = sizeof(devices) / sizeof(devices[0]);
1533 ret = pGetRawInputDeviceList(NULL, &odevcount, sizeof(devices[0]));
1534 ok(ret == 0, "expected 0, got %d\n", ret);
1535 ok(odevcount == oret, "expected %d, got %d\n", oret, odevcount);
1536 }
1537
1538 static void test_key_map(void)
1539 {
1540 HKL kl = GetKeyboardLayout(0);
1541 UINT kL, kR, s, sL;
1542 int i;
1543 static const UINT numpad_collisions[][2] = {
1544 { VK_NUMPAD0, VK_INSERT },
1545 { VK_NUMPAD1, VK_END },
1546 { VK_NUMPAD2, VK_DOWN },
1547 { VK_NUMPAD3, VK_NEXT },
1548 { VK_NUMPAD4, VK_LEFT },
1549 { VK_NUMPAD6, VK_RIGHT },
1550 { VK_NUMPAD7, VK_HOME },
1551 { VK_NUMPAD8, VK_UP },
1552 { VK_NUMPAD9, VK_PRIOR },
1553 };
1554
1555 s = MapVirtualKeyExA(VK_SHIFT, MAPVK_VK_TO_VSC, kl);
1556 ok(s != 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
1557 sL = MapVirtualKeyExA(VK_LSHIFT, MAPVK_VK_TO_VSC, kl);
1558 ok(s == sL || broken(sL == 0), /* win9x */
1559 "%x != %x\n", s, sL);
1560
1561 kL = MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK, kl);
1562 ok(kL == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL);
1563 kR = MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK, kl);
1564 ok(kR == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR);
1565
1566 kL = MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK_EX, kl);
1567 ok(kL == VK_LSHIFT || broken(kL == 0), /* win9x */
1568 "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL);
1569 kR = MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK_EX, kl);
1570 ok(kR == VK_RSHIFT || broken(kR == 0), /* win9x */
1571 "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR);
1572
1573 /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
1574 for (i = 0; i < sizeof(numpad_collisions)/sizeof(numpad_collisions[0]); i++)
1575 {
1576 UINT numpad_scan = MapVirtualKeyExA(numpad_collisions[i][0], MAPVK_VK_TO_VSC, kl);
1577 UINT other_scan = MapVirtualKeyExA(numpad_collisions[i][1], MAPVK_VK_TO_VSC, kl);
1578
1579 /* do they really collide for this layout? */
1580 if (numpad_scan && other_scan == numpad_scan)
1581 {
1582 UINT vkey = MapVirtualKeyExA(numpad_scan, MAPVK_VSC_TO_VK, kl);
1583 ok(vkey != numpad_collisions[i][0],
1584 "Got numpad vKey %x for scan code %x when there was another choice\n",
1585 vkey, numpad_scan);
1586 }
1587 }
1588 }
1589
1590 #define shift 1
1591 #define ctrl 2
1592
1593 static const struct tounicode_tests
1594 {
1595 UINT vk;
1596 DWORD modifiers;
1597 WCHAR chr; /* if vk is 0, lookup vk using this char */
1598 int expect_ret;
1599 WCHAR expect_buf[4];
1600 } utests[] =
1601 {
1602 { 'A', 0, 0, 1, {'a',0}},
1603 { 'A', ctrl, 0, 1, {1, 0}},
1604 { 'A', shift|ctrl, 0, 1, {1, 0}},
1605 { VK_TAB, ctrl, 0, 0, {0}},
1606 { VK_TAB, shift|ctrl, 0, 0, {0}},
1607 { VK_RETURN, ctrl, 0, 1, {'\n', 0}},
1608 { VK_RETURN, shift|ctrl, 0, 0, {0}},
1609 { '4', ctrl, 0, 0, {0}},
1610 { '4', shift|ctrl, 0, 0, {0}},
1611 { 0, ctrl, '!', 0, {0}},
1612 { 0, ctrl, '\"', 0, {0}},
1613 { 0, ctrl, '#', 0, {0}},
1614 { 0, ctrl, '$', 0, {0}},
1615 { 0, ctrl, '%', 0, {0}},
1616 { 0, ctrl, '\'', 0, {0}},
1617 { 0, ctrl, '(', 0, {0}},
1618 { 0, ctrl, ')', 0, {0}},
1619 { 0, ctrl, '*', 0, {0}},
1620 { 0, ctrl, '+', 0, {0}},
1621 { 0, ctrl, ',', 0, {0}},
1622 { 0, ctrl, '-', 0, {0}},
1623 { 0, ctrl, '.', 0, {0}},
1624 { 0, ctrl, '/', 0, {0}},
1625 { 0, ctrl, ':', 0, {0}},
1626 { 0, ctrl, ';', 0, {0}},
1627 { 0, ctrl, '<', 0, {0}},
1628 { 0, ctrl, '=', 0, {0}},
1629 { 0, ctrl, '>', 0, {0}},
1630 { 0, ctrl, '?', 0, {0}},
1631 { 0, ctrl, '@', 1, {0}},
1632 { 0, ctrl, '[', 1, {0x1b}},
1633 { 0, ctrl, '\\', 1, {0x1c}},
1634 { 0, ctrl, ']', 1, {0x1d}},
1635 { 0, ctrl, '^', 1, {0x1e}},
1636 { 0, ctrl, '_', 1, {0x1f}},
1637 { 0, ctrl, '`', 0, {0}},
1638 { VK_SPACE, 0, 0, 1, {' ',0}},
1639 { VK_SPACE, shift, 0, 1, {' ',0}},
1640 { VK_SPACE, ctrl, 0, 1, {' ',0}},
1641 };
1642
1643 static void test_ToUnicode(void)
1644 {
1645 WCHAR wStr[4];
1646 BYTE state[256];
1647 const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f, SC_A = 0x1e;
1648 const BYTE HIGHEST_BIT = 0x80;
1649 int i, ret;
1650 for(i=0; i<256; i++)
1651 state[i]=0;
1652
1653 wStr[1] = 0xAA;
1654 SetLastError(0xdeadbeef);
1655 ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 4, 0);
1656 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1657 {
1658 win_skip("ToUnicode is not implemented\n");
1659 return;
1660 }
1661
1662 ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret);
1663 if(ret == 1)
1664 {
1665 ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]);
1666 ok(wStr[1]==0 || broken(wStr[1]!=0) /* nt4 */,
1667 "ToUnicode didn't null-terminate the buffer when there was room.\n");
1668 }
1669
1670 for (i = 0; i < sizeof(utests) / sizeof(utests[0]); i++)
1671 {
1672 UINT vk = utests[i].vk, mod = utests[i].modifiers, scan;
1673
1674 if(!vk)
1675 {
1676 short vk_ret = VkKeyScanW(utests[i].chr);
1677 if (vk_ret == -1) continue;
1678 vk = vk_ret & 0xff;
1679 if (vk_ret & 0x100) mod |= shift;
1680 if (vk_ret & 0x200) mod |= ctrl;
1681 }
1682 scan = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC);
1683
1684 state[VK_SHIFT] = state[VK_LSHIFT] = (mod & shift) ? HIGHEST_BIT : 0;
1685 state[VK_CONTROL] = state[VK_LCONTROL] = (mod & ctrl) ? HIGHEST_BIT : 0;
1686
1687 ret = ToUnicode(vk, scan, state, wStr, 4, 0);
1688 ok(ret == utests[i].expect_ret, "%d: got %d expected %d\n", i, ret, utests[i].expect_ret);
1689 if (ret)
1690 ok(!lstrcmpW(wStr, utests[i].expect_buf), "%d: got %s expected %s\n", i, wine_dbgstr_w(wStr),
1691 wine_dbgstr_w(utests[i].expect_buf));
1692
1693 }
1694 state[VK_SHIFT] = state[VK_LSHIFT] = 0;
1695 state[VK_CONTROL] = state[VK_LCONTROL] = 0;
1696
1697 ret = ToUnicode(VK_TAB, SC_TAB, NULL, wStr, 4, 0);
1698 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
1699 ret = ToUnicode(VK_RETURN, SC_RETURN, NULL, wStr, 4, 0);
1700 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
1701 ret = ToUnicode('A', SC_A, NULL, wStr, 4, 0);
1702 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
1703 ret = ToUnicodeEx(VK_TAB, SC_TAB, NULL, wStr, 4, 0, GetKeyboardLayout(0));
1704 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
1705 ret = ToUnicodeEx(VK_RETURN, SC_RETURN, NULL, wStr, 4, 0, GetKeyboardLayout(0));
1706 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
1707 ret = ToUnicodeEx('A', SC_A, NULL, wStr, 4, 0, GetKeyboardLayout(0));
1708 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
1709 }
1710
1711 static void test_ToAscii(void)
1712 {
1713 WORD character;
1714 BYTE state[256];
1715 const BYTE SC_RETURN = 0x1c, SC_A = 0x1e;
1716 const BYTE HIGHEST_BIT = 0x80;
1717 int ret;
1718
1719 memset(state, 0, sizeof(state));
1720
1721 character = 0;
1722 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
1723 ok(ret == 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret);
1724 ok(character == '\r', "ToAscii for Return was %i (expected 13)\n", character);
1725
1726 character = 0;
1727 ret = ToAscii('A', SC_A, state, &character, 0);
1728 ok(ret == 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret);
1729 ok(character == 'a', "ToAscii for character 'A' was %i (expected %i)\n", character, 'a');
1730
1731 state[VK_CONTROL] |= HIGHEST_BIT;
1732 state[VK_LCONTROL] |= HIGHEST_BIT;
1733 character = 0;
1734 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
1735 ok(ret == 1, "ToAscii for CTRL + Return key didn't return 1 (was %i)\n", ret);
1736 ok(character == '\n', "ToAscii for CTRL + Return was %i (expected 10)\n", character);
1737
1738 character = 0;
1739 ret = ToAscii('A', SC_A, state, &character, 0);
1740 ok(ret == 1, "ToAscii for CTRL + character 'A' didn't return 1 (was %i)\n", ret);
1741 ok(character == 1, "ToAscii for CTRL + character 'A' was %i (expected 1)\n", character);
1742
1743 state[VK_SHIFT] |= HIGHEST_BIT;
1744 state[VK_LSHIFT] |= HIGHEST_BIT;
1745 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
1746 ok(ret == 0, "ToAscii for CTRL + Shift + Return key didn't return 0 (was %i)\n", ret);
1747
1748 ret = ToAscii(VK_RETURN, SC_RETURN, NULL, &character, 0);
1749 ok(ret == 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret);
1750 ret = ToAscii('A', SC_A, NULL, &character, 0);
1751 ok(ret == 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret);
1752 ret = ToAsciiEx(VK_RETURN, SC_RETURN, NULL, &character, 0, GetKeyboardLayout(0));
1753 ok(ret == 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret);
1754 ret = ToAsciiEx('A', SC_A, NULL, &character, 0, GetKeyboardLayout(0));
1755 ok(ret == 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret);
1756 }
1757
1758 static void test_get_async_key_state(void)
1759 {
1760 /* input value sanity checks */
1761 ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
1762 ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
1763 }
1764
1765 static void test_keyboard_layout_name(void)
1766 {
1767 BOOL ret;
1768 char klid[KL_NAMELENGTH];
1769
1770 if (0) /* crashes on native system */
1771 ret = GetKeyboardLayoutNameA(NULL);
1772
1773 SetLastError(0xdeadbeef);
1774 ret = GetKeyboardLayoutNameW(NULL);
1775 ok(!ret, "got %d\n", ret);
1776 ok(GetLastError() == ERROR_NOACCESS, "got %d\n", GetLastError());
1777
1778 if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) return;
1779
1780 klid[0] = 0;
1781 ret = GetKeyboardLayoutNameA(klid);
1782 ok(ret, "GetKeyboardLayoutNameA failed %u\n", GetLastError());
1783 ok(!strcmp(klid, "00000409"), "expected 00000409, got %s\n", klid);
1784 }
1785
1786 static void test_key_names(void)
1787 {
1788 char buffer[40];
1789 WCHAR bufferW[40];
1790 int ret, prev;
1791 LONG lparam = 0x1d << 16;
1792
1793 memset( buffer, 0xcc, sizeof(buffer) );
1794 ret = GetKeyNameTextA( lparam, buffer, sizeof(buffer) );
1795 ok( ret > 0, "wrong len %u for '%s'\n", ret, buffer );
1796 ok( ret == strlen(buffer), "wrong len %u for '%s'\n", ret, buffer );
1797
1798 memset( buffer, 0xcc, sizeof(buffer) );
1799 prev = ret;
1800 ret = GetKeyNameTextA( lparam, buffer, prev );
1801 ok( ret == prev - 1, "wrong len %u for '%s'\n", ret, buffer );
1802 ok( ret == strlen(buffer), "wrong len %u for '%s'\n", ret, buffer );
1803
1804 memset( buffer, 0xcc, sizeof(buffer) );
1805 ret = GetKeyNameTextA( lparam, buffer, 0 );
1806 ok( ret == 0, "wrong len %u for '%s'\n", ret, buffer );
1807 ok( buffer[0] == 0, "wrong string '%s'\n", buffer );
1808
1809 memset( bufferW, 0xcc, sizeof(bufferW) );
1810 ret = GetKeyNameTextW( lparam, bufferW, sizeof(bufferW)/sizeof(WCHAR) );
1811 ok( ret > 0, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
1812 ok( ret == lstrlenW(bufferW), "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
1813
1814 memset( bufferW, 0xcc, sizeof(bufferW) );
1815 prev = ret;
1816 ret = GetKeyNameTextW( lparam, bufferW, prev );
1817 ok( ret == prev - 1, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
1818 ok( ret == lstrlenW(bufferW), "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
1819
1820 memset( bufferW, 0xcc, sizeof(bufferW) );
1821 ret = GetKeyNameTextW( lparam, bufferW, 0 );
1822 ok( ret == 0, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
1823 ok( bufferW[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW) );
1824 }
1825
1826 static void simulate_click(BOOL left, int x, int y)
1827 {
1828 INPUT input[2];
1829 UINT events_no;
1830
1831 SetCursorPos(x, y);
1832 memset(input, 0, sizeof(input));
1833 input[0].type = INPUT_MOUSE;
1834 U(input[0]).mi.dx = x;
1835 U(input[0]).mi.dy = y;
1836 U(input[0]).mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN;
1837 input[1].type = INPUT_MOUSE;
1838 U(input[1]).mi.dx = x;
1839 U(input[1]).mi.dy = y;
1840 U(input[1]).mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP;
1841 events_no = SendInput(2, input, sizeof(input[0]));
1842 ok(events_no == 2, "SendInput returned %d\n", events_no);
1843 }
1844
1845 static BOOL wait_for_message( MSG *msg )
1846 {
1847 BOOL ret;
1848
1849 for (;;)
1850 {
1851 ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE);
1852 if (ret)
1853 {
1854 if (msg->message == WM_PAINT) DispatchMessageA(msg);
1855 else break;
1856 }
1857 else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT) break;
1858 }
1859 if (!ret) msg->message = 0;
1860 return ret;
1861 }
1862
1863 static BOOL wait_for_event(HANDLE event, int timeout)
1864 {
1865 DWORD end_time = GetTickCount() + timeout;
1866 MSG msg;
1867
1868 do {
1869 if(MsgWaitForMultipleObjects(1, &event, FALSE, timeout, QS_ALLINPUT) == WAIT_OBJECT_0)
1870 return TRUE;
1871 while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
1872 DispatchMessageA(&msg);
1873 timeout = end_time - GetTickCount();
1874 }while(timeout > 0);
1875
1876 return FALSE;
1877 }
1878
1879 static WNDPROC def_static_proc;
1880 static DWORD hittest_no;
1881 static LRESULT WINAPI static_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1882 {
1883 if (msg == WM_NCHITTEST)
1884 {
1885 /* break infinite hittest loop */
1886 if(hittest_no > 50) return HTCLIENT;
1887 hittest_no++;
1888 }
1889
1890 return def_static_proc(hwnd, msg, wp, lp);
1891 }
1892
1893 struct thread_data
1894 {
1895 HANDLE start_event;
1896 HANDLE end_event;
1897 HWND win;
1898 };
1899
1900 static DWORD WINAPI create_static_win(void *arg)
1901 {
1902 struct thread_data *thread_data = arg;
1903 HWND win;
1904
1905 win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
1906 100, 100, 100, 100, 0, NULL, NULL, NULL);
1907 ok(win != 0, "CreateWindow failed\n");
1908 def_static_proc = (void*)SetWindowLongPtrA(win,
1909 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
1910 thread_data->win = win;
1911
1912 SetEvent(thread_data->start_event);
1913 wait_for_event(thread_data->end_event, 5000);
1914 return 0;
1915 }
1916
1917 static void test_Input_mouse(void)
1918 {
1919 BOOL got_button_down, got_button_up;
1920 HWND hwnd, button_win, static_win;
1921 struct thread_data thread_data;
1922 HANDLE thread;
1923 DWORD thread_id;
1924 POINT pt;
1925 MSG msg;
1926
1927 button_win = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP,
1928 100, 100, 100, 100, 0, NULL, NULL, NULL);
1929 ok(button_win != 0, "CreateWindow failed\n");
1930
1931 pt.x = pt.y = 150;
1932 hwnd = WindowFromPoint(pt);
1933 if (hwnd != button_win)
1934 {
1935 skip("there's another window covering test window\n");
1936 DestroyWindow(button_win);
1937 return;
1938 }
1939
1940 /* simple button click test */
1941 simulate_click(TRUE, 150, 150);
1942 got_button_down = got_button_up = FALSE;
1943 while (wait_for_message(&msg))
1944 {
1945 DispatchMessageA(&msg);
1946
1947 if (msg.message == WM_LBUTTONDOWN)
1948 {
1949 got_button_down = TRUE;
1950 }
1951 else if (msg.message == WM_LBUTTONUP)
1952 {
1953 got_button_up = TRUE;
1954 break;
1955 }
1956 }
1957 ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
1958 ok(got_button_up, "expected WM_LBUTTONUP message\n");
1959
1960 /* click through HTTRANSPARENT child window */
1961 static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_CHILD,
1962 0, 0, 100, 100, button_win, NULL, NULL, NULL);
1963 ok(static_win != 0, "CreateWindow failed\n");
1964 def_static_proc = (void*)SetWindowLongPtrA(static_win,
1965 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
1966 simulate_click(FALSE, 150, 150);
1967 hittest_no = 0;
1968 got_button_down = got_button_up = FALSE;
1969 while (wait_for_message(&msg))
1970 {
1971 DispatchMessageA(&msg);
1972
1973 if (msg.message == WM_RBUTTONDOWN)
1974 {
1975 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
1976 got_button_down = TRUE;
1977 }
1978 else if (msg.message == WM_RBUTTONUP)
1979 {
1980 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
1981 got_button_up = TRUE;
1982 break;
1983 }
1984 }
1985 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
1986 ok(got_button_down, "expected WM_RBUTTONDOWN message\n");
1987 ok(got_button_up, "expected WM_RBUTTONUP message\n");
1988 DestroyWindow(static_win);
1989
1990 /* click through HTTRANSPARENT top-level window */
1991 static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
1992 100, 100, 100, 100, 0, NULL, NULL, NULL);
1993 ok(static_win != 0, "CreateWindow failed\n");
1994 def_static_proc = (void*)SetWindowLongPtrA(static_win,
1995 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
1996 simulate_click(TRUE, 150, 150);
1997 hittest_no = 0;
1998 got_button_down = got_button_up = FALSE;
1999 while (wait_for_message(&msg))
2000 {
2001 DispatchMessageA(&msg);
2002
2003 if (msg.message == WM_LBUTTONDOWN)
2004 {
2005 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2006 got_button_down = TRUE;
2007 }
2008 else if (msg.message == WM_LBUTTONUP)
2009 {
2010 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2011 got_button_up = TRUE;
2012 break;
2013 }
2014 }
2015 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
2016 ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
2017 ok(got_button_up, "expected WM_LBUTTONUP message\n");
2018 DestroyWindow(static_win);
2019
2020 /* click on HTTRANSPARENT top-level window that belongs to other thread */
2021 thread_data.start_event = CreateEventA(NULL, FALSE, FALSE, NULL);
2022 ok(thread_data.start_event != NULL, "CreateEvent failed\n");
2023 thread_data.end_event = CreateEventA(NULL, FALSE, FALSE, NULL);
2024 ok(thread_data.end_event != NULL, "CreateEvent failed\n");
2025 thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, NULL);
2026 ok(thread != NULL, "CreateThread failed\n");
2027 hittest_no = 0;
2028 got_button_down = got_button_up = FALSE;
2029 WaitForSingleObject(thread_data.start_event, INFINITE);
2030 simulate_click(FALSE, 150, 150);
2031 while (wait_for_message(&msg))
2032 {
2033 DispatchMessageA(&msg);
2034
2035 if (msg.message == WM_RBUTTONDOWN)
2036 got_button_down = TRUE;
2037 else if (msg.message == WM_RBUTTONUP)
2038 got_button_up = TRUE;
2039 }
2040 SetEvent(thread_data.end_event);
2041 WaitForSingleObject(thread, INFINITE);
2042 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
2043 ok(!got_button_down, "unexpected WM_RBUTTONDOWN message\n");
2044 ok(!got_button_up, "unexpected WM_RBUTTONUP message\n");
2045
2046 /* click on HTTRANSPARENT top-level window that belongs to other thread,
2047 * thread input queues are attached */
2048 thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, &thread_id);
2049 ok(thread != NULL, "CreateThread failed\n");
2050 hittest_no = 0;
2051 got_button_down = got_button_up = FALSE;
2052 WaitForSingleObject(thread_data.start_event, INFINITE);
2053 ok(AttachThreadInput(thread_id, GetCurrentThreadId(), TRUE),
2054 "AttachThreadInput failed\n");
2055 while (wait_for_message(&msg)) DispatchMessageA(&msg);
2056 SetWindowPos(thread_data.win, button_win, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2057 simulate_click(TRUE, 150, 150);
2058 while (wait_for_message(&msg))
2059 {
2060 DispatchMessageA(&msg);
2061
2062 if (msg.message == WM_LBUTTONDOWN)
2063 got_button_down = TRUE;
2064 else if (msg.message == WM_LBUTTONUP)
2065 got_button_up = TRUE;
2066 }
2067 SetEvent(thread_data.end_event);
2068 WaitForSingleObject(thread, INFINITE);
2069 todo_wine ok(hittest_no > 50, "expected loop with WM_NCHITTEST messages\n");
2070 ok(!got_button_down, "unexpected WM_LBUTTONDOWN message\n");
2071 ok(!got_button_up, "unexpected WM_LBUTTONUP message\n");
2072
2073 /* click after SetCapture call */
2074 hwnd = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP,
2075 0, 0, 100, 100, 0, NULL, NULL, NULL);
2076 ok(hwnd != 0, "CreateWindow failed\n");
2077 SetCapture(button_win);
2078 got_button_down = got_button_up = FALSE;
2079 simulate_click(FALSE, 50, 50);
2080 while (wait_for_message(&msg))
2081 {
2082 DispatchMessageA(&msg);
2083
2084 if (msg.message == WM_RBUTTONDOWN)
2085 {
2086 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2087 got_button_down = TRUE;
2088 }
2089 else if (msg.message == WM_RBUTTONUP)
2090 {
2091 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2092 got_button_up = TRUE;
2093 break;
2094 }
2095 }
2096 ok(got_button_down, "expected WM_RBUTTONDOWN message\n");
2097 ok(got_button_up, "expected WM_RBUTTONUP message\n");
2098 DestroyWindow(hwnd);
2099
2100 /* click on child window after SetCapture call */
2101 hwnd = CreateWindowA("button", "button2", WS_VISIBLE | WS_CHILD,
2102 0, 0, 100, 100, button_win, NULL, NULL, NULL);
2103 ok(hwnd != 0, "CreateWindow failed\n");
2104 got_button_down = got_button_up = FALSE;
2105 simulate_click(TRUE, 150, 150);
2106 while (wait_for_message(&msg))
2107 {
2108 DispatchMessageA(&msg);
2109
2110 if (msg.message == WM_LBUTTONDOWN)
2111 {
2112 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2113 got_button_down = TRUE;
2114 }
2115 else if (msg.message == WM_LBUTTONUP)
2116 {
2117 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
2118 got_button_up = TRUE;
2119 break;
2120 }
2121 }
2122 ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
2123 ok(got_button_up, "expected WM_LBUTTONUP message\n");
2124 DestroyWindow(hwnd);
2125 ok(ReleaseCapture(), "ReleaseCapture failed\n");
2126
2127 CloseHandle(thread_data.start_event);
2128 CloseHandle(thread_data.end_event);
2129 DestroyWindow(button_win);
2130 }
2131
2132
2133 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2134 {
2135 if (message == WM_USER+1)
2136 {
2137 HWND hwnd = (HWND)lParam;
2138 ok(GetFocus() == hwnd, "thread expected focus %p, got %p\n", hwnd, GetFocus());
2139 ok(GetActiveWindow() == hwnd, "thread expected active %p, got %p\n", hwnd, GetActiveWindow());
2140 }
2141 return DefWindowProcA(hwnd, message, wParam, lParam);
2142 }
2143
2144 struct wnd_event
2145 {
2146 HWND hwnd;
2147 HANDLE wait_event;
2148 HANDLE start_event;
2149 DWORD attach_from;
2150 DWORD attach_to;
2151 BOOL setWindows;
2152 };
2153
2154 static DWORD WINAPI thread_proc(void *param)
2155 {
2156 MSG msg;
2157 struct wnd_event *wnd_event = param;
2158 BOOL ret;
2159
2160 if (wnd_event->wait_event)
2161 {
2162 ok(WaitForSingleObject(wnd_event->wait_event, INFINITE) == WAIT_OBJECT_0,
2163 "WaitForSingleObject failed\n");
2164 CloseHandle(wnd_event->wait_event);
2165 }
2166
2167 if (wnd_event->attach_from)
2168 {
2169 ret = AttachThreadInput(wnd_event->attach_from, GetCurrentThreadId(), TRUE);
2170 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2171 }
2172
2173 if (wnd_event->attach_to)
2174 {
2175 ret = AttachThreadInput(GetCurrentThreadId(), wnd_event->attach_to, TRUE);
2176 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2177 }
2178
2179 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
2180 100, 100, 200, 200, 0, 0, 0, NULL);
2181 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
2182
2183 if (wnd_event->setWindows)
2184 {
2185 SetFocus(wnd_event->hwnd);
2186 SetActiveWindow(wnd_event->hwnd);
2187 }
2188
2189 SetEvent(wnd_event->start_event);
2190
2191 while (GetMessageA(&msg, 0, 0, 0))
2192 {
2193 TranslateMessage(&msg);
2194 DispatchMessageA(&msg);
2195 }
2196
2197 return 0;
2198 }
2199
2200 static void test_attach_input(void)
2201 {
2202 HANDLE hThread;
2203 HWND ourWnd, Wnd2;
2204 DWORD ret, tid;
2205 struct wnd_event wnd_event;
2206 WNDCLASSA cls;
2207
2208 cls.style = 0;
2209 cls.lpfnWndProc = MsgCheckProcA;
2210 cls.cbClsExtra = 0;
2211 cls.cbWndExtra = 0;
2212 cls.hInstance = GetModuleHandleA(0);
2213 cls.hIcon = 0;
2214 cls.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
2215 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2216 cls.lpszMenuName = NULL;
2217 cls.lpszClassName = "TestWindowClass";
2218 if(!RegisterClassA(&cls)) return;
2219
2220 wnd_event.wait_event = NULL;
2221 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
2222 wnd_event.attach_from = 0;
2223 wnd_event.attach_to = 0;
2224 wnd_event.setWindows = FALSE;
2225 if (!wnd_event.start_event)
2226 {
2227 win_skip("skipping interthread message test under win9x\n");
2228 return;
2229 }
2230
2231 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2232 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
2233
2234 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2235 CloseHandle(wnd_event.start_event);
2236
2237 ourWnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
2238 0, 0, 0, 0, 0, 0, 0, NULL);
2239 ok(ourWnd!= 0, "failed to create ourWnd window\n");
2240
2241 Wnd2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
2242 0, 0, 0, 0, 0, 0, 0, NULL);
2243 ok(Wnd2!= 0, "failed to create Wnd2 window\n");
2244
2245 SetFocus(ourWnd);
2246 SetActiveWindow(ourWnd);
2247
2248 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
2249 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2250
2251 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
2252 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
2253
2254 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd);
2255
2256 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
2257 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2258 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
2259 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
2260
2261 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
2262
2263 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
2264 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2265
2266 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
2267 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
2268 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd);
2269
2270 SetActiveWindow(Wnd2);
2271 SetFocus(Wnd2);
2272 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
2273 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
2274
2275 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2);
2276
2277 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
2278 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2279 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
2280 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
2281
2282 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
2283
2284 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
2285 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2286
2287 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2288 CloseHandle(hThread);
2289
2290 wnd_event.wait_event = NULL;
2291 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
2292 wnd_event.attach_from = 0;
2293 wnd_event.attach_to = 0;
2294 wnd_event.setWindows = TRUE;
2295
2296 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2297 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
2298
2299 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2300 CloseHandle(wnd_event.start_event);
2301
2302 SetFocus(ourWnd);
2303 SetActiveWindow(ourWnd);
2304
2305 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
2306 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2307
2308 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
2309 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
2310
2311 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
2312
2313 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
2314 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2315
2316 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
2317 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
2318
2319 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
2320
2321 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
2322 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2323
2324 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
2325 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
2326
2327 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
2328
2329 SetFocus(Wnd2);
2330 SetActiveWindow(Wnd2);
2331 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
2332 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
2333
2334 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2);
2335
2336 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
2337 ok(ret, "AttachThreadInput error %d\n", GetLastError());
2338
2339 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
2340 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
2341
2342 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
2343
2344 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
2345 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2346
2347 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2348 CloseHandle(hThread);
2349
2350 wnd_event.wait_event = CreateEventW(NULL, 0, 0, NULL);
2351 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
2352 wnd_event.attach_from = 0;
2353 wnd_event.attach_to = 0;
2354 wnd_event.setWindows = TRUE;
2355
2356 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2357 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
2358
2359 SetLastError(0xdeadbeef);
2360 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
2361 ok(!ret, "AttachThreadInput succeeded\n");
2362 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2363 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2364
2365 SetLastError(0xdeadbeef);
2366 ret = AttachThreadInput(tid, GetCurrentThreadId(), TRUE);
2367 ok(!ret, "AttachThreadInput succeeded\n");
2368 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2369 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2370
2371 SetEvent(wnd_event.wait_event);
2372
2373 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2374 CloseHandle(wnd_event.start_event);
2375
2376 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
2377 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2378
2379 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2380 CloseHandle(hThread);
2381
2382 wnd_event.wait_event = NULL;
2383 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
2384 wnd_event.attach_from = GetCurrentThreadId();
2385 wnd_event.attach_to = 0;
2386 wnd_event.setWindows = FALSE;
2387
2388 SetFocus(ourWnd);
2389 SetActiveWindow(ourWnd);
2390
2391 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2392 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
2393
2394 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2395 CloseHandle(wnd_event.start_event);
2396
2397 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
2398 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
2399
2400 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
2401 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2402
2403 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2404 CloseHandle(hThread);
2405
2406 wnd_event.wait_event = NULL;
2407 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
2408 wnd_event.attach_from = 0;
2409 wnd_event.attach_to = GetCurrentThreadId();
2410 wnd_event.setWindows = FALSE;
2411
2412 SetFocus(ourWnd);
2413 SetActiveWindow(ourWnd);
2414
2415 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
2416 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
2417
2418 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2419 CloseHandle(wnd_event.start_event);
2420
2421 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
2422 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
2423
2424 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
2425 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2426
2427 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
2428 CloseHandle(hThread);
2429 DestroyWindow(ourWnd);
2430 DestroyWindow(Wnd2);
2431 }
2432
2433 static DWORD WINAPI get_key_state_thread(void *arg)
2434 {
2435 HANDLE *semaphores = arg;
2436 DWORD result;
2437
2438 ReleaseSemaphore(semaphores[0], 1, NULL);
2439 result = WaitForSingleObject(semaphores[1], 1000);
2440 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
2441
2442 result = GetKeyState('X');
2443 ok((result & 0x8000) || broken(!(result & 0x8000)), /* > Win 2003 */
2444 "expected that highest bit is set, got %x\n", result);
2445
2446 ReleaseSemaphore(semaphores[0], 1, NULL);
2447 result = WaitForSingleObject(semaphores[1], 1000);
2448 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
2449
2450 result = GetKeyState('X');
2451 ok(!(result & 0x8000), "expected that highest bit is unset, got %x\n", result);
2452
2453 return 0;
2454 }
2455
2456 static void test_GetKeyState(void)
2457 {
2458 HANDLE semaphores[2];
2459 HANDLE thread;
2460 DWORD result;
2461 HWND hwnd;
2462
2463 semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL);
2464 ok(semaphores[0] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
2465 semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
2466 ok(semaphores[1] != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
2467
2468 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
2469 10, 10, 200, 200, NULL, NULL, NULL, NULL);
2470 ok(hwnd != NULL, "CreateWindowA failed %u\n", GetLastError());
2471
2472 thread = CreateThread(NULL, 0, get_key_state_thread, semaphores, 0, NULL);
2473 ok(thread != NULL, "CreateThread failed %u\n", GetLastError());
2474 result = WaitForSingleObject(semaphores[0], 1000);
2475 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
2476
2477 SetFocus(hwnd);
2478 keybd_event('X', 0, 0, 0);
2479
2480 ReleaseSemaphore(semaphores[1], 1, NULL);
2481 result = WaitForSingleObject(semaphores[0], 1000);
2482 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
2483
2484 keybd_event('X', 0, KEYEVENTF_KEYUP, 0);
2485
2486 ReleaseSemaphore(semaphores[1], 1, NULL);
2487 result = WaitForSingleObject(thread, 1000);
2488 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
2489 CloseHandle(thread);
2490
2491 DestroyWindow(hwnd);
2492 CloseHandle(semaphores[0]);
2493 CloseHandle(semaphores[1]);
2494 }
2495
2496 START_TEST(input)
2497 {
2498 init_function_pointers();
2499
2500 if (pSendInput)
2501 {
2502 test_Input_blackbox();
2503 test_Input_whitebox();
2504 test_Input_unicode();
2505 test_Input_mouse();
2506 }
2507 else win_skip("SendInput is not available\n");
2508
2509 test_keynames();
2510 test_mouse_ll_hook();
2511 test_key_map();
2512 test_ToUnicode();
2513 test_ToAscii();
2514 test_get_async_key_state();
2515 test_keyboard_layout_name();
2516 test_key_names();
2517 test_attach_input();
2518 test_GetKeyState();
2519
2520 if(pGetMouseMovePointsEx)
2521 test_GetMouseMovePointsEx();
2522 else
2523 win_skip("GetMouseMovePointsEx is not available\n");
2524
2525 if(pGetRawInputDeviceList)
2526 test_GetRawInputDeviceList();
2527 else
2528 win_skip("GetRawInputDeviceList is not available\n");
2529 }