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
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 */
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
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
56 #include "ddk/hidsdi.h"
58 #include "wine/test.h"
62 static LONG timetag
= 0x10000000;
64 #define DESKTOP_ALL_ACCESS 0x01ff
69 LONG last_syskey_down
;
75 LONG last_hook_syskey_down
;
76 LONG last_hook_syskey_up
;
79 BOOL sendinput_broken
;
82 static BOOL (WINAPI
*pGetCurrentInputMessageSource
)( INPUT_MESSAGE_SOURCE
*source
);
83 static BOOL (WINAPI
*pGetPointerType
)(UINT32
, POINTER_INPUT_TYPE
*);
84 static int (WINAPI
*pGetMouseMovePointsEx
) (UINT
, LPMOUSEMOVEPOINT
, LPMOUSEMOVEPOINT
, int, DWORD
);
85 static UINT (WINAPI
*pGetRawInputDeviceList
) (PRAWINPUTDEVICELIST
, PUINT
, UINT
);
86 static UINT (WINAPI
*pGetRawInputDeviceInfoW
) (HANDLE
, UINT
, void *, UINT
*);
87 static UINT (WINAPI
*pGetRawInputDeviceInfoA
) (HANDLE
, UINT
, void *, UINT
*);
88 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
, PBOOL
);
90 #define MAXKEYEVENTS 12
91 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
92 and only one message */
94 /* keyboard message names, sorted as their value */
95 static const char *MSGNAME
[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
96 "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
98 /* keyevents, add more as needed */
100 { ALTDOWN
= 1, ALTUP
, XDOWN
, XUP
, SHIFTDOWN
, SHIFTUP
, CTRLDOWN
, CTRLUP
} KEV
;
102 static const int GETVKEY
[]={0, VK_MENU
, VK_MENU
, 'X', 'X', VK_SHIFT
, VK_SHIFT
, VK_CONTROL
, VK_CONTROL
};
103 /* matching scan codes */
104 static const int GETSCAN
[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
105 /* matching updown events */
106 static const int GETFLAGS
[]={0, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
};
107 /* matching descriptions */
108 static const char *getdesc
[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
110 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
128 /*******************************************
129 * add new test sets here
130 * the software will make all combinations of the
131 * keyevent defined here
133 static const struct {
135 KEV keydwn
[MAXKEYEVENTS
];
136 KEV keyup
[MAXKEYEVENTS
];
138 { 2, { ALTDOWN
, XDOWN
}, { ALTUP
, XUP
}},
139 { 3, { ALTDOWN
, XDOWN
, SHIFTDOWN
}, { ALTUP
, XUP
, SHIFTUP
}},
140 { 3, { ALTDOWN
, XDOWN
, CTRLDOWN
}, { ALTUP
, XUP
, CTRLUP
}},
141 { 3, { SHIFTDOWN
, XDOWN
, CTRLDOWN
}, { SHIFTUP
, XUP
, CTRLUP
}},
142 { 0 } /* mark the end */
145 /**********************adapted from input.c **********************************/
147 static BYTE InputKeyStateTable
[256];
148 static BYTE AsyncKeyStateTable
[256];
149 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
150 or a WM_KEYUP message */
151 static BOOL is_wow64
;
153 static void init_function_pointers(void)
155 HMODULE hdll
= GetModuleHandleA("user32");
157 #define GET_PROC(func) \
158 if (!(p ## func = (void*)GetProcAddress(hdll, #func))) \
159 trace("GetProcAddress(%s) failed\n", #func)
161 GET_PROC(GetCurrentInputMessageSource
);
162 GET_PROC(GetMouseMovePointsEx
);
163 GET_PROC(GetPointerType
);
164 GET_PROC(GetRawInputDeviceList
);
165 GET_PROC(GetRawInputDeviceInfoW
);
166 GET_PROC(GetRawInputDeviceInfoA
);
168 hdll
= GetModuleHandleA("kernel32");
169 GET_PROC(IsWow64Process
);
172 if (!pIsWow64Process
|| !pIsWow64Process( GetCurrentProcess(), &is_wow64
))
176 static int KbdMessage( KEV kev
, WPARAM
*pwParam
, LPARAM
*plParam
)
179 int VKey
= GETVKEY
[kev
];
182 flags
= LOBYTE(GETSCAN
[kev
]);
183 if (GETFLAGS
[kev
] & KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
185 if (GETFLAGS
[kev
] & KEYEVENTF_KEYUP
)
188 if( (InputKeyStateTable
[VK_MENU
] & 0x80) && (
189 (VKey
== VK_MENU
) || (VKey
== VK_CONTROL
) ||
190 !(InputKeyStateTable
[VK_CONTROL
] & 0x80))) {
191 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
192 (VKey
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
193 message
= WM_SYSKEYUP
;
196 InputKeyStateTable
[VKey
] &= ~0x80;
197 flags
|= KF_REPEAT
| KF_UP
;
201 if (InputKeyStateTable
[VKey
] & 0x80) flags
|= KF_REPEAT
;
202 if (!(InputKeyStateTable
[VKey
] & 0x80)) InputKeyStateTable
[VKey
] ^= 0x01;
203 InputKeyStateTable
[VKey
] |= 0x80;
204 AsyncKeyStateTable
[VKey
] |= 0x80;
206 message
= WM_KEYDOWN
;
207 if( (InputKeyStateTable
[VK_MENU
] & 0x80) &&
208 !(InputKeyStateTable
[VK_CONTROL
] & 0x80)) {
209 message
= WM_SYSKEYDOWN
;
214 if (InputKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
216 if( plParam
) *plParam
= MAKELPARAM( 1, flags
);
217 if( pwParam
) *pwParam
= VKey
;
221 /****************************** end copy input.c ****************************/
224 * . prepare the keyevents for SendInputs
225 * . calculate the "expected" messages
226 * . Send the events to our window
227 * . retrieve the messages from the input queue
230 static BOOL
do_test( HWND hwnd
, int seqnr
, const KEV td
[] )
232 TEST_INPUT inputs
[MAXKEYEVENTS
];
233 KMSG expmsg
[MAXKEYEVENTS
];
240 TrackSysKey
=0; /* see input.c */
241 for (i
= 0; i
< MAXKEYEVENTS
; i
++)
243 inputs
[evtctr
].type
= INPUT_KEYBOARD
;
244 inputs
[evtctr
].u
.ki
.wVk
= GETVKEY
[td
[i
]];
245 inputs
[evtctr
].u
.ki
.wScan
= GETSCAN
[td
[i
]];
246 inputs
[evtctr
].u
.ki
.dwFlags
= GETFLAGS
[td
[i
]];
247 inputs
[evtctr
].u
.ki
.dwExtraInfo
= 0;
248 inputs
[evtctr
].u
.ki
.time
= ++timetag
;
251 strcat(buf
, getdesc
[td
[i
]]);
253 expmsg
[i
].message
= KbdMessage(td
[i
], &(expmsg
[i
].wParam
), &(expmsg
[i
].lParam
));
255 expmsg
[i
].message
= 0;
257 for( kmctr
= 0; kmctr
< MAXKEYEVENTS
&& expmsg
[kmctr
].message
; kmctr
++)
259 ok( evtctr
<= MAXKEYEVENTS
, "evtctr is above MAXKEYEVENTS\n" );
260 ret
= SendInput(evtctr
, (INPUT
*)inputs
, sizeof(INPUT
));
261 ok(ret
== evtctr
, "SendInput failed to send some events\n");
263 if (winetest_debug
> 1)
264 trace("======== key stroke sequence #%d: %s =============\n",
266 while( PeekMessageA(&msg
,hwnd
,WM_KEYFIRST
,WM_KEYLAST
,PM_REMOVE
) ) {
267 if (winetest_debug
> 1)
268 trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i
,
269 MSGNAME
[msg
.message
- WM_KEYFIRST
], msg
.wParam
, msg
.lParam
, msg
.time
);
271 ok( msg
.message
== expmsg
[i
].message
&&
272 msg
.wParam
== expmsg
[i
].wParam
&&
273 msg
.lParam
== expmsg
[i
].lParam
,
274 "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n",
275 seqnr
, i
, msg
.message
, msg
.wParam
, msg
.lParam
,
276 MSGNAME
[(expmsg
[i
]).message
- WM_KEYFIRST
], expmsg
[i
].wParam
, expmsg
[i
].lParam
);
280 if (winetest_debug
> 1)
281 trace("%d messages retrieved\n", i
);
284 skip( "simulated keyboard input doesn't work\n" );
287 ok( i
== kmctr
, "message count is wrong: got %d expected: %d\n", i
, kmctr
);
291 /* test all combinations of the specified key events */
292 static BOOL
TestASet( HWND hWnd
, int nrkev
, const KEV kevdwn
[], const KEV kevup
[] )
296 KEV kbuf
[MAXKEYEVENTS
];
297 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
300 skip( "skipping test with inconsistent results on non-us keyboard\n" );
304 assert( nrkev
==2 || nrkev
==3);
305 for(i
=0;i
<MAXKEYEVENTS
;i
++) kbuf
[i
]=0;
306 /* two keys involved gives 4 test cases */
308 for(i
=0;i
<nrkev
;i
++) {
309 for(j
=0;j
<nrkev
;j
++) {
311 kbuf
[1] = kevdwn
[1-i
];
313 kbuf
[3] = kevup
[1-j
];
314 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
318 /* three keys involved gives 36 test cases */
320 for(i
=0;i
<nrkev
;i
++){
321 for(j
=0;j
<nrkev
;j
++){
323 for(k
=0;k
<nrkev
;k
++){
324 if(k
==i
|| k
==j
) continue;
325 for(l
=0;l
<nrkev
;l
++){
326 for(m
=0;m
<nrkev
;m
++){
328 for(n
=0;n
<nrkev
;n
++){
329 if(n
==l
||n
==m
) continue;
336 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
347 /* test each set specified in the global testkeyset array */
348 static void TestSysKeys( HWND hWnd
)
351 for(i
=0; testkeyset
[i
].nrkev
;i
++)
352 if (!TestASet( hWnd
, testkeyset
[i
].nrkev
, testkeyset
[i
].keydwn
, testkeyset
[i
].keyup
)) break;
355 static LRESULT CALLBACK
WndProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
358 return DefWindowProcA( hWnd
, msg
, wParam
, lParam
);
361 static void test_Input_whitebox(void)
365 HANDLE hInstance
= GetModuleHandleA( NULL
);
367 wclass
.lpszClassName
= "InputSysKeyTestClass";
368 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
369 wclass
.lpfnWndProc
= WndProc
;
370 wclass
.hInstance
= hInstance
;
371 wclass
.hIcon
= LoadIconA( 0, (LPCSTR
)IDI_APPLICATION
);
372 wclass
.hCursor
= LoadCursorA( NULL
, (LPCSTR
)IDC_ARROW
);
373 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1 );
374 wclass
.lpszMenuName
= 0;
375 wclass
.cbClsExtra
= 0;
376 wclass
.cbWndExtra
= 0;
377 RegisterClassA( &wclass
);
378 /* create the test window that will receive the keystrokes */
379 hWndTest
= CreateWindowA( wclass
.lpszClassName
, "InputSysKeyTest",
380 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
381 NULL
, NULL
, hInstance
, NULL
);
383 ShowWindow( hWndTest
, SW_SHOW
);
384 SetWindowPos( hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
385 SetForegroundWindow( hWndTest
);
386 UpdateWindow( hWndTest
);
388 /* flush pending messages */
389 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
391 SetFocus( hWndTest
);
392 TestSysKeys( hWndTest
);
393 DestroyWindow(hWndTest
);
396 static inline BOOL
is_keyboard_message( UINT message
)
398 return (message
>= WM_KEYFIRST
&& message
<= WM_KEYLAST
);
401 static inline BOOL
is_mouse_message( UINT message
)
403 return (message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
);
406 /* try to make sure pending X events have been processed before continuing */
407 static void empty_message_queue(void)
411 int min_timeout
= 50;
412 DWORD time
= GetTickCount() + diff
;
416 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
417 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
419 if (is_keyboard_message(msg
.message
) || is_mouse_message(msg
.message
))
420 ok(msg
.time
!= 0, "message %#x has time set to 0\n", msg
.message
);
422 TranslateMessage(&msg
);
423 DispatchMessageA(&msg
);
425 diff
= time
- GetTickCount();
429 struct transition_s
{
449 UINT message
; /* the WM_* code */
450 msg_flags_t flags
; /* message props */
451 WPARAM wParam
; /* expected value of wParam */
452 LPARAM lParam
; /* expected value of lParam */
455 static const struct sendinput_test_s
{
459 struct transition_s expected_transitions
[MAXKEYEVENTS
+1];
460 struct message expected_messages
[MAXKEYMESSAGES
+1];
461 } sendinput_test
[] = {
464 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
465 {{WM_SYSKEYDOWN
, hook
|wparam
, VK_LMENU
}, {WM_SYSKEYDOWN
}, {0}}},
466 {'F', 0, FALSE
, {{'F', 0x00}, {0}},
467 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
},
469 {WM_SYSCOMMAND
}, {0}}},
470 {'F', KEYEVENTF_KEYUP
, FALSE
, {{'F', 0x80}, {0}},
471 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
472 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
473 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
477 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
478 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
479 {'O', 0, FALSE
, {{'O', 0x00}, {0}},
480 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
481 {'O', KEYEVENTF_KEYUP
, FALSE
, {{'O', 0x80}, {0}},
482 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
483 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
484 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
486 /* test ALT+CTRL+X */
488 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
489 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
}, {0}}},
490 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
491 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
492 {'X', 0, FALSE
, {{'X', 0x00}, {0}},
493 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
494 {'X', KEYEVENTF_KEYUP
, FALSE
, {{'X', 0x80}, {0}},
495 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
496 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
497 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
498 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
499 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
503 {VK_LSHIFT
, 0, FALSE
, {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
504 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
505 {'A', 0, FALSE
, {{'A', 0x00}, {0}},
506 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
507 {'A', KEYEVENTF_KEYUP
, FALSE
, {{'A', 0x80}, {0}},
508 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
509 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
, {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
510 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
511 /* test L-SHIFT & R-SHIFT: */
512 /* RSHIFT == LSHIFT */
514 {VK_RSHIFT
, 0, FALSE
,
515 /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
516 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00, TRUE
}, {VK_RSHIFT
, 0x00, TRUE
}, {0}},
517 {{WM_KEYDOWN
, hook
|wparam
, VK_RSHIFT
},
519 {VK_RSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
520 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80, TRUE
}, {VK_RSHIFT
, 0x80, TRUE
}, {0}},
521 {{WM_KEYUP
, hook
, hook
|wparam
, VK_RSHIFT
},
524 /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
526 {VK_LSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
527 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
528 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_EXTENDED
},
529 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
530 {VK_LSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
531 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
532 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
533 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
534 /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
536 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
537 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
538 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
539 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
540 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
541 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
542 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
543 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
545 /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
546 win2k - sends to hook whatever we generated here
547 winXP+ - Attempts to convert key to L/R key but not always correct
549 /* SHIFT == LSHIFT */
552 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
553 {{WM_KEYDOWN
, hook
/* |wparam */|lparam
, VK_SHIFT
, 0},
554 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
555 {VK_SHIFT
, KEYEVENTF_KEYUP
, FALSE
,
556 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
557 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
},
558 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
559 /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
561 {VK_SHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
562 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
563 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_EXTENDED
},
564 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
565 {VK_SHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
566 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
567 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
568 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
570 /* test L-CONTROL & R-CONTROL: */
571 /* RCONTROL == LCONTROL */
573 {VK_RCONTROL
, 0, FALSE
,
574 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
575 {{WM_KEYDOWN
, hook
|wparam
, VK_RCONTROL
},
576 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
577 {VK_RCONTROL
, KEYEVENTF_KEYUP
, FALSE
,
578 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
579 {{WM_KEYUP
, hook
|wparam
, VK_RCONTROL
},
580 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
581 /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
583 {VK_LCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
584 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
585 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_EXTENDED
},
586 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
587 {VK_LCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
588 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
589 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
590 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
591 /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
593 {VK_RCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
594 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
595 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_EXTENDED
},
596 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
597 {VK_RCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
598 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
599 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
600 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
601 /* CONTROL == LCONTROL */
603 {VK_CONTROL
, 0, FALSE
,
604 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
605 {{WM_KEYDOWN
, hook
/*|wparam, VK_CONTROL*/},
606 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
607 {VK_CONTROL
, KEYEVENTF_KEYUP
, FALSE
,
608 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
609 {{WM_KEYUP
, hook
/*|wparam, VK_CONTROL*/},
610 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
611 /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
613 {VK_CONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
614 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
615 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_EXTENDED
},
616 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
617 {VK_CONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
618 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
619 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
620 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
622 /* test L-MENU & R-MENU: */
626 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
627 {{WM_SYSKEYDOWN
, hook
|wparam
|optional
, VK_LCONTROL
},
628 {WM_SYSKEYDOWN
, hook
|wparam
, VK_RMENU
},
629 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
630 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
631 {VK_RMENU
, KEYEVENTF_KEYUP
, TRUE
,
632 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
633 {{WM_KEYUP
, hook
|wparam
|optional
, VK_LCONTROL
},
634 {WM_KEYUP
, hook
|wparam
, VK_RMENU
},
635 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
636 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
637 {WM_SYSCOMMAND
, optional
}, {0}}},
638 /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
640 {VK_LMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
641 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {0}},
642 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_EXTENDED
},
643 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
644 {VK_LMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
645 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {0}},
646 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
647 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
648 {WM_SYSCOMMAND
}, {0}}},
649 /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
651 {VK_RMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
652 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
653 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, 0},
654 {WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_EXTENDED
},
655 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
656 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
657 {VK_RMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
658 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
659 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, LLKHF_UP
},
660 {WM_KEYUP
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
661 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
662 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
663 {WM_SYSCOMMAND
, optional
}, {0}}},
667 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
668 {{WM_SYSKEYDOWN
, hook
/*|wparam, VK_MENU*/},
669 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
670 {VK_MENU
, KEYEVENTF_KEYUP
, TRUE
,
671 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
672 {{WM_KEYUP
, hook
/*|wparam, VK_MENU*/},
673 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
674 {WM_SYSCOMMAND
}, {0}}},
675 /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
677 {VK_MENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
678 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
679 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, 0},
680 {WM_SYSKEYDOWN
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_EXTENDED
},
681 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
682 {VK_MENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
683 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
684 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, LLKHF_UP
},
685 {WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_UP
|LLKHF_EXTENDED
},
686 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
687 {WM_SYSCOMMAND
}, {0}}},
689 /* test LSHIFT & RSHIFT */
691 {VK_LSHIFT
, 0, FALSE
,
692 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
693 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, 0},
694 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
695 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
696 {{VK_RSHIFT
, 0x00}, {0}},
697 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
698 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
699 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
700 {{VK_RSHIFT
, 0x80}, {0}},
701 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
702 {WM_KEYUP
, optional
}, {0}}},
703 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
704 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
705 {{WM_KEYUP
, hook
|wparam
, VK_LSHIFT
},
706 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
708 {0, 0, FALSE
, {{0}}, {{0}}} /* end */
711 static struct message sent_messages
[MAXKEYMESSAGES
];
712 static UINT sent_messages_cnt
;
714 /* Verify that only specified key state transitions occur */
715 static void compare_and_check(int id
, BYTE
*ks1
, BYTE
*ks2
,
716 const struct sendinput_test_s
*test
, BOOL foreground
)
718 int i
, failcount
= 0;
719 const struct transition_s
*t
= test
->expected_transitions
;
721 const struct message
*expected
= test
->expected_messages
;
723 while (t
->wVk
&& foreground
) {
724 /* We won't receive any information from GetKeyboardState() if we're
725 * not the foreground window. */
726 BOOL matched
= ((ks1
[t
->wVk
]&0x80) == (t
->before_state
&0x80)
727 && (ks2
[t
->wVk
]&0x80) == (~t
->before_state
&0x80));
729 if (!matched
&& !t
->optional
&& test
->_todo_wine
)
733 ok(matched
, "%2d (%x/%x): %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);
739 ok(matched
|| t
->optional
, "%2d (%x/%x): %02x from %02x -> %02x "
740 "instead of %02x -> %02x\n", id
, test
->wVk
, test
->dwFlags
,
741 t
->wVk
, ks1
[t
->wVk
]&0x80, ks2
[t
->wVk
]&0x80, t
->before_state
,
742 ~t
->before_state
&0x80);
744 ks2
[t
->wVk
] = ks1
[t
->wVk
]; /* clear the match */
747 for (i
= 0; i
< 256; i
++)
748 if (ks2
[i
] != ks1
[i
] && test
->_todo_wine
)
752 ok(FALSE
, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
753 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
756 ok(ks2
[i
] == ks1
[i
], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
757 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
759 while (expected
->message
&& actual_cnt
< sent_messages_cnt
)
761 const struct message
*actual
= &sent_messages
[actual_cnt
];
763 if (expected
->message
== actual
->message
)
765 if (expected
->flags
& wparam
)
767 if ((expected
->flags
& optional
) && (expected
->wParam
!= actual
->wParam
))
772 if (expected
->wParam
!= actual
->wParam
&& test
->_todo_wine
)
776 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
777 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
780 ok(expected
->wParam
== actual
->wParam
,
781 "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
782 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
784 if (expected
->flags
& lparam
)
786 if (expected
->lParam
!= actual
->lParam
&& test
->_todo_wine
)
790 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
791 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
794 ok(expected
->lParam
== actual
->lParam
,
795 "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
796 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
798 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
799 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
800 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
803 else if (expected
->flags
& optional
)
808 else if (!(expected
->flags
& hook
) && !foreground
)
810 /* If we weren't able to receive foreground status, we won't get
811 * any window messages. */
815 /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
816 else if ((expected
->flags
& hook
) &&
817 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
818 (actual
->message
== expected
->message
- 4))
820 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
821 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
822 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
824 /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
825 * instead of SYSKEYDOWN/UP to the WNDPROC */
826 else if (test
->wVk
== VK_RMENU
&& !(expected
->flags
& hook
) &&
827 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
828 (actual
->message
== expected
->message
- 4))
830 ok(expected
->wParam
== actual
->wParam
&& expected
->lParam
== actual
->lParam
,
831 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
832 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
834 else if (test
->_todo_wine
)
839 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
840 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
844 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
845 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
850 /* skip all optional trailing messages */
851 while (expected
->message
&& ((expected
->flags
& optional
) || (!(expected
->flags
& hook
) && !foreground
)))
855 if (expected
->message
|| actual_cnt
< sent_messages_cnt
)
857 if (test
->_todo_wine
)
861 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
862 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
865 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
866 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
869 if( test
->_todo_wine
&& !failcount
) /* succeeded yet marked todo */
871 ok(TRUE
, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id
, test
->wVk
, test
->dwFlags
);
873 sent_messages_cnt
= 0;
876 /* WndProc2 checks that we get at least the messages specified */
877 static LRESULT CALLBACK
WndProc2(HWND hWnd
, UINT Msg
, WPARAM wParam
,
880 if (winetest_debug
> 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg
, wParam
, lParam
);
882 if ((Msg
>= WM_KEYFIRST
&& Msg
<= WM_KEYLAST
) || Msg
== WM_SYSCOMMAND
)
884 ok(sent_messages_cnt
< MAXKEYMESSAGES
, "Too many messages\n");
885 if (sent_messages_cnt
< MAXKEYMESSAGES
)
887 sent_messages
[sent_messages_cnt
].message
= Msg
;
888 sent_messages
[sent_messages_cnt
].flags
= 0;
889 sent_messages
[sent_messages_cnt
].wParam
= wParam
;
890 sent_messages
[sent_messages_cnt
++].lParam
= HIWORD(lParam
) & (KF_UP
|KF_EXTENDED
);
893 return DefWindowProcA(hWnd
, Msg
, wParam
, lParam
);
896 static LRESULT CALLBACK
hook_proc(int code
, WPARAM wparam
, LPARAM lparam
)
898 KBDLLHOOKSTRUCT
*hook_info
= (KBDLLHOOKSTRUCT
*)lparam
;
900 if (code
== HC_ACTION
)
902 ok(sent_messages_cnt
< MAXKEYMESSAGES
, "Too many messages\n");
903 if (sent_messages_cnt
< MAXKEYMESSAGES
)
905 sent_messages
[sent_messages_cnt
].message
= wparam
;
906 sent_messages
[sent_messages_cnt
].flags
= hook
;
907 sent_messages
[sent_messages_cnt
].wParam
= hook_info
->vkCode
;
908 sent_messages
[sent_messages_cnt
++].lParam
= hook_info
->flags
& (LLKHF_UP
|LLKHF_EXTENDED
);
911 if(0) /* For some reason not stable on Wine */
913 if (wparam
== WM_KEYDOWN
|| wparam
== WM_SYSKEYDOWN
)
914 ok(!(GetAsyncKeyState(hook_info
->vkCode
) & 0x8000), "key %x should be up\n", hook_info
->vkCode
);
915 else if (wparam
== WM_KEYUP
|| wparam
== WM_SYSKEYUP
)
916 ok(GetAsyncKeyState(hook_info
->vkCode
) & 0x8000, "key %x should be down\n", hook_info
->vkCode
);
919 if (winetest_debug
> 1)
920 trace("Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam
,
921 hook_info
->vkCode
, hook_info
->scanCode
, hook_info
->flags
, hook_info
->dwExtraInfo
);
923 return CallNextHookEx( 0, code
, wparam
, lparam
);
925 static void test_Input_blackbox(void)
929 BYTE ks1
[256], ks2
[256];
930 LONG_PTR prevWndProc
;
935 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409)
937 skip("Skipping Input_blackbox test on non-US keyboard\n");
940 window
= CreateWindowA("Static", NULL
, WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
941 |WS_VISIBLE
, 0, 0, 200, 60, NULL
, NULL
,
943 ok(window
!= NULL
, "error: %d\n", (int) GetLastError());
944 SetWindowPos( window
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
945 foreground
= SetForegroundWindow( window
);
947 skip("Failed to set foreground window; some tests will be skipped.\n");
949 if (!(hook
= SetWindowsHookExA(WH_KEYBOARD_LL
, hook_proc
, GetModuleHandleA( NULL
), 0)))
951 DestroyWindow(window
);
952 win_skip("WH_KEYBOARD_LL is not supported\n");
956 /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
957 * key state set by SendInput(). */
958 empty_message_queue();
960 prevWndProc
= SetWindowLongPtrA(window
, GWLP_WNDPROC
, (LONG_PTR
) WndProc2
);
961 ok(prevWndProc
!= 0 || GetLastError() == 0, "error: %d\n", (int) GetLastError());
963 i
.type
= INPUT_KEYBOARD
;
965 i
.u
.ki
.dwExtraInfo
= 0;
967 for (ii
= 0; ii
< ARRAY_SIZE(sendinput_test
)-1; ii
++) {
968 GetKeyboardState(ks1
);
969 i
.u
.ki
.wScan
= ii
+1 /* useful for debugging */;
970 i
.u
.ki
.dwFlags
= sendinput_test
[ii
].dwFlags
;
971 i
.u
.ki
.wVk
= sendinput_test
[ii
].wVk
;
972 SendInput(1, (INPUT
*)&i
, sizeof(TEST_INPUT
));
973 empty_message_queue();
974 GetKeyboardState(ks2
);
975 compare_and_check(ii
, ks1
, ks2
, &sendinput_test
[ii
], foreground
);
978 empty_message_queue();
979 DestroyWindow(window
);
980 UnhookWindowsHookEx(hook
);
983 static void reset_key_status(WORD vk
)
985 key_status
.last_key_down
= -1;
986 key_status
.last_key_up
= -1;
987 key_status
.last_syskey_down
= -1;
988 key_status
.last_syskey_up
= -1;
989 key_status
.last_char
= -1;
990 key_status
.last_syschar
= -1;
991 key_status
.last_hook_down
= -1;
992 key_status
.last_hook_up
= -1;
993 key_status
.last_hook_syskey_down
= -1;
994 key_status
.last_hook_syskey_up
= -1;
996 key_status
.expect_alt
= FALSE
;
997 key_status
.sendinput_broken
= FALSE
;
1000 static void test_unicode_keys(HWND hwnd
, HHOOK hook
)
1002 TEST_INPUT inputs
[2];
1005 /* init input data that never changes */
1006 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
1007 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
1008 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
1010 /* pressing & releasing a single unicode character */
1011 inputs
[0].u
.ki
.wVk
= 0;
1012 inputs
[0].u
.ki
.wScan
= 0x3c0;
1013 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1015 reset_key_status(VK_PACKET
);
1016 SendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1017 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1018 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1019 TranslateMessage(&msg
);
1021 DispatchMessageW(&msg
);
1023 if(!key_status
.sendinput_broken
){
1024 ok(key_status
.last_key_down
== VK_PACKET
,
1025 "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_down
);
1026 ok(key_status
.last_char
== 0x3c0,
1027 "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status
.last_char
);
1029 ok(key_status
.last_hook_down
== 0x3c0,
1030 "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_down
);
1033 inputs
[1].u
.ki
.wVk
= 0;
1034 inputs
[1].u
.ki
.wScan
= 0x3c0;
1035 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1037 reset_key_status(VK_PACKET
);
1038 SendInput(1, (INPUT
*)(inputs
+1), sizeof(INPUT
));
1039 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1040 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1041 TranslateMessage(&msg
);
1043 DispatchMessageW(&msg
);
1045 if(!key_status
.sendinput_broken
){
1046 ok(key_status
.last_key_up
== VK_PACKET
,
1047 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1049 ok(key_status
.last_hook_up
== 0x3c0,
1050 "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_up
);
1053 /* holding alt, pressing & releasing a unicode character, releasing alt */
1054 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1055 inputs
[0].u
.ki
.wScan
= 0;
1056 inputs
[0].u
.ki
.dwFlags
= 0;
1058 inputs
[1].u
.ki
.wVk
= 0;
1059 inputs
[1].u
.ki
.wScan
= 0x3041;
1060 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1062 reset_key_status(VK_PACKET
);
1063 key_status
.expect_alt
= TRUE
;
1064 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1065 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1066 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1067 TranslateMessage(&msg
);
1069 DispatchMessageW(&msg
);
1071 if(!key_status
.sendinput_broken
){
1072 ok(key_status
.last_syskey_down
== VK_PACKET
,
1073 "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_syskey_down
);
1074 ok(key_status
.last_syschar
== 0x3041,
1075 "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status
.last_syschar
);
1077 ok(key_status
.last_hook_syskey_down
== 0x3041,
1078 "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_syskey_down
);
1081 inputs
[1].u
.ki
.wVk
= 0;
1082 inputs
[1].u
.ki
.wScan
= 0x3041;
1083 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1085 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1086 inputs
[0].u
.ki
.wScan
= 0;
1087 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1089 reset_key_status(VK_PACKET
);
1090 key_status
.expect_alt
= TRUE
;
1091 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1092 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1093 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1094 TranslateMessage(&msg
);
1096 DispatchMessageW(&msg
);
1098 if(!key_status
.sendinput_broken
){
1099 ok(key_status
.last_key_up
== VK_PACKET
,
1100 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1102 ok(key_status
.last_hook_up
== 0x3041,
1103 "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_up
);
1106 /* Press and release, non-zero key code. */
1107 inputs
[0].u
.ki
.wVk
= 0x51;
1108 inputs
[0].u
.ki
.wScan
= 0x123;
1109 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1111 inputs
[1].u
.ki
.wVk
= 0x51;
1112 inputs
[1].u
.ki
.wScan
= 0x123;
1113 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1115 reset_key_status(inputs
[0].u
.ki
.wVk
);
1116 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1117 while (PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
))
1119 TranslateMessage(&msg
);
1120 DispatchMessageW(&msg
);
1123 if (!key_status
.sendinput_broken
)
1125 ok(key_status
.last_key_down
== 0x51, "Unexpected key down %#x.\n", key_status
.last_key_down
);
1126 ok(key_status
.last_key_up
== 0x51, "Unexpected key up %#x.\n", key_status
.last_key_up
);
1129 ok(key_status
.last_hook_up
== 0x23, "Unexpected hook message %#x.\n", key_status
.last_hook_up
);
1133 static LRESULT CALLBACK
unicode_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1138 key_status
.last_key_down
= wParam
;
1141 key_status
.last_syskey_down
= wParam
;
1144 key_status
.last_key_up
= wParam
;
1147 key_status
.last_syskey_up
= wParam
;
1150 key_status
.last_char
= wParam
;
1153 key_status
.last_syschar
= wParam
;
1156 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1159 static LRESULT CALLBACK
llkbd_unicode_hook(int nCode
, WPARAM wParam
, LPARAM lParam
)
1161 if(nCode
== HC_ACTION
){
1162 LPKBDLLHOOKSTRUCT info
= (LPKBDLLHOOKSTRUCT
)lParam
;
1164 key_status
.sendinput_broken
= TRUE
;
1165 win_skip("SendInput doesn't support unicode on this platform\n");
1167 if(key_status
.expect_alt
){
1168 ok(info
->vkCode
== VK_LMENU
, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU
, info
->vkCode
);
1169 key_status
.expect_alt
= FALSE
;
1171 todo_wine_if(key_status
.vk
!= VK_PACKET
)
1172 ok(info
->vkCode
== key_status
.vk
, "Unexpected vkCode %#x, expected %#x.\n", info
->vkCode
, key_status
.vk
);
1176 key_status
.last_hook_down
= info
->scanCode
;
1179 key_status
.last_hook_up
= info
->scanCode
;
1182 key_status
.last_hook_syskey_down
= info
->scanCode
;
1185 key_status
.last_hook_syskey_up
= info
->scanCode
;
1189 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
1192 static void test_Input_unicode(void)
1194 WCHAR classNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1195 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1196 WCHAR windowNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1197 'K','e','y','T','e','s','t',0};
1200 HANDLE hInstance
= GetModuleHandleW(NULL
);
1202 HMODULE hModuleImm32
;
1203 BOOL (WINAPI
*pImmDisableIME
)(DWORD
);
1204 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
1207 skip( "skipping test with inconsistent results on non-us keyboard\n" );
1211 wclass
.lpszClassName
= classNameW
;
1212 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1213 wclass
.lpfnWndProc
= unicode_wnd_proc
;
1214 wclass
.hInstance
= hInstance
;
1215 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1216 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1217 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1218 wclass
.lpszMenuName
= 0;
1219 wclass
.cbClsExtra
= 0;
1220 wclass
.cbWndExtra
= 0;
1221 if(!RegisterClassW(&wclass
)){
1222 win_skip("Unicode functions not supported\n");
1226 hModuleImm32
= LoadLibraryA("imm32.dll");
1228 pImmDisableIME
= (void *)GetProcAddress(hModuleImm32
, "ImmDisableIME");
1232 pImmDisableIME
= NULL
;
1233 FreeLibrary(hModuleImm32
);
1235 /* create the test window that will receive the keystrokes */
1236 hWndTest
= CreateWindowW(wclass
.lpszClassName
, windowNameW
,
1237 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1238 NULL
, NULL
, hInstance
, NULL
);
1241 assert(IsWindowUnicode(hWndTest
));
1243 hook
= SetWindowsHookExW(WH_KEYBOARD_LL
, llkbd_unicode_hook
, GetModuleHandleW(NULL
), 0);
1245 win_skip("unable to set WH_KEYBOARD_LL hook\n");
1247 ShowWindow(hWndTest
, SW_SHOW
);
1248 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1249 SetForegroundWindow(hWndTest
);
1250 UpdateWindow(hWndTest
);
1252 /* flush pending messages */
1253 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1257 test_unicode_keys(hWndTest
, hook
);
1260 UnhookWindowsHookEx(hook
);
1261 DestroyWindow(hWndTest
);
1264 static void test_keynames(void)
1269 for (i
= 0; i
< 512; i
++)
1271 strcpy(buff
, "----");
1272 len
= GetKeyNameTextA(i
<< 16, buff
, sizeof(buff
));
1273 ok(len
|| !buff
[0], "%d: Buffer is not zeroed\n", i
);
1277 static POINT pt_old
, pt_new
;
1278 static BOOL clipped
;
1281 static LRESULT CALLBACK
hook_proc1( int code
, WPARAM wparam
, LPARAM lparam
)
1283 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1286 if (code
== HC_ACTION
)
1288 /* This is our new cursor position */
1290 /* Should return previous position */
1292 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1294 /* Should set new position until hook chain is finished. */
1295 pt
.x
= pt_old
.x
+ STEP
;
1296 pt
.y
= pt_old
.y
+ STEP
;
1297 SetCursorPos(pt
.x
, pt
.y
);
1300 ok(pt1
.x
== pt_old
.x
&& pt1
.y
== pt_old
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1302 ok(pt1
.x
== pt
.x
&& pt1
.y
== pt
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1304 return CallNextHookEx( 0, code
, wparam
, lparam
);
1307 static LRESULT CALLBACK
hook_proc2( int code
, WPARAM wparam
, LPARAM lparam
)
1309 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1312 if (code
== HC_ACTION
)
1314 ok(hook
->pt
.x
== pt_new
.x
&& hook
->pt
.y
== pt_new
.y
,
1315 "Wrong hook coords: (%d %d) != (%d,%d)\n", hook
->pt
.x
, hook
->pt
.y
, pt_new
.x
, pt_new
.y
);
1317 /* Should match position set above */
1320 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1322 ok(pt
.x
== pt_old
.x
+STEP
&& pt
.y
== pt_old
.y
+STEP
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1324 return CallNextHookEx( 0, code
, wparam
, lparam
);
1327 static LRESULT CALLBACK
hook_proc3( int code
, WPARAM wparam
, LPARAM lparam
)
1331 if (code
== HC_ACTION
)
1333 /* MSLLHOOKSTRUCT does not seem to be reliable and contains different data on each run. */
1335 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1337 return CallNextHookEx( 0, code
, wparam
, lparam
);
1340 static void test_mouse_ll_hook(void)
1347 GetCursorPos(&pt_org
);
1348 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1349 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
1350 SetCursorPos(100, 100);
1352 if (!(hook2
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc2
, GetModuleHandleA(0), 0)))
1354 win_skip( "cannot set MOUSE_LL hook\n" );
1357 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc1
, GetModuleHandleA(0), 0);
1359 GetCursorPos(&pt_old
);
1360 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, 0, 0, 0);
1361 GetCursorPos(&pt_old
);
1362 ok(pt_old
.x
== pt_new
.x
&& pt_old
.y
== pt_new
.y
, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1363 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, 0, 0, 0);
1364 GetCursorPos(&pt_old
);
1365 ok(pt_old
.x
== pt_new
.x
&& pt_old
.y
== pt_new
.y
, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1366 mouse_event(MOUSEEVENTF_MOVE
, 0, -STEP
, 0, 0);
1367 GetCursorPos(&pt_old
);
1368 ok(pt_old
.x
== pt_new
.x
&& pt_old
.y
== pt_new
.y
, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1369 mouse_event(MOUSEEVENTF_MOVE
, 0, +STEP
, 0, 0);
1370 GetCursorPos(&pt_old
);
1371 ok(pt_old
.x
== pt_new
.x
&& pt_old
.y
== pt_new
.y
, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1373 SetRect(&rc
, 50, 50, 151, 151);
1377 SetCursorPos(40, 40);
1378 GetCursorPos(&pt_old
);
1379 ok(pt_old
.x
== 50 && pt_old
.y
== 50, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1380 SetCursorPos(160, 160);
1381 GetCursorPos(&pt_old
);
1382 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1383 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1384 GetCursorPos(&pt_old
);
1385 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1388 pt_new
.x
= pt_new
.y
= 150;
1390 UnhookWindowsHookEx(hook1
);
1392 /* Now check that mouse buttons do not change mouse position
1393 if we don't have MOUSEEVENTF_MOVE flag specified. */
1395 /* We reusing the same hook callback, so make it happy */
1396 pt_old
.x
= pt_new
.x
- STEP
;
1397 pt_old
.y
= pt_new
.y
- STEP
;
1398 mouse_event(MOUSEEVENTF_LEFTUP
, 123, 456, 0, 0);
1400 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1401 mouse_event(MOUSEEVENTF_RIGHTUP
, 456, 123, 0, 0);
1403 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1405 mouse_event(MOUSEEVENTF_LEFTUP
| MOUSEEVENTF_ABSOLUTE
, 123, 456, 0, 0);
1407 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1408 mouse_event(MOUSEEVENTF_RIGHTUP
| MOUSEEVENTF_ABSOLUTE
, 456, 123, 0, 0);
1410 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1412 UnhookWindowsHookEx(hook2
);
1413 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc3
, GetModuleHandleA(0), 0);
1415 SetRect(&rc
, 150, 150, 150, 150);
1419 SetCursorPos(140, 140);
1420 GetCursorPos(&pt_old
);
1421 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1422 SetCursorPos(160, 160);
1423 GetCursorPos(&pt_old
);
1425 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1426 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, -STEP
, 0, 0);
1427 GetCursorPos(&pt_old
);
1428 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1429 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1430 GetCursorPos(&pt_old
);
1432 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1433 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1434 GetCursorPos(&pt_old
);
1435 ok((pt_old
.x
== 150 && pt_old
.y
== 150) ||
1436 broken(pt_old
.x
== 149 && pt_old
.y
== 149) /* w1064v1809 */,
1437 "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1438 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1439 GetCursorPos(&pt_old
);
1441 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1446 SetCursorPos(140, 140);
1447 SetRect(&rc
, 150, 150, 150, 150);
1449 GetCursorPos(&pt_old
);
1450 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1453 SetCursorPos(160, 160);
1454 SetRect(&rc
, 150, 150, 150, 150);
1456 GetCursorPos(&pt_old
);
1458 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1461 SetCursorPos(150, 150);
1462 SetRect(&rc
, 150, 150, 150, 150);
1464 GetCursorPos(&pt_old
);
1466 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1469 UnhookWindowsHookEx(hook1
);
1472 DestroyWindow(hwnd
);
1473 SetCursorPos(pt_org
.x
, pt_org
.y
);
1476 static void test_GetMouseMovePointsEx(const char *argv0
)
1479 #define MYERROR 0xdeadbeef
1480 PROCESS_INFORMATION process_info
;
1481 STARTUPINFOA startup_info
;
1482 char path
[MAX_PATH
];
1483 int i
, count
, retval
;
1485 MOUSEMOVEPOINT out
[200];
1489 /* Get a valid content for the input struct */
1490 if(!GetCursorPos(&point
)) {
1491 win_skip("GetCursorPos() failed with error %u\n", GetLastError());
1494 memset(&in
, 0, sizeof(MOUSEMOVEPOINT
));
1498 /* test first parameter
1499 * everything different than sizeof(MOUSEMOVEPOINT)
1500 * is expected to fail with ERROR_INVALID_PARAMETER
1502 SetLastError(MYERROR
);
1503 retval
= pGetMouseMovePointsEx(0, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1504 if (retval
== ERROR_INVALID_PARAMETER
)
1506 win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1509 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1510 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1511 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1513 SetLastError(MYERROR
);
1514 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1515 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1516 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1517 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1519 SetLastError(MYERROR
);
1520 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)+1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1521 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1522 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1523 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1525 /* test second and third parameter
1527 SetLastError(MYERROR
);
1528 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1529 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1530 ok(GetLastError() == ERROR_NOACCESS
|| GetLastError() == MYERROR
,
1531 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1533 SetLastError(MYERROR
);
1534 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1535 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1536 ok(ERROR_NOACCESS
== GetLastError(),
1537 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1539 SetLastError(MYERROR
);
1540 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1541 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1542 ok(ERROR_NOACCESS
== GetLastError(),
1543 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1545 SetLastError(MYERROR
);
1547 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, count
, GMMP_USE_DISPLAY_POINTS
);
1549 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1551 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1553 /* test fourth parameter
1554 * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1556 SetLastError(MYERROR
);
1558 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1559 ok(retval
== count
, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1560 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1561 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1563 SetLastError(MYERROR
);
1565 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1567 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1569 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1571 SetLastError(MYERROR
);
1573 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1575 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1577 ok((0 <= retval
) && (retval
<= count
), "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1579 SetLastError(MYERROR
);
1580 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
+1, 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 %u\n", GetLastError());
1585 /* it was not possible to force an error with the fifth parameter on win2k */
1587 /* test combinations of wrong parameters to see which error wins */
1588 SetLastError(MYERROR
);
1589 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1590 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1591 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1592 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1594 SetLastError(MYERROR
);
1595 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1596 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1597 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1598 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1600 SetLastError(MYERROR
);
1601 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1602 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1603 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1604 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1606 SetLastError(MYERROR
);
1607 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1608 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1609 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1610 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1612 /* more than 64 to be sure we wrap around */
1613 for (i
= 0; i
< 67; i
++)
1617 SetCursorPos( in
.x
, in
.y
);
1620 SetLastError( MYERROR
);
1621 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1622 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1623 ok( GetLastError() == MYERROR
, "expected error to stay %x, got %x\n", MYERROR
, GetLastError() );
1625 for (i
= 0; i
< retval
; i
++)
1627 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
);
1634 SetLastError( MYERROR
);
1635 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1636 ok( retval
== -1, "expected to get -1 but got %d\n", retval
);
1637 ok( GetLastError() == ERROR_POINT_NOT_FOUND
, "expected error to be set to %x, got %x\n", ERROR_POINT_NOT_FOUND
, GetLastError() );
1639 /* make sure there's no deduplication */
1642 SetCursorPos( in
.x
, in
.y
);
1643 SetCursorPos( in
.x
, in
.y
);
1644 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1645 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1646 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
);
1647 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
);
1649 /* make sure 2 events are distinguishable by their timestamps */
1652 SetCursorPos( 30, 30 );
1653 SetCursorPos( in
.x
, in
.y
);
1654 SetCursorPos( 150, 150 );
1656 SetCursorPos( in
.x
, in
.y
);
1658 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1659 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1660 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
);
1661 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
);
1662 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
);
1664 in
.time
= out
[2].time
;
1665 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1666 ok( retval
== 62, "expected to get 62 mouse move points but got %d\n", retval
);
1667 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
);
1668 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
);
1670 /* events created through other means should also be on the list with correct extra info */
1671 mouse_event( MOUSEEVENTF_MOVE
, -13, 17, 0, 0xcafecafe );
1672 ok( GetCursorPos( &point
), "failed to get cursor position\n" );
1673 ok( in
.x
!= point
.x
&& in
.y
!= point
.y
, "cursor didn't change position after mouse_event()\n" );
1677 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1678 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1679 ok( out
[0].dwExtraInfo
== 0xcafecafe, "wrong extra info, got 0x%lx expected 0xcafecafe\n", out
[0].dwExtraInfo
);
1681 input
.type
= INPUT_MOUSE
;
1682 memset( &input
, 0, sizeof(input
) );
1683 input
.u
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1684 input
.u
.mi
.dwExtraInfo
= 0xdeadbeef;
1685 input
.u
.mi
.dx
= -17;
1687 SendInput( 1, (INPUT
*)&input
, sizeof(INPUT
) );
1688 ok( GetCursorPos( &point
), "failed to get cursor position\n" );
1689 ok( in
.x
!= point
.x
&& in
.y
!= point
.y
, "cursor didn't change position after mouse_event()\n" );
1693 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1694 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1695 ok( out
[0].dwExtraInfo
== 0xdeadbeef, "wrong extra info, got 0x%lx expected 0xdeadbeef\n", out
[0].dwExtraInfo
);
1697 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
, GMMP_USE_HIGH_RESOLUTION_POINTS
);
1698 todo_wine
ok( retval
== 64, "expected to get 64 high resolution mouse move points but got %d\n", retval
);
1700 sprintf(path
, "%s input get_mouse_move_points_test", argv0
);
1701 memset(&startup_info
, 0, sizeof(startup_info
));
1702 startup_info
.cb
= sizeof(startup_info
);
1703 startup_info
.dwFlags
= STARTF_USESHOWWINDOW
;
1704 startup_info
.wShowWindow
= SW_SHOWNORMAL
;
1705 retval
= CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup_info
, &process_info
);
1706 ok(retval
, "CreateProcess \"%s\" failed err %u.\n", path
, GetLastError());
1707 winetest_wait_child_process(process_info
.hProcess
);
1708 CloseHandle(process_info
.hProcess
);
1709 CloseHandle(process_info
.hThread
);
1714 static void test_GetMouseMovePointsEx_process(void)
1718 MOUSEMOVEPOINT out
[64], out2
[64];
1721 HWINSTA winstation0
, winstation1
;
1723 memset( out
, 0, sizeof(out
) );
1724 memset( out2
, 0, sizeof(out2
) );
1726 /* move point history is shared between desktops within the same windowstation */
1727 ok( GetCursorPos( &point
), "failed to get cursor position\n" );
1731 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, ARRAY_SIZE(out
), GMMP_USE_DISPLAY_POINTS
);
1732 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1734 desk0
= OpenInputDesktop( 0, FALSE
, DESKTOP_ALL_ACCESS
);
1735 ok( desk0
!= NULL
, "OpenInputDesktop has failed with %d\n", GetLastError() );
1736 desk1
= CreateDesktopA( "getmousemovepointsex_test_desktop", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
1737 ok( desk1
!= NULL
, "CreateDesktopA failed with %d\n", GetLastError() );
1739 ok( SetThreadDesktop( desk1
), "SetThreadDesktop failed!\n" );
1740 ok( SwitchDesktop( desk1
), "SwitchDesktop failed\n" );
1742 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out2
, ARRAY_SIZE(out2
), GMMP_USE_DISPLAY_POINTS
);
1743 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 new desktop\n" );
1750 SetCursorPos( in
.x
, in
.y
);
1752 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out2
, ARRAY_SIZE(out2
), GMMP_USE_DISPLAY_POINTS
);
1753 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1755 ok( SetThreadDesktop( desk0
), "SetThreadDesktop failed!\n" );
1756 ok( SwitchDesktop( desk0
), "SwitchDesktop failed\n" );
1758 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, ARRAY_SIZE(out
), GMMP_USE_DISPLAY_POINTS
);
1759 ok( retval
== 64, "expected to get 64 mouse move points but got %d\n", retval
);
1760 ok( memcmp( out
, out2
, sizeof( out2
) ) == 0, "expected to get exact same history on the old desktop\n" );
1762 CloseDesktop( desk1
);
1763 CloseDesktop( desk0
);
1765 /* non-default windowstations are non-interactive */
1766 winstation0
= GetProcessWindowStation();
1767 ok( winstation0
!= NULL
, "GetProcessWindowStation has failed with %d\n", GetLastError() );
1768 desk0
= OpenInputDesktop( 0, FALSE
, DESKTOP_ALL_ACCESS
);
1769 ok( desk0
!= NULL
, "OpenInputDesktop has failed with %d\n", GetLastError() );
1770 winstation1
= CreateWindowStationA( "test_winstation", 0, WINSTA_ALL_ACCESS
, NULL
);
1772 if (winstation1
== NULL
&& GetLastError() == ERROR_ACCESS_DENIED
)
1774 win_skip("not enough privileges for CreateWindowStation\n");
1775 CloseDesktop( desk0
);
1776 CloseWindowStation( winstation0
);
1780 ok( winstation1
!= NULL
, "CreateWindowStationA has failed with %d\n", GetLastError() );
1781 ok( SetProcessWindowStation( winstation1
), "SetProcessWindowStation has failed\n" );
1783 desk1
= CreateDesktopA( "getmousemovepointsex_test_desktop", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
1784 ok( desk1
!= NULL
, "CreateDesktopA failed with %d\n", GetLastError() );
1785 ok( SetThreadDesktop( desk1
), "SetThreadDesktop failed!\n" );
1787 SetLastError( 0xDEADBEEF );
1788 retval
= pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT
), &in
, out
, ARRAY_SIZE(out
), GMMP_USE_DISPLAY_POINTS
);
1789 todo_wine
ok( retval
== -1, "expected to get -1 mouse move points but got %d\n", retval
);
1790 todo_wine
ok( GetLastError() == ERROR_ACCESS_DENIED
, "expected ERROR_ACCESS_DENIED got %d\n", GetLastError() );
1792 ok( SetProcessWindowStation( winstation0
), "SetProcessWindowStation has failed\n" );
1793 ok( SetThreadDesktop( desk0
), "SetThreadDesktop failed!\n" );
1794 CloseDesktop( desk1
);
1795 CloseWindowStation( winstation1
);
1796 CloseDesktop( desk0
);
1797 CloseWindowStation( winstation0
);
1800 static void test_GetRawInputDeviceList(void)
1802 RAWINPUTDEVICELIST devices
[32];
1803 UINT ret
, oret
, devcount
, odevcount
, i
;
1807 SetLastError(0xdeadbeef);
1808 ret
= pGetRawInputDeviceList(NULL
, NULL
, 0);
1809 err
= GetLastError();
1810 ok(ret
== -1, "expected -1, got %d\n", ret
);
1811 ok(err
== ERROR_INVALID_PARAMETER
, "expected 87, got %d\n", err
);
1813 SetLastError(0xdeadbeef);
1814 ret
= pGetRawInputDeviceList(NULL
, NULL
, sizeof(devices
[0]));
1815 err
= GetLastError();
1816 ok(ret
== -1, "expected -1, got %d\n", ret
);
1817 ok(err
== ERROR_NOACCESS
, "expected 998, got %d\n", err
);
1820 ret
= pGetRawInputDeviceList(NULL
, &devcount
, sizeof(devices
[0]));
1821 ok(ret
== 0, "expected 0, got %d\n", ret
);
1822 ok(devcount
> 0, "expected non-zero\n");
1824 SetLastError(0xdeadbeef);
1826 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1827 err
= GetLastError();
1828 ok(ret
== -1, "expected -1, got %d\n", ret
);
1829 ok(err
== ERROR_INSUFFICIENT_BUFFER
, "expected 122, got %d\n", err
);
1830 ok(devcount
> 0, "expected non-zero\n");
1832 /* devcount contains now the correct number of devices */
1833 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1834 ok(ret
> 0, "expected non-zero\n");
1836 for(i
= 0; i
< devcount
; ++i
)
1841 RID_DEVICE_INFO info
;
1845 /* get required buffer size */
1848 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICENAME
, name
, &sz
);
1849 ok(ret
== -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err
);
1850 ok(sz
> 5 && sz
< ARRAY_SIZE(name
), "Size should have been set and not too large (got: %u)\n", sz
);
1852 /* buffer size for RIDI_DEVICENAME is in CHARs, not BYTEs */
1853 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICENAME
, name
, &sz
);
1854 ok(ret
== sz
, "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1855 len
= lstrlenW(name
);
1856 ok(len
+ 1 == ret
, "GetRawInputDeviceInfo returned wrong length (name: %u, ret: %u)\n", len
+ 1, ret
);
1858 /* test A variant with same size */
1859 ret
= pGetRawInputDeviceInfoA(devices
[i
].hDevice
, RIDI_DEVICENAME
, nameA
, &sz
);
1860 ok(ret
== sz
, "GetRawInputDeviceInfoA gave wrong return: %d\n", err
);
1861 len
= strlen(nameA
);
1862 ok(len
+ 1 == ret
, "GetRawInputDeviceInfoA returned wrong length (name: %u, ret: %u)\n", len
+ 1, ret
);
1864 /* buffer size for RIDI_DEVICEINFO is in BYTEs */
1865 memset(&info
, 0, sizeof(info
));
1866 info
.cbSize
= sizeof(info
);
1867 sz
= sizeof(info
) - 1;
1868 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1869 ok(ret
== -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err
);
1870 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1872 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1873 ok(ret
== sizeof(info
), "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1874 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1875 ok(info
.dwType
== devices
[i
].dwType
, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info
.dwType
);
1877 memset(&info
, 0, sizeof(info
));
1878 info
.cbSize
= sizeof(info
);
1879 ret
= pGetRawInputDeviceInfoA(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1880 ok(ret
== sizeof(info
), "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1881 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1882 ok(info
.dwType
== devices
[i
].dwType
, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info
.dwType
);
1884 /* setupapi returns an NT device path, but CreateFile() < Vista can't
1885 * understand that; so use the \\?\ prefix instead */
1887 file
= CreateFileW(name
, 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
1888 todo_wine_if(i
== 0 || i
== 1)
1889 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to open %s, error %u\n", wine_dbgstr_w(name
), GetLastError());
1892 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_PREPARSEDDATA
, NULL
, &sz
);
1893 ok(ret
== 0, "GetRawInputDeviceInfo gave wrong return: %u\n", ret
);
1894 ok((info
.dwType
== RIM_TYPEHID
&& sz
!= 0) ||
1895 (info
.dwType
!= RIM_TYPEHID
&& sz
== 0),
1896 "Got wrong PPD size for type 0x%x: %u\n", info
.dwType
, sz
);
1898 ppd
= HeapAlloc(GetProcessHeap(), 0, sz
);
1899 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_PREPARSEDDATA
, ppd
, &sz
);
1900 ok(ret
== sz
, "GetRawInputDeviceInfo gave wrong return: %u, should be %u\n", ret
, sz
);
1902 if (file
!= INVALID_HANDLE_VALUE
&& ret
== sz
)
1904 PHIDP_PREPARSED_DATA preparsed
;
1906 if (info
.dwType
== RIM_TYPEHID
)
1908 br
= HidD_GetPreparsedData(file
, &preparsed
);
1909 ok(br
== TRUE
, "HidD_GetPreparsedData failed\n");
1912 ok(!memcmp(preparsed
, ppd
, sz
), "Expected to get same preparsed data\n");
1916 /* succeeds on hardware, fails in some VMs */
1917 br
= HidD_GetPreparsedData(file
, &preparsed
);
1918 ok(br
== TRUE
|| broken(br
== FALSE
), "HidD_GetPreparsedData failed\n");
1922 HidD_FreePreparsedData(preparsed
);
1925 HeapFree(GetProcessHeap(), 0, ppd
);
1930 /* check if variable changes from larger to smaller value */
1931 devcount
= odevcount
= ARRAY_SIZE(devices
);
1932 oret
= ret
= pGetRawInputDeviceList(devices
, &odevcount
, sizeof(devices
[0]));
1933 ok(ret
> 0, "expected non-zero\n");
1934 ok(devcount
== odevcount
, "expected %d, got %d\n", devcount
, odevcount
);
1935 devcount
= odevcount
;
1936 odevcount
= ARRAY_SIZE(devices
);
1937 ret
= pGetRawInputDeviceList(NULL
, &odevcount
, sizeof(devices
[0]));
1938 ok(ret
== 0, "expected 0, got %d\n", ret
);
1939 ok(odevcount
== oret
, "expected %d, got %d\n", oret
, odevcount
);
1942 static void test_GetRawInputData(void)
1947 /* Null raw input handle */
1948 SetLastError(0xdeadbeef);
1949 ret
= GetRawInputData(NULL
, RID_INPUT
, NULL
, &size
, sizeof(RAWINPUTHEADER
));
1950 ok(ret
== ~0U, "Expect ret %u, got %u\n", ~0U, ret
);
1951 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetRawInputData returned %08x\n", GetLastError());
1954 static void test_RegisterRawInputDevices(void)
1957 RAWINPUTDEVICE raw_devices
[2];
1958 UINT count
, raw_devices_count
;
1961 memset(raw_devices
, 0, sizeof(raw_devices
));
1962 raw_devices
[0].usUsagePage
= 0x01;
1963 raw_devices
[0].usUsage
= 0x05;
1964 raw_devices
[1].usUsagePage
= 0x01;
1965 raw_devices
[1].usUsage
= 0x04;
1967 hwnd
= CreateWindowExA(WS_EX_TOPMOST
, "static", "dinput", WS_POPUP
| WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, NULL
, NULL
);
1968 ok(hwnd
!= NULL
, "CreateWindowExA failed\n");
1971 res
= RegisterRawInputDevices(NULL
, 0, 0);
1972 ok(res
== FALSE
, "RegisterRawInputDevices succeeded\n");
1975 SetLastError(0xdeadbeef);
1976 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), 0);
1977 ok(res
== FALSE
, "RegisterRawInputDevices succeeded\n");
1978 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "RegisterRawInputDevices returned %08x\n", GetLastError());
1980 SetLastError(0xdeadbeef);
1981 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
1982 ok(res
== TRUE
, "RegisterRawInputDevices failed\n");
1983 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
1985 SetLastError(0xdeadbeef);
1986 count
= GetRegisteredRawInputDevices(NULL
, NULL
, 0);
1987 ok(count
== ~0U, "GetRegisteredRawInputDevices returned %u\n", count
);
1988 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
1990 SetLastError(0xdeadbeef);
1991 raw_devices_count
= 0;
1992 count
= GetRegisteredRawInputDevices(NULL
, &raw_devices_count
, 0);
1993 ok(count
== ~0U, "GetRegisteredRawInputDevices returned %u\n", count
);
1994 ok(raw_devices_count
== 0, "Unexpected registered devices count: %u\n", raw_devices_count
);
1995 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
1997 SetLastError(0xdeadbeef);
1998 raw_devices_count
= 0;
1999 count
= GetRegisteredRawInputDevices(NULL
, &raw_devices_count
, sizeof(RAWINPUTDEVICE
));
2000 ok(count
== 0, "GetRegisteredRawInputDevices returned %u\n", count
);
2001 ok(raw_devices_count
== 2, "Unexpected registered devices count: %u\n", raw_devices_count
);
2002 ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
2004 SetLastError(0xdeadbeef);
2005 raw_devices_count
= 0;
2006 count
= GetRegisteredRawInputDevices(raw_devices
, &raw_devices_count
, sizeof(RAWINPUTDEVICE
));
2007 if (broken(count
== 0) /* depends on windows versions */)
2008 win_skip("Ignoring GetRegisteredRawInputDevices success\n");
2011 ok(count
== ~0U, "GetRegisteredRawInputDevices returned %u\n", count
);
2012 ok(raw_devices_count
== 0, "Unexpected registered devices count: %u\n", raw_devices_count
);
2013 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
2016 SetLastError(0xdeadbeef);
2017 raw_devices_count
= 1;
2018 count
= GetRegisteredRawInputDevices(raw_devices
, &raw_devices_count
, sizeof(RAWINPUTDEVICE
));
2019 ok(count
== ~0U, "GetRegisteredRawInputDevices returned %u\n", count
);
2020 ok(raw_devices_count
== 2, "Unexpected registered devices count: %u\n", raw_devices_count
);
2021 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
2023 SetLastError(0xdeadbeef);
2024 memset(raw_devices
, 0, sizeof(raw_devices
));
2025 raw_devices_count
= ARRAY_SIZE(raw_devices
);
2026 count
= GetRegisteredRawInputDevices(raw_devices
, &raw_devices_count
, sizeof(RAWINPUTDEVICE
));
2027 ok(count
== 2, "GetRegisteredRawInputDevices returned %u\n", count
);
2028 ok(raw_devices_count
== 2, "Unexpected registered devices count: %u\n", raw_devices_count
);
2029 ok(GetLastError() == 0xdeadbeef, "GetRegisteredRawInputDevices unexpected error %08x\n", GetLastError());
2030 ok(raw_devices
[0].usUsagePage
== 0x01, "Unexpected usage page: %x\n", raw_devices
[0].usUsagePage
);
2031 ok(raw_devices
[0].usUsage
== 0x04, "Unexpected usage: %x\n", raw_devices
[0].usUsage
);
2032 ok(raw_devices
[1].usUsagePage
== 0x01, "Unexpected usage page: %x\n", raw_devices
[1].usUsagePage
);
2033 ok(raw_devices
[1].usUsage
== 0x05, "Unexpected usage: %x\n", raw_devices
[1].usUsage
);
2035 /* RIDEV_REMOVE requires hwndTarget == NULL */
2036 raw_devices
[0].dwFlags
= RIDEV_REMOVE
;
2037 raw_devices
[0].hwndTarget
= hwnd
;
2038 raw_devices
[1].dwFlags
= RIDEV_REMOVE
;
2039 raw_devices
[1].hwndTarget
= hwnd
;
2041 SetLastError(0xdeadbeef);
2042 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2043 ok(res
== FALSE
, "RegisterRawInputDevices succeeded\n");
2044 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "RegisterRawInputDevices returned %08x\n", GetLastError());
2046 raw_devices
[0].hwndTarget
= 0;
2047 raw_devices
[1].hwndTarget
= 0;
2049 SetLastError(0xdeadbeef);
2050 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2051 ok(res
== TRUE
, "RegisterRawInputDevices failed\n");
2052 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
2055 /* RIDEV_INPUTSINK requires hwndTarget != NULL */
2056 raw_devices
[0].dwFlags
= RIDEV_INPUTSINK
;
2057 raw_devices
[0].hwndTarget
= 0;
2058 raw_devices
[1].dwFlags
= RIDEV_INPUTSINK
;
2059 raw_devices
[1].hwndTarget
= 0;
2061 SetLastError(0xdeadbeef);
2062 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2063 ok(res
== FALSE
, "RegisterRawInputDevices failed\n");
2064 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "RegisterRawInputDevices returned %08x\n", GetLastError());
2066 raw_devices
[0].hwndTarget
= hwnd
;
2067 raw_devices
[1].hwndTarget
= hwnd
;
2069 SetLastError(0xdeadbeef);
2070 res
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2071 ok(res
== TRUE
, "RegisterRawInputDevices succeeded\n");
2072 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
2074 DestroyWindow(hwnd
);
2077 static int rawinputbuffer_wndproc_count
;
2080 typedef RAWINPUT RAWINPUT64
;
2084 RAWINPUTHEADER header
;
2088 RAWKEYBOARD keyboard
;
2094 static int rawinput_buffer_mouse_x(void *buffer
, size_t index
)
2096 if (is_wow64
) return ((RAWINPUT64
*)buffer
)[index
].data
.mouse
.lLastX
;
2097 return ((RAWINPUT
*)buffer
)[index
].data
.mouse
.lLastX
;
2100 static LRESULT CALLBACK
rawinputbuffer_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
2103 char buffer
[16 * sizeof(RAWINPUT64
)];
2104 UINT size
, count
, rawinput_size
, iteration
= rawinputbuffer_wndproc_count
++;
2107 if (is_wow64
) rawinput_size
= sizeof(RAWINPUT64
);
2108 else rawinput_size
= sizeof(RAWINPUT
);
2110 if (msg
== WM_INPUT
)
2112 count
= GetRawInputBuffer(NULL
, NULL
, sizeof(RAWINPUTHEADER
));
2113 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2115 size
= sizeof(buffer
);
2116 count
= GetRawInputBuffer(NULL
, &size
, sizeof(RAWINPUTHEADER
));
2117 ok(count
== 0, "GetRawInputBuffer returned %u\n", count
);
2118 ok(size
== rawinput_size
, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2120 size
= sizeof(buffer
);
2121 memset(buffer
, 0, sizeof(buffer
));
2122 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2123 ok(count
== 3, "GetRawInputBuffer returned %u\n", count
);
2124 ok(size
== sizeof(buffer
), "GetRawInputBuffer returned unexpected size: %u\n", size
);
2125 ok(rawinput_buffer_mouse_x(buffer
, 0) == 2, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 0));
2126 ok(rawinput_buffer_mouse_x(buffer
, 1) == 3, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 1));
2127 ok(rawinput_buffer_mouse_x(buffer
, 2) == 4, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 2));
2129 /* the first event should be removed by the next GetRawInputBuffer call
2130 * and the others should do another round through the message loop but not more */
2133 mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2134 mouse_event(MOUSEEVENTF_MOVE
, 6, 0, 0, 0);
2135 mouse_event(MOUSEEVENTF_MOVE
, 2, 0, 0, 0);
2136 mouse_event(MOUSEEVENTF_MOVE
, 3, 0, 0, 0);
2137 mouse_event(MOUSEEVENTF_MOVE
, 4, 0, 0, 0);
2139 /* even though rawinput_size is the minimum required size,
2140 * it needs one more byte to return success */
2141 size
= rawinput_size
+ 1;
2142 memset(buffer
, 0, sizeof(buffer
));
2143 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2144 ok(count
== 1, "GetRawInputBuffer returned %u\n", count
);
2145 ok(rawinput_buffer_mouse_x(buffer
, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 0));
2147 /* peek the messages now, they should still arrive in the correct order */
2148 while (PeekMessageA(&message
, 0, WM_INPUT
, WM_INPUT
, PM_REMOVE
)) DispatchMessageA(&message
);
2151 /* reading the message data now should fail on the second iteration, the data
2152 * from the first message has been overwritten. */
2154 memset(&ri
, 0, sizeof(ri
));
2155 SetLastError(0xdeadbeef);
2156 count
= GetRawInputData((HRAWINPUT
)lparam
, RID_HEADER
, &ri
, &size
, sizeof(RAWINPUTHEADER
));
2159 SetLastError(0xdeadbeef);
2160 count
= GetRawInputData((HRAWINPUT
)lparam
, RID_INPUT
, &ri
, &size
, 0);
2161 ok(count
== ~0U, "GetRawInputData succeeded\n");
2162 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRawInputData returned %08x\n", GetLastError());
2164 SetLastError(0xdeadbeef);
2166 count
= GetRawInputData((HRAWINPUT
)lparam
, RID_INPUT
, &ri
, &size
, sizeof(RAWINPUTHEADER
));
2167 ok(count
== ~0U, "GetRawInputData succeeded\n");
2168 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "GetRawInputData returned %08x\n", GetLastError());
2170 SetLastError(0xdeadbeef);
2172 count
= GetRawInputData((HRAWINPUT
)lparam
, 0, &ri
, &size
, sizeof(RAWINPUTHEADER
));
2173 ok(count
== ~0U, "GetRawInputData succeeded\n");
2174 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRawInputData returned %08x\n", GetLastError());
2176 SetLastError(0xdeadbeef);
2178 count
= GetRawInputData((HRAWINPUT
)lparam
, RID_INPUT
, &ri
, &size
, sizeof(RAWINPUTHEADER
));
2179 ok(count
== sizeof(ri
), "GetRawInputData failed\n");
2180 ok(ri
.data
.mouse
.lLastX
== 6, "Unexpected rawinput data: %d\n", ri
.data
.mouse
.lLastX
);
2181 ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08x\n", GetLastError());
2185 ok(count
== ~0U, "GetRawInputData succeeded\n");
2186 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetRawInputData returned %08x\n", GetLastError());
2192 return DefWindowProcA(hwnd
, msg
, wparam
, lparam
);
2195 static void test_GetRawInputBuffer(void)
2197 RAWINPUTDEVICE raw_devices
[1];
2198 char buffer
[16 * sizeof(RAWINPUT64
)];
2199 UINT size
, count
, rawinput_size
;
2203 if (is_wow64
) rawinput_size
= sizeof(RAWINPUT64
);
2204 else rawinput_size
= sizeof(RAWINPUT
);
2206 hwnd
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2207 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2208 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)rawinputbuffer_wndproc
);
2209 ok(hwnd
!= 0, "CreateWindow failed\n");
2210 empty_message_queue();
2212 raw_devices
[0].usUsagePage
= 0x01;
2213 raw_devices
[0].usUsage
= 0x02;
2214 raw_devices
[0].dwFlags
= RIDEV_INPUTSINK
;
2215 raw_devices
[0].hwndTarget
= hwnd
;
2217 SetLastError(0xdeadbeef);
2218 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2219 ok(ret
, "RegisterRawInputDevices failed\n");
2220 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
2222 SetLastError(0xdeadbeef);
2223 count
= GetRawInputBuffer(NULL
, NULL
, sizeof(RAWINPUTHEADER
));
2224 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2225 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRawInputBuffer returned %08x\n", GetLastError());
2227 size
= sizeof(buffer
);
2228 count
= GetRawInputBuffer(NULL
, &size
, sizeof(RAWINPUTHEADER
));
2229 ok(count
== 0U, "GetRawInputBuffer returned %u\n", count
);
2230 ok(size
== 0U, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2233 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2234 ok(count
== 0U, "GetRawInputBuffer returned %u\n", count
);
2235 ok(size
== 0U, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2237 SetLastError(0xdeadbeef);
2238 size
= sizeof(buffer
);
2239 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, 0);
2240 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2241 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRawInputBuffer returned %08x\n", GetLastError());
2243 size
= sizeof(buffer
);
2244 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2245 ok(count
== 0U, "GetRawInputBuffer returned %u\n", count
);
2246 ok(size
== 0U, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2248 mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2250 SetLastError(0xdeadbeef);
2252 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2253 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2254 ok(size
== rawinput_size
, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2255 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "GetRawInputBuffer returned %08x\n", GetLastError());
2258 count
= GetRawInputBuffer(NULL
, &size
, sizeof(RAWINPUTHEADER
));
2259 ok(count
== 0, "GetRawInputBuffer returned %u\n", count
);
2260 ok(size
== rawinput_size
, "GetRawInputBuffer returned unexpected size: %u\n", size
);
2262 SetLastError(0xdeadbeef);
2263 size
= sizeof(buffer
);
2264 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, 0);
2265 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2266 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "GetRawInputBuffer returned %08x\n", GetLastError());
2268 size
= sizeof(buffer
);
2269 memset(buffer
, 0, sizeof(buffer
));
2270 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2271 ok(count
== 1U, "GetRawInputBuffer returned %u\n", count
);
2272 ok(size
== sizeof(buffer
), "GetRawInputBuffer returned unexpected size: %u\n", size
);
2273 ok(rawinput_buffer_mouse_x(buffer
, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 0));
2276 /* NOTE: calling with size == rawinput_size returns an error, */
2277 /* BUT it fills the buffer nonetheless and empties the internal buffer (!!) */
2278 mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2280 SetLastError(0xdeadbeef);
2281 size
= rawinput_size
;
2282 memset(buffer
, 0, sizeof(buffer
));
2283 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2284 ok(count
== ~0U, "GetRawInputBuffer succeeded\n");
2285 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "GetRawInputBuffer returned %08x\n", GetLastError());
2286 ok(rawinput_buffer_mouse_x(buffer
, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer
, 0));
2288 size
= sizeof(buffer
);
2289 count
= GetRawInputBuffer((RAWINPUT
*)buffer
, &size
, sizeof(RAWINPUTHEADER
));
2290 ok(count
== 0U, "GetRawInputBuffer returned %u\n", count
);
2293 rawinputbuffer_wndproc_count
= 0;
2294 mouse_event(MOUSEEVENTF_MOVE
, 1, 0, 0, 0);
2295 mouse_event(MOUSEEVENTF_MOVE
, 2, 0, 0, 0);
2296 mouse_event(MOUSEEVENTF_MOVE
, 3, 0, 0, 0);
2297 mouse_event(MOUSEEVENTF_MOVE
, 4, 0, 0, 0);
2298 empty_message_queue();
2299 ok(rawinputbuffer_wndproc_count
== 2, "Spurious WM_INPUT messages\n");
2301 raw_devices
[0].dwFlags
= RIDEV_REMOVE
;
2302 raw_devices
[0].hwndTarget
= 0;
2304 SetLastError(0xdeadbeef);
2305 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2306 ok(ret
, "RegisterRawInputDevices failed\n");
2307 ok(GetLastError() == 0xdeadbeef, "RegisterRawInputDevices returned %08x\n", GetLastError());
2309 DestroyWindow(hwnd
);
2312 static BOOL rawinput_test_received_legacy
;
2313 static BOOL rawinput_test_received_raw
;
2314 static BOOL rawinput_test_received_rawfg
;
2316 static LRESULT CALLBACK
rawinput_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
2321 if (msg
== WM_INPUT
)
2323 todo_wine_if(rawinput_test_received_raw
)
2324 ok(!rawinput_test_received_raw
, "Unexpected spurious WM_INPUT message.\n");
2325 ok(wparam
== RIM_INPUT
|| wparam
== RIM_INPUTSINK
, "Unexpected wparam: %lu\n", wparam
);
2327 rawinput_test_received_raw
= TRUE
;
2328 if (wparam
== RIM_INPUT
) rawinput_test_received_rawfg
= TRUE
;
2330 ret
= GetRawInputData((HRAWINPUT
)lparam
, RID_INPUT
, NULL
, &raw_size
, sizeof(RAWINPUTHEADER
));
2331 ok(ret
== 0, "GetRawInputData failed\n");
2332 ok(raw_size
<= sizeof(raw
), "Unexpected rawinput data size: %u", raw_size
);
2334 raw_size
= sizeof(raw
);
2335 ret
= GetRawInputData((HRAWINPUT
)lparam
, RID_INPUT
, &raw
, &raw_size
, sizeof(RAWINPUTHEADER
));
2336 ok(ret
> 0 && ret
!= (UINT
)-1, "GetRawInputData failed\n");
2337 ok(raw
.header
.dwType
== RIM_TYPEMOUSE
, "Unexpected rawinput type: %u\n", raw
.header
.dwType
);
2339 ok(!(raw
.data
.mouse
.usFlags
& MOUSE_MOVE_ABSOLUTE
), "Unexpected absolute rawinput motion\n");
2340 ok(!(raw
.data
.mouse
.usFlags
& MOUSE_VIRTUAL_DESKTOP
), "Unexpected virtual desktop rawinput motion\n");
2343 if (msg
== WM_MOUSEMOVE
) rawinput_test_received_legacy
= TRUE
;
2345 return DefWindowProcA(hwnd
, msg
, wparam
, lparam
);
2348 struct rawinput_test
2350 BOOL register_device
;
2351 BOOL register_window
;
2352 DWORD register_flags
;
2361 struct rawinput_test rawinput_tests
[] =
2363 { FALSE
, FALSE
, 0, TRUE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2364 { TRUE
, FALSE
, 0, TRUE
, TRUE
, TRUE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2365 { TRUE
, TRUE
, 0, TRUE
, TRUE
, TRUE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2366 { TRUE
, TRUE
, RIDEV_NOLEGACY
, FALSE
, TRUE
, TRUE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2368 /* same-process foreground tests */
2369 { TRUE
, FALSE
, 0, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2370 { TRUE
, TRUE
, 0, FALSE
, TRUE
, TRUE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2372 /* cross-process foreground tests */
2373 { TRUE
, TRUE
, 0, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2374 { TRUE
, TRUE
, RIDEV_INPUTSINK
, FALSE
, TRUE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2375 { TRUE
, TRUE
, 0, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2377 /* multi-process rawinput tests */
2378 { TRUE
, TRUE
, 0, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2379 { TRUE
, TRUE
, RIDEV_INPUTSINK
, FALSE
, TRUE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2380 { TRUE
, TRUE
, RIDEV_INPUTSINK
, FALSE
, TRUE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2382 { TRUE
, TRUE
, RIDEV_EXINPUTSINK
, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2383 { TRUE
, TRUE
, RIDEV_EXINPUTSINK
, FALSE
, TRUE
, FALSE
, /* todos: */ FALSE
, TRUE
, FALSE
},
2385 /* cross-desktop foreground tests */
2386 { TRUE
, FALSE
, 0, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2387 { TRUE
, TRUE
, 0, FALSE
, TRUE
, TRUE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2388 { TRUE
, TRUE
, RIDEV_INPUTSINK
, FALSE
, FALSE
, FALSE
, /* todos: */ FALSE
, FALSE
, FALSE
},
2391 static void rawinput_test_process(void)
2393 RAWINPUTDEVICE raw_devices
[1];
2394 HANDLE ready
, start
, done
;
2401 ready
= OpenEventA(EVENT_ALL_ACCESS
, FALSE
, "rawinput_test_process_ready");
2402 ok(ready
!= 0, "OpenEventA failed, error: %u\n", GetLastError());
2404 start
= OpenEventA(EVENT_ALL_ACCESS
, FALSE
, "rawinput_test_process_start");
2405 ok(start
!= 0, "OpenEventA failed, error: %u\n", GetLastError());
2407 done
= OpenEventA(EVENT_ALL_ACCESS
, FALSE
, "rawinput_test_process_done");
2408 ok(done
!= 0, "OpenEventA failed, error: %u\n", GetLastError());
2410 for (i
= 0; i
< ARRAY_SIZE(rawinput_tests
); ++i
)
2412 WaitForSingleObject(ready
, INFINITE
);
2428 hwnd
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2429 pt
.x
- 50, pt
.y
- 50, 100, 100, 0, NULL
, NULL
, NULL
);
2430 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)rawinput_wndproc
);
2431 ok(hwnd
!= 0, "CreateWindow failed\n");
2432 empty_message_queue();
2434 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2435 * make the window visible and foreground as hard as possible. */
2436 ShowWindow(hwnd
, SW_SHOW
);
2437 SetWindowPos(hwnd
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2438 SetForegroundWindow(hwnd
);
2440 empty_message_queue();
2442 if (i
== 9 || i
== 10 || i
== 11 || i
== 12)
2444 raw_devices
[0].usUsagePage
= 0x01;
2445 raw_devices
[0].usUsage
= 0x02;
2446 raw_devices
[0].dwFlags
= i
== 11 ? RIDEV_INPUTSINK
: 0;
2447 raw_devices
[0].hwndTarget
= i
== 11 ? hwnd
: 0;
2449 SetLastError(0xdeadbeef);
2450 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2451 ok(ret
, "%d: RegisterRawInputDevices failed\n", i
);
2452 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i
, GetLastError());
2455 rawinput_test_received_legacy
= FALSE
;
2456 rawinput_test_received_raw
= FALSE
;
2457 rawinput_test_received_rawfg
= FALSE
;
2462 if (i
!= 8) mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2463 empty_message_queue();
2469 while (MsgWaitForMultipleObjects(1, &done
, FALSE
, INFINITE
, QS_ALLINPUT
) != WAIT_OBJECT_0
)
2470 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
2474 if (i
== 9 || i
== 10 || i
== 11 || i
== 12)
2476 raw_devices
[0].dwFlags
= RIDEV_REMOVE
;
2477 raw_devices
[0].hwndTarget
= 0;
2479 ok(rawinput_test_received_legacy
, "%d: foreground process expected WM_MOUSEMOVE message\n", i
);
2480 ok(rawinput_test_received_raw
, "%d: foreground process expected WM_INPUT message\n", i
);
2481 ok(rawinput_test_received_rawfg
, "%d: foreground process expected RIM_INPUT message\n", i
);
2483 SetLastError(0xdeadbeef);
2484 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2485 ok(ret
, "%d: RegisterRawInputDevices failed\n", i
);
2486 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i
, GetLastError());
2489 if (hwnd
) DestroyWindow(hwnd
);
2492 WaitForSingleObject(ready
, INFINITE
);
2498 struct rawinput_test_thread_params
2506 static DWORD WINAPI
rawinput_test_desk_thread(void *arg
)
2508 struct rawinput_test_thread_params
*params
= arg
;
2509 RAWINPUTDEVICE raw_devices
[1];
2516 ok( SetThreadDesktop( params
->desk
), "SetThreadDesktop failed\n" );
2518 for (i
= 14; i
< ARRAY_SIZE(rawinput_tests
); ++i
)
2520 WaitForSingleObject(params
->ready
, INFINITE
);
2521 ResetEvent(params
->ready
);
2530 hwnd
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2531 pt
.x
- 50, pt
.y
- 50, 100, 100, 0, NULL
, NULL
, NULL
);
2532 ok(hwnd
!= 0, "CreateWindow failed\n");
2533 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)rawinput_wndproc
);
2534 empty_message_queue();
2536 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2537 * make the window visible and foreground as hard as possible. */
2538 ShowWindow(hwnd
, SW_SHOW
);
2539 SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2540 SetForegroundWindow(hwnd
);
2542 empty_message_queue();
2544 raw_devices
[0].usUsagePage
= 0x01;
2545 raw_devices
[0].usUsage
= 0x02;
2546 raw_devices
[0].dwFlags
= rawinput_tests
[i
].register_flags
;
2547 raw_devices
[0].hwndTarget
= rawinput_tests
[i
].register_window
? hwnd
: 0;
2549 rawinput_test_received_legacy
= FALSE
;
2550 rawinput_test_received_raw
= FALSE
;
2551 rawinput_test_received_rawfg
= FALSE
;
2553 SetLastError(0xdeadbeef);
2554 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2555 ok(ret
, "%d: RegisterRawInputDevices failed\n", i
);
2556 ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i
, GetLastError());
2560 SetEvent(params
->start
);
2562 while (MsgWaitForMultipleObjects(1, ¶ms
->done
, FALSE
, INFINITE
, QS_ALLINPUT
) != WAIT_OBJECT_0
)
2563 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
2565 ResetEvent(params
->done
);
2566 if (hwnd
) DestroyWindow(hwnd
);
2572 static DWORD WINAPI
rawinput_test_thread(void *arg
)
2574 struct rawinput_test_thread_params
*params
= arg
;
2580 for (i
= 0; i
< 14; ++i
)
2582 WaitForSingleObject(params
->ready
, INFINITE
);
2583 ResetEvent(params
->ready
);
2591 hwnd
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2592 pt
.x
- 50, pt
.y
- 50, 100, 100, 0, NULL
, NULL
, NULL
);
2593 ok(hwnd
!= 0, "CreateWindow failed\n");
2594 empty_message_queue();
2596 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2597 * make the window visible and foreground as hard as possible. */
2598 ShowWindow(hwnd
, SW_SHOW
);
2599 SetWindowPos(hwnd
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2600 SetForegroundWindow(hwnd
);
2602 empty_message_queue();
2604 mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2605 empty_message_queue();
2609 SetEvent(params
->start
);
2611 WaitForSingleObject(params
->done
, INFINITE
);
2612 ResetEvent(params
->done
);
2613 if (hwnd
) DestroyWindow(hwnd
);
2616 thread
= CreateThread(NULL
, 0, rawinput_test_desk_thread
, params
, 0, NULL
);
2617 ok(thread
!= NULL
, "CreateThread failed\n");
2618 WaitForSingleObject(thread
, INFINITE
);
2619 CloseHandle(thread
);
2624 static void test_rawinput(const char* argv0
)
2626 struct rawinput_test_thread_params params
;
2627 PROCESS_INFORMATION process_info
;
2628 RAWINPUTDEVICE raw_devices
[1];
2629 STARTUPINFOA startup_info
;
2630 HANDLE thread
, process_ready
, process_start
, process_done
;
2635 char path
[MAX_PATH
];
2638 params
.desk
= CreateDesktopA( "rawinput_test_desktop", NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
2639 ok( params
.desk
!= NULL
, "CreateDesktopA failed, last error: %u\n", GetLastError() );
2641 params
.ready
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2642 ok(params
.ready
!= NULL
, "CreateEvent failed\n");
2644 params
.start
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2645 ok(params
.start
!= NULL
, "CreateEvent failed\n");
2647 params
.done
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2648 ok(params
.done
!= NULL
, "CreateEvent failed\n");
2650 thread
= CreateThread(NULL
, 0, rawinput_test_thread
, ¶ms
, 0, NULL
);
2651 ok(thread
!= NULL
, "CreateThread failed\n");
2653 process_ready
= CreateEventA(NULL
, FALSE
, FALSE
, "rawinput_test_process_ready");
2654 ok(process_ready
!= NULL
, "CreateEventA failed\n");
2656 process_start
= CreateEventA(NULL
, FALSE
, FALSE
, "rawinput_test_process_start");
2657 ok(process_start
!= NULL
, "CreateEventA failed\n");
2659 process_done
= CreateEventA(NULL
, FALSE
, FALSE
, "rawinput_test_process_done");
2660 ok(process_done
!= NULL
, "CreateEventA failed\n");
2662 memset(&startup_info
, 0, sizeof(startup_info
));
2663 startup_info
.cb
= sizeof(startup_info
);
2664 startup_info
.dwFlags
= STARTF_USESHOWWINDOW
;
2665 startup_info
.wShowWindow
= SW_SHOWNORMAL
;
2667 sprintf(path
, "%s input rawinput_test", argv0
);
2668 ret
= CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup_info
, &process_info
);
2669 ok(ret
, "CreateProcess \"%s\" failed err %u.\n", path
, GetLastError());
2671 SetCursorPos(100, 100);
2672 empty_message_queue();
2674 for (i
= 0; i
< ARRAY_SIZE(rawinput_tests
); ++i
)
2678 hwnd
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2679 pt
.x
- 50, pt
.y
- 50, 100, 100, 0, NULL
, NULL
, NULL
);
2680 ok(hwnd
!= 0, "CreateWindow failed\n");
2681 if (i
!= 14 && i
!= 15 && i
!= 16)
2682 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)rawinput_wndproc
);
2683 empty_message_queue();
2685 /* FIXME: Try to workaround X11/Win32 focus inconsistencies and
2686 * make the window visible and foreground as hard as possible. */
2687 ShowWindow(hwnd
, SW_SHOW
);
2688 SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2689 SetForegroundWindow(hwnd
);
2691 empty_message_queue();
2693 rawinput_test_received_legacy
= FALSE
;
2694 rawinput_test_received_raw
= FALSE
;
2695 rawinput_test_received_rawfg
= FALSE
;
2697 raw_devices
[0].usUsagePage
= 0x01;
2698 raw_devices
[0].usUsage
= 0x02;
2699 raw_devices
[0].dwFlags
= rawinput_tests
[i
].register_flags
;
2700 raw_devices
[0].hwndTarget
= rawinput_tests
[i
].register_window
? hwnd
: 0;
2702 if (!rawinput_tests
[i
].register_device
)
2706 SetLastError(0xdeadbeef);
2707 skipped
= !RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2708 if (rawinput_tests
[i
].register_flags
== RIDEV_EXINPUTSINK
&& skipped
)
2709 win_skip("RIDEV_EXINPUTSINK not supported\n");
2711 ok(!skipped
, "%d: RegisterRawInputDevices failed: %u\n", i
, GetLastError());
2714 SetEvent(params
.ready
);
2715 WaitForSingleObject(params
.start
, INFINITE
);
2716 ResetEvent(params
.start
);
2718 /* we need the main window to be over the other thread window, as although
2719 * it is in another desktop, it will receive the messages directly otherwise */
2724 SetWindowPos(hwnd
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2725 SetForegroundWindow(hwnd
);
2726 empty_message_queue();
2728 rawinput_test_received_legacy
= FALSE
;
2729 rawinput_test_received_raw
= FALSE
;
2730 rawinput_test_received_rawfg
= FALSE
;
2734 SetEvent(process_ready
);
2735 WaitForSingleObject(process_start
, INFINITE
);
2736 ResetEvent(process_start
);
2738 if (i
<= 3 || i
== 8) mouse_event(MOUSEEVENTF_MOVE
, 5, 0, 0, 0);
2739 empty_message_queue();
2741 SetEvent(process_done
);
2742 SetEvent(params
.done
);
2746 todo_wine_if(rawinput_tests
[i
].todo_legacy
)
2747 ok(rawinput_test_received_legacy
== rawinput_tests
[i
].expect_legacy
,
2748 "%d: %sexpected WM_MOUSEMOVE message\n", i
, rawinput_tests
[i
].expect_legacy
? "" : "un");
2749 todo_wine_if(rawinput_tests
[i
].todo_raw
)
2750 ok(rawinput_test_received_raw
== rawinput_tests
[i
].expect_raw
,
2751 "%d: %sexpected WM_INPUT message\n", i
, rawinput_tests
[i
].expect_raw
? "" : "un");
2752 todo_wine_if(rawinput_tests
[i
].todo_rawfg
)
2753 ok(rawinput_test_received_rawfg
== rawinput_tests
[i
].expect_rawfg
,
2754 "%d: %sexpected RIM_INPUT message\n", i
, rawinput_tests
[i
].expect_rawfg
? "" : "un");
2757 GetCursorPos(&newpt
);
2758 ok((newpt
.x
- pt
.x
) == 5 || (newpt
.x
- pt
.x
) == 4, "%d: Unexpected cursor movement\n", i
);
2760 if (rawinput_tests
[i
].register_device
)
2762 raw_devices
[0].dwFlags
= RIDEV_REMOVE
;
2763 raw_devices
[0].hwndTarget
= 0;
2765 SetLastError(0xdeadbeef);
2766 ret
= RegisterRawInputDevices(raw_devices
, ARRAY_SIZE(raw_devices
), sizeof(RAWINPUTDEVICE
));
2767 ok(ret
, "%d: RegisterRawInputDevices failed: %u\n", i
, GetLastError());
2770 DestroyWindow(hwnd
);
2773 SetEvent(process_ready
);
2774 winetest_wait_child_process(process_info
.hProcess
);
2775 CloseHandle(process_info
.hProcess
);
2776 CloseHandle(process_info
.hThread
);
2777 CloseHandle(process_done
);
2778 CloseHandle(process_start
);
2779 CloseHandle(process_ready
);
2781 WaitForSingleObject(thread
, INFINITE
);
2783 CloseHandle(params
.done
);
2784 CloseHandle(params
.start
);
2785 CloseHandle(params
.ready
);
2786 CloseHandle(thread
);
2788 CloseDesktop(params
.desk
);
2791 static void test_key_map(void)
2793 HKL kl
= GetKeyboardLayout(0);
2796 static const UINT numpad_collisions
[][2] = {
2797 { VK_NUMPAD0
, VK_INSERT
},
2798 { VK_NUMPAD1
, VK_END
},
2799 { VK_NUMPAD2
, VK_DOWN
},
2800 { VK_NUMPAD3
, VK_NEXT
},
2801 { VK_NUMPAD4
, VK_LEFT
},
2802 { VK_NUMPAD6
, VK_RIGHT
},
2803 { VK_NUMPAD7
, VK_HOME
},
2804 { VK_NUMPAD8
, VK_UP
},
2805 { VK_NUMPAD9
, VK_PRIOR
},
2808 s
= MapVirtualKeyExA(VK_SHIFT
, MAPVK_VK_TO_VSC
, kl
);
2809 ok(s
!= 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
2810 sL
= MapVirtualKeyExA(VK_LSHIFT
, MAPVK_VK_TO_VSC
, kl
);
2811 ok(s
== sL
|| broken(sL
== 0), /* win9x */
2812 "%x != %x\n", s
, sL
);
2814 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK
, kl
);
2815 ok(kL
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL
);
2816 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK
, kl
);
2817 ok(kR
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR
);
2819 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK_EX
, kl
);
2820 ok(kL
== VK_LSHIFT
|| broken(kL
== 0), /* win9x */
2821 "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL
);
2822 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK_EX
, kl
);
2823 ok(kR
== VK_RSHIFT
|| broken(kR
== 0), /* win9x */
2824 "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR
);
2826 /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
2827 for (i
= 0; i
< ARRAY_SIZE(numpad_collisions
); i
++)
2829 UINT numpad_scan
= MapVirtualKeyExA(numpad_collisions
[i
][0], MAPVK_VK_TO_VSC
, kl
);
2830 UINT other_scan
= MapVirtualKeyExA(numpad_collisions
[i
][1], MAPVK_VK_TO_VSC
, kl
);
2832 /* do they really collide for this layout? */
2833 if (numpad_scan
&& other_scan
== numpad_scan
)
2835 UINT vkey
= MapVirtualKeyExA(numpad_scan
, MAPVK_VSC_TO_VK
, kl
);
2836 ok(vkey
!= numpad_collisions
[i
][0],
2837 "Got numpad vKey %x for scan code %x when there was another choice\n",
2842 /* test the scan code prefixes of the right variant of a keys */
2843 s
= MapVirtualKeyExA(VK_RCONTROL
, MAPVK_VK_TO_VSC
, kl
);
2844 ok(s
>> 8 == 0x00, "Scan code prefixes should not be returned when not using MAPVK_VK_TO_VSC_EX %#1x\n", s
>> 8);
2845 s
= MapVirtualKeyExA(VK_RCONTROL
, MAPVK_VK_TO_VSC_EX
, kl
);
2846 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);
2847 s
= MapVirtualKeyExA(VK_RMENU
, MAPVK_VK_TO_VSC_EX
, kl
);
2848 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);
2849 s
= MapVirtualKeyExA(VK_RSHIFT
, MAPVK_VK_TO_VSC_EX
, kl
);
2850 ok(s
>> 8 == 0x00 || broken(s
== 0), "The scan code shouldn't have a prefix, got %#1x\n", s
>> 8);
2856 static const struct tounicode_tests
2860 WCHAR chr
; /* if vk is 0, lookup vk using this char */
2862 WCHAR expect_buf
[4];
2865 { 0, 0, 'a', 1, {'a',0}},
2866 { 0, shift
, 'a', 1, {'A',0}},
2867 { 0, ctrl
, 'a', 1, {1, 0}},
2868 { 0, shift
|ctrl
, 'a', 1, {1, 0}},
2869 { VK_TAB
, ctrl
, 0, 0, {}},
2870 { VK_TAB
, shift
|ctrl
, 0, 0, {}},
2871 { VK_RETURN
, ctrl
, 0, 1, {'\n', 0}},
2872 { VK_RETURN
, shift
|ctrl
, 0, 0, {}},
2873 { 0, ctrl
, '4', 0, {}},
2874 { 0, shift
|ctrl
, '4', 0, {}},
2875 { 0, ctrl
, '!', 0, {}},
2876 { 0, ctrl
, '\"', 0, {}},
2877 { 0, ctrl
, '#', 0, {}},
2878 { 0, ctrl
, '$', 0, {}},
2879 { 0, ctrl
, '%', 0, {}},
2880 { 0, ctrl
, '\'', 0, {}},
2881 { 0, ctrl
, '(', 0, {}},
2882 { 0, ctrl
, ')', 0, {}},
2883 { 0, ctrl
, '*', 0, {}},
2884 { 0, ctrl
, '+', 0, {}},
2885 { 0, ctrl
, ',', 0, {}},
2886 { 0, ctrl
, '-', 0, {}},
2887 { 0, ctrl
, '.', 0, {}},
2888 { 0, ctrl
, '/', 0, {}},
2889 { 0, ctrl
, ':', 0, {}},
2890 { 0, ctrl
, ';', 0, {}},
2891 { 0, ctrl
, '<', 0, {}},
2892 { 0, ctrl
, '=', 0, {}},
2893 { 0, ctrl
, '>', 0, {}},
2894 { 0, ctrl
, '?', 0, {}},
2895 { 0, ctrl
, '@', 1, {0}},
2896 { 0, ctrl
, '[', 1, {0x1b}},
2897 { 0, ctrl
, '\\', 1, {0x1c}},
2898 { 0, ctrl
, ']', 1, {0x1d}},
2899 { 0, ctrl
, '^', 1, {0x1e}},
2900 { 0, ctrl
, '_', 1, {0x1f}},
2901 { 0, ctrl
, '`', 0, {}},
2902 { VK_SPACE
, 0, 0, 1, {' ',0}},
2903 { VK_SPACE
, shift
, 0, 1, {' ',0}},
2904 { VK_SPACE
, ctrl
, 0, 1, {' ',0}},
2907 static void test_ToUnicode(void)
2911 const BYTE SC_RETURN
= 0x1c, SC_TAB
= 0x0f, SC_A
= 0x1e;
2912 const BYTE HIGHEST_BIT
= 0x80;
2914 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
2916 for(i
=0; i
<256; i
++)
2920 SetLastError(0xdeadbeef);
2921 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, state
, wStr
, 4, 0);
2922 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2924 win_skip("ToUnicode is not implemented\n");
2928 ok(ret
== 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret
);
2931 ok(wStr
[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr
[0]);
2932 ok(wStr
[1]==0 || broken(wStr
[1]!=0) /* nt4 */,
2933 "ToUnicode didn't null-terminate the buffer when there was room.\n");
2936 for (i
= 0; i
< ARRAY_SIZE(utests
); i
++)
2938 UINT vk
= utests
[i
].vk
, mod
= utests
[i
].modifiers
, scan
;
2944 if (!us_kbd
) continue;
2945 vk_ret
= VkKeyScanW(utests
[i
].chr
);
2946 if (vk_ret
== -1) continue;
2948 if (vk_ret
& 0x100) mod
|= shift
;
2949 if (vk_ret
& 0x200) mod
|= ctrl
;
2951 scan
= MapVirtualKeyW(vk
, MAPVK_VK_TO_VSC
);
2953 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = (mod
& shift
) ? HIGHEST_BIT
: 0;
2954 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = (mod
& ctrl
) ? HIGHEST_BIT
: 0;
2956 ret
= ToUnicode(vk
, scan
, state
, wStr
, 4, 0);
2957 ok(ret
== utests
[i
].expect_ret
, "%d: got %d expected %d\n", i
, ret
, utests
[i
].expect_ret
);
2959 ok(!lstrcmpW(wStr
, utests
[i
].expect_buf
), "%d: got %s expected %s\n", i
, wine_dbgstr_w(wStr
),
2960 wine_dbgstr_w(utests
[i
].expect_buf
));
2963 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = 0;
2964 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = 0;
2966 ret
= ToUnicode(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0);
2967 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
2968 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0);
2969 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
2970 ret
= ToUnicode('A', SC_A
, NULL
, wStr
, 4, 0);
2971 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
2972 ret
= ToUnicodeEx(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
2973 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
2974 ret
= ToUnicodeEx(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
2975 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
2976 ret
= ToUnicodeEx('A', SC_A
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
2977 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
2980 static void test_ToAscii(void)
2984 const BYTE SC_RETURN
= 0x1c, SC_A
= 0x1e;
2985 const BYTE HIGHEST_BIT
= 0x80;
2987 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
2989 memset(state
, 0, sizeof(state
));
2992 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
2993 ok(ret
== 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret
);
2994 ok(character
== '\r', "ToAscii for Return was %i (expected 13)\n", character
);
2997 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
2998 ok(ret
== 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret
);
2999 if (us_kbd
) ok(character
== 'a', "ToAscii for character 'A' was %i (expected %i)\n", character
, 'a');
3001 state
[VK_CONTROL
] |= HIGHEST_BIT
;
3002 state
[VK_LCONTROL
] |= HIGHEST_BIT
;
3004 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
3005 ok(ret
== 1, "ToAscii for CTRL + Return key didn't return 1 (was %i)\n", ret
);
3006 ok(character
== '\n', "ToAscii for CTRL + Return was %i (expected 10)\n", character
);
3009 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
3010 ok(ret
== 1, "ToAscii for CTRL + character 'A' didn't return 1 (was %i)\n", ret
);
3011 ok(character
== 1, "ToAscii for CTRL + character 'A' was %i (expected 1)\n", character
);
3013 state
[VK_SHIFT
] |= HIGHEST_BIT
;
3014 state
[VK_LSHIFT
] |= HIGHEST_BIT
;
3015 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
3016 ok(ret
== 0, "ToAscii for CTRL + Shift + Return key didn't return 0 (was %i)\n", ret
);
3018 ret
= ToAscii(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0);
3019 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
3020 ret
= ToAscii('A', SC_A
, NULL
, &character
, 0);
3021 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
3022 ret
= ToAsciiEx(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0, GetKeyboardLayout(0));
3023 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
3024 ret
= ToAsciiEx('A', SC_A
, NULL
, &character
, 0, GetKeyboardLayout(0));
3025 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
3028 static void test_get_async_key_state(void)
3030 /* input value sanity checks */
3031 ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
3032 ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
3035 static void test_keyboard_layout_name(void)
3038 char klid
[KL_NAMELENGTH
];
3040 if (0) /* crashes on native system */
3041 ret
= GetKeyboardLayoutNameA(NULL
);
3043 SetLastError(0xdeadbeef);
3044 ret
= GetKeyboardLayoutNameW(NULL
);
3045 ok(!ret
, "got %d\n", ret
);
3046 ok(GetLastError() == ERROR_NOACCESS
, "got %d\n", GetLastError());
3048 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409) return;
3051 ret
= GetKeyboardLayoutNameA(klid
);
3052 ok(ret
, "GetKeyboardLayoutNameA failed %u\n", GetLastError());
3053 ok(!strcmp(klid
, "00000409"), "expected 00000409, got %s\n", klid
);
3056 static void test_key_names(void)
3061 LONG lparam
= 0x1d << 16;
3063 memset( buffer
, 0xcc, sizeof(buffer
) );
3064 ret
= GetKeyNameTextA( lparam
, buffer
, sizeof(buffer
) );
3065 ok( ret
> 0, "wrong len %u for '%s'\n", ret
, buffer
);
3066 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
3068 memset( buffer
, 0xcc, sizeof(buffer
) );
3070 ret
= GetKeyNameTextA( lparam
, buffer
, prev
);
3071 ok( ret
== prev
- 1, "wrong len %u for '%s'\n", ret
, buffer
);
3072 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
3074 memset( buffer
, 0xcc, sizeof(buffer
) );
3075 ret
= GetKeyNameTextA( lparam
, buffer
, 0 );
3076 ok( ret
== 0, "wrong len %u for '%s'\n", ret
, buffer
);
3077 ok( buffer
[0] == 0, "wrong string '%s'\n", buffer
);
3079 memset( bufferW
, 0xcc, sizeof(bufferW
) );
3080 ret
= GetKeyNameTextW( lparam
, bufferW
, ARRAY_SIZE(bufferW
));
3081 ok( ret
> 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
3082 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
3084 memset( bufferW
, 0xcc, sizeof(bufferW
) );
3086 ret
= GetKeyNameTextW( lparam
, bufferW
, prev
);
3087 ok( ret
== prev
- 1, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
3088 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
3090 memset( bufferW
, 0xcc, sizeof(bufferW
) );
3091 ret
= GetKeyNameTextW( lparam
, bufferW
, 0 );
3092 ok( ret
== 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
3093 ok( bufferW
[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW
) );
3096 static void simulate_click(BOOL left
, int x
, int y
)
3102 memset(input
, 0, sizeof(input
));
3103 input
[0].type
= INPUT_MOUSE
;
3104 U(input
[0]).mi
.dx
= x
;
3105 U(input
[0]).mi
.dy
= y
;
3106 U(input
[0]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTDOWN
: MOUSEEVENTF_RIGHTDOWN
;
3107 input
[1].type
= INPUT_MOUSE
;
3108 U(input
[1]).mi
.dx
= x
;
3109 U(input
[1]).mi
.dy
= y
;
3110 U(input
[1]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTUP
: MOUSEEVENTF_RIGHTUP
;
3111 events_no
= SendInput(2, input
, sizeof(input
[0]));
3112 ok(events_no
== 2, "SendInput returned %d\n", events_no
);
3115 static BOOL
wait_for_message( MSG
*msg
)
3121 ret
= PeekMessageA(msg
, 0, 0, 0, PM_REMOVE
);
3124 if (msg
->message
== WM_PAINT
) DispatchMessageA(msg
);
3127 else if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, 100, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
3129 if (!ret
) msg
->message
= 0;
3133 static BOOL
wait_for_event(HANDLE event
, int timeout
)
3135 DWORD end_time
= GetTickCount() + timeout
;
3139 if(MsgWaitForMultipleObjects(1, &event
, FALSE
, timeout
, QS_ALLINPUT
) == WAIT_OBJECT_0
)
3141 while(PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
3142 DispatchMessageA(&msg
);
3143 timeout
= end_time
- GetTickCount();
3144 }while(timeout
> 0);
3149 static WNDPROC def_static_proc
;
3150 static DWORD hittest_no
;
3151 static LRESULT WINAPI
static_hook_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
3153 if (msg
== WM_NCHITTEST
)
3155 /* break infinite hittest loop */
3156 if(hittest_no
> 50) return HTCLIENT
;
3160 return def_static_proc(hwnd
, msg
, wp
, lp
);
3170 static DWORD WINAPI
create_static_win(void *arg
)
3172 struct thread_data
*thread_data
= arg
;
3176 win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
3177 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
3178 ok(win
!= 0, "CreateWindow failed\n");
3179 def_static_proc
= (void*)SetWindowLongPtrA(win
,
3180 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
3181 thread_data
->win
= win
;
3183 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
3184 SetEvent(thread_data
->start_event
);
3185 wait_for_event(thread_data
->end_event
, 5000);
3189 static LRESULT CALLBACK
mouse_move_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3191 static DWORD last_x
= 200, expect_x
= 210;
3193 if (msg
== WM_MOUSEMOVE
)
3195 POINT pt
= {LOWORD(lparam
), HIWORD(lparam
)};
3196 MapWindowPoints(hwnd
, NULL
, &pt
, 1);
3198 if (pt
.x
!= last_x
) ok( pt
.x
== expect_x
, "got unexpected WM_MOUSEMOVE x %d, expected %d\n", pt
.x
, expect_x
);
3200 expect_x
= pt
.x
== 200 ? 210 : 200;
3204 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);
3207 static void test_Input_mouse(void)
3209 BOOL got_button_down
, got_button_up
;
3210 HWND hwnd
, button_win
, static_win
;
3211 struct thread_data thread_data
;
3218 SetLastError(0xdeadbeef);
3219 ret
= GetCursorPos(NULL
);
3220 ok(!ret
, "GetCursorPos succeed\n");
3221 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_NOACCESS
, "error %u\n", GetLastError());
3223 SetLastError(0xdeadbeef);
3224 ret
= GetCursorPos(&pt_org
);
3225 ok(ret
, "GetCursorPos failed\n");
3226 ok(GetLastError() == 0xdeadbeef, "error %u\n", GetLastError());
3228 button_win
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
3229 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
3230 ok(button_win
!= 0, "CreateWindow failed\n");
3233 hwnd
= WindowFromPoint(pt
);
3234 if (hwnd
!= button_win
)
3236 skip("there's another window covering test window\n");
3237 DestroyWindow(button_win
);
3241 /* simple button click test */
3242 simulate_click(TRUE
, 150, 150);
3243 got_button_down
= got_button_up
= FALSE
;
3244 while (wait_for_message(&msg
))
3246 DispatchMessageA(&msg
);
3248 if (msg
.message
== WM_LBUTTONDOWN
)
3250 got_button_down
= TRUE
;
3252 else if (msg
.message
== WM_LBUTTONUP
)
3254 got_button_up
= TRUE
;
3258 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
3259 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
3261 /* click through HTTRANSPARENT child window */
3262 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_CHILD
,
3263 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
3264 ok(static_win
!= 0, "CreateWindow failed\n");
3265 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
3266 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
3267 simulate_click(FALSE
, 150, 150);
3269 got_button_down
= got_button_up
= FALSE
;
3270 while (wait_for_message(&msg
))
3272 DispatchMessageA(&msg
);
3274 if (msg
.message
== WM_RBUTTONDOWN
)
3276 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3277 got_button_down
= TRUE
;
3279 else if (msg
.message
== WM_RBUTTONUP
)
3281 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3282 got_button_up
= TRUE
;
3286 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
3287 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
3288 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
3289 DestroyWindow(static_win
);
3291 /* click through HTTRANSPARENT top-level window */
3292 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
3293 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
3294 ok(static_win
!= 0, "CreateWindow failed\n");
3295 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
3296 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
3297 simulate_click(TRUE
, 150, 150);
3299 got_button_down
= got_button_up
= FALSE
;
3300 while (wait_for_message(&msg
))
3302 DispatchMessageA(&msg
);
3304 if (msg
.message
== WM_LBUTTONDOWN
)
3306 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3307 got_button_down
= TRUE
;
3309 else if (msg
.message
== WM_LBUTTONUP
)
3311 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3312 got_button_up
= TRUE
;
3316 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
3317 todo_wine
ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
3318 todo_wine
ok(got_button_up
, "expected WM_LBUTTONUP message\n");
3319 DestroyWindow(static_win
);
3321 /* click on HTTRANSPARENT top-level window that belongs to other thread */
3322 thread_data
.start_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
3323 ok(thread_data
.start_event
!= NULL
, "CreateEvent failed\n");
3324 thread_data
.end_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
3325 ok(thread_data
.end_event
!= NULL
, "CreateEvent failed\n");
3326 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, NULL
);
3327 ok(thread
!= NULL
, "CreateThread failed\n");
3329 got_button_down
= got_button_up
= FALSE
;
3330 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
3331 simulate_click(FALSE
, 150, 150);
3332 while (wait_for_message(&msg
))
3334 DispatchMessageA(&msg
);
3336 if (msg
.message
== WM_RBUTTONDOWN
)
3337 got_button_down
= TRUE
;
3338 else if (msg
.message
== WM_RBUTTONUP
)
3339 got_button_up
= TRUE
;
3341 SetEvent(thread_data
.end_event
);
3342 WaitForSingleObject(thread
, INFINITE
);
3343 CloseHandle(thread
);
3344 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
3345 ok(!got_button_down
, "unexpected WM_RBUTTONDOWN message\n");
3346 ok(!got_button_up
, "unexpected WM_RBUTTONUP message\n");
3348 /* click on HTTRANSPARENT top-level window that belongs to other thread,
3349 * thread input queues are attached */
3350 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, &thread_id
);
3351 ok(thread
!= NULL
, "CreateThread failed\n");
3353 got_button_down
= got_button_up
= FALSE
;
3354 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
3355 ok(AttachThreadInput(thread_id
, GetCurrentThreadId(), TRUE
),
3356 "AttachThreadInput failed\n");
3357 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
3358 SetWindowPos(thread_data
.win
, button_win
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
3359 simulate_click(TRUE
, 150, 150);
3360 while (wait_for_message(&msg
))
3362 DispatchMessageA(&msg
);
3364 if (msg
.message
== WM_LBUTTONDOWN
)
3365 got_button_down
= TRUE
;
3366 else if (msg
.message
== WM_LBUTTONUP
)
3367 got_button_up
= TRUE
;
3369 SetEvent(thread_data
.end_event
);
3370 WaitForSingleObject(thread
, INFINITE
);
3371 todo_wine
ok(hittest_no
> 50, "expected loop with WM_NCHITTEST messages\n");
3372 ok(!got_button_down
, "unexpected WM_LBUTTONDOWN message\n");
3373 ok(!got_button_up
, "unexpected WM_LBUTTONUP message\n");
3375 /* click after SetCapture call */
3376 hwnd
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
3377 0, 0, 100, 100, 0, NULL
, NULL
, NULL
);
3378 ok(hwnd
!= 0, "CreateWindow failed\n");
3379 SetCapture(button_win
);
3380 got_button_down
= got_button_up
= FALSE
;
3381 simulate_click(FALSE
, 50, 50);
3382 while (wait_for_message(&msg
))
3384 DispatchMessageA(&msg
);
3386 if (msg
.message
== WM_RBUTTONDOWN
)
3388 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3389 got_button_down
= TRUE
;
3391 else if (msg
.message
== WM_RBUTTONUP
)
3393 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3394 got_button_up
= TRUE
;
3398 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
3399 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
3400 DestroyWindow(hwnd
);
3402 /* click on child window after SetCapture call */
3403 hwnd
= CreateWindowA("button", "button2", WS_VISIBLE
| WS_CHILD
,
3404 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
3405 ok(hwnd
!= 0, "CreateWindow failed\n");
3406 got_button_down
= got_button_up
= FALSE
;
3407 simulate_click(TRUE
, 150, 150);
3408 while (wait_for_message(&msg
))
3410 DispatchMessageA(&msg
);
3412 if (msg
.message
== WM_LBUTTONDOWN
)
3414 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3415 got_button_down
= TRUE
;
3417 else if (msg
.message
== WM_LBUTTONUP
)
3419 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
3420 got_button_up
= TRUE
;
3424 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
3425 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
3426 DestroyWindow(hwnd
);
3427 ok(ReleaseCapture(), "ReleaseCapture failed\n");
3428 SetCursorPos(pt_org
.x
, pt_org
.y
);
3430 CloseHandle(thread_data
.start_event
);
3431 CloseHandle(thread_data
.end_event
);
3432 DestroyWindow(button_win
);
3434 SetCursorPos(200, 200);
3435 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
3436 100, 100, 200, 200, NULL
, NULL
, NULL
, NULL
);
3437 ok(hwnd
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
3439 /* warm up test case by moving cursor and window a bit first */
3440 SetCursorPos(210, 200);
3441 SetWindowPos(hwnd
, NULL
, 110, 100, 0, 0, SWP_NOSIZE
);
3442 empty_message_queue();
3443 SetCursorPos(200, 200);
3444 SetWindowPos(hwnd
, NULL
, 100, 100, 0, 0, SWP_NOSIZE
);
3445 empty_message_queue();
3446 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)mouse_move_wndproc
);
3448 SetCursorPos(210, 200);
3449 SetWindowPos(hwnd
, NULL
, 110, 100, 0, 0, SWP_NOSIZE
);
3450 empty_message_queue();
3452 ok(pt
.x
== 210 && pt
.y
== 200, "GetCursorPos returned %dx%d, expected 210x200\n", pt
.x
, pt
.y
);
3454 SetCursorPos(200, 200);
3455 SetWindowPos(hwnd
, NULL
, 100, 100, 0, 0, SWP_NOSIZE
);
3456 empty_message_queue();
3458 ok(pt
.x
== 200 && pt
.y
== 200, "GetCursorPos returned %dx%d, expected 200x200\n", pt
.x
, pt
.y
);
3460 SetCursorPos(pt_org
.x
, pt_org
.y
);
3461 empty_message_queue();
3462 DestroyWindow(hwnd
);
3466 static LRESULT WINAPI
MsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
3468 if (message
== WM_USER
+1)
3470 HWND hwnd
= (HWND
)lParam
;
3471 ok(GetFocus() == hwnd
, "thread expected focus %p, got %p\n", hwnd
, GetFocus());
3472 ok(GetActiveWindow() == hwnd
, "thread expected active %p, got %p\n", hwnd
, GetActiveWindow());
3474 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
3487 static DWORD WINAPI
thread_proc(void *param
)
3490 struct wnd_event
*wnd_event
= param
;
3493 if (wnd_event
->wait_event
)
3495 ok(WaitForSingleObject(wnd_event
->wait_event
, INFINITE
) == WAIT_OBJECT_0
,
3496 "WaitForSingleObject failed\n");
3497 CloseHandle(wnd_event
->wait_event
);
3500 if (wnd_event
->attach_from
)
3502 ret
= AttachThreadInput(wnd_event
->attach_from
, GetCurrentThreadId(), TRUE
);
3503 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3506 if (wnd_event
->attach_to
)
3508 ret
= AttachThreadInput(GetCurrentThreadId(), wnd_event
->attach_to
, TRUE
);
3509 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3512 wnd_event
->hwnd
= CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW
,
3513 100, 100, 200, 200, 0, 0, 0, NULL
);
3514 ok(wnd_event
->hwnd
!= 0, "Failed to create overlapped window\n");
3516 if (wnd_event
->setWindows
)
3518 SetFocus(wnd_event
->hwnd
);
3519 SetActiveWindow(wnd_event
->hwnd
);
3522 SetEvent(wnd_event
->start_event
);
3524 while (GetMessageA(&msg
, 0, 0, 0))
3526 TranslateMessage(&msg
);
3527 DispatchMessageA(&msg
);
3533 static void test_attach_input(void)
3538 struct wnd_event wnd_event
;
3542 cls
.lpfnWndProc
= MsgCheckProcA
;
3545 cls
.hInstance
= GetModuleHandleA(0);
3547 cls
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
3548 cls
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
3549 cls
.lpszMenuName
= NULL
;
3550 cls
.lpszClassName
= "TestWindowClass";
3551 if(!RegisterClassA(&cls
)) return;
3553 wnd_event
.wait_event
= NULL
;
3554 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
3555 wnd_event
.attach_from
= 0;
3556 wnd_event
.attach_to
= 0;
3557 wnd_event
.setWindows
= FALSE
;
3558 if (!wnd_event
.start_event
)
3560 win_skip("skipping interthread message test under win9x\n");
3564 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
3565 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
3567 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3568 CloseHandle(wnd_event
.start_event
);
3570 ourWnd
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
3571 0, 0, 0, 0, 0, 0, 0, NULL
);
3572 ok(ourWnd
!= 0, "failed to create ourWnd window\n");
3574 Wnd2
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
3575 0, 0, 0, 0, 0, 0, 0, NULL
);
3576 ok(Wnd2
!= 0, "failed to create Wnd2 window\n");
3579 SetActiveWindow(ourWnd
);
3581 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
3582 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3584 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
3585 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
3587 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
3589 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
3590 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3591 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
3592 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
3594 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
3596 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
3597 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3599 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
3600 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
3601 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
3603 SetActiveWindow(Wnd2
);
3605 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
3606 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
3608 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
3610 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
3611 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3612 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
3613 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
3615 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
3617 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
3618 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
3620 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3621 CloseHandle(hThread
);
3623 wnd_event
.wait_event
= NULL
;
3624 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
3625 wnd_event
.attach_from
= 0;
3626 wnd_event
.attach_to
= 0;
3627 wnd_event
.setWindows
= TRUE
;
3629 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
3630 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
3632 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3633 CloseHandle(wnd_event
.start_event
);
3636 SetActiveWindow(ourWnd
);
3638 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
3639 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3641 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
3642 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
3644 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
3646 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
3647 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3649 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
3650 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
3652 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
3654 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
3655 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3657 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
3658 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
3660 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
3663 SetActiveWindow(Wnd2
);
3664 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
3665 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
3667 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
3669 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
3670 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
3672 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
3673 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
3675 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
3677 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
3678 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
3680 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3681 CloseHandle(hThread
);
3683 wnd_event
.wait_event
= CreateEventW(NULL
, 0, 0, NULL
);
3684 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
3685 wnd_event
.attach_from
= 0;
3686 wnd_event
.attach_to
= 0;
3687 wnd_event
.setWindows
= TRUE
;
3689 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
3690 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
3692 SetLastError(0xdeadbeef);
3693 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
3694 ok(!ret
, "AttachThreadInput succeeded\n");
3695 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
3696 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3698 SetLastError(0xdeadbeef);
3699 ret
= AttachThreadInput(tid
, GetCurrentThreadId(), TRUE
);
3700 ok(!ret
, "AttachThreadInput succeeded\n");
3701 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
3702 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3704 SetEvent(wnd_event
.wait_event
);
3706 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3707 CloseHandle(wnd_event
.start_event
);
3709 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
3710 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
3712 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3713 CloseHandle(hThread
);
3715 wnd_event
.wait_event
= NULL
;
3716 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
3717 wnd_event
.attach_from
= GetCurrentThreadId();
3718 wnd_event
.attach_to
= 0;
3719 wnd_event
.setWindows
= FALSE
;
3722 SetActiveWindow(ourWnd
);
3724 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
3725 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
3727 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3728 CloseHandle(wnd_event
.start_event
);
3730 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
3731 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
3733 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
3734 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
3736 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3737 CloseHandle(hThread
);
3739 wnd_event
.wait_event
= NULL
;
3740 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
3741 wnd_event
.attach_from
= 0;
3742 wnd_event
.attach_to
= GetCurrentThreadId();
3743 wnd_event
.setWindows
= FALSE
;
3746 SetActiveWindow(ourWnd
);
3748 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
3749 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
3751 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3752 CloseHandle(wnd_event
.start_event
);
3754 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
3755 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
3757 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
3758 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
3760 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
3761 CloseHandle(hThread
);
3762 DestroyWindow(ourWnd
);
3763 DestroyWindow(Wnd2
);
3766 struct get_key_state_test_desc
3769 BOOL peek_message_main
;
3770 BOOL set_keyboard_state_main
;
3771 BOOL set_keyboard_state
;
3774 struct get_key_state_test_desc get_key_state_tests
[] =
3776 /* 0: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
3777 {FALSE
, TRUE
, FALSE
, FALSE
},
3778 /* 1: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
3779 /* - GetKeyboardState misses key press if called before GetKeyState */
3780 /* - GetKeyboardState catches key press, if called after GetKeyState */
3781 { TRUE
, FALSE
, FALSE
, FALSE
},
3782 /* 2: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
3783 { TRUE
, TRUE
, FALSE
, FALSE
},
3785 /* same tests but with SetKeyboardState called in main thread */
3786 /* 3: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
3787 {FALSE
, TRUE
, TRUE
, FALSE
},
3788 /* 4: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
3789 /* - GetKeyboardState misses key press if called before GetKeyState */
3790 /* - GetKeyboardState catches key press, if called after GetKeyState */
3791 { TRUE
, FALSE
, TRUE
, FALSE
},
3792 /* 5: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
3793 { TRUE
, TRUE
, TRUE
, FALSE
},
3795 /* same tests but with SetKeyboardState called in other thread */
3796 /* 6: not peeking in thread, no msg queue: GetKeyState / GetKeyboardState miss key press */
3797 {FALSE
, TRUE
, TRUE
, TRUE
},
3798 /* 7: peeking on thread init, not in main: GetKeyState / GetKeyboardState catch key press */
3799 /* - GetKeyboardState misses key press if called before GetKeyState */
3800 /* - GetKeyboardState catches key press, if called after GetKeyState */
3801 { TRUE
, FALSE
, TRUE
, TRUE
},
3802 /* 8: peeking on thread init, and in main: GetKeyState / GetKeyboardState catch key press */
3803 { TRUE
, TRUE
, TRUE
, TRUE
},
3806 struct get_key_state_thread_params
3808 HANDLE semaphores
[2];
3812 #define check_get_keyboard_state(i, j, c, x, todo_c, todo_x) check_get_keyboard_state_(i, j, c, x, todo_c, todo_x, __LINE__)
3813 static void check_get_keyboard_state_(int i
, int j
, int c
, int x
, int todo_c
, int todo_x
, int line
)
3815 unsigned char keystate
[256];
3818 memset(keystate
, 0, sizeof(keystate
));
3819 ret
= GetKeyboardState(keystate
);
3820 ok_(__FILE__
, line
)(ret
, "GetKeyboardState failed, %u\n", GetLastError());
3821 todo_wine_if(todo_x
) ok_(__FILE__
, line
)(!(keystate
['X'] & 0x80) == !x
, "%d:%d: expected that X keystate is %s\n", i
, j
, x
? "set" : "unset");
3822 todo_wine_if(todo_c
) ok_(__FILE__
, line
)(!(keystate
['C'] & 0x80) == !c
, "%d:%d: expected that C keystate is %s\n", i
, j
, c
? "set" : "unset");
3824 /* calling it twice shouldn't change */
3825 memset(keystate
, 0, sizeof(keystate
));
3826 ret
= GetKeyboardState(keystate
);
3827 ok_(__FILE__
, line
)(ret
, "GetKeyboardState failed, %u\n", GetLastError());
3828 todo_wine_if(todo_x
) ok_(__FILE__
, line
)(!(keystate
['X'] & 0x80) == !x
, "%d:%d: expected that X keystate is %s\n", i
, j
, x
? "set" : "unset");
3829 todo_wine_if(todo_c
) ok_(__FILE__
, line
)(!(keystate
['C'] & 0x80) == !c
, "%d:%d: expected that C keystate is %s\n", i
, j
, c
? "set" : "unset");
3832 #define check_get_key_state(i, j, c, x, todo_c, todo_x) check_get_key_state_(i, j, c, x, todo_c, todo_x, __LINE__)
3833 static void check_get_key_state_(int i
, int j
, int c
, int x
, int todo_c
, int todo_x
, int line
)
3837 state
= GetKeyState('X');
3838 todo_wine_if(todo_x
) ok_(__FILE__
, line
)(!(state
& 0x8000) == !x
, "%d:%d: expected that X highest bit is %s, got %#x\n", i
, j
, x
? "set" : "unset", state
);
3839 ok_(__FILE__
, line
)(!(state
& 0x007e), "%d:%d: expected that X undefined bits are unset, got %#x\n", i
, j
, state
);
3841 state
= GetKeyState('C');
3842 todo_wine_if(todo_c
) ok_(__FILE__
, line
)(!(state
& 0x8000) == !c
, "%d:%d: expected that C highest bit is %s, got %#x\n", i
, j
, c
? "set" : "unset", state
);
3843 ok_(__FILE__
, line
)(!(state
& 0x007e), "%d:%d: expected that C undefined bits are unset, got %#x\n", i
, j
, state
);
3846 static DWORD WINAPI
get_key_state_thread(void *arg
)
3848 struct get_key_state_thread_params
*params
= arg
;
3849 struct get_key_state_test_desc
* test
;
3850 HANDLE
*semaphores
= params
->semaphores
;
3854 BOOL expect_x
, expect_c
;
3856 int i
= params
->index
, j
;
3858 test
= get_key_state_tests
+ i
;
3859 has_queue
= test
->peek_message
;
3861 if (test
->peek_message
)
3863 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
3864 ok(!is_keyboard_message(msg
.message
), "%d: PeekMessageA got keyboard message.\n", i
);
3867 for (j
= 0; j
< 4; ++j
)
3869 /* initialization */
3870 ReleaseSemaphore(semaphores
[0], 1, NULL
);
3871 result
= WaitForSingleObject(semaphores
[1], 1000);
3872 ok(result
== WAIT_OBJECT_0
, "%d:%d: WaitForSingleObject returned %u\n", i
, j
, result
);
3874 if (test
->set_keyboard_state
)
3876 keystate
['C'] = 0xff;
3877 SetKeyboardState(keystate
);
3881 ReleaseSemaphore(semaphores
[0], 1, NULL
);
3882 result
= WaitForSingleObject(semaphores
[1], 1000);
3883 ok(result
== WAIT_OBJECT_0
, "%d:%d: WaitForSingleObject returned %u\n", i
, j
, result
);
3885 if (test
->set_keyboard_state
) expect_x
= TRUE
;
3886 else if (!has_queue
&& j
== 0) expect_x
= FALSE
;
3887 else expect_x
= TRUE
;
3889 if (test
->set_keyboard_state
) expect_c
= TRUE
;
3890 else expect_c
= FALSE
;
3892 check_get_keyboard_state(i
, j
, expect_c
, FALSE
, /* todo */ i
== 6, !has_queue
);
3893 check_get_key_state(i
, j
, expect_c
, expect_x
, /* todo */ i
== 6, i
!= 6 && (has_queue
|| j
== 0));
3894 check_get_keyboard_state(i
, j
, expect_c
, expect_x
, /* todo */ i
== 6, i
!= 6 && (has_queue
|| j
== 0));
3897 ReleaseSemaphore(semaphores
[0], 1, NULL
);
3898 result
= WaitForSingleObject(semaphores
[1], 1000);
3899 ok(result
== WAIT_OBJECT_0
, "%d: WaitForSingleObject returned %u\n", i
, result
);
3901 check_get_keyboard_state(i
, j
, expect_c
, expect_x
, /* todo */ i
== 6, has_queue
|| i
== 6 || j
> 0);
3902 check_get_key_state(i
, j
, expect_c
, FALSE
, /* todo */ i
== 6, FALSE
);
3903 check_get_keyboard_state(i
, j
, expect_c
, FALSE
, /* todo */ i
== 6, FALSE
);
3909 static void test_GetKeyState(void)
3911 struct get_key_state_thread_params params
;
3915 BOOL expect_x
, expect_c
;
3920 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
3923 skip("skipping test with inconsistent results on non-us keyboard\n");
3927 memset(keystate
, 0, sizeof(keystate
));
3928 params
.semaphores
[0] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
3929 ok(params
.semaphores
[0] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
3930 params
.semaphores
[1] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
3931 ok(params
.semaphores
[1] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
3933 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
3934 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
3935 ok(hwnd
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
3936 empty_message_queue();
3938 for (i
= 0; i
< ARRAY_SIZE(get_key_state_tests
); ++i
)
3940 struct get_key_state_test_desc
* test
= get_key_state_tests
+ i
;
3943 thread
= CreateThread(NULL
, 0, get_key_state_thread
, ¶ms
, 0, NULL
);
3944 ok(thread
!= NULL
, "CreateThread failed %u\n", GetLastError());
3946 for (j
= 0; j
< 4; ++j
)
3948 /* initialization */
3949 result
= WaitForSingleObject(params
.semaphores
[0], 1000);
3950 ok(result
== WAIT_OBJECT_0
, "%d:%d: WaitForSingleObject returned %u\n", i
, j
, result
);
3952 SetForegroundWindow(hwnd
);
3954 empty_message_queue();
3956 ReleaseSemaphore(params
.semaphores
[1], 1, NULL
);
3959 result
= WaitForSingleObject(params
.semaphores
[0], 1000);
3960 ok(result
== WAIT_OBJECT_0
, "%d:%d: WaitForSingleObject returned %u\n", i
, j
, result
);
3962 keybd_event('X', 0, 0, 0);
3963 if (test
->set_keyboard_state_main
)
3966 keystate
['C'] = 0xff;
3967 SetKeyboardState(keystate
);
3969 else expect_c
= FALSE
;
3971 check_get_keyboard_state(i
, j
, expect_c
, FALSE
, /* todo */ FALSE
, FALSE
);
3972 check_get_key_state(i
, j
, expect_c
, FALSE
, /* todo */ FALSE
, FALSE
);
3973 check_get_keyboard_state(i
, j
, expect_c
, FALSE
, /* todo */ FALSE
, FALSE
);
3975 if (test
->peek_message_main
) while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
3977 if (test
->peek_message_main
) expect_x
= TRUE
;
3978 else expect_x
= FALSE
;
3980 check_get_keyboard_state(i
, j
, expect_c
, expect_x
, /* todo */ FALSE
, FALSE
);
3981 check_get_key_state(i
, j
, expect_c
, expect_x
, /* todo */ FALSE
, FALSE
);
3982 check_get_keyboard_state(i
, j
, expect_c
, expect_x
, /* todo */ FALSE
, FALSE
);
3984 ReleaseSemaphore(params
.semaphores
[1], 1, NULL
);
3987 result
= WaitForSingleObject(params
.semaphores
[0], 1000);
3988 ok(result
== WAIT_OBJECT_0
, "%d:%d: WaitForSingleObject returned %u\n", i
, j
, result
);
3990 keybd_event('X', 0, KEYEVENTF_KEYUP
, 0);
3991 if (test
->set_keyboard_state_main
)
3994 keystate
['C'] = 0x00;
3995 SetKeyboardState(keystate
);
3998 check_get_keyboard_state(i
, j
, FALSE
, expect_x
, /* todo */ FALSE
, FALSE
);
3999 check_get_key_state(i
, j
, FALSE
, expect_x
, /* todo */ FALSE
, FALSE
);
4000 check_get_keyboard_state(i
, j
, FALSE
, expect_x
, /* todo */ FALSE
, FALSE
);
4002 if (test
->peek_message_main
) while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) DispatchMessageA(&msg
);
4004 check_get_keyboard_state(i
, j
, FALSE
, FALSE
, /* todo */ FALSE
, FALSE
);
4005 check_get_key_state(i
, j
, FALSE
, FALSE
, /* todo */ FALSE
, FALSE
);
4006 check_get_keyboard_state(i
, j
, FALSE
, FALSE
, /* todo */ FALSE
, FALSE
);
4008 ReleaseSemaphore(params
.semaphores
[1], 1, NULL
);
4011 result
= WaitForSingleObject(thread
, 1000);
4012 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
4013 CloseHandle(thread
);
4016 DestroyWindow(hwnd
);
4017 CloseHandle(params
.semaphores
[0]);
4018 CloseHandle(params
.semaphores
[1]);
4021 static void test_OemKeyScan(void)
4023 DWORD ret
, expect
, vkey
, scan
;
4027 for (oem
= 0; oem
< 0x200; oem
++)
4029 ret
= OemKeyScan( oem
);
4031 oem_char
= LOBYTE( oem
);
4032 /* OemKeyScan returns -1 for any character that cannot be mapped,
4033 * whereas OemToCharBuff changes unmappable characters to question
4034 * marks. The ASCII characters 0-127, including the real question mark
4035 * character, are all mappable and are the same in all OEM codepages. */
4036 if (!OemToCharBuffW( &oem_char
, &wchr
, 1 ) || (wchr
== '?' && oem_char
< 0))
4040 vkey
= VkKeyScanW( wchr
);
4041 scan
= MapVirtualKeyW( LOBYTE( vkey
), MAPVK_VK_TO_VSC
);
4048 expect
= vkey
| scan
;
4051 ok( ret
== expect
, "%04x: got %08x expected %08x\n", oem
, ret
, expect
);
4055 static INPUT_MESSAGE_SOURCE expect_src
;
4057 static LRESULT WINAPI
msg_source_proc( HWND hwnd
, UINT message
, WPARAM wp
, LPARAM lp
)
4059 INPUT_MESSAGE_SOURCE source
;
4062 ok( pGetCurrentInputMessageSource( &source
), "GetCurrentInputMessageSource failed\n" );
4070 case WM_LBUTTONDOWN
:
4072 case WM_RBUTTONDOWN
:
4074 ok( source
.deviceType
== expect_src
.deviceType
|| /* also accept system-generated WM_MOUSEMOVE */
4075 (message
== WM_MOUSEMOVE
&& source
.deviceType
== IMDT_UNAVAILABLE
),
4076 "%x: wrong deviceType %x/%x\n", message
, source
.deviceType
, expect_src
.deviceType
);
4077 ok( source
.originId
== expect_src
.originId
||
4078 (message
== WM_MOUSEMOVE
&& source
.originId
== IMO_SYSTEM
),
4079 "%x: wrong originId %x/%x\n", message
, source
.originId
, expect_src
.originId
);
4080 SendMessageA( hwnd
, WM_USER
, 0, 0 );
4081 PostMessageA( hwnd
, WM_USER
, 0, 0 );
4082 if (PeekMessageW( &msg
, hwnd
, WM_USER
, WM_USER
, PM_REMOVE
)) DispatchMessageW( &msg
);
4083 ok( source
.deviceType
== expect_src
.deviceType
|| /* also accept system-generated WM_MOUSEMOVE */
4084 (message
== WM_MOUSEMOVE
&& source
.deviceType
== IMDT_UNAVAILABLE
),
4085 "%x: wrong deviceType %x/%x\n", message
, source
.deviceType
, expect_src
.deviceType
);
4086 ok( source
.originId
== expect_src
.originId
||
4087 (message
== WM_MOUSEMOVE
&& source
.originId
== IMO_SYSTEM
),
4088 "%x: wrong originId %x/%x\n", message
, source
.originId
, expect_src
.originId
);
4091 ok( source
.deviceType
== IMDT_UNAVAILABLE
, "%x: wrong deviceType %x\n",
4092 message
, source
.deviceType
);
4093 ok( source
.originId
== 0, "%x: wrong originId %x\n", message
, source
.originId
);
4097 return DefWindowProcA( hwnd
, message
, wp
, lp
);
4100 static void test_input_message_source(void)
4103 TEST_INPUT inputs
[2];
4109 cls
.lpfnWndProc
= msg_source_proc
;
4112 cls
.hInstance
= GetModuleHandleA(0);
4114 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
4115 cls
.hbrBackground
= 0;
4116 cls
.lpszMenuName
= NULL
;
4117 cls
.lpszClassName
= "message source class";
4118 RegisterClassA(&cls
);
4119 hwnd
= CreateWindowA( cls
.lpszClassName
, "test", WS_OVERLAPPED
, 0, 0, 100, 100,
4121 ShowWindow( hwnd
, SW_SHOWNORMAL
);
4122 UpdateWindow( hwnd
);
4123 SetForegroundWindow( hwnd
);
4126 inputs
[0].type
= INPUT_KEYBOARD
;
4127 inputs
[0].u
.ki
.dwExtraInfo
= 0;
4128 inputs
[0].u
.ki
.time
= 0;
4129 inputs
[0].u
.ki
.wVk
= 0;
4130 inputs
[0].u
.ki
.wScan
= 0x3c0;
4131 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
4132 inputs
[1] = inputs
[0];
4133 inputs
[1].u
.ki
.dwFlags
|= KEYEVENTF_KEYUP
;
4135 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
4136 expect_src
.originId
= IMO_UNAVAILABLE
;
4137 SendMessageA( hwnd
, WM_KEYDOWN
, 0, 0 );
4138 SendMessageA( hwnd
, WM_MOUSEMOVE
, 0, 0 );
4140 SendInput( 2, (INPUT
*)inputs
, sizeof(INPUT
) );
4141 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
4143 expect_src
.deviceType
= IMDT_KEYBOARD
;
4144 expect_src
.originId
= IMO_INJECTED
;
4145 TranslateMessage( &msg
);
4146 DispatchMessageW( &msg
);
4148 GetWindowRect( hwnd
, &rc
);
4149 simulate_click( TRUE
, (rc
.left
+ rc
.right
) / 2, (rc
.top
+ rc
.bottom
) / 2 );
4150 simulate_click( FALSE
, (rc
.left
+ rc
.right
) / 2 + 1, (rc
.top
+ rc
.bottom
) / 2 + 1 );
4151 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
4153 expect_src
.deviceType
= IMDT_MOUSE
;
4154 expect_src
.originId
= IMO_INJECTED
;
4155 TranslateMessage( &msg
);
4156 DispatchMessageW( &msg
);
4159 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
4160 expect_src
.originId
= IMO_UNAVAILABLE
;
4161 SendMessageA( hwnd
, WM_KEYDOWN
, 0, 0 );
4162 SendMessageA( hwnd
, WM_LBUTTONDOWN
, 0, 0 );
4163 PostMessageA( hwnd
, WM_KEYUP
, 0, 0 );
4164 PostMessageA( hwnd
, WM_LBUTTONUP
, 0, 0 );
4165 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
4167 TranslateMessage( &msg
);
4168 DispatchMessageW( &msg
);
4171 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
4172 expect_src
.originId
= IMO_SYSTEM
;
4173 SetCursorPos( (rc
.left
+ rc
.right
) / 2 - 1, (rc
.top
+ rc
.bottom
) / 2 - 1 );
4174 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
4176 TranslateMessage( &msg
);
4177 DispatchMessageW( &msg
);
4180 DestroyWindow( hwnd
);
4181 UnregisterClassA( cls
.lpszClassName
, GetModuleHandleA(0) );
4184 static void test_GetPointerType(void)
4187 POINTER_INPUT_TYPE type
= -1;
4190 SetLastError(0xdeadbeef);
4191 ret
= pGetPointerType(id
, NULL
);
4192 ok(!ret
, "GetPointerType should have failed.\n");
4193 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4194 "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError());
4196 SetLastError(0xdeadbeef);
4197 ret
= pGetPointerType(id
, &type
);
4198 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4199 "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError());
4200 ok(!ret
, "GetPointerType failed, got type %d for %u.\n", type
, id
);
4201 ok(type
== -1, " type %d\n", type
);
4204 ret
= pGetPointerType(id
, &type
);
4205 ok(ret
, "GetPointerType failed, got type %d for %u.\n", type
, id
);
4206 ok(type
== PT_MOUSE
, " type %d\n", type
);
4209 static void test_UnregisterDeviceNotification(void)
4211 BOOL ret
= UnregisterDeviceNotification(NULL
);
4212 ok(ret
== FALSE
, "Unregistering NULL Device Notification returned: %d\n", ret
);
4221 init_function_pointers();
4222 GetCursorPos( &pos
);
4224 argc
= winetest_get_mainargs(&argv
);
4225 if (argc
>= 3 && strcmp(argv
[2], "rawinput_test") == 0)
4227 rawinput_test_process();
4231 if (argc
>= 3 && strcmp(argv
[2], "get_mouse_move_points_test") == 0)
4233 test_GetMouseMovePointsEx_process();
4237 test_Input_blackbox();
4238 test_Input_whitebox();
4239 test_Input_unicode();
4242 test_mouse_ll_hook();
4246 test_get_async_key_state();
4247 test_keyboard_layout_name();
4249 test_attach_input();
4252 test_GetRawInputData();
4253 test_GetRawInputBuffer();
4254 test_RegisterRawInputDevices();
4255 test_rawinput(argv
[0]);
4257 if(pGetMouseMovePointsEx
)
4258 test_GetMouseMovePointsEx(argv
[0]);
4260 win_skip("GetMouseMovePointsEx is not available\n");
4262 if(pGetRawInputDeviceList
)
4263 test_GetRawInputDeviceList();
4265 win_skip("GetRawInputDeviceList is not available\n");
4267 if (pGetCurrentInputMessageSource
)
4268 test_input_message_source();
4270 win_skip("GetCurrentInputMessageSource is not available\n");
4272 SetCursorPos( pos
.x
, pos
.y
);
4275 test_GetPointerType();
4277 win_skip("GetPointerType is not available\n");
4279 test_UnregisterDeviceNotification();