user32/tests: Test EnableMouseInPointer behavior.
[wine.git] / dlls / user32 / tests / input.c
blobfde5aedeb4a2f635f152549b42bf0e690d77a2e1
1 /* Test Key event to Key message translation
3 * Copyright 2003 Rein Klazes
4 * Copyright 2019 Remi Bernon for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 /* test whether the right type of messages:
22 * WM_KEYUP/DOWN vs WM_SYSKEYUP/DOWN are sent in case of combined
23 * keystrokes.
25 * For instance <ALT>-X can be accomplished by
26 * the sequence ALT-KEY-DOWN, X-KEY-DOWN, ALT-KEY-UP, X-KEY-UP
27 * but also X-KEY-DOWN, ALT-KEY-DOWN, X-KEY-UP, ALT-KEY-UP
28 * Whether a KEY or a SYSKEY message is sent is not always clear, it is
29 * also not the same in WINNT as in WIN9X */
31 /* NOTE that there will be test failures under WIN9X
32 * No applications are known to me that rely on this
33 * so I don't fix it */
35 /* TODO:
36 * 1. extend it to the wm_command and wm_syscommand notifications
37 * 2. add some more tests with special cases like dead keys or right (alt) key
38 * 3. there is some adapted code from input.c in here. Should really
39 * make that code exactly the same.
40 * 4. resolve the win9x case when there is a need or the testing frame work
41 * offers a nice way.
42 * 5. The test app creates a window, the user should not take the focus
43 * away during its short existence. I could do something to prevent that
44 * if it is a problem.
48 #include <stdarg.h>
49 #include <assert.h>
51 #include "windef.h"
52 #include "winbase.h"
53 #include "wingdi.h"
54 #include "winuser.h"
55 #include "winnls.h"
56 #include "winreg.h"
57 #include "ddk/hidsdi.h"
58 #include "imm.h"
60 #include "wine/test.h"
62 /* globals */
63 static HWND hWndTest;
64 static LONG timetag = 0x10000000;
66 #define DESKTOP_ALL_ACCESS 0x01ff
68 static struct {
69 LONG last_key_down;
70 LONG last_key_up;
71 LONG last_syskey_down;
72 LONG last_syskey_up;
73 LONG last_char;
74 LONG last_syschar;
75 LONG last_hook_down;
76 LONG last_hook_up;
77 LONG last_hook_syskey_down;
78 LONG last_hook_syskey_up;
79 WORD vk;
80 BOOL expect_alt;
81 BOOL sendinput_broken;
82 } key_status;
84 static BOOL (WINAPI *pEnableMouseInPointer)( BOOL );
85 static BOOL (WINAPI *pGetCurrentInputMessageSource)( INPUT_MESSAGE_SOURCE *source );
86 static BOOL (WINAPI *pGetPointerType)(UINT32, POINTER_INPUT_TYPE*);
87 static BOOL (WINAPI *pGetPointerInfo)(UINT32, POINTER_INFO*);
88 static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD);
89 static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT);
90 static UINT (WINAPI *pGetRawInputDeviceInfoW) (HANDLE, UINT, void *, UINT *);
91 static UINT (WINAPI *pGetRawInputDeviceInfoA) (HANDLE, UINT, void *, UINT *);
92 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
94 #define MAXKEYEVENTS 12
95 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
96 and only one message */
98 /* keyboard message names, sorted as their value */
99 static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
100 "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
102 /* keyevents, add more as needed */
103 typedef enum KEVtag
104 { ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV;
105 /* matching VK's */
106 static const int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL};
107 /* matching scan codes */
108 static const int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
109 /* matching updown events */
110 static const int GETFLAGS[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP};
111 /* matching descriptions */
112 static const char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
114 typedef struct {
115 UINT message;
116 WPARAM wParam;
117 LPARAM lParam;
118 } KMSG;
120 /*******************************************
121 * add new test sets here
122 * the software will make all combinations of the
123 * keyevent defined here
125 static const struct {
126 int nrkev;
127 KEV keydwn[MAXKEYEVENTS];
128 KEV keyup[MAXKEYEVENTS];
129 } testkeyset[]= {
130 { 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}},
131 { 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}},
132 { 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}},
133 { 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}},
134 { 0 } /* mark the end */
137 /**********************adapted from input.c **********************************/
139 static BYTE InputKeyStateTable[256];
140 static BYTE AsyncKeyStateTable[256];
141 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
142 or a WM_KEYUP message */
143 static BOOL is_wow64;
145 static void init_function_pointers(void)
147 HMODULE hdll = GetModuleHandleA("user32");
149 #define GET_PROC(func) \
150 if (!(p ## func = (void*)GetProcAddress(hdll, #func))) \
151 trace("GetProcAddress(%s) failed\n", #func)
153 GET_PROC(EnableMouseInPointer);
154 GET_PROC(GetCurrentInputMessageSource);
155 GET_PROC(GetMouseMovePointsEx);
156 GET_PROC(GetPointerInfo);
157 GET_PROC(GetPointerType);
158 GET_PROC(GetRawInputDeviceList);
159 GET_PROC(GetRawInputDeviceInfoW);
160 GET_PROC(GetRawInputDeviceInfoA);
162 hdll = GetModuleHandleA("kernel32");
163 GET_PROC(IsWow64Process);
164 #undef GET_PROC
166 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ))
167 is_wow64 = FALSE;
170 static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam )
172 UINT message;
173 int VKey = GETVKEY[kev];
174 WORD flags;
176 flags = LOBYTE(GETSCAN[kev]);
177 if (GETFLAGS[kev] & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
179 if (GETFLAGS[kev] & KEYEVENTF_KEYUP )
181 message = WM_KEYUP;
182 if( (InputKeyStateTable[VK_MENU] & 0x80) && (
183 (VKey == VK_MENU) || (VKey == VK_CONTROL) ||
184 !(InputKeyStateTable[VK_CONTROL] & 0x80))) {
185 if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
186 (VKey != VK_MENU)) /* <ALT>-down...<something else>-up */
187 message = WM_SYSKEYUP;
188 TrackSysKey = 0;
190 InputKeyStateTable[VKey] &= ~0x80;
191 flags |= KF_REPEAT | KF_UP;
193 else
195 if (InputKeyStateTable[VKey] & 0x80) flags |= KF_REPEAT;
196 if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01;
197 InputKeyStateTable[VKey] |= 0x80;
198 AsyncKeyStateTable[VKey] |= 0x80;
200 message = WM_KEYDOWN;
201 if( (InputKeyStateTable[VK_MENU] & 0x80) &&
202 !(InputKeyStateTable[VK_CONTROL] & 0x80)) {
203 message = WM_SYSKEYDOWN;
204 TrackSysKey = VKey;
208 if (InputKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
210 if( plParam) *plParam = MAKELPARAM( 1, flags );
211 if( pwParam) *pwParam = VKey;
212 return message;
215 /****************************** end copy input.c ****************************/
218 * . prepare the keyevents for SendInputs
219 * . calculate the "expected" messages
220 * . Send the events to our window
221 * . retrieve the messages from the input queue
222 * . verify
224 static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] )
226 INPUT inputs[MAXKEYEVENTS];
227 KMSG expmsg[MAXKEYEVENTS];
228 MSG msg;
229 char buf[100];
230 UINT evtctr=0, ret;
231 int kmctr, i;
233 buf[0]='\0';
234 TrackSysKey=0; /* see input.c */
235 for (i = 0; i < MAXKEYEVENTS; i++)
237 inputs[evtctr].type = INPUT_KEYBOARD;
238 inputs[evtctr].ki.wVk = GETVKEY[td[i]];
239 inputs[evtctr].ki.wScan = GETSCAN[td[i]];
240 inputs[evtctr].ki.dwFlags = GETFLAGS[td[i]];
241 inputs[evtctr].ki.dwExtraInfo = 0;
242 inputs[evtctr].ki.time = ++timetag;
243 if (td[i]) evtctr++;
245 strcat(buf, getdesc[td[i]]);
246 if(td[i])
247 expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam));
248 else
249 expmsg[i].message = 0;
251 for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++)
253 ok( evtctr <= MAXKEYEVENTS, "evtctr is above MAXKEYEVENTS\n" );
254 ret = SendInput(evtctr, inputs, sizeof(INPUT));
255 ok(ret == evtctr, "SendInput failed to send some events\n");
256 i = 0;
257 if (winetest_debug > 1)
258 trace("======== key stroke sequence #%d: %s =============\n",
259 seqnr + 1, buf);
260 while( PeekMessageA(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) {
261 if (winetest_debug > 1)
262 trace("message[%d] %-15s wParam %04Ix lParam %08Ix time %lx\n", i,
263 MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time);
264 if( i < kmctr ) {
265 ok( msg.message == expmsg[i].message &&
266 msg.wParam == expmsg[i].wParam &&
267 msg.lParam == expmsg[i].lParam,
268 "%u/%u: wrong message %x/%08Ix/%08Ix expected %s/%08Ix/%08Ix\n",
269 seqnr, i, msg.message, msg.wParam, msg.lParam,
270 MSGNAME[(expmsg[i]).message - WM_KEYFIRST], expmsg[i].wParam, expmsg[i].lParam );
272 i++;
274 if (winetest_debug > 1)
275 trace("%d messages retrieved\n", i);
276 if (!i && kmctr)
278 skip( "simulated keyboard input doesn't work\n" );
279 return FALSE;
281 ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr);
282 return TRUE;
285 /* test all combinations of the specified key events */
286 static BOOL TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] )
288 int i,j,k,l,m,n;
289 static int count=0;
290 KEV kbuf[MAXKEYEVENTS];
291 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
292 if (!us_kbd)
294 skip( "skipping test with inconsistent results on non-us keyboard\n" );
295 return TRUE;
298 assert( nrkev==2 || nrkev==3);
299 for(i=0;i<MAXKEYEVENTS;i++) kbuf[i]=0;
300 /* two keys involved gives 4 test cases */
301 if(nrkev==2) {
302 for(i=0;i<nrkev;i++) {
303 for(j=0;j<nrkev;j++) {
304 kbuf[0] = kevdwn[i];
305 kbuf[1] = kevdwn[1-i];
306 kbuf[2] = kevup[j];
307 kbuf[3] = kevup[1-j];
308 if (!do_test( hWnd, count++, kbuf)) return FALSE;
312 /* three keys involved gives 36 test cases */
313 if(nrkev==3){
314 for(i=0;i<nrkev;i++){
315 for(j=0;j<nrkev;j++){
316 if(j==i) continue;
317 for(k=0;k<nrkev;k++){
318 if(k==i || k==j) continue;
319 for(l=0;l<nrkev;l++){
320 for(m=0;m<nrkev;m++){
321 if(m==l) continue;
322 for(n=0;n<nrkev;n++){
323 if(n==l ||n==m) continue;
324 kbuf[0] = kevdwn[i];
325 kbuf[1] = kevdwn[j];
326 kbuf[2] = kevdwn[k];
327 kbuf[3] = kevup[l];
328 kbuf[4] = kevup[m];
329 kbuf[5] = kevup[n];
330 if (!do_test( hWnd, count++, kbuf)) return FALSE;
338 return TRUE;
341 /* test each set specified in the global testkeyset array */
342 static void TestSysKeys( HWND hWnd)
344 int i;
345 for(i=0; testkeyset[i].nrkev;i++)
346 if (!TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn, testkeyset[i].keyup)) break;
349 static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam,
350 LPARAM lParam )
352 return DefWindowProcA( hWnd, msg, wParam, lParam );
355 static void test_Input_whitebox(void)
357 MSG msg;
358 WNDCLASSA wclass;
359 HANDLE hInstance = GetModuleHandleA( NULL );
361 wclass.lpszClassName = "InputSysKeyTestClass";
362 wclass.style = CS_HREDRAW | CS_VREDRAW;
363 wclass.lpfnWndProc = WndProc;
364 wclass.hInstance = hInstance;
365 wclass.hIcon = LoadIconA( 0, (LPCSTR)IDI_APPLICATION );
366 wclass.hCursor = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
367 wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
368 wclass.lpszMenuName = 0;
369 wclass.cbClsExtra = 0;
370 wclass.cbWndExtra = 0;
371 RegisterClassA( &wclass );
372 /* create the test window that will receive the keystrokes */
373 hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest",
374 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
375 NULL, NULL, hInstance, NULL);
376 assert( hWndTest );
377 ShowWindow( hWndTest, SW_SHOW);
378 SetWindowPos( hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
379 SetForegroundWindow( hWndTest );
380 UpdateWindow( hWndTest);
382 /* flush pending messages */
383 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
385 SetFocus( hWndTest );
386 TestSysKeys( hWndTest );
387 DestroyWindow(hWndTest);
390 static inline BOOL is_keyboard_message( UINT message )
392 return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
395 static inline BOOL is_mouse_message( UINT message )
397 return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST);
400 /* try to make sure pending X events have been processed before continuing */
401 static void empty_message_queue(void)
403 MSG msg;
404 int diff = 200;
405 int min_timeout = 50;
406 DWORD time = GetTickCount() + diff;
408 while (diff > 0)
410 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
411 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
413 if (is_keyboard_message(msg.message) || is_mouse_message(msg.message))
414 ok(msg.time != 0, "message %#x has time set to 0\n", msg.message);
416 TranslateMessage(&msg);
417 DispatchMessageA(&msg);
419 diff = time - GetTickCount();
423 struct transition_s {
424 WORD wVk;
425 BYTE before_state;
426 BYTE optional;
429 typedef enum {
430 sent=0x1,
431 posted=0x2,
432 parent=0x4,
433 wparam=0x8,
434 lparam=0x10,
435 defwinproc=0x20,
436 beginpaint=0x40,
437 optional=0x80,
438 hook=0x100,
439 winevent_hook=0x200
440 } msg_flags_t;
442 struct message {
443 UINT message; /* the WM_* code */
444 msg_flags_t flags; /* message props */
445 WPARAM wParam; /* expected value of wParam */
446 LPARAM lParam; /* expected value of lParam */
449 static const struct sendinput_test_s {
450 WORD wVk;
451 DWORD dwFlags;
452 BOOL _todo_wine;
453 struct transition_s expected_transitions[MAXKEYEVENTS+1];
454 struct message expected_messages[MAXKEYMESSAGES+1];
455 } sendinput_test[] = {
456 /* test ALT+F */
457 /* 0 */
458 {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
459 {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}},
460 {'F', 0, FALSE, {{'F', 0x00}, {0}},
461 {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN},
462 {WM_SYSCHAR},
463 {WM_SYSCOMMAND}, {0}}},
464 {'F', KEYEVENTF_KEYUP, FALSE, {{'F', 0x80}, {0}},
465 {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
466 {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
467 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
469 /* test CTRL+O */
470 /* 4 */
471 {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
472 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
473 {'O', 0, FALSE, {{'O', 0x00}, {0}},
474 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
475 {'O', KEYEVENTF_KEYUP, FALSE, {{'O', 0x80}, {0}},
476 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
477 {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
478 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
480 /* test ALT+CTRL+X */
481 /* 8 */
482 {VK_LMENU, 0, FALSE, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
483 {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}},
484 {VK_LCONTROL, 0, FALSE, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
485 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
486 {'X', 0, FALSE, {{'X', 0x00}, {0}},
487 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
488 {'X', KEYEVENTF_KEYUP, FALSE, {{'X', 0x80}, {0}},
489 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
490 {VK_LCONTROL, KEYEVENTF_KEYUP, FALSE, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
491 {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
492 {VK_LMENU, KEYEVENTF_KEYUP, FALSE, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
493 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
495 /* test SHIFT+A */
496 /* 14 */
497 {VK_LSHIFT, 0, FALSE, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
498 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
499 {'A', 0, FALSE, {{'A', 0x00}, {0}},
500 {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
501 {'A', KEYEVENTF_KEYUP, FALSE, {{'A', 0x80}, {0}},
502 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
503 {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
504 {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
505 /* test L-SHIFT & R-SHIFT: */
506 /* RSHIFT == LSHIFT */
507 /* 18 */
508 {VK_RSHIFT, 0, FALSE,
509 /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
510 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}},
511 {{WM_KEYDOWN, hook|wparam, VK_RSHIFT},
512 {WM_KEYDOWN}, {0}}},
513 {VK_RSHIFT, KEYEVENTF_KEYUP, FALSE,
514 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}},
515 {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT},
516 {WM_KEYUP}, {0}}},
518 /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
519 /* 20 */
520 {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
521 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
522 {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED},
523 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
524 {VK_LSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
525 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
526 {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED},
527 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
528 /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
529 /* 22 */
530 {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
531 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
532 {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
533 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
534 {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
535 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
536 {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
537 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
539 /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
540 win2k - sends to hook whatever we generated here
541 winXP+ - Attempts to convert key to L/R key but not always correct
543 /* SHIFT == LSHIFT */
544 /* 24 */
545 {VK_SHIFT, 0, FALSE,
546 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
547 {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0},
548 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
549 {VK_SHIFT, KEYEVENTF_KEYUP, FALSE,
550 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
551 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP},
552 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
553 /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
554 /* 26 */
555 {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
556 {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
557 {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED},
558 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
559 {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
560 {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
561 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED},
562 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
564 /* test L-CONTROL & R-CONTROL: */
565 /* RCONTROL == LCONTROL */
566 /* 28 */
567 {VK_RCONTROL, 0, FALSE,
568 {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
569 {{WM_KEYDOWN, hook|wparam, VK_RCONTROL},
570 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
571 {VK_RCONTROL, KEYEVENTF_KEYUP, FALSE,
572 {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
573 {{WM_KEYUP, hook|wparam, VK_RCONTROL},
574 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
575 /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
576 /* 30 */
577 {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
578 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
579 {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED},
580 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
581 {VK_LCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
582 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
583 {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED},
584 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
585 /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
586 /* 32 */
587 {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
588 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
589 {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED},
590 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
591 {VK_RCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
592 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
593 {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED},
594 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
595 /* CONTROL == LCONTROL */
596 /* 34 */
597 {VK_CONTROL, 0, FALSE,
598 {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
599 {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/},
600 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
601 {VK_CONTROL, KEYEVENTF_KEYUP, FALSE,
602 {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
603 {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/},
604 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
605 /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
606 /* 36 */
607 {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, FALSE,
608 {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
609 {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED},
610 {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
611 {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
612 {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
613 {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED},
614 {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
616 /* test L-MENU & R-MENU: */
617 /* RMENU == LMENU */
618 /* 38 */
619 {VK_RMENU, 0, FALSE,
620 {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
621 {{WM_SYSKEYDOWN, hook|wparam|optional, VK_LCONTROL},
622 {WM_SYSKEYDOWN, hook|wparam, VK_RMENU},
623 {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
624 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
625 {VK_RMENU, KEYEVENTF_KEYUP, TRUE,
626 {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
627 {{WM_KEYUP, hook|wparam|optional, VK_LCONTROL},
628 {WM_KEYUP, hook|wparam, VK_RMENU},
629 {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
630 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
631 {WM_SYSCOMMAND, optional}, {0}}},
632 /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
633 /* 40 */
634 {VK_LMENU, KEYEVENTF_EXTENDEDKEY, FALSE,
635 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
636 {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED},
637 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
638 {VK_LMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
639 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}},
640 {{WM_KEYUP, hook|wparam|lparam, VK_LMENU, LLKHF_UP|LLKHF_EXTENDED},
641 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
642 {WM_SYSCOMMAND}, {0}}},
643 /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
644 /* 42 */
645 {VK_RMENU, KEYEVENTF_EXTENDEDKEY, FALSE,
646 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
647 {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_LCONTROL, 0},
648 {WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED},
649 {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
650 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
651 {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
652 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
653 {{WM_KEYUP, hook|wparam|lparam|optional, VK_LCONTROL, LLKHF_UP},
654 {WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED},
655 {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
656 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
657 {WM_SYSCOMMAND, optional}, {0}}},
658 /* MENU == LMENU */
659 /* 44 */
660 {VK_MENU, 0, FALSE,
661 {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
662 {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/},
663 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
664 {VK_MENU, KEYEVENTF_KEYUP, TRUE,
665 {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
666 {{WM_KEYUP, hook/*|wparam, VK_MENU*/},
667 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
668 {WM_SYSCOMMAND}, {0}}},
669 /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
670 /* 46 */
671 {VK_MENU, KEYEVENTF_EXTENDEDKEY, FALSE,
672 {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
673 {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_CONTROL, 0},
674 {WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED},
675 {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
676 {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, TRUE,
677 {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
678 {{WM_KEYUP, hook|wparam|lparam|optional, VK_CONTROL, LLKHF_UP},
679 {WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED},
680 {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
681 {WM_SYSCOMMAND}, {0}}},
683 /* test LSHIFT & RSHIFT */
684 /* 48 */
685 {VK_LSHIFT, 0, FALSE,
686 {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
687 {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0},
688 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
689 {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, FALSE,
690 {{VK_RSHIFT, 0x00}, {0}},
691 {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
692 {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
693 {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, FALSE,
694 {{VK_RSHIFT, 0x80}, {0}},
695 {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
696 {WM_KEYUP, optional}, {0}}},
697 {VK_LSHIFT, KEYEVENTF_KEYUP, FALSE,
698 {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
699 {{WM_KEYUP, hook|wparam, VK_LSHIFT},
700 {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
702 {0, 0, FALSE, {{0}}, {{0}}} /* end */
705 static struct message sent_messages[MAXKEYMESSAGES];
706 static UINT sent_messages_cnt;
708 /* Verify that only specified key state transitions occur */
709 static void compare_and_check(int id, BYTE *ks1, BYTE *ks2,
710 const struct sendinput_test_s *test, BOOL foreground)
712 int i, failcount = 0;
713 const struct transition_s *t = test->expected_transitions;
714 UINT actual_cnt = 0;
715 const struct message *expected = test->expected_messages;
717 while (t->wVk && foreground) {
718 /* We won't receive any information from GetKeyboardState() if we're
719 * not the foreground window. */
720 BOOL matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80)
721 && (ks2[t->wVk]&0x80) == (~t->before_state&0x80));
723 if (!matched && !t->optional && test->_todo_wine)
725 failcount++;
726 todo_wine {
727 ok(matched, "%2d (%x/%lx): %02x from %02x -> %02x "
728 "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
729 t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
730 ~t->before_state&0x80);
732 } else {
733 ok(matched || t->optional, "%2d (%x/%lx): %02x from %02x -> %02x "
734 "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
735 t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
736 ~t->before_state&0x80);
738 ks2[t->wVk] = ks1[t->wVk]; /* clear the match */
739 t++;
741 for (i = 0; i < 256; i++)
742 if (ks2[i] != ks1[i] && test->_todo_wine)
744 failcount++;
745 todo_wine
746 ok(FALSE, "%2d (%x/%lx): %02x from %02x -> %02x unexpected\n",
747 id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
749 else
750 ok(ks2[i] == ks1[i], "%2d (%x/%lx): %02x from %02x -> %02x unexpected\n",
751 id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
753 while (expected->message && actual_cnt < sent_messages_cnt)
755 const struct message *actual = &sent_messages[actual_cnt];
757 if (expected->message == actual->message)
759 if (expected->flags & wparam)
761 if ((expected->flags & optional) && (expected->wParam != actual->wParam))
763 expected++;
764 continue;
766 if (expected->wParam != actual->wParam && test->_todo_wine)
768 failcount++;
769 todo_wine
770 ok(FALSE, "%2d (%x/%lx): in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
771 id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
773 else
774 ok(expected->wParam == actual->wParam,
775 "%2d (%x/%lx): in msg 0x%04x expecting wParam 0x%Ix got 0x%Ix\n",
776 id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
778 if (expected->flags & lparam)
780 if (expected->lParam != actual->lParam && test->_todo_wine)
782 failcount++;
783 todo_wine
784 ok(FALSE, "%2d (%x/%lx): in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
785 id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
787 else
788 ok(expected->lParam == actual->lParam,
789 "%2d (%x/%lx): in msg 0x%04x expecting lParam 0x%Ix got 0x%Ix\n",
790 id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
792 ok((expected->flags & hook) == (actual->flags & hook),
793 "%2d (%x/%lx): the msg 0x%04x should have been sent by a hook\n",
794 id, test->wVk, test->dwFlags, expected->message);
797 else if (expected->flags & optional)
799 expected++;
800 continue;
802 else if (!(expected->flags & hook) && !foreground)
804 /* If we weren't able to receive foreground status, we won't get
805 * any window messages. */
806 expected++;
807 continue;
809 /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
810 else if ((expected->flags & hook) &&
811 (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
812 (actual->message == expected->message - 4))
814 ok((expected->flags & hook) == (actual->flags & hook),
815 "%2d (%x/%lx): the msg 0x%04x should have been sent by a hook\n",
816 id, test->wVk, test->dwFlags, expected->message);
818 /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
819 * instead of SYSKEYDOWN/UP to the WNDPROC */
820 else if (test->wVk == VK_RMENU && !(expected->flags & hook) &&
821 (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
822 (actual->message == expected->message - 4))
824 ok(expected->wParam == actual->wParam && expected->lParam == actual->lParam,
825 "%2d (%x/%lx): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
826 id, test->wVk, test->dwFlags, expected->message, actual->message);
828 else if (test->_todo_wine)
830 failcount++;
831 todo_wine
832 ok(FALSE,
833 "%2d (%x/%lx): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
834 id, test->wVk, test->dwFlags, expected->message, actual->message);
836 else
837 ok(FALSE,
838 "%2d (%x/%lx): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
839 id, test->wVk, test->dwFlags, expected->message, actual->message);
841 actual_cnt++;
842 expected++;
844 /* skip all optional trailing messages */
845 while (expected->message && ((expected->flags & optional) || (!(expected->flags & hook) && !foreground)))
846 expected++;
849 if (expected->message || actual_cnt < sent_messages_cnt)
851 if (test->_todo_wine)
853 failcount++;
854 todo_wine
855 ok(FALSE, "%2d (%x/%lx): the msg sequence is not complete: expected %04x - actual %04x\n",
856 id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
858 else
859 ok(FALSE, "%2d (%x/%lx): the msg sequence is not complete: expected %04x - actual %04x\n",
860 id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
863 if( test->_todo_wine && !failcount) /* succeeded yet marked todo */
864 todo_wine
865 ok(TRUE, "%2d (%x/%lx): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags);
867 sent_messages_cnt = 0;
870 /* WndProc2 checks that we get at least the messages specified */
871 static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam,
872 LPARAM lParam)
874 if (winetest_debug > 1) trace("MSG: %8x W:%8Ix L:%8Ix\n", Msg, wParam, lParam);
876 if ((Msg >= WM_KEYFIRST && Msg <= WM_KEYLAST) || Msg == WM_SYSCOMMAND)
878 ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
879 if (sent_messages_cnt < MAXKEYMESSAGES)
881 sent_messages[sent_messages_cnt].message = Msg;
882 sent_messages[sent_messages_cnt].flags = 0;
883 sent_messages[sent_messages_cnt].wParam = wParam;
884 sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED);
887 return DefWindowProcA(hWnd, Msg, wParam, lParam);
890 static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam)
892 KBDLLHOOKSTRUCT *hook_info = (KBDLLHOOKSTRUCT *)lparam;
894 if (code == HC_ACTION)
896 ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
897 if (sent_messages_cnt < MAXKEYMESSAGES)
899 sent_messages[sent_messages_cnt].message = wparam;
900 sent_messages[sent_messages_cnt].flags = hook;
901 sent_messages[sent_messages_cnt].wParam = hook_info->vkCode;
902 sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED);
905 if(0) /* For some reason not stable on Wine */
907 if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN)
908 ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %lx should be up\n", hook_info->vkCode);
909 else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP)
910 ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %lx should be down\n", hook_info->vkCode);
913 if (winetest_debug > 1)
914 trace("Hook: w=%Ix vk:%8lx sc:%8lx fl:%8lx %Ix\n", wparam,
915 hook_info->vkCode, hook_info->scanCode, hook_info->flags, hook_info->dwExtraInfo);
917 return CallNextHookEx( 0, code, wparam, lparam );
919 static void test_Input_blackbox(void)
921 INPUT i;
922 int ii;
923 BYTE ks1[256], ks2[256];
924 LONG_PTR prevWndProc;
925 BOOL foreground;
926 HWND window;
927 HHOOK hook;
929 if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409)
931 skip("Skipping Input_blackbox test on non-US keyboard\n");
932 return;
934 window = CreateWindowA("Static", NULL, WS_POPUP|WS_HSCROLL|WS_VSCROLL
935 |WS_VISIBLE, 0, 0, 200, 60, NULL, NULL,
936 NULL, NULL);
937 ok(window != NULL, "error: %d\n", (int) GetLastError());
938 SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
939 foreground = SetForegroundWindow( window );
940 if (!foreground)
941 skip("Failed to set foreground window; some tests will be skipped.\n");
943 if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0)))
945 DestroyWindow(window);
946 win_skip("WH_KEYBOARD_LL is not supported\n");
947 return;
950 /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
951 * key state set by SendInput(). */
952 empty_message_queue();
954 prevWndProc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR) WndProc2);
955 ok(prevWndProc != 0 || GetLastError() == 0, "error: %d\n", (int) GetLastError());
957 i.type = INPUT_KEYBOARD;
958 i.ki.time = 0;
959 i.ki.dwExtraInfo = 0;
961 for (ii = 0; ii < ARRAY_SIZE(sendinput_test)-1; ii++) {
962 GetKeyboardState(ks1);
963 i.ki.wScan = ii+1 /* useful for debugging */;
964 i.ki.dwFlags = sendinput_test[ii].dwFlags;
965 i.ki.wVk = sendinput_test[ii].wVk;
966 SendInput(1, &i, sizeof(INPUT));
967 empty_message_queue();
968 GetKeyboardState(ks2);
969 compare_and_check(ii, ks1, ks2, &sendinput_test[ii], foreground);
972 empty_message_queue();
973 DestroyWindow(window);
974 UnhookWindowsHookEx(hook);
977 static void reset_key_status(WORD vk)
979 key_status.last_key_down = -1;
980 key_status.last_key_up = -1;
981 key_status.last_syskey_down = -1;
982 key_status.last_syskey_up = -1;
983 key_status.last_char = -1;
984 key_status.last_syschar = -1;
985 key_status.last_hook_down = -1;
986 key_status.last_hook_up = -1;
987 key_status.last_hook_syskey_down = -1;
988 key_status.last_hook_syskey_up = -1;
989 key_status.vk = vk;
990 key_status.expect_alt = FALSE;
991 key_status.sendinput_broken = FALSE;
994 static void test_unicode_keys(HWND hwnd, HHOOK hook)
996 INPUT inputs[2];
997 MSG msg;
999 /* init input data that never changes */
1000 inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
1001 inputs[1].ki.dwExtraInfo = inputs[0].ki.dwExtraInfo = 0;
1002 inputs[1].ki.time = inputs[0].ki.time = 0;
1004 /* pressing & releasing a single unicode character */
1005 inputs[0].ki.wVk = 0;
1006 inputs[0].ki.wScan = 0x3c0;
1007 inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;
1009 reset_key_status(VK_PACKET);
1010 SendInput(1, inputs, sizeof(INPUT));
1011 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1012 if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
1013 TranslateMessage(&msg);
1015 DispatchMessageW(&msg);
1017 if(!key_status.sendinput_broken){
1018 ok(key_status.last_key_down == VK_PACKET,
1019 "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%lx)\n", VK_PACKET, key_status.last_key_down);
1020 ok(key_status.last_char == 0x3c0,
1021 "Last char msg wparam should have been 0x3c0 (was: 0x%lx)\n", key_status.last_char);
1022 if(hook)
1023 ok(key_status.last_hook_down == 0x3c0,
1024 "Last hookdown msg should have been 0x3c0, was: 0x%lx\n", key_status.last_hook_down);
1027 inputs[1].ki.wVk = 0;
1028 inputs[1].ki.wScan = 0x3c0;
1029 inputs[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1031 reset_key_status(VK_PACKET);
1032 SendInput(1, inputs + 1, sizeof(INPUT));
1033 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1034 if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
1035 TranslateMessage(&msg);
1037 DispatchMessageW(&msg);
1039 if(!key_status.sendinput_broken){
1040 ok(key_status.last_key_up == VK_PACKET,
1041 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%lx)\n", VK_PACKET, key_status.last_key_up);
1042 if(hook)
1043 ok(key_status.last_hook_up == 0x3c0,
1044 "Last hookup msg should have been 0x3c0, was: 0x%lx\n", key_status.last_hook_up);
1047 /* holding alt, pressing & releasing a unicode character, releasing alt */
1048 inputs[0].ki.wVk = VK_LMENU;
1049 inputs[0].ki.wScan = 0;
1050 inputs[0].ki.dwFlags = 0;
1052 inputs[1].ki.wVk = 0;
1053 inputs[1].ki.wScan = 0x3041;
1054 inputs[1].ki.dwFlags = KEYEVENTF_UNICODE;
1056 reset_key_status(VK_PACKET);
1057 key_status.expect_alt = TRUE;
1058 SendInput(2, inputs, sizeof(INPUT));
1059 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1060 if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1061 TranslateMessage(&msg);
1063 DispatchMessageW(&msg);
1065 if(!key_status.sendinput_broken){
1066 ok(key_status.last_syskey_down == VK_PACKET,
1067 "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%lx)\n", VK_PACKET, key_status.last_syskey_down);
1068 ok(key_status.last_syschar == 0x3041,
1069 "Last syschar msg should have been 0x3041 (was: 0x%lx)\n", key_status.last_syschar);
1070 if(hook)
1071 ok(key_status.last_hook_syskey_down == 0x3041,
1072 "Last hooksysdown msg should have been 0x3041, was: 0x%lx\n", key_status.last_hook_syskey_down);
1075 inputs[1].ki.wVk = 0;
1076 inputs[1].ki.wScan = 0x3041;
1077 inputs[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1079 inputs[0].ki.wVk = VK_LMENU;
1080 inputs[0].ki.wScan = 0;
1081 inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
1083 reset_key_status(VK_PACKET);
1084 key_status.expect_alt = TRUE;
1085 SendInput(2, inputs, sizeof(INPUT));
1086 while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1087 if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1088 TranslateMessage(&msg);
1090 DispatchMessageW(&msg);
1092 if(!key_status.sendinput_broken){
1093 ok(key_status.last_key_up == VK_PACKET,
1094 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%lx)\n", VK_PACKET, key_status.last_key_up);
1095 if(hook)
1096 ok(key_status.last_hook_up == 0x3041,
1097 "Last hook up msg should have been 0x3041, was: 0x%lx\n", key_status.last_hook_up);
1100 /* Press and release, non-zero key code. */
1101 inputs[0].ki.wVk = 0x51;
1102 inputs[0].ki.wScan = 0x123;
1103 inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;
1105 inputs[1].ki.wVk = 0x51;
1106 inputs[1].ki.wScan = 0x123;
1107 inputs[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1109 reset_key_status(inputs[0].ki.wVk);
1110 SendInput(2, inputs, sizeof(INPUT));
1111 while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE))
1113 TranslateMessage(&msg);
1114 DispatchMessageW(&msg);
1117 if (!key_status.sendinput_broken)
1119 ok(key_status.last_key_down == 0x51, "Unexpected key down %#lx.\n", key_status.last_key_down);
1120 ok(key_status.last_key_up == 0x51, "Unexpected key up %#lx.\n", key_status.last_key_up);
1121 if (hook)
1122 todo_wine
1123 ok(key_status.last_hook_up == 0x23, "Unexpected hook message %#lx.\n", key_status.last_hook_up);
1127 static LRESULT CALLBACK unicode_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
1128 LPARAM lParam )
1130 switch(msg){
1131 case WM_KEYDOWN:
1132 key_status.last_key_down = wParam;
1133 break;
1134 case WM_SYSKEYDOWN:
1135 key_status.last_syskey_down = wParam;
1136 break;
1137 case WM_KEYUP:
1138 key_status.last_key_up = wParam;
1139 break;
1140 case WM_SYSKEYUP:
1141 key_status.last_syskey_up = wParam;
1142 break;
1143 case WM_CHAR:
1144 key_status.last_char = wParam;
1145 break;
1146 case WM_SYSCHAR:
1147 key_status.last_syschar = wParam;
1148 break;
1150 return DefWindowProcW(hWnd, msg, wParam, lParam);
1153 static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lParam)
1155 if(nCode == HC_ACTION){
1156 LPKBDLLHOOKSTRUCT info = (LPKBDLLHOOKSTRUCT)lParam;
1157 if(!info->vkCode){
1158 key_status.sendinput_broken = TRUE;
1159 win_skip("SendInput doesn't support unicode on this platform\n");
1160 }else{
1161 if(key_status.expect_alt){
1162 ok(info->vkCode == VK_LMENU, "vkCode should have been VK_LMENU[0x%04x], was: 0x%lx\n", VK_LMENU, info->vkCode);
1163 key_status.expect_alt = FALSE;
1164 }else
1165 todo_wine_if(key_status.vk != VK_PACKET)
1166 ok(info->vkCode == key_status.vk, "Unexpected vkCode %#lx, expected %#x.\n", info->vkCode, key_status.vk);
1168 switch(wParam){
1169 case WM_KEYDOWN:
1170 key_status.last_hook_down = info->scanCode;
1171 break;
1172 case WM_KEYUP:
1173 key_status.last_hook_up = info->scanCode;
1174 break;
1175 case WM_SYSKEYDOWN:
1176 key_status.last_hook_syskey_down = info->scanCode;
1177 break;
1178 case WM_SYSKEYUP:
1179 key_status.last_hook_syskey_up = info->scanCode;
1180 break;
1183 return CallNextHookEx(NULL, nCode, wParam, lParam);
1186 static void test_Input_unicode(void)
1188 WCHAR classNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1189 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1190 WCHAR windowNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1191 'K','e','y','T','e','s','t',0};
1192 MSG msg;
1193 WNDCLASSW wclass;
1194 HANDLE hInstance = GetModuleHandleW(NULL);
1195 HHOOK hook;
1196 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
1197 if (!us_kbd)
1199 skip( "skipping test with inconsistent results on non-us keyboard\n" );
1200 return;
1203 wclass.lpszClassName = classNameW;
1204 wclass.style = CS_HREDRAW | CS_VREDRAW;
1205 wclass.lpfnWndProc = unicode_wnd_proc;
1206 wclass.hInstance = hInstance;
1207 wclass.hIcon = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
1208 wclass.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
1209 wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1210 wclass.lpszMenuName = 0;
1211 wclass.cbClsExtra = 0;
1212 wclass.cbWndExtra = 0;
1213 if(!RegisterClassW(&wclass)){
1214 win_skip("Unicode functions not supported\n");
1215 return;
1218 ImmDisableIME(0);
1220 /* create the test window that will receive the keystrokes */
1221 hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW,
1222 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
1223 NULL, NULL, hInstance, NULL);
1225 assert(hWndTest);
1226 assert(IsWindowUnicode(hWndTest));
1228 hook = SetWindowsHookExW(WH_KEYBOARD_LL, llkbd_unicode_hook, GetModuleHandleW(NULL), 0);
1229 if(!hook)
1230 win_skip("unable to set WH_KEYBOARD_LL hook\n");
1232 ShowWindow(hWndTest, SW_SHOW);
1233 SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1234 SetForegroundWindow(hWndTest);
1235 UpdateWindow(hWndTest);
1237 /* flush pending messages */
1238 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
1240 SetFocus(hWndTest);
1242 test_unicode_keys(hWndTest, hook);
1244 if(hook)
1245 UnhookWindowsHookEx(hook);
1246 DestroyWindow(hWndTest);
1249 static void test_keynames(void)
1251 int i, len;
1252 char buff[256];
1254 for (i = 0; i < 512; i++)
1256 strcpy(buff, "----");
1257 len = GetKeyNameTextA(i << 16, buff, sizeof(buff));
1258 ok(len || !buff[0], "%d: Buffer is not zeroed\n", i);
1262 static POINT pt_old, pt_new;
1263 static BOOL clipped;
1264 #define STEP 3
1266 static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam )
1268 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1269 POINT pt, pt1;
1271 if (code == HC_ACTION)
1273 /* This is our new cursor position */
1274 pt_new = hook->pt;
1275 /* Should return previous position */
1276 GetCursorPos(&pt);
1277 ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%ld,%ld)\n", pt.x, pt.y);
1279 /* Should set new position until hook chain is finished. */
1280 pt.x = pt_old.x + STEP;
1281 pt.y = pt_old.y + STEP;
1282 SetCursorPos(pt.x, pt.y);
1283 GetCursorPos(&pt1);
1284 if (clipped)
1285 ok(pt1.x == pt_old.x && pt1.y == pt_old.y, "Wrong set pos: (%ld,%ld)\n", pt1.x, pt1.y);
1286 else
1287 ok(pt1.x == pt.x && pt1.y == pt.y, "Wrong set pos: (%ld,%ld)\n", pt1.x, pt1.y);
1289 return CallNextHookEx( 0, code, wparam, lparam );
1292 static LRESULT CALLBACK hook_proc2( int code, WPARAM wparam, LPARAM lparam )
1294 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1295 POINT pt;
1297 if (code == HC_ACTION)
1299 ok(hook->pt.x == pt_new.x && hook->pt.y == pt_new.y,
1300 "Wrong hook coords: (%ld %ld) != (%ld,%ld)\n", hook->pt.x, hook->pt.y, pt_new.x, pt_new.y);
1302 /* Should match position set above */
1303 GetCursorPos(&pt);
1304 if (clipped)
1305 ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%ld,%ld)\n", pt.x, pt.y);
1306 else
1307 ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%ld,%ld)\n", pt.x, pt.y);
1309 return CallNextHookEx( 0, code, wparam, lparam );
1312 static LRESULT CALLBACK hook_proc3( int code, WPARAM wparam, LPARAM lparam )
1314 POINT pt;
1316 if (code == HC_ACTION)
1318 /* MSLLHOOKSTRUCT does not seem to be reliable and contains different data on each run. */
1319 GetCursorPos(&pt);
1320 ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%ld,%ld)\n", pt.x, pt.y);
1322 return CallNextHookEx( 0, code, wparam, lparam );
1325 static void test_mouse_ll_hook(void)
1327 HWND hwnd;
1328 HHOOK hook1, hook2;
1329 POINT pt_org, pt;
1330 RECT rc;
1332 GetCursorPos(&pt_org);
1333 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1334 10, 10, 200, 200, NULL, NULL, NULL, NULL);
1335 SetCursorPos(100, 100);
1337 if (!(hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0)))
1339 win_skip( "cannot set MOUSE_LL hook\n" );
1340 goto done;
1342 hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0);
1344 GetCursorPos(&pt_old);
1345 mouse_event(MOUSEEVENTF_MOVE, -STEP, 0, 0, 0);
1346 GetCursorPos(&pt_old);
1347 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1348 mouse_event(MOUSEEVENTF_MOVE, +STEP, 0, 0, 0);
1349 GetCursorPos(&pt_old);
1350 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1351 mouse_event(MOUSEEVENTF_MOVE, 0, -STEP, 0, 0);
1352 GetCursorPos(&pt_old);
1353 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1354 mouse_event(MOUSEEVENTF_MOVE, 0, +STEP, 0, 0);
1355 GetCursorPos(&pt_old);
1356 ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1358 SetRect(&rc, 50, 50, 151, 151);
1359 ClipCursor(&rc);
1360 clipped = TRUE;
1362 SetCursorPos(40, 40);
1363 GetCursorPos(&pt_old);
1364 ok(pt_old.x == 50 && pt_old.y == 50, "Wrong new pos: (%ld,%ld)\n", pt_new.x, pt_new.y);
1365 SetCursorPos(160, 160);
1366 GetCursorPos(&pt_old);
1367 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%ld,%ld)\n", pt_new.x, pt_new.y);
1368 mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0);
1369 GetCursorPos(&pt_old);
1370 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%ld,%ld)\n", pt_new.x, pt_new.y);
1372 clipped = FALSE;
1373 pt_new.x = pt_new.y = 150;
1374 ClipCursor(NULL);
1375 UnhookWindowsHookEx(hook1);
1377 /* Now check that mouse buttons do not change mouse position
1378 if we don't have MOUSEEVENTF_MOVE flag specified. */
1380 /* We reusing the same hook callback, so make it happy */
1381 pt_old.x = pt_new.x - STEP;
1382 pt_old.y = pt_new.y - STEP;
1383 mouse_event(MOUSEEVENTF_LEFTUP, 123, 456, 0, 0);
1384 GetCursorPos(&pt);
1385 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%ld,%ld)\n", pt.x, pt.y);
1386 mouse_event(MOUSEEVENTF_RIGHTUP, 456, 123, 0, 0);
1387 GetCursorPos(&pt);
1388 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%ld,%ld)\n", pt.x, pt.y);
1390 mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 123, 456, 0, 0);
1391 GetCursorPos(&pt);
1392 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%ld,%ld)\n", pt.x, pt.y);
1393 mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE, 456, 123, 0, 0);
1394 GetCursorPos(&pt);
1395 ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%ld,%ld)\n", pt.x, pt.y);
1397 UnhookWindowsHookEx(hook2);
1398 hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc3, GetModuleHandleA(0), 0);
1400 SetRect(&rc, 150, 150, 150, 150);
1401 ClipCursor(&rc);
1402 clipped = TRUE;
1404 SetCursorPos(140, 140);
1405 GetCursorPos(&pt_old);
1406 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1407 SetCursorPos(160, 160);
1408 GetCursorPos(&pt_old);
1409 todo_wine
1410 ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1411 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
1412 GetCursorPos(&pt_old);
1413 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1414 mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0);
1415 GetCursorPos(&pt_old);
1416 todo_wine
1417 ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1418 mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0);
1419 GetCursorPos(&pt_old);
1420 ok((pt_old.x == 150 && pt_old.y == 150) ||
1421 broken(pt_old.x == 149 && pt_old.y == 149) /* w1064v1809 */,
1422 "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1423 mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0);
1424 GetCursorPos(&pt_old);
1425 todo_wine
1426 ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1428 clipped = FALSE;
1429 ClipCursor(NULL);
1431 SetCursorPos(140, 140);
1432 SetRect(&rc, 150, 150, 150, 150);
1433 ClipCursor(&rc);
1434 GetCursorPos(&pt_old);
1435 ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1436 ClipCursor(NULL);
1438 SetCursorPos(160, 160);
1439 SetRect(&rc, 150, 150, 150, 150);
1440 ClipCursor(&rc);
1441 GetCursorPos(&pt_old);
1442 todo_wine
1443 ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1444 ClipCursor(NULL);
1446 SetCursorPos(150, 150);
1447 SetRect(&rc, 150, 150, 150, 150);
1448 ClipCursor(&rc);
1449 GetCursorPos(&pt_old);
1450 todo_wine
1451 ok(pt_old.x == 149 && pt_old.y == 149, "Wrong new pos: (%ld,%ld)\n", pt_old.x, pt_old.y);
1452 ClipCursor(NULL);
1454 UnhookWindowsHookEx(hook1);
1456 done:
1457 DestroyWindow(hwnd);
1458 SetCursorPos(pt_org.x, pt_org.y);
1461 static void test_GetMouseMovePointsEx(const char *argv0)
1463 #define BUFLIM 64
1464 #define MYERROR 0xdeadbeef
1465 PROCESS_INFORMATION process_info;
1466 STARTUPINFOA startup_info;
1467 char path[MAX_PATH];
1468 int i, count, retval;
1469 MOUSEMOVEPOINT in;
1470 MOUSEMOVEPOINT out[200];
1471 POINT point;
1472 INPUT input;
1474 /* Get a valid content for the input struct */
1475 if(!GetCursorPos(&point)) {
1476 win_skip("GetCursorPos() failed with error %lu\n", GetLastError());
1477 return;
1479 memset(&in, 0, sizeof(MOUSEMOVEPOINT));
1480 in.x = point.x;
1481 in.y = point.y;
1483 /* test first parameter
1484 * everything different than sizeof(MOUSEMOVEPOINT)
1485 * is expected to fail with ERROR_INVALID_PARAMETER
1487 SetLastError(MYERROR);
1488 retval = pGetMouseMovePointsEx(0, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1489 if (retval == ERROR_INVALID_PARAMETER)
1491 win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1492 return;
1494 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1495 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1496 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1498 SetLastError(MYERROR);
1499 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1500 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1501 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1502 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1504 SetLastError(MYERROR);
1505 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1506 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1507 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1508 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1510 /* test second and third parameter
1512 SetLastError(MYERROR);
1513 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1514 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1515 ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR,
1516 "expected error ERROR_NOACCESS, got %lu\n", GetLastError());
1518 SetLastError(MYERROR);
1519 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1520 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1521 ok(ERROR_NOACCESS == GetLastError(),
1522 "expected error ERROR_NOACCESS, got %lu\n", GetLastError());
1524 SetLastError(MYERROR);
1525 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1526 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1527 ok(ERROR_NOACCESS == GetLastError(),
1528 "expected error ERROR_NOACCESS, got %lu\n", GetLastError());
1530 SetLastError(MYERROR);
1531 count = 0;
1532 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, count, GMMP_USE_DISPLAY_POINTS);
1533 if (retval == -1)
1534 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError());
1535 else
1536 ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1538 /* test fourth parameter
1539 * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1541 SetLastError(MYERROR);
1542 count = -1;
1543 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1544 ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1545 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1546 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1548 SetLastError(MYERROR);
1549 count = 0;
1550 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1551 if (retval == -1)
1552 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError());
1553 else
1554 ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1556 SetLastError(MYERROR);
1557 count = BUFLIM;
1558 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1559 if (retval == -1)
1560 ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %lu\n", GetLastError());
1561 else
1562 ok((0 <= retval) && (retval <= count), "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1564 SetLastError(MYERROR);
1565 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1566 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1567 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1568 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1570 /* it was not possible to force an error with the fifth parameter on win2k */
1572 /* test combinations of wrong parameters to see which error wins */
1573 SetLastError(MYERROR);
1574 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1575 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1576 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1577 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1579 SetLastError(MYERROR);
1580 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1581 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1582 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1583 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1585 SetLastError(MYERROR);
1586 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1587 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1588 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1589 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1591 SetLastError(MYERROR);
1592 retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1593 ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1594 ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1595 "expected error ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
1597 /* more than 64 to be sure we wrap around */
1598 for (i = 0; i < 67; i++)
1600 in.x = i;
1601 in.y = i*2;
1602 SetCursorPos( in.x, in.y );
1605 SetLastError( MYERROR );
1606 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1607 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1608 ok( GetLastError() == MYERROR, "expected error to stay %x, got %lx\n", MYERROR, GetLastError() );
1610 for (i = 0; i < retval; i++)
1612 ok( out[i].x == in.x && out[i].y == in.y, "wrong position %d, expected %dx%d got %dx%d\n", i, in.x, in.y, out[i].x, out[i].y );
1613 in.x--;
1614 in.y -= 2;
1617 in.x = 1500;
1618 in.y = 1500;
1619 SetLastError( MYERROR );
1620 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1621 ok( retval == -1, "expected to get -1 but got %d\n", retval );
1622 ok( GetLastError() == ERROR_POINT_NOT_FOUND, "expected error to be set to %x, got %lx\n", ERROR_POINT_NOT_FOUND, GetLastError() );
1624 /* make sure there's no deduplication */
1625 in.x = 6;
1626 in.y = 6;
1627 SetCursorPos( in.x, in.y );
1628 SetCursorPos( in.x, in.y );
1629 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1630 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1631 ok( out[0].x == 6 && out[0].y == 6, "expected cursor position to be 6x6 but got %d %d\n", out[0].x, out[0].y );
1632 ok( out[1].x == 6 && out[1].y == 6, "expected cursor position to be 6x6 but got %d %d\n", out[1].x, out[1].y );
1634 /* make sure 2 events are distinguishable by their timestamps */
1635 in.x = 150;
1636 in.y = 75;
1637 SetCursorPos( 30, 30 );
1638 SetCursorPos( in.x, in.y );
1639 SetCursorPos( 150, 150 );
1640 Sleep( 3 );
1641 SetCursorPos( in.x, in.y );
1643 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1644 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1645 ok( out[0].x == 150 && out[0].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[0].x, out[0].y );
1646 ok( out[1].x == 150 && out[1].y == 150, "expected cursor position to be 150x150 but got %d %d\n", out[1].x, out[1].y );
1647 ok( out[2].x == 150 && out[2].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[2].x, out[2].y );
1649 in.time = out[2].time;
1650 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1651 ok( retval == 62, "expected to get 62 mouse move points but got %d\n", retval );
1652 ok( out[0].x == 150 && out[0].y == 75, "expected cursor position to be 150x75 but got %d %d\n", out[0].x, out[0].y );
1653 ok( out[1].x == 30 && out[1].y == 30, "expected cursor position to be 30x30 but got %d %d\n", out[1].x, out[1].y );
1655 /* events created through other means should also be on the list with correct extra info */
1656 mouse_event( MOUSEEVENTF_MOVE, -13, 17, 0, 0xcafecafe );
1657 ok( GetCursorPos( &point ), "failed to get cursor position\n" );
1658 ok( in.x != point.x && in.y != point.y, "cursor didn't change position after mouse_event()\n" );
1659 in.time = 0;
1660 in.x = point.x;
1661 in.y = point.y;
1662 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1663 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1664 ok( out[0].dwExtraInfo == 0xcafecafe, "wrong extra info, got 0x%Ix expected 0xcafecafe\n", out[0].dwExtraInfo );
1666 input.type = INPUT_MOUSE;
1667 memset( &input, 0, sizeof(input) );
1668 input.mi.dwFlags = MOUSEEVENTF_MOVE;
1669 input.mi.dwExtraInfo = 0xdeadbeef;
1670 input.mi.dx = -17;
1671 input.mi.dy = 13;
1672 SendInput( 1, (INPUT *)&input, sizeof(INPUT) );
1673 ok( GetCursorPos( &point ), "failed to get cursor position\n" );
1674 ok( in.x != point.x && in.y != point.y, "cursor didn't change position after mouse_event()\n" );
1675 in.time = 0;
1676 in.x = point.x;
1677 in.y = point.y;
1678 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS );
1679 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1680 ok( out[0].dwExtraInfo == 0xdeadbeef, "wrong extra info, got 0x%Ix expected 0xdeadbeef\n", out[0].dwExtraInfo );
1682 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_HIGH_RESOLUTION_POINTS );
1683 todo_wine ok( retval == 64, "expected to get 64 high resolution mouse move points but got %d\n", retval );
1685 sprintf(path, "%s input get_mouse_move_points_test", argv0);
1686 memset(&startup_info, 0, sizeof(startup_info));
1687 startup_info.cb = sizeof(startup_info);
1688 startup_info.dwFlags = STARTF_USESHOWWINDOW;
1689 startup_info.wShowWindow = SW_SHOWNORMAL;
1690 retval = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info );
1691 ok(retval, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError());
1692 winetest_wait_child_process(process_info.hProcess);
1693 CloseHandle(process_info.hProcess);
1694 CloseHandle(process_info.hThread);
1695 #undef BUFLIM
1696 #undef MYERROR
1699 static void test_GetMouseMovePointsEx_process(void)
1701 int retval;
1702 MOUSEMOVEPOINT in;
1703 MOUSEMOVEPOINT out[64], out2[64];
1704 POINT point;
1705 HDESK desk0, desk1;
1706 HWINSTA winstation0, winstation1;
1708 memset( out, 0, sizeof(out) );
1709 memset( out2, 0, sizeof(out2) );
1711 /* move point history is shared between desktops within the same windowstation */
1712 ok( GetCursorPos( &point ), "failed to get cursor position\n" );
1713 in.time = 0;
1714 in.x = point.x;
1715 in.y = point.y;
1716 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS );
1717 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1719 desk0 = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS );
1720 ok( desk0 != NULL, "OpenInputDesktop has failed with %ld\n", GetLastError() );
1721 desk1 = CreateDesktopA( "getmousemovepointsex_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
1722 ok( desk1 != NULL, "CreateDesktopA failed with %ld\n", GetLastError() );
1724 ok( SetThreadDesktop( desk1 ), "SetThreadDesktop failed!\n" );
1725 ok( SwitchDesktop( desk1 ), "SwitchDesktop failed\n" );
1727 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out2, ARRAY_SIZE(out2), GMMP_USE_DISPLAY_POINTS );
1728 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1730 ok( memcmp( out, out2, sizeof(out2) ) == 0, "expected to get exact same history on the new desktop\n" );
1732 in.time = 0;
1733 in.x = 38;
1734 in.y = 27;
1735 SetCursorPos( in.x, in.y );
1737 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out2, ARRAY_SIZE(out2), GMMP_USE_DISPLAY_POINTS );
1738 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1740 ok( SetThreadDesktop( desk0 ), "SetThreadDesktop failed!\n" );
1741 ok( SwitchDesktop( desk0 ), "SwitchDesktop failed\n" );
1743 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS );
1744 ok( retval == 64, "expected to get 64 mouse move points but got %d\n", retval );
1745 ok( memcmp( out, out2, sizeof( out2 ) ) == 0, "expected to get exact same history on the old desktop\n" );
1747 CloseDesktop( desk1 );
1748 CloseDesktop( desk0 );
1750 /* non-default windowstations are non-interactive */
1751 winstation0 = GetProcessWindowStation();
1752 ok( winstation0 != NULL, "GetProcessWindowStation has failed with %ld\n", GetLastError() );
1753 desk0 = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS );
1754 ok( desk0 != NULL, "OpenInputDesktop has failed with %ld\n", GetLastError() );
1755 winstation1 = CreateWindowStationA( "test_winstation", 0, WINSTA_ALL_ACCESS, NULL );
1757 if (winstation1 == NULL && GetLastError() == ERROR_ACCESS_DENIED)
1759 win_skip("not enough privileges for CreateWindowStation\n");
1760 CloseDesktop( desk0 );
1761 CloseWindowStation( winstation0 );
1762 return;
1765 ok( winstation1 != NULL, "CreateWindowStationA has failed with %ld\n", GetLastError() );
1766 ok( SetProcessWindowStation( winstation1 ), "SetProcessWindowStation has failed\n" );
1768 desk1 = CreateDesktopA( "getmousemovepointsex_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
1769 ok( desk1 != NULL, "CreateDesktopA failed with %ld\n", GetLastError() );
1770 ok( SetThreadDesktop( desk1 ), "SetThreadDesktop failed!\n" );
1772 SetLastError( 0xDEADBEEF );
1773 retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, ARRAY_SIZE(out), GMMP_USE_DISPLAY_POINTS );
1774 todo_wine ok( retval == -1, "expected to get -1 mouse move points but got %d\n", retval );
1775 todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED got %ld\n", GetLastError() );
1777 ok( SetProcessWindowStation( winstation0 ), "SetProcessWindowStation has failed\n" );
1778 ok( SetThreadDesktop( desk0 ), "SetThreadDesktop failed!\n" );
1779 CloseDesktop( desk1 );
1780 CloseWindowStation( winstation1 );
1781 CloseDesktop( desk0 );
1782 CloseWindowStation( winstation0 );
1785 static void test_GetRawInputDeviceList(void)
1787 RAWINPUTDEVICELIST devices[32];
1788 UINT ret, oret, devcount, odevcount, i;
1789 DWORD err;
1790 BOOLEAN br;
1792 SetLastError(0xdeadbeef);
1793 ret = pGetRawInputDeviceList(NULL, NULL, 0);
1794 err = GetLastError();
1795 ok(ret == -1, "expected -1, got %d\n", ret);
1796 ok(err == ERROR_INVALID_PARAMETER, "expected 87, got %ld\n", err);
1798 SetLastError(0xdeadbeef);
1799 ret = pGetRawInputDeviceList(NULL, NULL, sizeof(devices[0]));
1800 err = GetLastError();
1801 ok(ret == -1, "expected -1, got %d\n", ret);
1802 ok(err == ERROR_NOACCESS, "expected 998, got %ld\n", err);
1804 devcount = 0;
1805 ret = pGetRawInputDeviceList(NULL, &devcount, sizeof(devices[0]));
1806 ok(ret == 0, "expected 0, got %d\n", ret);
1807 ok(devcount > 0, "expected non-zero\n");
1809 SetLastError(0xdeadbeef);
1810 devcount = 0;
1811 ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0]));
1812 err = GetLastError();
1813 ok(ret == -1, "expected -1, got %d\n", ret);
1814 ok(err == ERROR_INSUFFICIENT_BUFFER, "expected 122, got %ld\n", err);
1815 ok(devcount > 0, "expected non-zero\n");
1817 /* devcount contains now the correct number of devices */
1818 ret = pGetRawInputDeviceList(devices, &devcount, sizeof(devices[0]));
1819 ok(ret > 0, "expected non-zero\n");
1821 if (devcount)
1823 RID_DEVICE_INFO info;
1824 UINT size;
1826 SetLastError( 0xdeadbeef );
1827 ret = pGetRawInputDeviceInfoW( UlongToHandle( 0xdeadbeef ), RIDI_DEVICEINFO, NULL, NULL );
1828 ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret );
1829 ok( GetLastError() == ERROR_NOACCESS, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() );
1831 SetLastError( 0xdeadbeef );
1832 size = 0xdeadbeef;
1833 ret = pGetRawInputDeviceInfoW( UlongToHandle( 0xdeadbeef ), RIDI_DEVICEINFO, NULL, &size );
1834 ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret );
1835 ok( size == 0xdeadbeef, "GetRawInputDeviceInfoW returned size %#x, expected 0.\n", size );
1836 ok( GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() );
1838 SetLastError( 0xdeadbeef );
1839 size = 0xdeadbeef;
1840 ret = pGetRawInputDeviceInfoW( devices[0].hDevice, 0xdeadbeef, NULL, &size );
1841 ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret );
1842 ok( size == 0xdeadbeef, "GetRawInputDeviceInfoW returned size %#x, expected 0.\n", size );
1843 ok( GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() );
1845 SetLastError( 0xdeadbeef );
1846 ret = pGetRawInputDeviceInfoW( devices[0].hDevice, RIDI_DEVICEINFO, &info, NULL );
1847 ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret );
1848 ok( GetLastError() == ERROR_NOACCESS, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() );
1850 SetLastError( 0xdeadbeef );
1851 size = 0;
1852 ret = pGetRawInputDeviceInfoW( devices[0].hDevice, RIDI_DEVICEINFO, &info, &size );
1853 ok( ret == ~0U, "GetRawInputDeviceInfoW returned %#x, expected ~0.\n", ret );
1854 ok( size == sizeof(info), "GetRawInputDeviceInfoW returned size %#x, expected %#Ix.\n", size, sizeof(info) );
1855 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputDeviceInfoW last error %#lx, expected 0xdeadbeef.\n", GetLastError() );
1858 for(i = 0; i < devcount; ++i)
1860 WCHAR name[128];
1861 char nameA[128];
1862 UINT sz, len;
1863 RID_DEVICE_INFO info;
1864 HANDLE file;
1865 char *ppd;
1867 /* get required buffer size */
1868 name[0] = '\0';
1869 sz = 5;
1870 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, name, &sz);
1871 ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %ld\n", err);
1872 ok(sz > 5 && sz < ARRAY_SIZE(name), "Size should have been set and not too large (got: %u)\n", sz);
1874 /* buffer size for RIDI_DEVICENAME is in CHARs, not BYTEs */
1875 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICENAME, name, &sz);
1876 ok(ret == sz, "GetRawInputDeviceInfo gave wrong return: %ld\n", err);
1877 len = lstrlenW(name);
1878 ok(len + 1 == ret, "GetRawInputDeviceInfo returned wrong length (name: %u, ret: %u)\n", len + 1, ret);
1880 /* test A variant with same size */
1881 ret = pGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, nameA, &sz);
1882 ok(ret == sz, "GetRawInputDeviceInfoA gave wrong return: %ld\n", err);
1883 len = strlen(nameA);
1884 ok(len + 1 == ret, "GetRawInputDeviceInfoA returned wrong length (name: %u, ret: %u)\n", len + 1, ret);
1886 /* buffer size for RIDI_DEVICEINFO is in BYTEs */
1887 memset(&info, 0, sizeof(info));
1888 info.cbSize = sizeof(info);
1889 sz = sizeof(info) - 1;
1890 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz);
1891 ok(ret == -1, "GetRawInputDeviceInfo gave wrong failure: %ld\n", err);
1892 ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n");
1894 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz);
1895 ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %ld\n", err);
1896 ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n");
1897 ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%lx\n", info.dwType);
1899 memset(&info, 0, sizeof(info));
1900 info.cbSize = sizeof(info);
1901 ret = pGetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &info, &sz);
1902 ok(ret == sizeof(info), "GetRawInputDeviceInfo gave wrong return: %ld\n", err);
1903 ok(sz == sizeof(info), "GetRawInputDeviceInfo set wrong size\n");
1904 ok(info.dwType == devices[i].dwType, "GetRawInputDeviceInfo set wrong type: 0x%lx\n", info.dwType);
1906 /* setupapi returns an NT device path, but CreateFile() < Vista can't
1907 * understand that; so use the \\?\ prefix instead */
1908 name[1] = '\\';
1909 file = CreateFileW(name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1910 ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %lu\n", wine_dbgstr_w(name), GetLastError());
1912 sz = 0;
1913 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_PREPARSEDDATA, NULL, &sz);
1914 ok(ret == 0, "GetRawInputDeviceInfo gave wrong return: %u\n", ret);
1915 ok((info.dwType == RIM_TYPEHID && sz != 0) ||
1916 (info.dwType != RIM_TYPEHID && sz == 0),
1917 "Got wrong PPD size for type 0x%lx: %u\n", info.dwType, sz);
1919 ppd = HeapAlloc(GetProcessHeap(), 0, sz);
1920 ret = pGetRawInputDeviceInfoW(devices[i].hDevice, RIDI_PREPARSEDDATA, ppd, &sz);
1921 ok(ret == sz, "GetRawInputDeviceInfo gave wrong return: %u, should be %u\n", ret, sz);
1923 if (file != INVALID_HANDLE_VALUE && ret == sz)
1925 PHIDP_PREPARSED_DATA preparsed;
1927 if (info.dwType == RIM_TYPEHID)
1929 br = HidD_GetPreparsedData(file, &preparsed);
1930 ok(br == TRUE, "HidD_GetPreparsedData failed\n");
1932 if (br)
1933 ok(!memcmp(preparsed, ppd, sz), "Expected to get same preparsed data\n");
1935 else
1937 /* succeeds on hardware, fails in some VMs */
1938 br = HidD_GetPreparsedData(file, &preparsed);
1939 ok(br == TRUE || broken(br == FALSE), "HidD_GetPreparsedData failed\n");
1942 if (br)
1943 HidD_FreePreparsedData(preparsed);
1946 HeapFree(GetProcessHeap(), 0, ppd);
1948 CloseHandle(file);
1951 /* check if variable changes from larger to smaller value */
1952 devcount = odevcount = ARRAY_SIZE(devices);
1953 oret = ret = pGetRawInputDeviceList(devices, &odevcount, sizeof(devices[0]));
1954 ok(ret > 0, "expected non-zero\n");
1955 ok(devcount == odevcount, "expected %d, got %d\n", devcount, odevcount);
1956 devcount = odevcount;
1957 odevcount = ARRAY_SIZE(devices);
1958 ret = pGetRawInputDeviceList(NULL, &odevcount, sizeof(devices[0]));
1959 ok(ret == 0, "expected 0, got %d\n", ret);
1960 ok(odevcount == oret, "expected %d, got %d\n", oret, odevcount);
1963 static void test_GetRawInputData(void)
1965 UINT size;
1966 UINT ret;
1968 /* Null raw input handle */
1969 SetLastError(0xdeadbeef);
1970 ret = GetRawInputData(NULL, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
1971 ok(ret == ~0U, "Expect ret %u, got %u\n", ~0U, ret);
1972 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputData returned %08lx\n", GetLastError());
1975 static void test_RegisterRawInputDevices(void)
1977 HWND hwnd;
1978 RAWINPUTDEVICE raw_devices[2];
1979 UINT count, raw_devices_count;
1980 BOOL res;
1982 memset(raw_devices, 0, sizeof(raw_devices));
1983 raw_devices[0].usUsagePage = 0x01;
1984 raw_devices[0].usUsage = 0x05;
1985 raw_devices[1].usUsagePage = 0x01;
1986 raw_devices[1].usUsage = 0x04;
1988 hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
1989 ok(hwnd != NULL, "CreateWindowExA failed\n");
1992 res = RegisterRawInputDevices(NULL, 0, 0);
1993 ok(res == FALSE, "RegisterRawInputDevices succeeded\n");
1996 SetLastError(0xdeadbeef);
1997 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), 0);
1998 ok(res == FALSE, "RegisterRawInputDevices succeeded\n");
1999 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2001 SetLastError(0xdeadbeef);
2002 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2003 ok(res == TRUE, "RegisterRawInputDevices failed\n");
2004 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2006 SetLastError(0xdeadbeef);
2007 count = GetRegisteredRawInputDevices(NULL, NULL, 0);
2008 ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count);
2009 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2011 SetLastError(0xdeadbeef);
2012 raw_devices_count = 0;
2013 count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, 0);
2014 ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count);
2015 ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count);
2016 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2018 SetLastError(0xdeadbeef);
2019 raw_devices_count = 0;
2020 count = GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE));
2021 ok(count == 0, "GetRegisteredRawInputDevices returned %u\n", count);
2022 ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count);
2023 ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2025 SetLastError(0xdeadbeef);
2026 raw_devices_count = 0;
2027 count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE));
2028 if (broken(count == 0) /* depends on windows versions */)
2029 win_skip("Ignoring GetRegisteredRawInputDevices success\n");
2030 else
2032 ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count);
2033 ok(raw_devices_count == 0, "Unexpected registered devices count: %u\n", raw_devices_count);
2034 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2037 SetLastError(0xdeadbeef);
2038 raw_devices_count = 1;
2039 count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE));
2040 ok(count == ~0U, "GetRegisteredRawInputDevices returned %u\n", count);
2041 ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count);
2042 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2044 SetLastError(0xdeadbeef);
2045 memset(raw_devices, 0, sizeof(raw_devices));
2046 raw_devices_count = ARRAY_SIZE(raw_devices);
2047 count = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE));
2048 ok(count == 2, "GetRegisteredRawInputDevices returned %u\n", count);
2049 ok(raw_devices_count == 2, "Unexpected registered devices count: %u\n", raw_devices_count);
2050 ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08lx\n", GetLastError());
2051 ok(raw_devices[0].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[0].usUsagePage);
2052 ok(raw_devices[0].usUsage == 0x04, "Unexpected usage: %x\n", raw_devices[0].usUsage);
2053 ok(raw_devices[1].usUsagePage == 0x01, "Unexpected usage page: %x\n", raw_devices[1].usUsagePage);
2054 ok(raw_devices[1].usUsage == 0x05, "Unexpected usage: %x\n", raw_devices[1].usUsage);
2056 /* RIDEV_REMOVE requires hwndTarget == NULL */
2057 raw_devices[0].dwFlags = RIDEV_REMOVE;
2058 raw_devices[0].hwndTarget = hwnd;
2059 raw_devices[1].dwFlags = RIDEV_REMOVE;
2060 raw_devices[1].hwndTarget = hwnd;
2062 SetLastError(0xdeadbeef);
2063 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2064 ok(res == FALSE, "RegisterRawInputDevices succeeded\n");
2065 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2067 raw_devices[0].hwndTarget = 0;
2068 raw_devices[1].hwndTarget = 0;
2070 SetLastError(0xdeadbeef);
2071 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2072 ok(res == TRUE, "RegisterRawInputDevices failed\n");
2073 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2076 /* RIDEV_INPUTSINK requires hwndTarget != NULL */
2077 raw_devices[0].dwFlags = RIDEV_INPUTSINK;
2078 raw_devices[0].hwndTarget = 0;
2079 raw_devices[1].dwFlags = RIDEV_INPUTSINK;
2080 raw_devices[1].hwndTarget = 0;
2082 SetLastError(0xdeadbeef);
2083 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2084 ok(res == FALSE, "RegisterRawInputDevices failed\n");
2085 ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2087 raw_devices[0].hwndTarget = hwnd;
2088 raw_devices[1].hwndTarget = hwnd;
2090 SetLastError(0xdeadbeef);
2091 res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2092 ok(res == TRUE, "RegisterRawInputDevices succeeded\n");
2093 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2095 DestroyWindow(hwnd);
2098 static int rawinputbuffer_wndproc_count;
2100 typedef struct
2102 DWORD dwType;
2103 DWORD dwSize;
2104 ULONG hDevice;
2105 ULONG wParam;
2106 } RAWINPUTHEADER32;
2108 #ifdef _WIN64
2109 typedef RAWINPUTHEADER RAWINPUTHEADER64;
2110 typedef RAWINPUT RAWINPUT64;
2111 #else
2112 typedef struct
2114 DWORD dwType;
2115 DWORD dwSize;
2116 ULONGLONG hDevice;
2117 ULONGLONG wParam;
2118 } RAWINPUTHEADER64;
2120 typedef struct
2122 RAWINPUTHEADER64 header;
2123 union {
2124 RAWMOUSE mouse;
2125 RAWKEYBOARD keyboard;
2126 RAWHID hid;
2127 } data;
2128 } RAWINPUT64;
2129 #endif
2131 static int rawinput_buffer_mouse_x(void *buffer, size_t index)
2133 if (is_wow64) return ((RAWINPUT64 *)buffer)[index].data.mouse.lLastX;
2134 return ((RAWINPUT *)buffer)[index].data.mouse.lLastX;
2137 static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2139 UINT i, size, count, rawinput_size, iteration = rawinputbuffer_wndproc_count++;
2140 RAWINPUT ri;
2141 char buffer[16 * sizeof(RAWINPUT64)];
2142 MSG message;
2144 if (is_wow64) rawinput_size = sizeof(RAWINPUT64);
2145 else rawinput_size = sizeof(RAWINPUT);
2147 if (msg == WM_INPUT)
2149 SetLastError(0xdeadbeef);
2150 count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER));
2151 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2152 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError());
2154 size = sizeof(buffer);
2155 count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
2156 ok(count == 0, "GetRawInputBuffer returned %u\n", count);
2157 ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
2159 size = sizeof(buffer);
2160 memset(buffer, 0, sizeof(buffer));
2161 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2162 ok(count == 3, "GetRawInputBuffer returned %u\n", count);
2163 ok(size == sizeof(buffer), "GetRawInputBuffer returned unexpected size: %u\n", size);
2165 for (i = 0; i < 3; ++i)
2167 if (is_wow64)
2169 const RAWINPUT64 *data = &((RAWINPUT64 *)buffer)[i];
2170 ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType);
2171 ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize);
2172 todo_wine_if (wparam)
2173 ok(data->header.wParam == wparam, "Unexpected wparam: %#I64x\n", data->header.wParam);
2175 else
2177 const RAWINPUT *data = &((RAWINPUT *)buffer)[i];
2178 ok(data->header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", data->header.dwType);
2179 ok(data->header.dwSize == sizeof(*data), "Unexpected rawinput size: %lu\n", data->header.dwSize);
2180 todo_wine_if (wparam)
2181 ok(data->header.wParam == wparam, "Unexpected wparam: %#Ix\n", data->header.wParam);
2185 ok(rawinput_buffer_mouse_x(buffer, 0) == 2, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
2186 ok(rawinput_buffer_mouse_x(buffer, 1) == 3, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 1));
2187 ok(rawinput_buffer_mouse_x(buffer, 2) == 4, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 2));
2189 /* the first event should be removed by the next GetRawInputBuffer call
2190 * and the others should do another round through the message loop but not more */
2191 if (iteration == 0)
2193 mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2194 mouse_event(MOUSEEVENTF_MOVE, 6, 0, 0, 0);
2195 mouse_event(MOUSEEVENTF_MOVE, 2, 0, 0, 0);
2196 mouse_event(MOUSEEVENTF_MOVE, 3, 0, 0, 0);
2197 mouse_event(MOUSEEVENTF_MOVE, 4, 0, 0, 0);
2199 /* even though rawinput_size is the minimum required size,
2200 * it needs one more byte to return success */
2201 size = rawinput_size + 1;
2202 memset(buffer, 0, sizeof(buffer));
2203 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2204 ok(count == 1, "GetRawInputBuffer returned %u\n", count);
2205 ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
2207 /* peek the messages now, they should still arrive in the correct order */
2208 while (PeekMessageA(&message, 0, WM_INPUT, WM_INPUT, PM_REMOVE)) DispatchMessageA(&message);
2211 /* reading the message data now should fail on the second iteration, the data
2212 * from the first message has been overwritten. */
2213 size = sizeof(ri);
2214 memset(&ri, 0, sizeof(ri));
2215 SetLastError(0xdeadbeef);
2216 count = GetRawInputData((HRAWINPUT)lparam, RID_HEADER, &ri, &size, sizeof(RAWINPUTHEADER));
2217 if (iteration == 1)
2219 SetLastError(0xdeadbeef);
2220 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, 0);
2221 ok(count == ~0u, "GetRawInputData returned %d\n", count);
2222 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
2224 SetLastError(0xdeadbeef);
2225 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) + 1);
2226 ok(count == ~0u, "GetRawInputData returned %d\n", count);
2227 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
2229 SetLastError(0xdeadbeef);
2230 size = 0;
2231 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER));
2232 ok(count == ~0U, "GetRawInputData succeeded\n");
2233 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputData returned %08lx\n", GetLastError());
2235 SetLastError(0xdeadbeef);
2236 size = sizeof(ri);
2237 count = GetRawInputData((HRAWINPUT)lparam, 0, &ri, &size, sizeof(RAWINPUTHEADER));
2238 ok(count == ~0U, "GetRawInputData succeeded\n");
2239 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
2241 SetLastError(0xdeadbeef);
2242 size = sizeof(ri);
2243 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER));
2244 ok(count == sizeof(ri), "GetRawInputData failed\n");
2245 ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX);
2246 ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError());
2248 SetLastError(0xdeadbeef);
2249 size = sizeof(buffer);
2250 if (sizeof(void *) == 8)
2252 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER32));
2253 ok(count == ~0u, "GetRawInputData returned %d\n", count);
2254 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
2256 else
2258 count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER64));
2259 if (is_wow64)
2261 todo_wine ok(count == sizeof(ri), "GetRawInputData returned %d\n", count);
2262 ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %ld\n", ri.data.mouse.lLastX);
2263 todo_wine ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08lx\n", GetLastError());
2265 else
2267 ok(count == ~0u, "GetRawInputData returned %d\n", count);
2268 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08lx\n", GetLastError());
2272 else
2274 ok(count == ~0U, "GetRawInputData succeeded\n");
2275 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputData returned %08lx\n", GetLastError());
2278 return 0;
2281 return DefWindowProcA(hwnd, msg, wparam, lparam);
2284 static void test_GetRawInputBuffer(void)
2286 unsigned int size, count, rawinput_size, header_size;
2287 RAWINPUTDEVICE raw_devices[1];
2288 char buffer[16 * sizeof(RAWINPUT64)];
2289 HWND hwnd;
2290 BOOL ret;
2291 POINT pt;
2293 if (is_wow64) rawinput_size = sizeof(RAWINPUT64);
2294 else rawinput_size = sizeof(RAWINPUT);
2296 SetCursorPos(300, 300);
2297 GetCursorPos(&pt);
2298 ok(pt.x == 300 && pt.y == 300, "Unexpected cursor position pos %ldx%ld\n", pt.x, pt.y);
2300 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2301 100, 100, 100, 100, 0, NULL, NULL, NULL);
2302 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinputbuffer_wndproc);
2303 ok(hwnd != 0, "CreateWindow failed\n");
2304 empty_message_queue();
2306 raw_devices[0].usUsagePage = 0x01;
2307 raw_devices[0].usUsage = 0x02;
2308 raw_devices[0].dwFlags = RIDEV_INPUTSINK;
2309 raw_devices[0].hwndTarget = hwnd;
2311 SetLastError(0xdeadbeef);
2312 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2313 ok(ret, "RegisterRawInputDevices failed\n");
2314 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2316 SetLastError(0xdeadbeef);
2317 count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER));
2318 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2319 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2321 size = sizeof(buffer);
2322 count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
2323 ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
2324 ok(size == 0U, "GetRawInputBuffer returned unexpected size: %u\n", size);
2326 size = 0;
2327 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2328 ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
2329 ok(size == 0U, "GetRawInputBuffer returned unexpected size: %u\n", size);
2331 SetLastError(0xdeadbeef);
2332 size = sizeof(buffer);
2333 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, 0);
2334 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2335 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2337 size = sizeof(buffer);
2338 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2339 ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
2340 ok(size == 0U, "GetRawInputBuffer returned unexpected size: %u\n", size);
2342 mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2344 SetLastError(0xdeadbeef);
2345 size = 0;
2346 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2347 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2348 ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
2349 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2351 size = 0;
2352 count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
2353 ok(count == 0, "GetRawInputBuffer returned %u\n", count);
2354 ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
2356 SetLastError(0xdeadbeef);
2357 size = sizeof(buffer);
2358 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, 0);
2359 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2360 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2362 SetLastError(0xdeadbeef);
2363 size = sizeof(buffer);
2364 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER) + 1);
2365 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2366 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2368 /* the function returns 64-bit RAWINPUT structures on WoW64, but still
2369 * forbids sizeof(RAWINPUTHEADER) from the wrong architecture */
2370 SetLastError(0xdeadbeef);
2371 size = sizeof(buffer);
2372 header_size = (sizeof(void *) == 8 ? sizeof(RAWINPUTHEADER32) : sizeof(RAWINPUTHEADER64));
2373 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, header_size);
2374 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2375 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2377 size = sizeof(buffer);
2378 memset(buffer, 0, sizeof(buffer));
2379 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2380 ok(count == 1U, "GetRawInputBuffer returned %u\n", count);
2381 ok(size == sizeof(buffer), "GetRawInputBuffer returned unexpected size: %u\n", size);
2382 ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
2385 /* NOTE: calling with size == rawinput_size returns an error, */
2386 /* BUT it fills the buffer nonetheless and empties the internal buffer (!!) */
2387 mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2389 SetLastError(0xdeadbeef);
2390 size = rawinput_size;
2391 memset(buffer, 0, sizeof(buffer));
2392 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2393 ok(count == ~0U, "GetRawInputBuffer succeeded\n");
2394 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputBuffer returned %08lx\n", GetLastError());
2395 ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
2397 size = sizeof(buffer);
2398 count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
2399 ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
2402 rawinputbuffer_wndproc_count = 0;
2403 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
2404 mouse_event(MOUSEEVENTF_MOVE, 2, 0, 0, 0);
2405 mouse_event(MOUSEEVENTF_MOVE, 3, 0, 0, 0);
2406 mouse_event(MOUSEEVENTF_MOVE, 4, 0, 0, 0);
2407 empty_message_queue();
2408 ok(rawinputbuffer_wndproc_count == 2, "Spurious WM_INPUT messages\n");
2410 raw_devices[0].dwFlags = RIDEV_REMOVE;
2411 raw_devices[0].hwndTarget = 0;
2413 SetLastError(0xdeadbeef);
2414 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2415 ok(ret, "RegisterRawInputDevices failed\n");
2416 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08lx\n", GetLastError());
2418 DestroyWindow(hwnd);
2421 static BOOL rawinput_test_received_legacy;
2422 static BOOL rawinput_test_received_raw;
2423 static BOOL rawinput_test_received_rawfg;
2425 static LRESULT CALLBACK rawinput_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2427 UINT ret, raw_size;
2428 RAWINPUT raw;
2430 if (msg == WM_INPUT)
2432 todo_wine_if(rawinput_test_received_raw)
2433 ok(!rawinput_test_received_raw, "Unexpected spurious WM_INPUT message.\n");
2434 ok(wparam == RIM_INPUT || wparam == RIM_INPUTSINK, "Unexpected wparam: %Iu\n", wparam);
2436 rawinput_test_received_raw = TRUE;
2437 if (wparam == RIM_INPUT) rawinput_test_received_rawfg = TRUE;
2439 ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &raw_size, sizeof(RAWINPUTHEADER));
2440 ok(ret == 0, "GetRawInputData failed\n");
2441 ok(raw_size <= sizeof(raw), "Unexpected rawinput data size: %u", raw_size);
2443 raw_size = sizeof(raw);
2444 ret = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw, &raw_size, sizeof(RAWINPUTHEADER));
2445 ok(ret > 0 && ret != (UINT)-1, "GetRawInputData failed\n");
2446 ok(raw.header.dwType == RIM_TYPEMOUSE, "Unexpected rawinput type: %lu\n", raw.header.dwType);
2447 ok(raw.header.dwSize == raw_size, "Expected size %u, got %lu\n", raw_size, raw.header.dwSize);
2448 todo_wine_if (wparam)
2449 ok(raw.header.wParam == wparam, "Expected wparam %Iu, got %Iu\n", wparam, raw.header.wParam);
2451 ok(!(raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE), "Unexpected absolute rawinput motion\n");
2452 ok(!(raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP), "Unexpected virtual desktop rawinput motion\n");
2455 if (msg == WM_MOUSEMOVE) rawinput_test_received_legacy = TRUE;
2457 return DefWindowProcA(hwnd, msg, wparam, lparam);
2460 struct rawinput_test
2462 BOOL register_device;
2463 BOOL register_window;
2464 DWORD register_flags;
2465 BOOL expect_legacy;
2466 BOOL expect_raw;
2467 BOOL expect_rawfg;
2468 BOOL todo_legacy;
2469 BOOL todo_raw;
2470 BOOL todo_rawfg;
2473 struct rawinput_test rawinput_tests[] =
2475 { FALSE, FALSE, 0, TRUE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2476 { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
2477 { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
2478 { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
2480 /* same-process foreground tests */
2481 { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2482 { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
2484 /* cross-process foreground tests */
2485 { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2486 { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2487 { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2489 /* multi-process rawinput tests */
2490 { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2491 { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2492 { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2494 { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2495 { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE },
2497 /* cross-desktop foreground tests */
2498 { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2499 { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
2500 { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
2503 static void rawinput_test_process(void)
2505 RAWINPUTDEVICE raw_devices[1];
2506 HANDLE ready, start, done;
2507 DWORD ret;
2508 POINT pt;
2509 HWND hwnd = NULL;
2510 MSG msg;
2511 int i;
2513 ready = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_ready");
2514 ok(ready != 0, "OpenEventA failed, error: %lu\n", GetLastError());
2516 start = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_start");
2517 ok(start != 0, "OpenEventA failed, error: %lu\n", GetLastError());
2519 done = OpenEventA(EVENT_ALL_ACCESS, FALSE, "rawinput_test_process_done");
2520 ok(done != 0, "OpenEventA failed, error: %lu\n", GetLastError());
2522 for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i)
2524 WaitForSingleObject(ready, INFINITE);
2525 ResetEvent(ready);
2527 switch (i)
2529 case 6:
2530 case 7:
2531 case 8:
2532 case 9:
2533 case 10:
2534 case 11:
2535 case 12:
2536 case 13:
2537 case 16:
2538 GetCursorPos(&pt);
2540 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2541 pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
2542 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
2543 ok(hwnd != 0, "CreateWindow failed\n");
2544 empty_message_queue();
2546 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2547 * make the window visible and foreground as hard as possible. */
2548 ShowWindow(hwnd, SW_SHOW);
2549 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2550 SetForegroundWindow(hwnd);
2551 UpdateWindow(hwnd);
2552 empty_message_queue();
2554 if (i == 9 || i == 10 || i == 11 || i == 12)
2556 raw_devices[0].usUsagePage = 0x01;
2557 raw_devices[0].usUsage = 0x02;
2558 raw_devices[0].dwFlags = i == 11 ? RIDEV_INPUTSINK : 0;
2559 raw_devices[0].hwndTarget = i == 11 ? hwnd : 0;
2561 SetLastError(0xdeadbeef);
2562 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2563 ok(ret, "%d: RegisterRawInputDevices failed\n", i);
2564 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError());
2567 rawinput_test_received_legacy = FALSE;
2568 rawinput_test_received_raw = FALSE;
2569 rawinput_test_received_rawfg = FALSE;
2571 /* fallthrough */
2572 case 14:
2573 case 15:
2574 if (i != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2575 empty_message_queue();
2576 break;
2579 SetEvent(start);
2581 while (MsgWaitForMultipleObjects(1, &done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
2582 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2584 ResetEvent(done);
2586 if (i == 9 || i == 10 || i == 11 || i == 12)
2588 raw_devices[0].dwFlags = RIDEV_REMOVE;
2589 raw_devices[0].hwndTarget = 0;
2591 flaky_wine
2592 ok(rawinput_test_received_legacy, "%d: foreground process expected WM_MOUSEMOVE message\n", i);
2593 ok(rawinput_test_received_raw, "%d: foreground process expected WM_INPUT message\n", i);
2594 ok(rawinput_test_received_rawfg, "%d: foreground process expected RIM_INPUT message\n", i);
2596 SetLastError(0xdeadbeef);
2597 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2598 ok(ret, "%d: RegisterRawInputDevices failed\n", i);
2599 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError());
2602 if (hwnd) DestroyWindow(hwnd);
2605 WaitForSingleObject(ready, INFINITE);
2606 CloseHandle(done);
2607 CloseHandle(start);
2608 CloseHandle(ready);
2611 struct rawinput_test_thread_params
2613 HDESK desk;
2614 HANDLE ready;
2615 HANDLE start;
2616 HANDLE done;
2619 static DWORD WINAPI rawinput_test_desk_thread(void *arg)
2621 struct rawinput_test_thread_params *params = arg;
2622 RAWINPUTDEVICE raw_devices[1];
2623 DWORD ret;
2624 POINT pt;
2625 HWND hwnd = NULL;
2626 MSG msg;
2627 int i;
2629 ok( SetThreadDesktop( params->desk ), "SetThreadDesktop failed\n" );
2631 for (i = 14; i < ARRAY_SIZE(rawinput_tests); ++i)
2633 WaitForSingleObject(params->ready, INFINITE);
2634 ResetEvent(params->ready);
2636 switch (i)
2638 case 14:
2639 case 15:
2640 case 16:
2641 GetCursorPos(&pt);
2643 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2644 pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
2645 ok(hwnd != 0, "CreateWindow failed\n");
2646 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
2647 empty_message_queue();
2649 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2650 * make the window visible and foreground as hard as possible. */
2651 ShowWindow(hwnd, SW_SHOW);
2652 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2653 SetForegroundWindow(hwnd);
2654 UpdateWindow(hwnd);
2655 empty_message_queue();
2657 raw_devices[0].usUsagePage = 0x01;
2658 raw_devices[0].usUsage = 0x02;
2659 raw_devices[0].dwFlags = rawinput_tests[i].register_flags;
2660 raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0;
2662 rawinput_test_received_legacy = FALSE;
2663 rawinput_test_received_raw = FALSE;
2664 rawinput_test_received_rawfg = FALSE;
2666 SetLastError(0xdeadbeef);
2667 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2668 ok(ret, "%d: RegisterRawInputDevices failed\n", i);
2669 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08lx\n", i, GetLastError());
2670 break;
2673 SetEvent(params->start);
2675 while (MsgWaitForMultipleObjects(1, &params->done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
2676 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2678 ResetEvent(params->done);
2679 if (hwnd) DestroyWindow(hwnd);
2682 return 0;
2685 static DWORD WINAPI rawinput_test_thread(void *arg)
2687 struct rawinput_test_thread_params *params = arg;
2688 HANDLE thread;
2689 POINT pt;
2690 HWND hwnd = NULL;
2691 int i;
2693 for (i = 0; i < 14; ++i)
2695 WaitForSingleObject(params->ready, INFINITE);
2696 ResetEvent(params->ready);
2698 switch (i)
2700 case 4:
2701 case 5:
2702 GetCursorPos(&pt);
2704 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2705 pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
2706 ok(hwnd != 0, "CreateWindow failed\n");
2707 empty_message_queue();
2709 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2710 * make the window visible and foreground as hard as possible. */
2711 ShowWindow(hwnd, SW_SHOW);
2712 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2713 SetForegroundWindow(hwnd);
2714 UpdateWindow(hwnd);
2715 empty_message_queue();
2717 mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2718 empty_message_queue();
2719 break;
2722 SetEvent(params->start);
2724 WaitForSingleObject(params->done, INFINITE);
2725 ResetEvent(params->done);
2726 if (hwnd) DestroyWindow(hwnd);
2729 thread = CreateThread(NULL, 0, rawinput_test_desk_thread, params, 0, NULL);
2730 ok(thread != NULL, "CreateThread failed\n");
2731 WaitForSingleObject(thread, INFINITE);
2732 CloseHandle(thread);
2734 return 0;
2737 static void test_rawinput(const char* argv0)
2739 struct rawinput_test_thread_params params;
2740 PROCESS_INFORMATION process_info;
2741 RAWINPUTDEVICE raw_devices[1];
2742 STARTUPINFOA startup_info;
2743 HANDLE thread, process_ready, process_start, process_done;
2744 DWORD ret;
2745 POINT pt, newpt;
2746 HWND hwnd;
2747 BOOL skipped;
2748 char path[MAX_PATH];
2749 int i;
2751 params.desk = CreateDesktopA( "rawinput_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
2752 ok( params.desk != NULL, "CreateDesktopA failed, last error: %lu\n", GetLastError() );
2754 params.ready = CreateEventA(NULL, FALSE, FALSE, NULL);
2755 ok(params.ready != NULL, "CreateEvent failed\n");
2757 params.start = CreateEventA(NULL, FALSE, FALSE, NULL);
2758 ok(params.start != NULL, "CreateEvent failed\n");
2760 params.done = CreateEventA(NULL, FALSE, FALSE, NULL);
2761 ok(params.done != NULL, "CreateEvent failed\n");
2763 thread = CreateThread(NULL, 0, rawinput_test_thread, &params, 0, NULL);
2764 ok(thread != NULL, "CreateThread failed\n");
2766 process_ready = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_ready");
2767 ok(process_ready != NULL, "CreateEventA failed\n");
2769 process_start = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_start");
2770 ok(process_start != NULL, "CreateEventA failed\n");
2772 process_done = CreateEventA(NULL, FALSE, FALSE, "rawinput_test_process_done");
2773 ok(process_done != NULL, "CreateEventA failed\n");
2775 memset(&startup_info, 0, sizeof(startup_info));
2776 startup_info.cb = sizeof(startup_info);
2777 startup_info.dwFlags = STARTF_USESHOWWINDOW;
2778 startup_info.wShowWindow = SW_SHOWNORMAL;
2780 sprintf(path, "%s input rawinput_test", argv0);
2781 ret = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info );
2782 ok(ret, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError());
2784 SetCursorPos(100, 100);
2785 empty_message_queue();
2787 for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i)
2789 GetCursorPos(&pt);
2791 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2792 pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
2793 ok(hwnd != 0, "CreateWindow failed\n");
2794 if (i != 14 && i != 15 && i != 16)
2795 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc);
2796 empty_message_queue();
2798 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2799 * make the window visible and foreground as hard as possible. */
2800 ShowWindow(hwnd, SW_SHOW);
2801 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2802 SetForegroundWindow(hwnd);
2803 UpdateWindow(hwnd);
2804 empty_message_queue();
2806 rawinput_test_received_legacy = FALSE;
2807 rawinput_test_received_raw = FALSE;
2808 rawinput_test_received_rawfg = FALSE;
2810 raw_devices[0].usUsagePage = 0x01;
2811 raw_devices[0].usUsage = 0x02;
2812 raw_devices[0].dwFlags = rawinput_tests[i].register_flags;
2813 raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0;
2815 if (!rawinput_tests[i].register_device)
2816 skipped = FALSE;
2817 else
2819 SetLastError(0xdeadbeef);
2820 skipped = !RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2821 if (rawinput_tests[i].register_flags == RIDEV_EXINPUTSINK && skipped)
2822 win_skip("RIDEV_EXINPUTSINK not supported\n");
2823 else
2824 ok(!skipped, "%d: RegisterRawInputDevices failed: %lu\n", i, GetLastError());
2827 SetEvent(params.ready);
2828 WaitForSingleObject(params.start, INFINITE);
2829 ResetEvent(params.start);
2831 /* we need the main window to be over the other thread window, as although
2832 * it is in another desktop, it will receive the messages directly otherwise */
2833 switch (i)
2835 case 14:
2836 case 15:
2837 DestroyWindow(hwnd);
2838 hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
2839 pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL);
2840 ok(hwnd != 0, "CreateWindow failed\n");
2841 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
2842 SetForegroundWindow(hwnd);
2843 empty_message_queue();
2845 rawinput_test_received_legacy = FALSE;
2846 rawinput_test_received_raw = FALSE;
2847 rawinput_test_received_rawfg = FALSE;
2848 break;
2851 SetEvent(process_ready);
2852 WaitForSingleObject(process_start, INFINITE);
2853 ResetEvent(process_start);
2855 if (i <= 3 || i == 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
2856 empty_message_queue();
2858 SetEvent(process_done);
2859 SetEvent(params.done);
2861 flaky_wine
2862 if (!skipped)
2864 todo_wine_if(rawinput_tests[i].todo_legacy)
2865 ok(rawinput_test_received_legacy == rawinput_tests[i].expect_legacy,
2866 "%d: %sexpected WM_MOUSEMOVE message\n", i, rawinput_tests[i].expect_legacy ? "" : "un");
2867 todo_wine_if(rawinput_tests[i].todo_raw)
2868 ok(rawinput_test_received_raw == rawinput_tests[i].expect_raw,
2869 "%d: %sexpected WM_INPUT message\n", i, rawinput_tests[i].expect_raw ? "" : "un");
2870 todo_wine_if(rawinput_tests[i].todo_rawfg)
2871 ok(rawinput_test_received_rawfg == rawinput_tests[i].expect_rawfg,
2872 "%d: %sexpected RIM_INPUT message\n", i, rawinput_tests[i].expect_rawfg ? "" : "un");
2875 GetCursorPos(&newpt);
2876 ok((newpt.x - pt.x) == 5 || (newpt.x - pt.x) == 4, "%d: Unexpected cursor movement\n", i);
2878 if (rawinput_tests[i].register_device)
2880 raw_devices[0].dwFlags = RIDEV_REMOVE;
2881 raw_devices[0].hwndTarget = 0;
2883 SetLastError(0xdeadbeef);
2884 ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE));
2885 ok(ret, "%d: RegisterRawInputDevices failed: %lu\n", i, GetLastError());
2888 DestroyWindow(hwnd);
2891 SetEvent(process_ready);
2892 winetest_wait_child_process(process_info.hProcess);
2893 CloseHandle(process_info.hProcess);
2894 CloseHandle(process_info.hThread);
2895 CloseHandle(process_done);
2896 CloseHandle(process_start);
2897 CloseHandle(process_ready);
2899 WaitForSingleObject(thread, INFINITE);
2901 CloseHandle(params.done);
2902 CloseHandle(params.start);
2903 CloseHandle(params.ready);
2904 CloseHandle(thread);
2906 CloseDesktop(params.desk);
2909 static void test_DefRawInputProc(void)
2911 LRESULT ret;
2913 SetLastError(0xdeadbeef);
2914 ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER));
2915 ok(!ret, "got %Id\n", ret);
2916 ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError());
2917 ret = DefRawInputProc(LongToPtr(0xcafe), 0xbeef, sizeof(RAWINPUTHEADER));
2918 ok(!ret, "got %Id\n", ret);
2919 ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError());
2920 ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER) - 1);
2921 ok(ret == -1, "got %Id\n", ret);
2922 ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError());
2923 ret = DefRawInputProc(NULL, 0, sizeof(RAWINPUTHEADER) + 1);
2924 ok(ret == -1, "got %Id\n", ret);
2925 ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError());
2928 static void test_key_map(void)
2930 HKL kl = GetKeyboardLayout(0);
2931 UINT kL, kR, s, sL;
2932 int i;
2933 static const UINT numpad_collisions[][2] = {
2934 { VK_NUMPAD0, VK_INSERT },
2935 { VK_NUMPAD1, VK_END },
2936 { VK_NUMPAD2, VK_DOWN },
2937 { VK_NUMPAD3, VK_NEXT },
2938 { VK_NUMPAD4, VK_LEFT },
2939 { VK_NUMPAD6, VK_RIGHT },
2940 { VK_NUMPAD7, VK_HOME },
2941 { VK_NUMPAD8, VK_UP },
2942 { VK_NUMPAD9, VK_PRIOR },
2945 s = MapVirtualKeyExA(VK_SHIFT, MAPVK_VK_TO_VSC, kl);
2946 ok(s != 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
2947 sL = MapVirtualKeyExA(VK_LSHIFT, MAPVK_VK_TO_VSC, kl);
2948 ok(s == sL || broken(sL == 0), /* win9x */
2949 "%x != %x\n", s, sL);
2951 kL = MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK, kl);
2952 ok(kL == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL);
2953 kR = MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK, kl);
2954 ok(kR == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR);
2956 kL = MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK_EX, kl);
2957 ok(kL == VK_LSHIFT || broken(kL == 0), /* win9x */
2958 "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL);
2959 kR = MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK_EX, kl);
2960 ok(kR == VK_RSHIFT || broken(kR == 0), /* win9x */
2961 "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR);
2963 /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
2964 for (i = 0; i < ARRAY_SIZE(numpad_collisions); i++)
2966 UINT numpad_scan = MapVirtualKeyExA(numpad_collisions[i][0], MAPVK_VK_TO_VSC, kl);
2967 UINT other_scan = MapVirtualKeyExA(numpad_collisions[i][1], MAPVK_VK_TO_VSC, kl);
2969 /* do they really collide for this layout? */
2970 if (numpad_scan && other_scan == numpad_scan)
2972 UINT vkey = MapVirtualKeyExA(numpad_scan, MAPVK_VSC_TO_VK, kl);
2973 ok(vkey != numpad_collisions[i][0],
2974 "Got numpad vKey %x for scan code %x when there was another choice\n",
2975 vkey, numpad_scan);
2979 /* test the scan code prefixes of the right variant of a keys */
2980 s = MapVirtualKeyExA(VK_RCONTROL, MAPVK_VK_TO_VSC, kl);
2981 ok(s >> 8 == 0x00, "Scan code prefixes should not be returned when not using MAPVK_VK_TO_VSC_EX %#1x\n", s >> 8);
2982 s = MapVirtualKeyExA(VK_RCONTROL, MAPVK_VK_TO_VSC_EX, kl);
2983 ok(s >> 8 == 0xE0 || broken(s == 0), "Scan code prefix for VK_RCONTROL should be 0xE0 when MAPVK_VK_TO_VSC_EX is set, was %#1x\n", s >> 8);
2984 s = MapVirtualKeyExA(VK_RMENU, MAPVK_VK_TO_VSC_EX, kl);
2985 ok(s >> 8 == 0xE0 || broken(s == 0), "Scan code prefix for VK_RMENU should be 0xE0 when MAPVK_VK_TO_VSC_EX is set, was %#1x\n", s >> 8);
2986 s = MapVirtualKeyExA(VK_RSHIFT, MAPVK_VK_TO_VSC_EX, kl);
2987 ok(s >> 8 == 0x00 || broken(s == 0), "The scan code shouldn't have a prefix, got %#1x\n", s >> 8);
2990 #define shift 1
2991 #define ctrl 2
2993 static const struct tounicode_tests
2995 UINT vk;
2996 DWORD modifiers;
2997 WCHAR chr; /* if vk is 0, lookup vk using this char */
2998 int expect_ret;
2999 WCHAR expect_buf[4];
3000 } utests[] =
3002 { 0, 0, 'a', 1, {'a',0}},
3003 { 0, shift, 'a', 1, {'A',0}},
3004 { 0, ctrl, 'a', 1, {1, 0}},
3005 { 0, shift|ctrl, 'a', 1, {1, 0}},
3006 { VK_TAB, ctrl, 0, 0, {}},
3007 { VK_TAB, shift|ctrl, 0, 0, {}},
3008 { VK_RETURN, ctrl, 0, 1, {'\n', 0}},
3009 { VK_RETURN, shift|ctrl, 0, 0, {}},
3010 { 0, ctrl, '4', 0, {}},
3011 { 0, shift|ctrl, '4', 0, {}},
3012 { 0, ctrl, '!', 0, {}},
3013 { 0, ctrl, '\"', 0, {}},
3014 { 0, ctrl, '#', 0, {}},
3015 { 0, ctrl, '$', 0, {}},
3016 { 0, ctrl, '%', 0, {}},
3017 { 0, ctrl, '\'', 0, {}},
3018 { 0, ctrl, '(', 0, {}},
3019 { 0, ctrl, ')', 0, {}},
3020 { 0, ctrl, '*', 0, {}},
3021 { 0, ctrl, '+', 0, {}},
3022 { 0, ctrl, ',', 0, {}},
3023 { 0, ctrl, '-', 0, {}},
3024 { 0, ctrl, '.', 0, {}},
3025 { 0, ctrl, '/', 0, {}},
3026 { 0, ctrl, ':', 0, {}},
3027 { 0, ctrl, ';', 0, {}},
3028 { 0, ctrl, '<', 0, {}},
3029 { 0, ctrl, '=', 0, {}},
3030 { 0, ctrl, '>', 0, {}},
3031 { 0, ctrl, '?', 0, {}},
3032 { 0, ctrl, '@', 1, {0}},
3033 { 0, ctrl, '[', 1, {0x1b}},
3034 { 0, ctrl, '\\', 1, {0x1c}},
3035 { 0, ctrl, ']', 1, {0x1d}},
3036 { 0, ctrl, '^', 1, {0x1e}},
3037 { 0, ctrl, '_', 1, {0x1f}},
3038 { 0, ctrl, '`', 0, {}},
3039 { VK_SPACE, 0, 0, 1, {' ',0}},
3040 { VK_SPACE, shift, 0, 1, {' ',0}},
3041 { VK_SPACE, ctrl, 0, 1, {' ',0}},
3044 static void test_ToUnicode(void)
3046 WCHAR wStr[4];
3047 BYTE state[256];
3048 const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f, SC_A = 0x1e;
3049 const BYTE HIGHEST_BIT = 0x80;
3050 int i, ret;
3051 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
3053 for(i=0; i<256; i++)
3054 state[i]=0;
3056 wStr[1] = 0xAA;
3057 SetLastError(0xdeadbeef);
3058 ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 4, 0);
3059 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3061 win_skip("ToUnicode is not implemented\n");
3062 return;
3065 ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret);
3066 if(ret == 1)
3068 ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]);
3069 ok(wStr[1]==0 || broken(wStr[1]!=0) /* nt4 */,
3070 "ToUnicode didn't null-terminate the buffer when there was room.\n");
3073 for (i = 0; i < ARRAY_SIZE(utests); i++)
3075 UINT vk = utests[i].vk, mod = utests[i].modifiers, scan;
3077 if(!vk)
3079 short vk_ret;
3081 if (!us_kbd) continue;
3082 vk_ret = VkKeyScanW(utests[i].chr);
3083 if (vk_ret == -1) continue;
3084 vk = vk_ret & 0xff;
3085 if (vk_ret & 0x100) mod |= shift;
3086 if (vk_ret & 0x200) mod |= ctrl;
3088 scan = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC);
3090 state[VK_SHIFT] = state[VK_LSHIFT] = (mod & shift) ? HIGHEST_BIT : 0;
3091 state[VK_CONTROL] = state[VK_LCONTROL] = (mod & ctrl) ? HIGHEST_BIT : 0;
3093 ret = ToUnicode(vk, scan, state, wStr, 4, 0);
3094 ok(ret == utests[i].expect_ret, "%d: got %d expected %d\n", i, ret, utests[i].expect_ret);
3095 if (ret)
3096 ok(!lstrcmpW(wStr, utests[i].expect_buf), "%d: got %s expected %s\n", i, wine_dbgstr_w(wStr),
3097 wine_dbgstr_w(utests[i].expect_buf));
3100 state[VK_SHIFT] = state[VK_LSHIFT] = 0;
3101 state[VK_CONTROL] = state[VK_LCONTROL] = 0;
3103 ret = ToUnicode(VK_TAB, SC_TAB, NULL, wStr, 4, 0);
3104 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
3105 ret = ToUnicode(VK_RETURN, SC_RETURN, NULL, wStr, 4, 0);
3106 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
3107 ret = ToUnicode('A', SC_A, NULL, wStr, 4, 0);
3108 ok(ret == 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret);
3109 ret = ToUnicodeEx(VK_TAB, SC_TAB, NULL, wStr, 4, 0, GetKeyboardLayout(0));
3110 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
3111 ret = ToUnicodeEx(VK_RETURN, SC_RETURN, NULL, wStr, 4, 0, GetKeyboardLayout(0));
3112 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
3113 ret = ToUnicodeEx('A', SC_A, NULL, wStr, 4, 0, GetKeyboardLayout(0));
3114 ok(ret == 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret);
3117 static void test_ToAscii(void)
3119 WORD character;
3120 BYTE state[256];
3121 const BYTE SC_RETURN = 0x1c, SC_A = 0x1e;
3122 const BYTE HIGHEST_BIT = 0x80;
3123 int ret;
3124 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
3126 memset(state, 0, sizeof(state));
3128 character = 0;
3129 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
3130 ok(ret == 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret);
3131 ok(character == '\r', "ToAscii for Return was %i (expected 13)\n", character);
3133 character = 0;
3134 ret = ToAscii('A', SC_A, state, &character, 0);
3135 ok(ret == 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret);
3136 if (us_kbd) ok(character == 'a', "ToAscii for character 'A' was %i (expected %i)\n", character, 'a');
3138 state[VK_CONTROL] |= HIGHEST_BIT;
3139 state[VK_LCONTROL] |= HIGHEST_BIT;
3140 character = 0;
3141 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
3142 ok(ret == 1, "ToAscii for CTRL + Return key didn't return 1 (was %i)\n", ret);
3143 ok(character == '\n', "ToAscii for CTRL + Return was %i (expected 10)\n", character);
3145 character = 0;
3146 ret = ToAscii('A', SC_A, state, &character, 0);
3147 ok(ret == 1, "ToAscii for CTRL + character 'A' didn't return 1 (was %i)\n", ret);
3148 ok(character == 1, "ToAscii for CTRL + character 'A' was %i (expected 1)\n", character);
3150 state[VK_SHIFT] |= HIGHEST_BIT;
3151 state[VK_LSHIFT] |= HIGHEST_BIT;
3152 ret = ToAscii(VK_RETURN, SC_RETURN, state, &character, 0);
3153 ok(ret == 0, "ToAscii for CTRL + Shift + Return key didn't return 0 (was %i)\n", ret);
3155 ret = ToAscii(VK_RETURN, SC_RETURN, NULL, &character, 0);
3156 ok(ret == 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret);
3157 ret = ToAscii('A', SC_A, NULL, &character, 0);
3158 ok(ret == 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret);
3159 ret = ToAsciiEx(VK_RETURN, SC_RETURN, NULL, &character, 0, GetKeyboardLayout(0));
3160 ok(ret == 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret);
3161 ret = ToAsciiEx('A', SC_A, NULL, &character, 0, GetKeyboardLayout(0));
3162 ok(ret == 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret);
3165 static void test_get_async_key_state(void)
3167 /* input value sanity checks */
3168 ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
3169 ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
3172 static void test_keyboard_layout_name(void)
3174 WCHAR klid[KL_NAMELENGTH], tmpklid[KL_NAMELENGTH], layout_path[MAX_PATH], value[5];
3175 HKL layout, tmplayout, *layouts, *layouts_preload;
3176 DWORD status, value_size, klid_size, type, id;
3177 int i, j, len;
3178 HKEY hkey;
3179 BOOL ret;
3181 if (0) /* crashes on native system */
3182 ret = GetKeyboardLayoutNameA(NULL);
3184 SetLastError(0xdeadbeef);
3185 ret = GetKeyboardLayoutNameW(NULL);
3186 ok(!ret, "got %d\n", ret);
3187 ok(GetLastError() == ERROR_NOACCESS, "got %ld\n", GetLastError());
3189 layout = GetKeyboardLayout(0);
3191 len = GetKeyboardLayoutList(0, NULL);
3192 ok(len > 0, "GetKeyboardLayoutList returned %d\n", len);
3194 layouts = malloc(len * sizeof(HKL));
3195 ok(layouts != NULL, "Could not allocate memory\n");
3197 len = GetKeyboardLayoutList(len, layouts);
3198 ok(len > 0, "GetKeyboardLayoutList returned %d\n", len);
3200 layouts_preload = calloc(len, sizeof(HKL));
3201 ok(layouts_preload != NULL, "Could not allocate memory\n");
3203 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkey ))
3205 i = 0;
3206 type = REG_SZ;
3207 klid_size = sizeof(klid);
3208 value_size = ARRAY_SIZE(value);
3209 while (i < len && !RegEnumValueW( hkey, i++, value, &value_size, NULL, &type, (void *)&klid, &klid_size ))
3211 klid_size = sizeof(klid);
3212 value_size = ARRAY_SIZE(value);
3213 layouts_preload[i - 1] = UlongToHandle( wcstoul( klid, NULL, 16 ) );
3215 id = (DWORD_PTR)layouts_preload[i - 1];
3216 if (id & 0x80000000) todo_wine_if(HIWORD(id) == 0xe001) ok((id & 0xf0000000) == 0xd0000000, "Unexpected preloaded keyboard layout high bits %#lx\n", id);
3217 else ok(!(id & 0xf0000000), "Unexpected preloaded keyboard layout high bits %#lx\n", id);
3220 ok(i <= len, "Unexpected keyboard count %d in preload list\n", i);
3221 RegCloseKey( hkey );
3224 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", &hkey ))
3226 for (i = 0; i < len && layouts_preload[i]; ++i)
3228 type = REG_SZ;
3229 klid_size = sizeof(klid);
3230 swprintf( tmpklid, KL_NAMELENGTH, L"%08x", HandleToUlong( layouts_preload[i] ) );
3231 if (!RegQueryValueExW( hkey, tmpklid, NULL, &type, (void *)&klid, &klid_size ))
3233 layouts_preload[i] = UlongToHandle( wcstoul( klid, NULL, 16 ) );
3235 /* Substitute should contain the keyboard layout id, not the HKL high word */
3236 id = (DWORD_PTR)layouts_preload[i];
3237 ok(!(id & 0xf0000000), "Unexpected substitute keyboard layout high bits %#lx\n", id);
3239 else
3241 id = (DWORD_PTR)layouts_preload[i];
3242 ok(!(id & 0xf0000000), "Unexpected preloaded keyboard layout high bits %#lx\n", id);
3246 RegCloseKey( hkey );
3249 for (i = len - 1; i >= 0; --i)
3251 id = (DWORD_PTR)layouts[i];
3252 ActivateKeyboardLayout(layouts[i], 0);
3253 GetKeyboardLayoutNameW(klid);
3255 for (j = 0; j < len; ++j)
3257 swprintf( tmpklid, KL_NAMELENGTH, L"%08X", layouts_preload[j] );
3258 if (!wcscmp( tmpklid, klid )) break;
3260 ok(j < len, "Could not find keyboard layout %s in preload list\n", wine_dbgstr_w(klid));
3262 if (id & 0x80000000)
3264 todo_wine ok((id >> 28) == 0xf, "hkl high bits %#lx, expected 0xf\n", id >> 28);
3266 value_size = sizeof(value);
3267 wcscpy(layout_path, L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\");
3268 wcscat(layout_path, klid);
3269 status = RegGetValueW(HKEY_LOCAL_MACHINE, layout_path, L"Layout Id", RRF_RT_REG_SZ, NULL, (void *)&value, &value_size);
3270 todo_wine ok(!status, "RegGetValueW returned %lx\n", status);
3271 ok(value_size == 5 * sizeof(WCHAR), "RegGetValueW returned size %ld\n", value_size);
3273 swprintf(tmpklid, KL_NAMELENGTH, L"%04X", (id >> 16) & 0x0fff);
3274 todo_wine ok(!wcsicmp(value, tmpklid), "RegGetValueW returned %s, expected %s\n", debugstr_w(value), debugstr_w(tmpklid));
3276 else
3278 swprintf(tmpklid, KL_NAMELENGTH, L"%08X", id >> 16);
3279 ok(!wcsicmp(klid, tmpklid), "GetKeyboardLayoutNameW returned %s, expected %s\n", debugstr_w(klid), debugstr_w(tmpklid));
3282 ActivateKeyboardLayout(layout, 0);
3283 tmplayout = LoadKeyboardLayoutW(klid, KLF_ACTIVATE);
3285 /* The low word of HKL is the selected user lang and may be different as LoadKeyboardLayoutW also selects the default lang from the layout */
3286 ok(((UINT_PTR)tmplayout & ~0xffff) == ((UINT_PTR)layouts[i] & ~0xffff), "LoadKeyboardLayoutW returned %p, expected %p\n", tmplayout, layouts[i]);
3288 /* The layout name only depends on the keyboard layout: the high word of HKL. */
3289 GetKeyboardLayoutNameW(tmpklid);
3290 ok(!wcsicmp(klid, tmpklid), "GetKeyboardLayoutNameW returned %s, expected %s\n", debugstr_w(tmpklid), debugstr_w(klid));
3293 ActivateKeyboardLayout(layout, 0);
3295 free(layouts);
3296 free(layouts_preload);
3299 static void test_key_names(void)
3301 char buffer[40];
3302 WCHAR bufferW[40];
3303 int ret, prev;
3304 LONG lparam = 0x1d << 16;
3306 memset( buffer, 0xcc, sizeof(buffer) );
3307 ret = GetKeyNameTextA( lparam, buffer, sizeof(buffer) );
3308 ok( ret > 0, "wrong len %u for '%s'\n", ret, buffer );
3309 ok( ret == strlen(buffer), "wrong len %u for '%s'\n", ret, buffer );
3311 memset( buffer, 0xcc, sizeof(buffer) );
3312 prev = ret;
3313 ret = GetKeyNameTextA( lparam, buffer, prev );
3314 ok( ret == prev - 1, "wrong len %u for '%s'\n", ret, buffer );
3315 ok( ret == strlen(buffer), "wrong len %u for '%s'\n", ret, buffer );
3317 memset( buffer, 0xcc, sizeof(buffer) );
3318 ret = GetKeyNameTextA( lparam, buffer, 0 );
3319 ok( ret == 0, "wrong len %u for '%s'\n", ret, buffer );
3320 ok( buffer[0] == 0, "wrong string '%s'\n", buffer );
3322 memset( bufferW, 0xcc, sizeof(bufferW) );
3323 ret = GetKeyNameTextW( lparam, bufferW, ARRAY_SIZE(bufferW));
3324 ok( ret > 0, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
3325 ok( ret == lstrlenW(bufferW), "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
3327 memset( bufferW, 0xcc, sizeof(bufferW) );
3328 prev = ret;
3329 ret = GetKeyNameTextW( lparam, bufferW, prev );
3330 ok( ret == prev - 1, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
3331 ok( ret == lstrlenW(bufferW), "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
3333 memset( bufferW, 0xcc, sizeof(bufferW) );
3334 ret = GetKeyNameTextW( lparam, bufferW, 0 );
3335 ok( ret == 0, "wrong len %u for %s\n", ret, wine_dbgstr_w(bufferW) );
3336 ok( bufferW[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW) );
3339 static void simulate_click(BOOL left, int x, int y)
3341 INPUT input[2];
3342 UINT events_no;
3344 SetCursorPos(x, y);
3345 memset(input, 0, sizeof(input));
3346 input[0].type = INPUT_MOUSE;
3347 U(input[0]).mi.dx = x;
3348 U(input[0]).mi.dy = y;
3349 U(input[0]).mi.dwFlags = left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN;
3350 input[1].type = INPUT_MOUSE;
3351 U(input[1]).mi.dx = x;
3352 U(input[1]).mi.dy = y;
3353 U(input[1]).mi.dwFlags = left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP;
3354 events_no = SendInput(2, input, sizeof(input[0]));
3355 ok(events_no == 2, "SendInput returned %d\n", events_no);
3358 static BOOL wait_for_message( MSG *msg )
3360 BOOL ret;
3362 for (;;)
3364 ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE);
3365 if (ret)
3367 if (msg->message == WM_PAINT) DispatchMessageA(msg);
3368 else break;
3370 else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT) break;
3372 if (!ret) msg->message = 0;
3373 return ret;
3376 static BOOL wait_for_event(HANDLE event, int timeout)
3378 DWORD end_time = GetTickCount() + timeout;
3379 MSG msg;
3381 do {
3382 if(MsgWaitForMultipleObjects(1, &event, FALSE, timeout, QS_ALLINPUT) == WAIT_OBJECT_0)
3383 return TRUE;
3384 while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
3385 DispatchMessageA(&msg);
3386 timeout = end_time - GetTickCount();
3387 }while(timeout > 0);
3389 return FALSE;
3392 static WNDPROC def_static_proc;
3393 static DWORD hittest_no;
3394 static LRESULT WINAPI static_hook_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
3396 if (msg == WM_NCHITTEST)
3398 /* break infinite hittest loop */
3399 if(hittest_no > 50) return HTCLIENT;
3400 hittest_no++;
3403 return def_static_proc(hwnd, msg, wp, lp);
3406 struct thread_data
3408 HANDLE start_event;
3409 HANDLE end_event;
3410 HWND win;
3413 static DWORD WINAPI create_static_win(void *arg)
3415 struct thread_data *thread_data = arg;
3416 HWND win;
3417 MSG msg;
3419 win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
3420 100, 100, 100, 100, 0, NULL, NULL, NULL);
3421 ok(win != 0, "CreateWindow failed\n");
3422 def_static_proc = (void*)SetWindowLongPtrA(win,
3423 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
3424 thread_data->win = win;
3426 while (wait_for_message(&msg)) DispatchMessageA(&msg);
3427 SetEvent(thread_data->start_event);
3428 wait_for_event(thread_data->end_event, 5000);
3429 return 0;
3432 static LRESULT CALLBACK mouse_move_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3434 static DWORD last_x = 200, expect_x = 210;
3436 if (msg == WM_MOUSEMOVE)
3438 POINT pt = {LOWORD(lparam), HIWORD(lparam)};
3439 MapWindowPoints(hwnd, NULL, &pt, 1);
3441 flaky
3442 if (pt.x != last_x) ok( pt.x == expect_x, "got unexpected WM_MOUSEMOVE x %ld, expected %ld\n", pt.x, expect_x );
3444 expect_x = pt.x == 200 ? 210 : 200;
3445 last_x = pt.x;
3448 return DefWindowProcW(hwnd, msg, wparam, lparam);
3451 static void test_Input_mouse(void)
3453 BOOL got_button_down, got_button_up;
3454 HWND hwnd, button_win, static_win;
3455 struct thread_data thread_data;
3456 HANDLE thread;
3457 DWORD thread_id;
3458 POINT pt, pt_org;
3459 MSG msg;
3460 BOOL ret;
3462 SetLastError(0xdeadbeef);
3463 ret = GetCursorPos(NULL);
3464 ok(!ret, "GetCursorPos succeed\n");
3465 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_NOACCESS, "error %lu\n", GetLastError());
3467 SetLastError(0xdeadbeef);
3468 ret = GetCursorPos(&pt_org);
3469 ok(ret, "GetCursorPos failed\n");
3470 ok(GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError());
3472 button_win = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP,
3473 100, 100, 100, 100, 0, NULL, NULL, NULL);
3474 ok(button_win != 0, "CreateWindow failed\n");
3476 pt.x = pt.y = 50;
3477 ClientToScreen(button_win, &pt);
3478 hwnd = WindowFromPoint(pt);
3479 if (hwnd != button_win)
3481 skip("there's another window covering test window\n");
3482 DestroyWindow(button_win);
3483 return;
3486 /* simple button click test */
3487 simulate_click(TRUE, pt.x, pt.y);
3488 got_button_down = got_button_up = FALSE;
3489 while (wait_for_message(&msg))
3491 DispatchMessageA(&msg);
3493 if (msg.message == WM_LBUTTONDOWN)
3495 got_button_down = TRUE;
3497 else if (msg.message == WM_LBUTTONUP)
3499 got_button_up = TRUE;
3500 break;
3503 ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
3504 ok(got_button_up, "expected WM_LBUTTONUP message\n");
3506 /* click through HTTRANSPARENT child window */
3507 static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_CHILD,
3508 0, 0, 100, 100, button_win, NULL, NULL, NULL);
3509 ok(static_win != 0, "CreateWindow failed\n");
3510 def_static_proc = (void*)SetWindowLongPtrA(static_win,
3511 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
3512 simulate_click(FALSE, pt.x, pt.y);
3513 hittest_no = 0;
3514 got_button_down = got_button_up = FALSE;
3515 while (wait_for_message(&msg))
3517 DispatchMessageA(&msg);
3519 if (msg.message == WM_RBUTTONDOWN)
3521 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3522 got_button_down = TRUE;
3524 else if (msg.message == WM_RBUTTONUP)
3526 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3527 got_button_up = TRUE;
3528 break;
3531 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
3532 ok(got_button_down, "expected WM_RBUTTONDOWN message\n");
3533 ok(got_button_up, "expected WM_RBUTTONUP message\n");
3534 DestroyWindow(static_win);
3536 /* click through HTTRANSPARENT top-level window */
3537 static_win = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP,
3538 100, 100, 100, 100, 0, NULL, NULL, NULL);
3539 ok(static_win != 0, "CreateWindow failed\n");
3540 def_static_proc = (void*)SetWindowLongPtrA(static_win,
3541 GWLP_WNDPROC, (LONG_PTR)static_hook_proc);
3542 pt.x = pt.y = 50;
3543 ClientToScreen(static_win, &pt);
3544 simulate_click(TRUE, pt.x, pt.y);
3545 hittest_no = 0;
3546 got_button_down = got_button_up = FALSE;
3547 while (wait_for_message(&msg))
3549 DispatchMessageA(&msg);
3551 if (msg.message == WM_LBUTTONDOWN)
3553 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3554 got_button_down = TRUE;
3556 else if (msg.message == WM_LBUTTONUP)
3558 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3559 got_button_up = TRUE;
3560 break;
3563 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
3564 todo_wine ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
3565 todo_wine ok(got_button_up, "expected WM_LBUTTONUP message\n");
3566 DestroyWindow(static_win);
3568 /* click on HTTRANSPARENT top-level window that belongs to other thread */
3569 thread_data.start_event = CreateEventA(NULL, FALSE, FALSE, NULL);
3570 ok(thread_data.start_event != NULL, "CreateEvent failed\n");
3571 thread_data.end_event = CreateEventA(NULL, FALSE, FALSE, NULL);
3572 ok(thread_data.end_event != NULL, "CreateEvent failed\n");
3573 thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, NULL);
3574 ok(thread != NULL, "CreateThread failed\n");
3575 hittest_no = 0;
3576 got_button_down = got_button_up = FALSE;
3577 WaitForSingleObject(thread_data.start_event, INFINITE);
3578 pt.x = pt.y = 50;
3579 ClientToScreen(thread_data.win, &pt);
3580 simulate_click(FALSE, pt.x, pt.y);
3581 while (wait_for_message(&msg))
3583 DispatchMessageA(&msg);
3585 if (msg.message == WM_RBUTTONDOWN)
3586 got_button_down = TRUE;
3587 else if (msg.message == WM_RBUTTONUP)
3588 got_button_up = TRUE;
3590 SetEvent(thread_data.end_event);
3591 WaitForSingleObject(thread, INFINITE);
3592 CloseHandle(thread);
3593 flaky_wine
3594 ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n");
3595 ok(!got_button_down, "unexpected WM_RBUTTONDOWN message\n");
3596 ok(!got_button_up, "unexpected WM_RBUTTONUP message\n");
3598 /* click on HTTRANSPARENT top-level window that belongs to other thread,
3599 * thread input queues are attached */
3600 thread = CreateThread(NULL, 0, create_static_win, &thread_data, 0, &thread_id);
3601 ok(thread != NULL, "CreateThread failed\n");
3602 hittest_no = 0;
3603 got_button_down = got_button_up = FALSE;
3604 WaitForSingleObject(thread_data.start_event, INFINITE);
3605 ok(AttachThreadInput(thread_id, GetCurrentThreadId(), TRUE),
3606 "AttachThreadInput failed\n");
3607 while (wait_for_message(&msg)) DispatchMessageA(&msg);
3608 SetWindowPos(thread_data.win, button_win, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
3609 pt.x = pt.y = 50;
3610 ClientToScreen(thread_data.win, &pt);
3611 simulate_click(TRUE, pt.x, pt.y);
3612 while (wait_for_message(&msg))
3614 DispatchMessageA(&msg);
3616 if (msg.message == WM_LBUTTONDOWN)
3617 got_button_down = TRUE;
3618 else if (msg.message == WM_LBUTTONUP)
3619 got_button_up = TRUE;
3621 SetEvent(thread_data.end_event);
3622 WaitForSingleObject(thread, INFINITE);
3623 todo_wine ok(hittest_no > 50, "expected loop with WM_NCHITTEST messages\n");
3624 ok(!got_button_down, "unexpected WM_LBUTTONDOWN message\n");
3625 ok(!got_button_up, "unexpected WM_LBUTTONUP message\n");
3627 /* click after SetCapture call */
3628 hwnd = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP,
3629 0, 0, 100, 100, 0, NULL, NULL, NULL);
3630 ok(hwnd != 0, "CreateWindow failed\n");
3631 SetCapture(button_win);
3632 got_button_down = got_button_up = FALSE;
3633 pt.x = pt.y = 50;
3634 ClientToScreen(hwnd, &pt);
3635 simulate_click(FALSE, pt.x, pt.y);
3636 while (wait_for_message(&msg))
3638 DispatchMessageA(&msg);
3640 if (msg.message == WM_RBUTTONDOWN)
3642 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3643 got_button_down = TRUE;
3645 else if (msg.message == WM_RBUTTONUP)
3647 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3648 got_button_up = TRUE;
3649 break;
3652 ok(got_button_down, "expected WM_RBUTTONDOWN message\n");
3653 ok(got_button_up, "expected WM_RBUTTONUP message\n");
3654 DestroyWindow(hwnd);
3656 /* click on child window after SetCapture call */
3657 hwnd = CreateWindowA("button", "button2", WS_VISIBLE | WS_CHILD,
3658 0, 0, 100, 100, button_win, NULL, NULL, NULL);
3659 ok(hwnd != 0, "CreateWindow failed\n");
3660 got_button_down = got_button_up = FALSE;
3661 pt.x = pt.y = 50;
3662 ClientToScreen(hwnd, &pt);
3663 simulate_click(TRUE, pt.x, pt.y);
3664 while (wait_for_message(&msg))
3666 DispatchMessageA(&msg);
3668 if (msg.message == WM_LBUTTONDOWN)
3670 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3671 got_button_down = TRUE;
3673 else if (msg.message == WM_LBUTTONUP)
3675 ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
3676 got_button_up = TRUE;
3677 break;
3680 ok(got_button_down, "expected WM_LBUTTONDOWN message\n");
3681 ok(got_button_up, "expected WM_LBUTTONUP message\n");
3682 DestroyWindow(hwnd);
3683 ok(ReleaseCapture(), "ReleaseCapture failed\n");
3684 SetCursorPos(pt_org.x, pt_org.y);
3686 CloseHandle(thread_data.start_event);
3687 CloseHandle(thread_data.end_event);
3688 DestroyWindow(button_win);
3690 SetCursorPos(200, 200);
3691 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
3692 100, 100, 200, 200, NULL, NULL, NULL, NULL);
3693 ok(hwnd != NULL, "CreateWindowA failed %lu\n", GetLastError());
3695 /* warm up test case by moving cursor and window a bit first */
3696 SetCursorPos(210, 200);
3697 SetWindowPos(hwnd, NULL, 110, 100, 0, 0, SWP_NOSIZE);
3698 empty_message_queue();
3699 SetCursorPos(200, 200);
3700 SetWindowPos(hwnd, NULL, 100, 100, 0, 0, SWP_NOSIZE);
3701 empty_message_queue();
3702 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)mouse_move_wndproc);
3704 SetCursorPos(210, 200);
3705 SetWindowPos(hwnd, NULL, 110, 100, 0, 0, SWP_NOSIZE);
3706 empty_message_queue();
3707 GetCursorPos(&pt);
3708 ok(pt.x == 210 && pt.y == 200, "GetCursorPos returned %ldx%ld, expected 210x200\n", pt.x, pt.y);
3710 SetCursorPos(200, 200);
3711 SetWindowPos(hwnd, NULL, 100, 100, 0, 0, SWP_NOSIZE);
3712 empty_message_queue();
3713 GetCursorPos(&pt);
3714 ok(pt.x == 200 && pt.y == 200, "GetCursorPos returned %ldx%ld, expected 200x200\n", pt.x, pt.y);
3716 SetCursorPos(pt_org.x, pt_org.y);
3717 empty_message_queue();
3718 DestroyWindow(hwnd);
3722 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3724 if (message == WM_USER+1)
3726 HWND hwnd = (HWND)lParam;
3727 ok(GetFocus() == hwnd, "thread expected focus %p, got %p\n", hwnd, GetFocus());
3728 ok(GetActiveWindow() == hwnd, "thread expected active %p, got %p\n", hwnd, GetActiveWindow());
3730 return DefWindowProcA(hwnd, message, wParam, lParam);
3733 struct wnd_event
3735 HWND hwnd;
3736 HANDLE wait_event;
3737 HANDLE start_event;
3738 DWORD attach_from;
3739 DWORD attach_to;
3740 BOOL setWindows;
3743 static DWORD WINAPI thread_proc(void *param)
3745 MSG msg;
3746 struct wnd_event *wnd_event = param;
3747 BOOL ret;
3749 if (wnd_event->wait_event)
3751 ok(WaitForSingleObject(wnd_event->wait_event, INFINITE) == WAIT_OBJECT_0,
3752 "WaitForSingleObject failed\n");
3753 CloseHandle(wnd_event->wait_event);
3756 if (wnd_event->attach_from)
3758 ret = AttachThreadInput(wnd_event->attach_from, GetCurrentThreadId(), TRUE);
3759 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3762 if (wnd_event->attach_to)
3764 ret = AttachThreadInput(GetCurrentThreadId(), wnd_event->attach_to, TRUE);
3765 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3768 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
3769 100, 100, 200, 200, 0, 0, 0, NULL);
3770 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
3772 if (wnd_event->setWindows)
3774 SetFocus(wnd_event->hwnd);
3775 SetActiveWindow(wnd_event->hwnd);
3778 SetEvent(wnd_event->start_event);
3780 while (GetMessageA(&msg, 0, 0, 0))
3782 TranslateMessage(&msg);
3783 DispatchMessageA(&msg);
3786 return 0;
3789 static void test_attach_input(void)
3791 HANDLE hThread;
3792 HWND ourWnd, Wnd2;
3793 DWORD ret, tid;
3794 struct wnd_event wnd_event;
3795 WNDCLASSA cls;
3797 cls.style = 0;
3798 cls.lpfnWndProc = MsgCheckProcA;
3799 cls.cbClsExtra = 0;
3800 cls.cbWndExtra = 0;
3801 cls.hInstance = GetModuleHandleA(0);
3802 cls.hIcon = 0;
3803 cls.hCursor = LoadCursorW( NULL, (LPCWSTR)IDC_ARROW);
3804 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
3805 cls.lpszMenuName = NULL;
3806 cls.lpszClassName = "TestWindowClass";
3807 if(!RegisterClassA(&cls)) return;
3809 wnd_event.wait_event = NULL;
3810 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
3811 wnd_event.attach_from = 0;
3812 wnd_event.attach_to = 0;
3813 wnd_event.setWindows = FALSE;
3814 if (!wnd_event.start_event)
3816 win_skip("skipping interthread message test under win9x\n");
3817 return;
3820 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3821 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3823 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3824 CloseHandle(wnd_event.start_event);
3826 ourWnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3827 0, 0, 0, 0, 0, 0, 0, NULL);
3828 ok(ourWnd!= 0, "failed to create ourWnd window\n");
3830 Wnd2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
3831 0, 0, 0, 0, 0, 0, 0, NULL);
3832 ok(Wnd2!= 0, "failed to create Wnd2 window\n");
3834 SetFocus(ourWnd);
3835 SetActiveWindow(ourWnd);
3837 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
3838 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3840 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
3841 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
3843 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd);
3845 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
3846 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3847 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
3848 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
3850 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
3852 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
3853 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3855 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
3856 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
3857 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd);
3859 SetActiveWindow(Wnd2);
3860 SetFocus(Wnd2);
3861 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
3862 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
3864 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2);
3866 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
3867 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3868 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
3869 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
3871 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
3873 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3874 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3876 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3877 CloseHandle(hThread);
3879 wnd_event.wait_event = NULL;
3880 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
3881 wnd_event.attach_from = 0;
3882 wnd_event.attach_to = 0;
3883 wnd_event.setWindows = TRUE;
3885 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3886 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3888 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3889 CloseHandle(wnd_event.start_event);
3891 SetFocus(ourWnd);
3892 SetActiveWindow(ourWnd);
3894 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
3895 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3897 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
3898 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
3900 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
3902 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
3903 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3905 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
3906 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
3908 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
3910 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
3911 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3913 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
3914 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
3916 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)wnd_event.hwnd);
3918 SetFocus(Wnd2);
3919 SetActiveWindow(Wnd2);
3920 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
3921 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
3923 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)Wnd2);
3925 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
3926 ok(ret, "AttachThreadInput error %ld\n", GetLastError());
3928 ok(GetActiveWindow() == Wnd2, "expected active %p, got %p\n", Wnd2, GetActiveWindow());
3929 ok(GetFocus() == Wnd2, "expected focus %p, got %p\n", Wnd2, GetFocus());
3931 SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
3933 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3934 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3936 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3937 CloseHandle(hThread);
3939 wnd_event.wait_event = CreateEventW(NULL, 0, 0, NULL);
3940 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
3941 wnd_event.attach_from = 0;
3942 wnd_event.attach_to = 0;
3943 wnd_event.setWindows = TRUE;
3945 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3946 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3948 SetLastError(0xdeadbeef);
3949 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
3950 ok(!ret, "AttachThreadInput succeeded\n");
3951 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
3952 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
3954 SetLastError(0xdeadbeef);
3955 ret = AttachThreadInput(tid, GetCurrentThreadId(), TRUE);
3956 ok(!ret, "AttachThreadInput succeeded\n");
3957 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
3958 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
3960 SetEvent(wnd_event.wait_event);
3962 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3963 CloseHandle(wnd_event.start_event);
3965 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3966 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3968 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3969 CloseHandle(hThread);
3971 wnd_event.wait_event = NULL;
3972 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
3973 wnd_event.attach_from = GetCurrentThreadId();
3974 wnd_event.attach_to = 0;
3975 wnd_event.setWindows = FALSE;
3977 SetFocus(ourWnd);
3978 SetActiveWindow(ourWnd);
3980 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
3981 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
3983 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3984 CloseHandle(wnd_event.start_event);
3986 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
3987 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
3989 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
3990 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
3992 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
3993 CloseHandle(hThread);
3995 wnd_event.wait_event = NULL;
3996 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
3997 wnd_event.attach_from = 0;
3998 wnd_event.attach_to = GetCurrentThreadId();
3999 wnd_event.setWindows = FALSE;
4001 SetFocus(ourWnd);
4002 SetActiveWindow(ourWnd);
4004 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
4005 ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
4007 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
4008 CloseHandle(wnd_event.start_event);
4010 ok(GetActiveWindow() == ourWnd, "expected active %p, got %p\n", ourWnd, GetActiveWindow());
4011 ok(GetFocus() == ourWnd, "expected focus %p, got %p\n", ourWnd, GetFocus());
4013 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
4014 ok(ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
4016 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
4017 CloseHandle(hThread);
4018 DestroyWindow(ourWnd);
4019 DestroyWindow(Wnd2);
4022 struct get_key_state_test_desc
4024 BOOL peek_message;
4025 BOOL peek_message_main;
4026 BOOL set_keyboard_state_main;
4027 BOOL set_keyboard_state;
4030 struct get_key_state_test_desc get_key_state_tests[] =
4032 /* 0: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
4033 {FALSE, TRUE, FALSE, FALSE},
4034 /* 1: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
4035 /* - GetKeyboardState misses key press if called before GetKeyState */
4036 /* - GetKeyboardState catches key press, if called after GetKeyState */
4037 { TRUE, FALSE, FALSE, FALSE},
4038 /* 2: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
4039 { TRUE, TRUE, FALSE, FALSE},
4041 /* same tests but with SetKeyboardState called in main thread */
4042 /* 3: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
4043 {FALSE, TRUE, TRUE, FALSE},
4044 /* 4: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
4045 /* - GetKeyboardState misses key press if called before GetKeyState */
4046 /* - GetKeyboardState catches key press, if called after GetKeyState */
4047 { TRUE, FALSE, TRUE, FALSE},
4048 /* 5: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
4049 { TRUE, TRUE, TRUE, FALSE},
4051 /* same tests but with SetKeyboardState called in other thread */
4052 /* 6: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
4053 {FALSE, TRUE, TRUE, TRUE},
4054 /* 7: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
4055 /* - GetKeyboardState misses key press if called before GetKeyState */
4056 /* - GetKeyboardState catches key press, if called after GetKeyState */
4057 { TRUE, FALSE, TRUE, TRUE},
4058 /* 8: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
4059 { TRUE, TRUE, TRUE, TRUE},
4062 struct get_key_state_thread_params
4064 HANDLE semaphores[2];
4065 int index;
4068 #define check_get_keyboard_state(i, j, c, x) check_get_keyboard_state_(i, j, c, x, __LINE__)
4069 static void check_get_keyboard_state_(int i, int j, int c, int x, int line)
4071 unsigned char keystate[256];
4072 BOOL ret;
4074 memset(keystate, 0, sizeof(keystate));
4075 ret = GetKeyboardState(keystate);
4076 ok_(__FILE__, line)(ret, "GetKeyboardState failed, %lu\n", GetLastError());
4077 ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset");
4078 ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset");
4080 /* calling it twice shouldn't change */
4081 memset(keystate, 0, sizeof(keystate));
4082 ret = GetKeyboardState(keystate);
4083 ok_(__FILE__, line)(ret, "GetKeyboardState failed, %lu\n", GetLastError());
4084 ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset");
4085 ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset");
4088 #define check_get_key_state(i, j, c, x) check_get_key_state_(i, j, c, x, __LINE__)
4089 static void check_get_key_state_(int i, int j, int c, int x, int line)
4091 SHORT state;
4093 state = GetKeyState('X');
4094 ok_(__FILE__, line)(!(state & 0x8000) == !x, "%d:%d: expected that X highest bit is %s, got %#x\n", i, j, x ? "set" : "unset", state);
4095 ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that X undefined bits are unset, got %#x\n", i, j, state);
4097 state = GetKeyState('C');
4098 ok_(__FILE__, line)(!(state & 0x8000) == !c, "%d:%d: expected that C highest bit is %s, got %#x\n", i, j, c ? "set" : "unset", state);
4099 ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that C undefined bits are unset, got %#x\n", i, j, state);
4102 static DWORD WINAPI get_key_state_thread(void *arg)
4104 struct get_key_state_thread_params *params = arg;
4105 struct get_key_state_test_desc* test;
4106 HANDLE *semaphores = params->semaphores;
4107 DWORD result;
4108 BYTE keystate[256];
4109 BOOL has_queue;
4110 BOOL expect_x, expect_c;
4111 MSG msg;
4112 int i = params->index, j;
4114 test = get_key_state_tests + i;
4115 has_queue = test->peek_message || test->set_keyboard_state;
4117 if (test->peek_message)
4119 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
4120 ok(!is_keyboard_message(msg.message), "%d: PeekMessageA got keyboard message.\n", i);
4123 for (j = 0; j < 4; ++j)
4125 /* initialization */
4126 ReleaseSemaphore(semaphores[0], 1, NULL);
4127 result = WaitForSingleObject(semaphores[1], 1000);
4128 ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result);
4130 if (test->set_keyboard_state)
4132 keystate['C'] = 0xff;
4133 SetKeyboardState(keystate);
4136 /* key pressed */
4137 ReleaseSemaphore(semaphores[0], 1, NULL);
4138 result = WaitForSingleObject(semaphores[1], 1000);
4139 ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result);
4141 if (test->set_keyboard_state) expect_x = TRUE;
4142 else if (!has_queue && j == 0) expect_x = FALSE;
4143 else expect_x = TRUE;
4145 if (test->set_keyboard_state) expect_c = TRUE;
4146 else expect_c = FALSE;
4148 check_get_keyboard_state(i, j, expect_c, FALSE);
4149 check_get_key_state(i, j, expect_c, expect_x);
4150 check_get_keyboard_state(i, j, expect_c, expect_x);
4152 /* key released */
4153 ReleaseSemaphore(semaphores[0], 1, NULL);
4154 result = WaitForSingleObject(semaphores[1], 1000);
4155 ok(result == WAIT_OBJECT_0, "%d: WaitForSingleObject returned %lu\n", i, result);
4157 check_get_keyboard_state(i, j, expect_c, expect_x);
4158 check_get_key_state(i, j, expect_c, FALSE);
4159 check_get_keyboard_state(i, j, expect_c, FALSE);
4162 return 0;
4165 static void test_GetKeyState(void)
4167 struct get_key_state_thread_params params;
4168 HANDLE thread;
4169 DWORD result;
4170 BYTE keystate[256];
4171 BOOL expect_x, expect_c;
4172 HWND hwnd;
4173 MSG msg;
4174 int i, j;
4176 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
4177 if (!us_kbd)
4179 skip("skipping test with inconsistent results on non-us keyboard\n");
4180 return;
4183 memset(keystate, 0, sizeof(keystate));
4184 params.semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL);
4185 ok(params.semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
4186 params.semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL);
4187 ok(params.semaphores[1] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError());
4189 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
4190 10, 10, 200, 200, NULL, NULL, NULL, NULL);
4191 ok(hwnd != NULL, "CreateWindowA failed %lu\n", GetLastError());
4192 empty_message_queue();
4194 for (i = 0; i < ARRAY_SIZE(get_key_state_tests); ++i)
4196 struct get_key_state_test_desc* test = get_key_state_tests + i;
4198 params.index = i;
4199 thread = CreateThread(NULL, 0, get_key_state_thread, &params, 0, NULL);
4200 ok(thread != NULL, "CreateThread failed %lu\n", GetLastError());
4202 for (j = 0; j < 4; ++j)
4204 /* initialization */
4205 result = WaitForSingleObject(params.semaphores[0], 1000);
4206 ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result);
4208 SetForegroundWindow(hwnd);
4209 SetFocus(hwnd);
4210 empty_message_queue();
4212 ReleaseSemaphore(params.semaphores[1], 1, NULL);
4214 /* key pressed */
4215 result = WaitForSingleObject(params.semaphores[0], 1000);
4216 ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result);
4218 keybd_event('X', 0, 0, 0);
4219 if (test->set_keyboard_state_main)
4221 expect_c = TRUE;
4222 keystate['C'] = 0xff;
4223 SetKeyboardState(keystate);
4225 else expect_c = FALSE;
4227 check_get_keyboard_state(i, j, expect_c, FALSE);
4228 check_get_key_state(i, j, expect_c, FALSE);
4229 check_get_keyboard_state(i, j, expect_c, FALSE);
4231 if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
4233 if (test->peek_message_main) expect_x = TRUE;
4234 else expect_x = FALSE;
4236 check_get_keyboard_state(i, j, expect_c, expect_x);
4237 check_get_key_state(i, j, expect_c, expect_x);
4238 check_get_keyboard_state(i, j, expect_c, expect_x);
4240 ReleaseSemaphore(params.semaphores[1], 1, NULL);
4242 /* key released */
4243 result = WaitForSingleObject(params.semaphores[0], 1000);
4244 ok(result == WAIT_OBJECT_0, "%d:%d: WaitForSingleObject returned %lu\n", i, j, result);
4246 keybd_event('X', 0, KEYEVENTF_KEYUP, 0);
4247 if (test->set_keyboard_state_main)
4249 expect_x = FALSE;
4250 keystate['C'] = 0x00;
4251 SetKeyboardState(keystate);
4254 check_get_keyboard_state(i, j, FALSE, expect_x);
4255 check_get_key_state(i, j, FALSE, expect_x);
4256 check_get_keyboard_state(i, j, FALSE, expect_x);
4258 if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
4260 check_get_keyboard_state(i, j, FALSE, FALSE);
4261 check_get_key_state(i, j, FALSE, FALSE);
4262 check_get_keyboard_state(i, j, FALSE, FALSE);
4264 ReleaseSemaphore(params.semaphores[1], 1, NULL);
4267 result = WaitForSingleObject(thread, 1000);
4268 ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result);
4269 CloseHandle(thread);
4272 DestroyWindow(hwnd);
4273 CloseHandle(params.semaphores[0]);
4274 CloseHandle(params.semaphores[1]);
4277 static void test_OemKeyScan(void)
4279 DWORD ret, expect, vkey, scan;
4280 WCHAR oem, wchr;
4281 char oem_char;
4283 BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409);
4284 if (!us_kbd)
4286 skip("skipping test with inconsistent results on non-us keyboard\n");
4287 return;
4290 for (oem = 0; oem < 0x200; oem++)
4292 ret = OemKeyScan( oem );
4294 oem_char = LOBYTE( oem );
4295 /* OemKeyScan returns -1 for any character that cannot be mapped,
4296 * whereas OemToCharBuff changes unmappable characters to question
4297 * marks. The ASCII characters 0-127, including the real question mark
4298 * character, are all mappable and are the same in all OEM codepages. */
4299 if (!OemToCharBuffW( &oem_char, &wchr, 1 ) || (wchr == '?' && oem_char < 0))
4300 expect = -1;
4301 else
4303 vkey = VkKeyScanW( wchr );
4304 scan = MapVirtualKeyW( LOBYTE( vkey ), MAPVK_VK_TO_VSC );
4305 if (!scan)
4306 expect = -1;
4307 else
4309 vkey &= 0xff00;
4310 vkey <<= 8;
4311 expect = vkey | scan;
4314 ok( ret == expect, "%04x: got %08lx expected %08lx\n", oem, ret, expect );
4318 static INPUT_MESSAGE_SOURCE expect_src;
4320 static LRESULT WINAPI msg_source_proc( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
4322 INPUT_MESSAGE_SOURCE source;
4323 MSG msg;
4325 ok( pGetCurrentInputMessageSource( &source ), "GetCurrentInputMessageSource failed\n" );
4326 switch (message)
4328 case WM_KEYDOWN:
4329 case WM_KEYUP:
4330 case WM_SYSKEYDOWN:
4331 case WM_SYSKEYUP:
4332 case WM_MOUSEMOVE:
4333 case WM_LBUTTONDOWN:
4334 case WM_LBUTTONUP:
4335 case WM_RBUTTONDOWN:
4336 case WM_RBUTTONUP:
4337 ok( source.deviceType == expect_src.deviceType || /* also accept system-generated WM_MOUSEMOVE */
4338 (message == WM_MOUSEMOVE && source.deviceType == IMDT_UNAVAILABLE),
4339 "%x: wrong deviceType %x/%x\n", message, source.deviceType, expect_src.deviceType );
4340 ok( source.originId == expect_src.originId ||
4341 (message == WM_MOUSEMOVE && source.originId == IMO_SYSTEM),
4342 "%x: wrong originId %x/%x\n", message, source.originId, expect_src.originId );
4343 SendMessageA( hwnd, WM_USER, 0, 0 );
4344 PostMessageA( hwnd, WM_USER, 0, 0 );
4345 if (PeekMessageW( &msg, hwnd, WM_USER, WM_USER, PM_REMOVE )) DispatchMessageW( &msg );
4346 ok( source.deviceType == expect_src.deviceType || /* also accept system-generated WM_MOUSEMOVE */
4347 (message == WM_MOUSEMOVE && source.deviceType == IMDT_UNAVAILABLE),
4348 "%x: wrong deviceType %x/%x\n", message, source.deviceType, expect_src.deviceType );
4349 ok( source.originId == expect_src.originId ||
4350 (message == WM_MOUSEMOVE && source.originId == IMO_SYSTEM),
4351 "%x: wrong originId %x/%x\n", message, source.originId, expect_src.originId );
4352 break;
4353 default:
4354 ok( source.deviceType == IMDT_UNAVAILABLE, "%x: wrong deviceType %x\n",
4355 message, source.deviceType );
4356 ok( source.originId == 0, "%x: wrong originId %x\n", message, source.originId );
4357 break;
4360 return DefWindowProcA( hwnd, message, wp, lp );
4363 static void test_input_message_source(void)
4365 WNDCLASSA cls;
4366 INPUT inputs[2];
4367 HWND hwnd;
4368 RECT rc;
4369 MSG msg;
4371 cls.style = 0;
4372 cls.lpfnWndProc = msg_source_proc;
4373 cls.cbClsExtra = 0;
4374 cls.cbWndExtra = 0;
4375 cls.hInstance = GetModuleHandleA(0);
4376 cls.hIcon = 0;
4377 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
4378 cls.hbrBackground = 0;
4379 cls.lpszMenuName = NULL;
4380 cls.lpszClassName = "message source class";
4381 RegisterClassA(&cls);
4382 hwnd = CreateWindowA( cls.lpszClassName, "test", WS_OVERLAPPED, 0, 0, 100, 100,
4383 0, 0, 0, 0 );
4384 ShowWindow( hwnd, SW_SHOWNORMAL );
4385 UpdateWindow( hwnd );
4386 SetForegroundWindow( hwnd );
4387 SetFocus( hwnd );
4389 inputs[0].type = INPUT_KEYBOARD;
4390 inputs[0].ki.dwExtraInfo = 0;
4391 inputs[0].ki.time = 0;
4392 inputs[0].ki.wVk = 0;
4393 inputs[0].ki.wScan = 0x3c0;
4394 inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;
4395 inputs[1] = inputs[0];
4396 inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;
4398 expect_src.deviceType = IMDT_UNAVAILABLE;
4399 expect_src.originId = IMO_UNAVAILABLE;
4400 SendMessageA( hwnd, WM_KEYDOWN, 0, 0 );
4401 SendMessageA( hwnd, WM_MOUSEMOVE, 0, 0 );
4403 SendInput( 2, inputs, sizeof(INPUT) );
4404 while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ))
4406 expect_src.deviceType = IMDT_KEYBOARD;
4407 expect_src.originId = IMO_INJECTED;
4408 TranslateMessage( &msg );
4409 DispatchMessageW( &msg );
4411 GetWindowRect( hwnd, &rc );
4412 simulate_click( TRUE, (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2 );
4413 simulate_click( FALSE, (rc.left + rc.right) / 2 + 1, (rc.top + rc.bottom) / 2 + 1 );
4414 while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ))
4416 expect_src.deviceType = IMDT_MOUSE;
4417 expect_src.originId = IMO_INJECTED;
4418 TranslateMessage( &msg );
4419 DispatchMessageW( &msg );
4422 expect_src.deviceType = IMDT_UNAVAILABLE;
4423 expect_src.originId = IMO_UNAVAILABLE;
4424 SendMessageA( hwnd, WM_KEYDOWN, 0, 0 );
4425 SendMessageA( hwnd, WM_LBUTTONDOWN, 0, 0 );
4426 PostMessageA( hwnd, WM_KEYUP, 0, 0 );
4427 PostMessageA( hwnd, WM_LBUTTONUP, 0, 0 );
4428 while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ))
4430 TranslateMessage( &msg );
4431 DispatchMessageW( &msg );
4434 expect_src.deviceType = IMDT_UNAVAILABLE;
4435 expect_src.originId = IMO_SYSTEM;
4436 SetCursorPos( (rc.left + rc.right) / 2 - 1, (rc.top + rc.bottom) / 2 - 1 );
4437 while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ))
4439 TranslateMessage( &msg );
4440 DispatchMessageW( &msg );
4443 DestroyWindow( hwnd );
4444 UnregisterClassA( cls.lpszClassName, GetModuleHandleA(0) );
4447 static void test_pointer_info(void)
4449 BOOL ret;
4450 POINTER_INPUT_TYPE type = -1;
4451 POINTER_INFO info;
4452 UINT id = 0;
4454 SetLastError(0xdeadbeef);
4455 ret = pGetPointerType(id, NULL);
4456 ok(!ret, "GetPointerType should have failed.\n");
4457 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4458 "expected error ERROR_INVALID_PARAMETER, got %lu.\n", GetLastError());
4460 SetLastError(0xdeadbeef);
4461 ret = pGetPointerType(id, &type);
4462 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4463 "expected error ERROR_INVALID_PARAMETER, got %lu.\n", GetLastError());
4464 ok(!ret, "GetPointerType failed, got type %ld for %u.\n", type, id );
4465 ok(type == -1, " type %ld\n", type );
4467 id = 1;
4468 ret = pGetPointerType(id, &type);
4469 ok(ret, "GetPointerType failed, got type %ld for %u.\n", type, id );
4470 ok(type == PT_MOUSE, " type %ld\n", type );
4472 /* GetPointerInfo always fails unless the app receives WM_POINTER messages. */
4473 SetLastError(0xdeadbeef);
4474 ret = pGetPointerInfo(id, &info);
4475 ok(!ret, "succeeded.\n");
4476 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu.\n", GetLastError());
4479 static void test_UnregisterDeviceNotification(void)
4481 BOOL ret = UnregisterDeviceNotification(NULL);
4482 ok(ret == FALSE, "Unregistering NULL Device Notification returned: %d\n", ret);
4485 static void test_SendInput(void)
4487 INPUT input[16];
4488 UINT res, i;
4489 HWND hwnd;
4490 MSG msg;
4492 hwnd = CreateWindowW( L"static", L"test", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, 0, 0 );
4493 ok( hwnd != 0, "CreateWindowW failed\n" );
4495 ShowWindow( hwnd, SW_SHOWNORMAL );
4496 UpdateWindow( hwnd );
4497 SetForegroundWindow( hwnd );
4498 SetFocus( hwnd );
4499 empty_message_queue();
4501 SetLastError( 0xdeadbeef );
4502 res = SendInput( 0, NULL, 0 );
4503 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4504 SetLastError( 0xdeadbeef );
4505 res = SendInput( 1, NULL, 0 );
4506 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4507 SetLastError( 0xdeadbeef );
4508 res = SendInput( 1, NULL, sizeof(*input) );
4509 ok( res == 0 && (GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_INVALID_PARAMETER),
4510 "SendInput returned %u, error %#lx\n", res, GetLastError() );
4511 SetLastError( 0xdeadbeef );
4512 res = SendInput( 0, input, sizeof(*input) );
4513 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4514 SetLastError( 0xdeadbeef );
4515 res = SendInput( 0, NULL, sizeof(*input) );
4516 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4518 memset( input, 0, sizeof(input) );
4519 SetLastError( 0xdeadbeef );
4520 res = SendInput( 1, input, sizeof(*input) );
4521 ok( res == 1 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4522 SetLastError( 0xdeadbeef );
4523 res = SendInput( 16, input, sizeof(*input) );
4524 ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4526 SetLastError( 0xdeadbeef );
4527 res = SendInput( 1, input, 0 );
4528 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4529 SetLastError( 0xdeadbeef );
4530 res = SendInput( 1, input, sizeof(*input) + 1 );
4531 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4532 SetLastError( 0xdeadbeef );
4533 res = SendInput( 1, input, sizeof(*input) - 1 );
4534 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4536 for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_KEYBOARD;
4537 SetLastError( 0xdeadbeef );
4538 res = SendInput( 16, input, offsetof( INPUT, ki ) + sizeof(KEYBDINPUT) );
4539 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4540 SetLastError( 0xdeadbeef );
4541 res = SendInput( 16, input, sizeof(*input) );
4542 ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4543 empty_message_queue();
4545 for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE;
4546 SetLastError( 0xdeadbeef );
4547 res = SendInput( 16, input, offsetof( INPUT, hi ) + sizeof(HARDWAREINPUT) );
4548 ok( res == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4550 input[0].hi.uMsg = WM_KEYDOWN;
4551 input[0].hi.wParamL = 0;
4552 input[0].hi.wParamH = 'A';
4553 input[1].hi.uMsg = WM_KEYUP;
4554 input[1].hi.wParamL = 0;
4555 input[1].hi.wParamH = 'A' | 0xc000;
4556 SetLastError( 0xdeadbeef );
4557 res = SendInput( 16, input, sizeof(*input) );
4558 ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ||
4559 broken(res == 16 && GetLastError() == 0xdeadbeef) /* 32bit */,
4560 "SendInput returned %u, error %#lx\n", res, GetLastError() );
4561 while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg);
4562 ok( !res, "SendInput triggered unexpected message %#x\n", msg.message );
4563 empty_message_queue();
4565 memset( input, 0, sizeof(input) );
4566 input[0].type = INPUT_HARDWARE;
4567 input[1].type = INPUT_KEYBOARD;
4568 input[1].ki.wVk = 'A';
4569 input[1].ki.dwFlags = 0;
4570 input[2].type = INPUT_KEYBOARD;
4571 input[2].ki.wVk = 'A';
4572 input[2].ki.dwFlags = KEYEVENTF_KEYUP;
4573 SetLastError( 0xdeadbeef );
4574 res = SendInput( 16, input, sizeof(*input) );
4575 ok( (res == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ||
4576 broken(res == 16 && GetLastError() == 0xdeadbeef),
4577 "SendInput returned %u, error %#lx\n", res, GetLastError() );
4578 while ((res = wait_for_message(&msg)) && (msg.message == WM_TIMER || broken(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP)))
4579 DispatchMessageA(&msg);
4580 ok( !res, "SendInput triggered unexpected message %#x\n", msg.message );
4581 empty_message_queue();
4583 for (i = 0; i < ARRAY_SIZE(input); ++i) input[i].type = INPUT_HARDWARE + 1;
4584 SetLastError( 0xdeadbeef );
4585 res = SendInput( 16, input, sizeof(*input) );
4586 ok( res == 16 && GetLastError() == 0xdeadbeef, "SendInput returned %u, error %#lx\n", res, GetLastError() );
4587 while ((res = wait_for_message(&msg)) && msg.message == WM_TIMER) DispatchMessageA(&msg);
4588 ok( !res, "SendInput triggered unexpected message %#x\n", msg.message );
4589 empty_message_queue();
4591 trace( "done\n" );
4592 DestroyWindow( hwnd );
4595 static void test_EnableMouseInPointer_process( const char *arg )
4597 DWORD enable = strtoul( arg, 0, 10 );
4598 BOOL ret;
4600 ret = pEnableMouseInPointer( enable );
4601 todo_wine
4602 ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() );
4604 SetLastError( 0xdeadbeef );
4605 ret = pEnableMouseInPointer( !enable );
4606 ok( !ret, "EnableMouseInPointer succeeded\n" );
4607 todo_wine
4608 ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() );
4610 ret = pEnableMouseInPointer( enable );
4611 todo_wine
4612 ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() );
4615 static void test_EnableMouseInPointer( char **argv, BOOL enable )
4617 STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)};
4618 PROCESS_INFORMATION info = {0};
4619 char cmdline[MAX_PATH * 2];
4620 BOOL ret;
4622 sprintf( cmdline, "%s %s EnableMouseInPointer %u", argv[0], argv[1], enable );
4623 ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info );
4624 ok( ret, "CreateProcessA failed, error %lu\n", GetLastError() );
4625 if (!ret) return;
4627 wait_child_process( info.hProcess );
4628 CloseHandle( info.hThread );
4629 CloseHandle( info.hProcess );
4632 START_TEST(input)
4634 char **argv;
4635 int argc;
4636 POINT pos;
4638 init_function_pointers();
4639 GetCursorPos( &pos );
4641 argc = winetest_get_mainargs(&argv);
4642 if (argc >= 3 && strcmp(argv[2], "rawinput_test") == 0)
4644 rawinput_test_process();
4645 return;
4648 if (argc >= 3 && strcmp(argv[2], "get_mouse_move_points_test") == 0)
4650 test_GetMouseMovePointsEx_process();
4651 return;
4654 if (argc >= 4 && strcmp( argv[2], "EnableMouseInPointer" ) == 0)
4656 winetest_push_context( "enable %s", argv[3] );
4657 test_EnableMouseInPointer_process( argv[3] );
4658 winetest_pop_context();
4659 return;
4662 test_SendInput();
4663 test_Input_blackbox();
4664 test_Input_whitebox();
4665 test_Input_unicode();
4666 test_Input_mouse();
4667 test_keynames();
4668 test_mouse_ll_hook();
4669 test_key_map();
4670 test_ToUnicode();
4671 test_ToAscii();
4672 test_get_async_key_state();
4673 test_keyboard_layout_name();
4674 test_key_names();
4675 test_attach_input();
4676 test_GetKeyState();
4677 test_OemKeyScan();
4678 test_GetRawInputData();
4679 test_GetRawInputBuffer();
4680 test_RegisterRawInputDevices();
4681 test_rawinput(argv[0]);
4682 test_DefRawInputProc();
4684 if(pGetMouseMovePointsEx)
4685 test_GetMouseMovePointsEx(argv[0]);
4686 else
4687 win_skip("GetMouseMovePointsEx is not available\n");
4689 if(pGetRawInputDeviceList)
4690 test_GetRawInputDeviceList();
4691 else
4692 win_skip("GetRawInputDeviceList is not available\n");
4694 if (pGetCurrentInputMessageSource)
4695 test_input_message_source();
4696 else
4697 win_skip("GetCurrentInputMessageSource is not available\n");
4699 SetCursorPos( pos.x, pos.y );
4701 if(pGetPointerType)
4702 test_pointer_info();
4703 else
4704 win_skip("GetPointerType is not available\n");
4706 test_UnregisterDeviceNotification();
4708 if (!pEnableMouseInPointer)
4709 win_skip( "EnableMouseInPointer not found, skipping tests\n" );
4710 else
4712 test_EnableMouseInPointer( argv, FALSE );
4713 test_EnableMouseInPointer( argv, TRUE );