1 /* Test Key event to Key message translation
3 * Copyright 2003 Rein Klazes
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 /* test whether the right type of messages:
21 * WM_KEYUP/DOWN vs WM_SYSKEYUP/DOWN are sent in case of combined
24 * For instance <ALT>-X can be accomplished by
25 * the sequence ALT-KEY-DOWN, X-KEY-DOWN, ALT-KEY-UP, X-KEY-UP
26 * but also X-KEY-DOWN, ALT-KEY-DOWN, X-KEY-UP, ALT-KEY-UP
27 * Whether a KEY or a SYSKEY message is sent is not always clear, it is
28 * also not the same in WINNT as in WIN9X */
30 /* NOTE that there will be test failures under WIN9X
31 * No applications are known to me that rely on this
32 * so I don't fix it */
35 * 1. extend it to the wm_command and wm_syscommand notifications
36 * 2. add some more tests with special cases like dead keys or right (alt) key
37 * 3. there is some adapted code from input.c in here. Should really
38 * make that code exactly the same.
39 * 4. resolve the win9x case when there is a need or the testing frame work
41 * 5. The test app creates a window, the user should not take the focus
42 * away during its short existence. I could do something to prevent that
56 #include "wine/test.h"
59 #include <reactos/undocuser.h>
64 static LONG timetag
= 0x10000000;
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 int (WINAPI
*pGetWindowRgnBox
)(HWND
, LPRECT
);
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 */
152 static void init_function_pointers(void)
154 HMODULE hdll
= GetModuleHandleA("user32");
156 #define GET_PROC(func) \
157 if (!(p ## func = (void*)GetProcAddress(hdll, #func))) \
158 trace("GetProcAddress(%s) failed\n", #func)
160 GET_PROC(GetCurrentInputMessageSource
);
161 GET_PROC(GetMouseMovePointsEx
);
162 GET_PROC(GetPointerType
);
163 GET_PROC(GetRawInputDeviceList
);
164 GET_PROC(GetRawInputDeviceInfoW
);
165 GET_PROC(GetRawInputDeviceInfoA
);
166 GET_PROC(GetWindowRgnBox
);
170 static int KbdMessage( KEV kev
, WPARAM
*pwParam
, LPARAM
*plParam
)
173 int VKey
= GETVKEY
[kev
];
176 flags
= LOBYTE(GETSCAN
[kev
]);
177 if (GETFLAGS
[kev
] & KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
179 if (GETFLAGS
[kev
] & KEYEVENTF_KEYUP
)
182 if( (InputKeyStateTable
[VK_MENU
] & 0x80) && (
183 (VKey
== VK_MENU
) || (VKey
== VK_CONTROL
) ||
184 !(InputKeyStateTable
[VK_CONTROL
] & 0x80))) {
185 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
186 (VKey
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
187 message
= WM_SYSKEYUP
;
190 InputKeyStateTable
[VKey
] &= ~0x80;
191 flags
|= KF_REPEAT
| KF_UP
;
195 if (InputKeyStateTable
[VKey
] & 0x80) flags
|= KF_REPEAT
;
196 if (!(InputKeyStateTable
[VKey
] & 0x80)) InputKeyStateTable
[VKey
] ^= 0x01;
197 InputKeyStateTable
[VKey
] |= 0x80;
198 AsyncKeyStateTable
[VKey
] |= 0x80;
200 message
= WM_KEYDOWN
;
201 if( (InputKeyStateTable
[VK_MENU
] & 0x80) &&
202 !(InputKeyStateTable
[VK_CONTROL
] & 0x80)) {
203 message
= WM_SYSKEYDOWN
;
208 if (InputKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
210 if( plParam
) *plParam
= MAKELPARAM( 1, flags
);
211 if( pwParam
) *pwParam
= VKey
;
215 /****************************** end copy input.c ****************************/
218 * . prepare the keyevents for SendInputs
219 * . calculate the "expected" messages
220 * . Send the events to our window
221 * . retrieve the messages from the input queue
224 static BOOL
do_test( HWND hwnd
, int seqnr
, const KEV td
[] )
226 TEST_INPUT inputs
[MAXKEYEVENTS
];
227 KMSG expmsg
[MAXKEYEVENTS
];
234 TrackSysKey
=0; /* see input.c */
235 for (i
= 0; i
< MAXKEYEVENTS
; i
++)
237 inputs
[evtctr
].type
= INPUT_KEYBOARD
;
238 inputs
[evtctr
].u
.ki
.wVk
= GETVKEY
[td
[i
]];
239 inputs
[evtctr
].u
.ki
.wScan
= GETSCAN
[td
[i
]];
240 inputs
[evtctr
].u
.ki
.dwFlags
= GETFLAGS
[td
[i
]];
241 inputs
[evtctr
].u
.ki
.dwExtraInfo
= 0;
242 inputs
[evtctr
].u
.ki
.time
= ++timetag
;
245 strcat(buf
, getdesc
[td
[i
]]);
247 expmsg
[i
].message
= KbdMessage(td
[i
], &(expmsg
[i
].wParam
), &(expmsg
[i
].lParam
));
249 expmsg
[i
].message
= 0;
251 for( kmctr
= 0; kmctr
< MAXKEYEVENTS
&& expmsg
[kmctr
].message
; kmctr
++)
253 ok( evtctr
<= MAXKEYEVENTS
, "evtctr is above MAXKEYEVENTS\n" );
254 ret
= SendInput(evtctr
, (INPUT
*)inputs
, sizeof(INPUT
));
255 ok(ret
== evtctr
, "SendInput failed to send some events\n");
257 if (winetest_debug
> 1)
258 trace("======== key stroke sequence #%d: %s =============\n",
260 while( PeekMessageA(&msg
,hwnd
,WM_KEYFIRST
,WM_KEYLAST
,PM_REMOVE
) ) {
261 if (winetest_debug
> 1)
262 trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i
,
263 MSGNAME
[msg
.message
- WM_KEYFIRST
], msg
.wParam
, msg
.lParam
, msg
.time
);
265 ok( msg
.message
== expmsg
[i
].message
&&
266 msg
.wParam
== expmsg
[i
].wParam
&&
267 msg
.lParam
== expmsg
[i
].lParam
,
268 "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n",
269 seqnr
, i
, msg
.message
, msg
.wParam
, msg
.lParam
,
270 MSGNAME
[(expmsg
[i
]).message
- WM_KEYFIRST
], expmsg
[i
].wParam
, expmsg
[i
].lParam
);
274 if (winetest_debug
> 1)
275 trace("%d messages retrieved\n", i
);
278 skip( "simulated keyboard input doesn't work\n" );
281 ok( i
== kmctr
, "message count is wrong: got %d expected: %d\n", i
, kmctr
);
285 /* test all combinations of the specified key events */
286 static BOOL
TestASet( HWND hWnd
, int nrkev
, const KEV kevdwn
[], const KEV kevup
[] )
290 KEV kbuf
[MAXKEYEVENTS
];
291 assert( nrkev
==2 || nrkev
==3);
292 for(i
=0;i
<MAXKEYEVENTS
;i
++) kbuf
[i
]=0;
293 /* two keys involved gives 4 test cases */
295 for(i
=0;i
<nrkev
;i
++) {
296 for(j
=0;j
<nrkev
;j
++) {
298 kbuf
[1] = kevdwn
[1-i
];
300 kbuf
[3] = kevup
[1-j
];
301 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
305 /* three keys involved gives 36 test cases */
307 for(i
=0;i
<nrkev
;i
++){
308 for(j
=0;j
<nrkev
;j
++){
310 for(k
=0;k
<nrkev
;k
++){
311 if(k
==i
|| k
==j
) continue;
312 for(l
=0;l
<nrkev
;l
++){
313 for(m
=0;m
<nrkev
;m
++){
315 for(n
=0;n
<nrkev
;n
++){
316 if(n
==l
||n
==m
) continue;
323 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
334 /* test each set specified in the global testkeyset array */
335 static void TestSysKeys( HWND hWnd
)
338 for(i
=0; testkeyset
[i
].nrkev
;i
++)
339 if (!TestASet( hWnd
, testkeyset
[i
].nrkev
, testkeyset
[i
].keydwn
, testkeyset
[i
].keyup
)) break;
342 static LRESULT CALLBACK
WndProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
345 return DefWindowProcA( hWnd
, msg
, wParam
, lParam
);
348 static void test_Input_whitebox(void)
352 HANDLE hInstance
= GetModuleHandleA( NULL
);
354 wclass
.lpszClassName
= "InputSysKeyTestClass";
355 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
356 wclass
.lpfnWndProc
= WndProc
;
357 wclass
.hInstance
= hInstance
;
358 wclass
.hIcon
= LoadIconA( 0, (LPCSTR
)IDI_APPLICATION
);
359 wclass
.hCursor
= LoadCursorA( NULL
, (LPCSTR
)IDC_ARROW
);
360 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1 );
361 wclass
.lpszMenuName
= 0;
362 wclass
.cbClsExtra
= 0;
363 wclass
.cbWndExtra
= 0;
364 RegisterClassA( &wclass
);
365 /* create the test window that will receive the keystrokes */
366 hWndTest
= CreateWindowA( wclass
.lpszClassName
, "InputSysKeyTest",
367 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
368 NULL
, NULL
, hInstance
, NULL
);
370 ShowWindow( hWndTest
, SW_SHOW
);
371 SetWindowPos( hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
372 SetForegroundWindow( hWndTest
);
373 UpdateWindow( hWndTest
);
375 /* flush pending messages */
376 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
378 SetFocus( hWndTest
);
379 TestSysKeys( hWndTest
);
380 DestroyWindow(hWndTest
);
383 static inline BOOL
is_keyboard_message( UINT message
)
385 return (message
>= WM_KEYFIRST
&& message
<= WM_KEYLAST
);
388 static inline BOOL
is_mouse_message( UINT message
)
390 return (message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
);
393 /* try to make sure pending X events have been processed before continuing */
394 static void empty_message_queue(void)
398 int min_timeout
= 50;
399 DWORD time
= GetTickCount() + diff
;
403 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
404 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
406 if (is_keyboard_message(msg
.message
) || is_mouse_message(msg
.message
))
407 ok(msg
.time
!= 0, "message %#x has time set to 0\n", msg
.message
);
409 TranslateMessage(&msg
);
410 DispatchMessageA(&msg
);
412 diff
= time
- GetTickCount();
416 struct transition_s
{
436 UINT message
; /* the WM_* code */
437 msg_flags_t flags
; /* message props */
438 WPARAM wParam
; /* expected value of wParam */
439 LPARAM lParam
; /* expected value of lParam */
442 static const struct sendinput_test_s
{
446 struct transition_s expected_transitions
[MAXKEYEVENTS
+1];
447 struct message expected_messages
[MAXKEYMESSAGES
+1];
448 } sendinput_test
[] = {
451 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
452 {{WM_SYSKEYDOWN
, hook
|wparam
, VK_LMENU
}, {WM_SYSKEYDOWN
}, {0}}},
453 {'F', 0, FALSE
, {{'F', 0x00}, {0}},
454 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
},
456 {WM_SYSCOMMAND
}, {0}}},
457 {'F', KEYEVENTF_KEYUP
, FALSE
, {{'F', 0x80}, {0}},
458 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
459 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
460 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
464 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
465 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
466 {'O', 0, FALSE
, {{'O', 0x00}, {0}},
467 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
468 {'O', KEYEVENTF_KEYUP
, FALSE
, {{'O', 0x80}, {0}},
469 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
470 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
471 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
473 /* test ALT+CTRL+X */
475 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
476 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
}, {0}}},
477 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
478 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
479 {'X', 0, FALSE
, {{'X', 0x00}, {0}},
480 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
481 {'X', KEYEVENTF_KEYUP
, FALSE
, {{'X', 0x80}, {0}},
482 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
483 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
484 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
485 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
486 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
490 {VK_LSHIFT
, 0, FALSE
, {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
491 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
492 {'A', 0, FALSE
, {{'A', 0x00}, {0}},
493 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
494 {'A', KEYEVENTF_KEYUP
, FALSE
, {{'A', 0x80}, {0}},
495 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
496 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
, {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
497 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
498 /* test L-SHIFT & R-SHIFT: */
499 /* RSHIFT == LSHIFT */
501 {VK_RSHIFT
, 0, FALSE
,
502 /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
503 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00, TRUE
}, {VK_RSHIFT
, 0x00, TRUE
}, {0}},
504 {{WM_KEYDOWN
, hook
|wparam
, VK_RSHIFT
},
506 {VK_RSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
507 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80, TRUE
}, {VK_RSHIFT
, 0x80, TRUE
}, {0}},
508 {{WM_KEYUP
, hook
, hook
|wparam
, VK_RSHIFT
},
511 /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
513 {VK_LSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
514 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
515 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_EXTENDED
},
516 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
517 {VK_LSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
518 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
519 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
520 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
521 /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
523 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
524 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
525 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
526 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
527 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
528 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
529 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
530 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
532 /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
533 win2k - sends to hook whatever we generated here
534 winXP+ - Attempts to convert key to L/R key but not always correct
536 /* SHIFT == LSHIFT */
539 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
540 {{WM_KEYDOWN
, hook
/* |wparam */|lparam
, VK_SHIFT
, 0},
541 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
542 {VK_SHIFT
, KEYEVENTF_KEYUP
, FALSE
,
543 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
544 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
},
545 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
546 /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
548 {VK_SHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
549 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
550 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_EXTENDED
},
551 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
552 {VK_SHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
553 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
554 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
555 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
557 /* test L-CONTROL & R-CONTROL: */
558 /* RCONTROL == LCONTROL */
560 {VK_RCONTROL
, 0, FALSE
,
561 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
562 {{WM_KEYDOWN
, hook
|wparam
, VK_RCONTROL
},
563 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
564 {VK_RCONTROL
, KEYEVENTF_KEYUP
, FALSE
,
565 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
566 {{WM_KEYUP
, hook
|wparam
, VK_RCONTROL
},
567 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
568 /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
570 {VK_LCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
571 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
572 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_EXTENDED
},
573 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
574 {VK_LCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
575 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
576 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
577 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
578 /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
580 {VK_RCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
581 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
582 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_EXTENDED
},
583 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
584 {VK_RCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
585 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
586 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
587 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
588 /* CONTROL == LCONTROL */
590 {VK_CONTROL
, 0, FALSE
,
591 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
592 {{WM_KEYDOWN
, hook
/*|wparam, VK_CONTROL*/},
593 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
594 {VK_CONTROL
, KEYEVENTF_KEYUP
, FALSE
,
595 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
596 {{WM_KEYUP
, hook
/*|wparam, VK_CONTROL*/},
597 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
598 /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
600 {VK_CONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
601 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
602 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_EXTENDED
},
603 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
604 {VK_CONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
605 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
606 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
607 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
609 /* test L-MENU & R-MENU: */
613 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
614 {{WM_SYSKEYDOWN
, hook
|wparam
|optional
, VK_LCONTROL
},
615 {WM_SYSKEYDOWN
, hook
|wparam
, VK_RMENU
},
616 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
617 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
618 {VK_RMENU
, KEYEVENTF_KEYUP
, TRUE
,
619 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
620 {{WM_KEYUP
, hook
|wparam
|optional
, VK_LCONTROL
},
621 {WM_KEYUP
, hook
|wparam
, VK_RMENU
},
622 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
623 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
624 {WM_SYSCOMMAND
, optional
}, {0}}},
625 /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
627 {VK_LMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
628 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {0}},
629 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_EXTENDED
},
630 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
631 {VK_LMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
632 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {0}},
633 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
634 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
635 {WM_SYSCOMMAND
}, {0}}},
636 /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
638 {VK_RMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
639 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
640 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, 0},
641 {WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_EXTENDED
},
642 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
643 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
644 {VK_RMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
645 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
646 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, LLKHF_UP
},
647 {WM_KEYUP
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
648 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
649 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
650 {WM_SYSCOMMAND
, optional
}, {0}}},
654 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
655 {{WM_SYSKEYDOWN
, hook
/*|wparam, VK_MENU*/},
656 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
657 {VK_MENU
, KEYEVENTF_KEYUP
, TRUE
,
658 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
659 {{WM_KEYUP
, hook
/*|wparam, VK_MENU*/},
660 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
661 {WM_SYSCOMMAND
}, {0}}},
662 /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
664 {VK_MENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
665 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
666 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, 0},
667 {WM_SYSKEYDOWN
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_EXTENDED
},
668 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
669 {VK_MENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
670 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
671 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, LLKHF_UP
},
672 {WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_UP
|LLKHF_EXTENDED
},
673 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
674 {WM_SYSCOMMAND
}, {0}}},
676 /* test LSHIFT & RSHIFT */
678 {VK_LSHIFT
, 0, FALSE
,
679 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
680 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, 0},
681 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
682 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
683 {{VK_RSHIFT
, 0x00}, {0}},
684 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
685 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
686 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
687 {{VK_RSHIFT
, 0x80}, {0}},
688 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
689 {WM_KEYUP
, optional
}, {0}}},
690 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
691 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
692 {{WM_KEYUP
, hook
|wparam
, VK_LSHIFT
},
693 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
695 {0, 0, FALSE
, {{0}}, {{0}}} /* end */
698 static struct message sent_messages
[MAXKEYMESSAGES
];
699 static UINT sent_messages_cnt
;
701 /* Verify that only specified key state transitions occur */
702 static void compare_and_check(int id
, BYTE
*ks1
, BYTE
*ks2
,
703 const struct sendinput_test_s
*test
, BOOL foreground
)
705 int i
, failcount
= 0;
706 const struct transition_s
*t
= test
->expected_transitions
;
708 const struct message
*expected
= test
->expected_messages
;
710 while (t
->wVk
&& foreground
) {
711 /* We won't receive any information from GetKeyboardState() if we're
712 * not the foreground window. */
713 BOOL matched
= ((ks1
[t
->wVk
]&0x80) == (t
->before_state
&0x80)
714 && (ks2
[t
->wVk
]&0x80) == (~t
->before_state
&0x80));
716 if (!matched
&& !t
->optional
&& test
->_todo_wine
)
720 ok(matched
, "%2d (%x/%x): %02x from %02x -> %02x "
721 "instead of %02x -> %02x\n", id
, test
->wVk
, test
->dwFlags
,
722 t
->wVk
, ks1
[t
->wVk
]&0x80, ks2
[t
->wVk
]&0x80, t
->before_state
,
723 ~t
->before_state
&0x80);
726 ok(matched
|| t
->optional
, "%2d (%x/%x): %02x from %02x -> %02x "
727 "instead of %02x -> %02x\n", id
, test
->wVk
, test
->dwFlags
,
728 t
->wVk
, ks1
[t
->wVk
]&0x80, ks2
[t
->wVk
]&0x80, t
->before_state
,
729 ~t
->before_state
&0x80);
731 ks2
[t
->wVk
] = ks1
[t
->wVk
]; /* clear the match */
734 for (i
= 0; i
< 256; i
++)
735 if (ks2
[i
] != ks1
[i
] && test
->_todo_wine
)
739 ok(FALSE
, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
740 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
743 ok(ks2
[i
] == ks1
[i
], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
744 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
746 while (expected
->message
&& actual_cnt
< sent_messages_cnt
)
748 const struct message
*actual
= &sent_messages
[actual_cnt
];
750 if (expected
->message
== actual
->message
)
752 if (expected
->flags
& wparam
)
754 if ((expected
->flags
& optional
) && (expected
->wParam
!= actual
->wParam
))
759 if (expected
->wParam
!= actual
->wParam
&& test
->_todo_wine
)
763 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
764 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
767 ok(expected
->wParam
== actual
->wParam
,
768 "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
769 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
771 if (expected
->flags
& lparam
)
773 if (expected
->lParam
!= actual
->lParam
&& test
->_todo_wine
)
777 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
778 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
781 ok(expected
->lParam
== actual
->lParam
,
782 "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
783 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
785 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
786 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
787 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
790 else if (expected
->flags
& optional
)
795 else if (!(expected
->flags
& hook
) && !foreground
)
797 /* If we weren't able to receive foreground status, we won't get
798 * any window messages. */
802 /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
803 else if ((expected
->flags
& hook
) &&
804 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
805 (actual
->message
== expected
->message
- 4))
807 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
808 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
809 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
811 /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
812 * instead of SYSKEYDOWN/UP to the WNDPROC */
813 else if (test
->wVk
== VK_RMENU
&& !(expected
->flags
& hook
) &&
814 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
815 (actual
->message
== expected
->message
- 4))
817 ok(expected
->wParam
== actual
->wParam
&& expected
->lParam
== actual
->lParam
,
818 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
819 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
821 else if (test
->_todo_wine
)
826 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
827 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
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
);
837 /* skip all optional trailing messages */
838 while (expected
->message
&& ((expected
->flags
& optional
) || (!(expected
->flags
& hook
) && !foreground
)))
842 if (expected
->message
|| actual_cnt
< sent_messages_cnt
)
844 if (test
->_todo_wine
)
848 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
849 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
852 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
853 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
856 if( test
->_todo_wine
&& !failcount
) /* succeeded yet marked todo */
858 ok(TRUE
, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id
, test
->wVk
, test
->dwFlags
);
860 sent_messages_cnt
= 0;
863 /* WndProc2 checks that we get at least the messages specified */
864 static LRESULT CALLBACK
WndProc2(HWND hWnd
, UINT Msg
, WPARAM wParam
,
867 if (winetest_debug
> 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg
, wParam
, lParam
);
869 if ((Msg
>= WM_KEYFIRST
&& Msg
<= WM_KEYLAST
) || Msg
== WM_SYSCOMMAND
)
871 ok(sent_messages_cnt
< MAXKEYMESSAGES
, "Too many messages\n");
872 if (sent_messages_cnt
< MAXKEYMESSAGES
)
874 sent_messages
[sent_messages_cnt
].message
= Msg
;
875 sent_messages
[sent_messages_cnt
].flags
= 0;
876 sent_messages
[sent_messages_cnt
].wParam
= wParam
;
877 sent_messages
[sent_messages_cnt
++].lParam
= HIWORD(lParam
) & (KF_UP
|KF_EXTENDED
);
880 return DefWindowProcA(hWnd
, Msg
, wParam
, lParam
);
883 static LRESULT CALLBACK
hook_proc(int code
, WPARAM wparam
, LPARAM lparam
)
885 KBDLLHOOKSTRUCT
*hook_info
= (KBDLLHOOKSTRUCT
*)lparam
;
887 if (code
== HC_ACTION
)
889 ok(sent_messages_cnt
< MAXKEYMESSAGES
, "Too many messages\n");
890 if (sent_messages_cnt
< MAXKEYMESSAGES
)
892 sent_messages
[sent_messages_cnt
].message
= wparam
;
893 sent_messages
[sent_messages_cnt
].flags
= hook
;
894 sent_messages
[sent_messages_cnt
].wParam
= hook_info
->vkCode
;
895 sent_messages
[sent_messages_cnt
++].lParam
= hook_info
->flags
& (LLKHF_UP
|LLKHF_EXTENDED
);
898 if(0) /* For some reason not stable on Wine */
900 if (wparam
== WM_KEYDOWN
|| wparam
== WM_SYSKEYDOWN
)
901 ok(!(GetAsyncKeyState(hook_info
->vkCode
) & 0x8000), "key %x should be up\n", hook_info
->vkCode
);
902 else if (wparam
== WM_KEYUP
|| wparam
== WM_SYSKEYUP
)
903 ok(GetAsyncKeyState(hook_info
->vkCode
) & 0x8000, "key %x should be down\n", hook_info
->vkCode
);
906 if (winetest_debug
> 1)
907 trace("Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam
,
908 hook_info
->vkCode
, hook_info
->scanCode
, hook_info
->flags
, hook_info
->dwExtraInfo
);
910 return CallNextHookEx( 0, code
, wparam
, lparam
);
912 static void test_Input_blackbox(void)
916 BYTE ks1
[256], ks2
[256];
917 LONG_PTR prevWndProc
;
922 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409)
924 skip("Skipping Input_blackbox test on non-US keyboard\n");
927 window
= CreateWindowA("Static", NULL
, WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
928 |WS_VISIBLE
, 0, 0, 200, 60, NULL
, NULL
,
930 ok(window
!= NULL
, "error: %d\n", (int) GetLastError());
931 SetWindowPos( window
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
932 foreground
= SetForegroundWindow( window
);
934 skip("Failed to set foreground window; some tests will be skipped.\n");
936 if (!(hook
= SetWindowsHookExA(WH_KEYBOARD_LL
, hook_proc
, GetModuleHandleA( NULL
), 0)))
938 DestroyWindow(window
);
939 win_skip("WH_KEYBOARD_LL is not supported\n");
943 /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
944 * key state set by SendInput(). */
945 empty_message_queue();
947 prevWndProc
= SetWindowLongPtrA(window
, GWLP_WNDPROC
, (LONG_PTR
) WndProc2
);
948 ok(prevWndProc
!= 0 || GetLastError() == 0, "error: %d\n", (int) GetLastError());
950 i
.type
= INPUT_KEYBOARD
;
952 i
.u
.ki
.dwExtraInfo
= 0;
954 for (ii
= 0; ii
< ARRAY_SIZE(sendinput_test
)-1; ii
++) {
955 GetKeyboardState(ks1
);
956 i
.u
.ki
.wScan
= ii
+1 /* useful for debugging */;
957 i
.u
.ki
.dwFlags
= sendinput_test
[ii
].dwFlags
;
958 i
.u
.ki
.wVk
= sendinput_test
[ii
].wVk
;
959 SendInput(1, (INPUT
*)&i
, sizeof(TEST_INPUT
));
960 empty_message_queue();
961 GetKeyboardState(ks2
);
962 compare_and_check(ii
, ks1
, ks2
, &sendinput_test
[ii
], foreground
);
965 empty_message_queue();
966 DestroyWindow(window
);
967 UnhookWindowsHookEx(hook
);
970 static void reset_key_status(WORD vk
)
972 key_status
.last_key_down
= -1;
973 key_status
.last_key_up
= -1;
974 key_status
.last_syskey_down
= -1;
975 key_status
.last_syskey_up
= -1;
976 key_status
.last_char
= -1;
977 key_status
.last_syschar
= -1;
978 key_status
.last_hook_down
= -1;
979 key_status
.last_hook_up
= -1;
980 key_status
.last_hook_syskey_down
= -1;
981 key_status
.last_hook_syskey_up
= -1;
983 key_status
.expect_alt
= FALSE
;
984 key_status
.sendinput_broken
= FALSE
;
987 static void test_unicode_keys(HWND hwnd
, HHOOK hook
)
989 TEST_INPUT inputs
[2];
992 /* init input data that never changes */
993 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
994 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
995 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
997 /* pressing & releasing a single unicode character */
998 inputs
[0].u
.ki
.wVk
= 0;
999 inputs
[0].u
.ki
.wScan
= 0x3c0;
1000 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1002 reset_key_status(VK_PACKET
);
1003 SendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1004 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1005 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1006 TranslateMessage(&msg
);
1008 DispatchMessageW(&msg
);
1010 if(!key_status
.sendinput_broken
){
1011 ok(key_status
.last_key_down
== VK_PACKET
,
1012 "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_down
);
1013 ok(key_status
.last_char
== 0x3c0,
1014 "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status
.last_char
);
1016 ok(key_status
.last_hook_down
== 0x3c0,
1017 "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_down
);
1020 inputs
[1].u
.ki
.wVk
= 0;
1021 inputs
[1].u
.ki
.wScan
= 0x3c0;
1022 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1024 reset_key_status(VK_PACKET
);
1025 SendInput(1, (INPUT
*)(inputs
+1), sizeof(INPUT
));
1026 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1027 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1028 TranslateMessage(&msg
);
1030 DispatchMessageW(&msg
);
1032 if(!key_status
.sendinput_broken
){
1033 ok(key_status
.last_key_up
== VK_PACKET
,
1034 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1036 ok(key_status
.last_hook_up
== 0x3c0,
1037 "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_up
);
1040 /* holding alt, pressing & releasing a unicode character, releasing alt */
1041 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1042 inputs
[0].u
.ki
.wScan
= 0;
1043 inputs
[0].u
.ki
.dwFlags
= 0;
1045 inputs
[1].u
.ki
.wVk
= 0;
1046 inputs
[1].u
.ki
.wScan
= 0x3041;
1047 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1049 reset_key_status(VK_PACKET
);
1050 key_status
.expect_alt
= TRUE
;
1051 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1052 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1053 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1054 TranslateMessage(&msg
);
1056 DispatchMessageW(&msg
);
1058 if(!key_status
.sendinput_broken
){
1059 ok(key_status
.last_syskey_down
== VK_PACKET
,
1060 "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_syskey_down
);
1061 ok(key_status
.last_syschar
== 0x3041,
1062 "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status
.last_syschar
);
1064 ok(key_status
.last_hook_syskey_down
== 0x3041,
1065 "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_syskey_down
);
1068 inputs
[1].u
.ki
.wVk
= 0;
1069 inputs
[1].u
.ki
.wScan
= 0x3041;
1070 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1072 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1073 inputs
[0].u
.ki
.wScan
= 0;
1074 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1076 reset_key_status(VK_PACKET
);
1077 key_status
.expect_alt
= TRUE
;
1078 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1079 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1080 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1081 TranslateMessage(&msg
);
1083 DispatchMessageW(&msg
);
1085 if(!key_status
.sendinput_broken
){
1086 ok(key_status
.last_key_up
== VK_PACKET
,
1087 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1089 ok(key_status
.last_hook_up
== 0x3041,
1090 "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_up
);
1093 /* Press and release, non-zero key code. */
1094 inputs
[0].u
.ki
.wVk
= 0x51;
1095 inputs
[0].u
.ki
.wScan
= 0x123;
1096 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1098 inputs
[1].u
.ki
.wVk
= 0x51;
1099 inputs
[1].u
.ki
.wScan
= 0x123;
1100 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1102 reset_key_status(inputs
[0].u
.ki
.wVk
);
1103 SendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1104 while (PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
))
1106 TranslateMessage(&msg
);
1107 DispatchMessageW(&msg
);
1110 if (!key_status
.sendinput_broken
)
1112 ok(key_status
.last_key_down
== 0x51, "Unexpected key down %#x.\n", key_status
.last_key_down
);
1113 ok(key_status
.last_key_up
== 0x51, "Unexpected key up %#x.\n", key_status
.last_key_up
);
1116 ok(key_status
.last_hook_up
== 0x23, "Unexpected hook message %#x.\n", key_status
.last_hook_up
);
1120 static LRESULT CALLBACK
unicode_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1125 key_status
.last_key_down
= wParam
;
1128 key_status
.last_syskey_down
= wParam
;
1131 key_status
.last_key_up
= wParam
;
1134 key_status
.last_syskey_up
= wParam
;
1137 key_status
.last_char
= wParam
;
1140 key_status
.last_syschar
= wParam
;
1143 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1146 static LRESULT CALLBACK
llkbd_unicode_hook(int nCode
, WPARAM wParam
, LPARAM lParam
)
1148 if(nCode
== HC_ACTION
){
1149 LPKBDLLHOOKSTRUCT info
= (LPKBDLLHOOKSTRUCT
)lParam
;
1151 key_status
.sendinput_broken
= TRUE
;
1152 win_skip("SendInput doesn't support unicode on this platform\n");
1154 if(key_status
.expect_alt
){
1155 ok(info
->vkCode
== VK_LMENU
, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU
, info
->vkCode
);
1156 key_status
.expect_alt
= FALSE
;
1158 todo_wine_if(key_status
.vk
!= VK_PACKET
)
1159 ok(info
->vkCode
== key_status
.vk
, "Unexpected vkCode %#x, expected %#x.\n", info
->vkCode
, key_status
.vk
);
1163 key_status
.last_hook_down
= info
->scanCode
;
1166 key_status
.last_hook_up
= info
->scanCode
;
1169 key_status
.last_hook_syskey_down
= info
->scanCode
;
1172 key_status
.last_hook_syskey_up
= info
->scanCode
;
1176 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
1179 static void test_Input_unicode(void)
1181 WCHAR classNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1182 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1183 WCHAR windowNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1184 'K','e','y','T','e','s','t',0};
1187 HANDLE hInstance
= GetModuleHandleW(NULL
);
1189 HMODULE hModuleImm32
;
1190 BOOL (WINAPI
*pImmDisableIME
)(DWORD
);
1192 wclass
.lpszClassName
= classNameW
;
1193 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1194 wclass
.lpfnWndProc
= unicode_wnd_proc
;
1195 wclass
.hInstance
= hInstance
;
1196 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1197 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1198 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1199 wclass
.lpszMenuName
= 0;
1200 wclass
.cbClsExtra
= 0;
1201 wclass
.cbWndExtra
= 0;
1202 if(!RegisterClassW(&wclass
)){
1203 win_skip("Unicode functions not supported\n");
1207 hModuleImm32
= LoadLibraryA("imm32.dll");
1209 pImmDisableIME
= (void *)GetProcAddress(hModuleImm32
, "ImmDisableIME");
1213 pImmDisableIME
= NULL
;
1214 FreeLibrary(hModuleImm32
);
1216 /* create the test window that will receive the keystrokes */
1217 hWndTest
= CreateWindowW(wclass
.lpszClassName
, windowNameW
,
1218 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1219 NULL
, NULL
, hInstance
, NULL
);
1222 assert(IsWindowUnicode(hWndTest
));
1224 hook
= SetWindowsHookExW(WH_KEYBOARD_LL
, llkbd_unicode_hook
, GetModuleHandleW(NULL
), 0);
1226 win_skip("unable to set WH_KEYBOARD_LL hook\n");
1228 ShowWindow(hWndTest
, SW_SHOW
);
1229 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1230 SetForegroundWindow(hWndTest
);
1231 UpdateWindow(hWndTest
);
1233 /* flush pending messages */
1234 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1238 test_unicode_keys(hWndTest
, hook
);
1241 UnhookWindowsHookEx(hook
);
1242 DestroyWindow(hWndTest
);
1245 static void test_keynames(void)
1250 for (i
= 0; i
< 512; i
++)
1252 strcpy(buff
, "----");
1253 len
= GetKeyNameTextA(i
<< 16, buff
, sizeof(buff
));
1254 ok(len
|| !buff
[0], "%d: Buffer is not zeroed\n", i
);
1258 static POINT pt_old
, pt_new
;
1259 static BOOL clipped
;
1262 static LRESULT CALLBACK
hook_proc1( int code
, WPARAM wparam
, LPARAM lparam
)
1264 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1267 if (code
== HC_ACTION
)
1269 /* This is our new cursor position */
1271 /* Should return previous position */
1273 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1275 /* Should set new position until hook chain is finished. */
1276 pt
.x
= pt_old
.x
+ STEP
;
1277 pt
.y
= pt_old
.y
+ STEP
;
1278 SetCursorPos(pt
.x
, pt
.y
);
1281 ok(pt1
.x
== pt_old
.x
&& pt1
.y
== pt_old
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1283 ok(pt1
.x
== pt
.x
&& pt1
.y
== pt
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1285 return CallNextHookEx( 0, code
, wparam
, lparam
);
1288 static LRESULT CALLBACK
hook_proc2( int code
, WPARAM wparam
, LPARAM lparam
)
1290 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1293 if (code
== HC_ACTION
)
1295 ok(hook
->pt
.x
== pt_new
.x
&& hook
->pt
.y
== pt_new
.y
,
1296 "Wrong hook coords: (%d %d) != (%d,%d)\n", hook
->pt
.x
, hook
->pt
.y
, pt_new
.x
, pt_new
.y
);
1298 /* Should match position set above */
1301 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1303 ok(pt
.x
== pt_old
.x
+STEP
&& pt
.y
== pt_old
.y
+STEP
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1305 return CallNextHookEx( 0, code
, wparam
, lparam
);
1308 static LRESULT CALLBACK
hook_proc3( int code
, WPARAM wparam
, LPARAM lparam
)
1312 if (code
== HC_ACTION
)
1314 /* MSLLHOOKSTRUCT does not seem to be reliable and contains different data on each run. */
1316 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1318 return CallNextHookEx( 0, code
, wparam
, lparam
);
1321 static void test_mouse_ll_hook(void)
1328 GetCursorPos(&pt_org
);
1329 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1330 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
1331 SetCursorPos(100, 100);
1333 if (!(hook2
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc2
, GetModuleHandleA(0), 0)))
1335 win_skip( "cannot set MOUSE_LL hook\n" );
1338 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc1
, GetModuleHandleA(0), 0);
1340 GetCursorPos(&pt_old
);
1341 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, 0, 0, 0);
1342 GetCursorPos(&pt_old
);
1343 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
);
1344 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, 0, 0, 0);
1345 GetCursorPos(&pt_old
);
1346 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
);
1347 mouse_event(MOUSEEVENTF_MOVE
, 0, -STEP
, 0, 0);
1348 GetCursorPos(&pt_old
);
1349 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
);
1350 mouse_event(MOUSEEVENTF_MOVE
, 0, +STEP
, 0, 0);
1351 GetCursorPos(&pt_old
);
1352 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
);
1354 SetRect(&rc
, 50, 50, 151, 151);
1358 SetCursorPos(40, 40);
1359 GetCursorPos(&pt_old
);
1360 ok(pt_old
.x
== 50 && pt_old
.y
== 50, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1361 SetCursorPos(160, 160);
1362 GetCursorPos(&pt_old
);
1363 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1364 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1365 GetCursorPos(&pt_old
);
1366 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1369 pt_new
.x
= pt_new
.y
= 150;
1371 UnhookWindowsHookEx(hook1
);
1373 /* Now check that mouse buttons do not change mouse position
1374 if we don't have MOUSEEVENTF_MOVE flag specified. */
1376 /* We reusing the same hook callback, so make it happy */
1377 pt_old
.x
= pt_new
.x
- STEP
;
1378 pt_old
.y
= pt_new
.y
- STEP
;
1379 mouse_event(MOUSEEVENTF_LEFTUP
, 123, 456, 0, 0);
1381 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1382 mouse_event(MOUSEEVENTF_RIGHTUP
, 456, 123, 0, 0);
1384 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1386 mouse_event(MOUSEEVENTF_LEFTUP
| MOUSEEVENTF_ABSOLUTE
, 123, 456, 0, 0);
1388 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1389 mouse_event(MOUSEEVENTF_RIGHTUP
| MOUSEEVENTF_ABSOLUTE
, 456, 123, 0, 0);
1391 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1393 UnhookWindowsHookEx(hook2
);
1394 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc3
, GetModuleHandleA(0), 0);
1396 SetRect(&rc
, 150, 150, 150, 150);
1400 SetCursorPos(140, 140);
1401 GetCursorPos(&pt_old
);
1402 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1403 SetCursorPos(160, 160);
1404 GetCursorPos(&pt_old
);
1406 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1407 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, -STEP
, 0, 0);
1408 GetCursorPos(&pt_old
);
1409 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1410 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1411 GetCursorPos(&pt_old
);
1413 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1414 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1415 GetCursorPos(&pt_old
);
1416 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1417 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1418 GetCursorPos(&pt_old
);
1420 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1425 SetCursorPos(140, 140);
1426 SetRect(&rc
, 150, 150, 150, 150);
1428 GetCursorPos(&pt_old
);
1429 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1432 SetCursorPos(160, 160);
1433 SetRect(&rc
, 150, 150, 150, 150);
1435 GetCursorPos(&pt_old
);
1437 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1440 SetCursorPos(150, 150);
1441 SetRect(&rc
, 150, 150, 150, 150);
1443 GetCursorPos(&pt_old
);
1445 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1448 UnhookWindowsHookEx(hook1
);
1451 DestroyWindow(hwnd
);
1452 SetCursorPos(pt_org
.x
, pt_org
.y
);
1455 static void test_GetMouseMovePointsEx(void)
1458 #define MYERROR 0xdeadbeef
1461 MOUSEMOVEPOINT out
[200];
1464 /* Get a valid content for the input struct */
1465 if(!GetCursorPos(&point
)) {
1466 win_skip("GetCursorPos() failed with error %u\n", GetLastError());
1469 memset(&in
, 0, sizeof(MOUSEMOVEPOINT
));
1473 /* test first parameter
1474 * everything different than sizeof(MOUSEMOVEPOINT)
1475 * is expected to fail with ERROR_INVALID_PARAMETER
1477 SetLastError(MYERROR
);
1478 retval
= pGetMouseMovePointsEx(0, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1479 if (retval
== ERROR_INVALID_PARAMETER
)
1481 win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1484 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1485 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1486 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1488 SetLastError(MYERROR
);
1489 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1490 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1491 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1492 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1494 SetLastError(MYERROR
);
1495 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)+1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1496 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1497 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1498 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1500 /* test second and third parameter
1502 SetLastError(MYERROR
);
1503 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1504 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1505 ok(GetLastError() == ERROR_NOACCESS
|| GetLastError() == MYERROR
,
1506 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1508 SetLastError(MYERROR
);
1509 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1510 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1511 ok(ERROR_NOACCESS
== GetLastError(),
1512 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1514 SetLastError(MYERROR
);
1515 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1516 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1517 ok(ERROR_NOACCESS
== GetLastError(),
1518 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1520 SetLastError(MYERROR
);
1522 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, count
, GMMP_USE_DISPLAY_POINTS
);
1524 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1526 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1528 /* test fourth parameter
1529 * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1531 SetLastError(MYERROR
);
1533 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1534 ok(retval
== count
, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1535 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1536 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1538 SetLastError(MYERROR
);
1540 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1542 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1544 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1546 SetLastError(MYERROR
);
1548 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1550 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1552 ok((0 <= retval
) && (retval
<= count
), "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1554 SetLastError(MYERROR
);
1555 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1556 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1557 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1558 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1560 /* it was not possible to force an error with the fifth parameter on win2k */
1562 /* test combinations of wrong parameters to see which error wins */
1563 SetLastError(MYERROR
);
1564 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1565 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1566 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1567 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1569 SetLastError(MYERROR
);
1570 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1571 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1572 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1573 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1575 SetLastError(MYERROR
);
1576 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1577 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1578 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1579 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1581 SetLastError(MYERROR
);
1582 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1583 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1584 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1585 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1591 static void test_GetRawInputDeviceList(void)
1593 RAWINPUTDEVICELIST devices
[32];
1594 UINT ret
, oret
, devcount
, odevcount
, i
;
1597 SetLastError(0xdeadbeef);
1598 ret
= pGetRawInputDeviceList(NULL
, NULL
, 0);
1599 err
= GetLastError();
1600 ok(ret
== -1, "expected -1, got %d\n", ret
);
1601 ok(err
== ERROR_INVALID_PARAMETER
, "expected 87, got %d\n", err
);
1603 SetLastError(0xdeadbeef);
1604 ret
= pGetRawInputDeviceList(NULL
, NULL
, sizeof(devices
[0]));
1605 err
= GetLastError();
1606 ok(ret
== -1, "expected -1, got %d\n", ret
);
1607 ok(err
== ERROR_NOACCESS
, "expected 998, got %d\n", err
);
1610 ret
= pGetRawInputDeviceList(NULL
, &devcount
, sizeof(devices
[0]));
1611 ok(ret
== 0, "expected 0, got %d\n", ret
);
1612 ok(devcount
> 0, "expected non-zero\n");
1614 SetLastError(0xdeadbeef);
1616 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1617 err
= GetLastError();
1618 ok(ret
== -1, "expected -1, got %d\n", ret
);
1619 ok(err
== ERROR_INSUFFICIENT_BUFFER
, "expected 122, got %d\n", err
);
1620 ok(devcount
> 0, "expected non-zero\n");
1622 /* devcount contains now the correct number of devices */
1623 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1624 ok(ret
> 0, "expected non-zero\n");
1626 for(i
= 0; i
< devcount
; ++i
)
1631 RID_DEVICE_INFO info
;
1634 /* get required buffer size */
1637 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICENAME
, name
, &sz
);
1638 ok(ret
== -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err
);
1639 ok(sz
> 5 && sz
< ARRAY_SIZE(name
), "Size should have been set and not too large (got: %u)\n", sz
);
1641 /* buffer size for RIDI_DEVICENAME is in CHARs, not BYTEs */
1642 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICENAME
, name
, &sz
);
1643 ok(ret
== sz
, "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1644 len
= lstrlenW(name
);
1645 ok(len
+ 1 == ret
, "GetRawInputDeviceInfo returned wrong length (name: %u, ret: %u)\n", len
+ 1, ret
);
1647 /* test A variant with same size */
1648 ret
= pGetRawInputDeviceInfoA(devices
[i
].hDevice
, RIDI_DEVICENAME
, nameA
, &sz
);
1649 ok(ret
== sz
, "GetRawInputDeviceInfoA gave wrong return: %d\n", err
);
1650 len
= strlen(nameA
);
1651 ok(len
+ 1 == ret
, "GetRawInputDeviceInfoA returned wrong length (name: %u, ret: %u)\n", len
+ 1, ret
);
1653 /* buffer size for RIDI_DEVICEINFO is in BYTEs */
1654 memset(&info
, 0, sizeof(info
));
1655 info
.cbSize
= sizeof(info
);
1656 sz
= sizeof(info
) - 1;
1657 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1658 ok(ret
== -1, "GetRawInputDeviceInfo gave wrong failure: %d\n", err
);
1659 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1661 ret
= pGetRawInputDeviceInfoW(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1662 ok(ret
== sizeof(info
), "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1663 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1664 ok(info
.dwType
== devices
[i
].dwType
, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info
.dwType
);
1666 memset(&info
, 0, sizeof(info
));
1667 info
.cbSize
= sizeof(info
);
1668 ret
= pGetRawInputDeviceInfoA(devices
[i
].hDevice
, RIDI_DEVICEINFO
, &info
, &sz
);
1669 ok(ret
== sizeof(info
), "GetRawInputDeviceInfo gave wrong return: %d\n", err
);
1670 ok(sz
== sizeof(info
), "GetRawInputDeviceInfo set wrong size\n");
1671 ok(info
.dwType
== devices
[i
].dwType
, "GetRawInputDeviceInfo set wrong type: 0x%x\n", info
.dwType
);
1673 /* setupapi returns an NT device path, but CreateFile() < Vista can't
1674 * understand that; so use the \\?\ prefix instead */
1676 file
= CreateFileW(name
, 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
1677 todo_wine_if(info
.dwType
!= RIM_TYPEHID
)
1678 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to open %s, error %u\n", wine_dbgstr_w(name
), GetLastError());
1682 /* check if variable changes from larger to smaller value */
1683 devcount
= odevcount
= ARRAY_SIZE(devices
);
1684 oret
= ret
= pGetRawInputDeviceList(devices
, &odevcount
, sizeof(devices
[0]));
1685 ok(ret
> 0, "expected non-zero\n");
1686 ok(devcount
== odevcount
, "expected %d, got %d\n", devcount
, odevcount
);
1687 devcount
= odevcount
;
1688 odevcount
= ARRAY_SIZE(devices
);
1689 ret
= pGetRawInputDeviceList(NULL
, &odevcount
, sizeof(devices
[0]));
1690 ok(ret
== 0, "expected 0, got %d\n", ret
);
1691 ok(odevcount
== oret
, "expected %d, got %d\n", oret
, odevcount
);
1694 static void test_GetRawInputData(void)
1699 /* Null raw input handle */
1700 ret
= GetRawInputData(NULL
, RID_INPUT
, NULL
, &size
, sizeof(RAWINPUTHEADER
));
1701 ok(ret
== ~0U, "Expect ret %u, got %u\n", ~0U, ret
);
1704 static void test_key_map(void)
1706 HKL kl
= GetKeyboardLayout(0);
1709 static const UINT numpad_collisions
[][2] = {
1710 { VK_NUMPAD0
, VK_INSERT
},
1711 { VK_NUMPAD1
, VK_END
},
1712 { VK_NUMPAD2
, VK_DOWN
},
1713 { VK_NUMPAD3
, VK_NEXT
},
1714 { VK_NUMPAD4
, VK_LEFT
},
1715 { VK_NUMPAD6
, VK_RIGHT
},
1716 { VK_NUMPAD7
, VK_HOME
},
1717 { VK_NUMPAD8
, VK_UP
},
1718 { VK_NUMPAD9
, VK_PRIOR
},
1721 s
= MapVirtualKeyExA(VK_SHIFT
, MAPVK_VK_TO_VSC
, kl
);
1722 ok(s
!= 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
1723 sL
= MapVirtualKeyExA(VK_LSHIFT
, MAPVK_VK_TO_VSC
, kl
);
1724 ok(s
== sL
|| broken(sL
== 0), /* win9x */
1725 "%x != %x\n", s
, sL
);
1727 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK
, kl
);
1728 ok(kL
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL
);
1729 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK
, kl
);
1730 ok(kR
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR
);
1732 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK_EX
, kl
);
1733 ok(kL
== VK_LSHIFT
|| broken(kL
== 0), /* win9x */
1734 "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL
);
1735 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK_EX
, kl
);
1736 ok(kR
== VK_RSHIFT
|| broken(kR
== 0), /* win9x */
1737 "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR
);
1739 /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
1740 for (i
= 0; i
< ARRAY_SIZE(numpad_collisions
); i
++)
1742 UINT numpad_scan
= MapVirtualKeyExA(numpad_collisions
[i
][0], MAPVK_VK_TO_VSC
, kl
);
1743 UINT other_scan
= MapVirtualKeyExA(numpad_collisions
[i
][1], MAPVK_VK_TO_VSC
, kl
);
1745 /* do they really collide for this layout? */
1746 if (numpad_scan
&& other_scan
== numpad_scan
)
1748 UINT vkey
= MapVirtualKeyExA(numpad_scan
, MAPVK_VSC_TO_VK
, kl
);
1749 ok(vkey
!= numpad_collisions
[i
][0],
1750 "Got numpad vKey %x for scan code %x when there was another choice\n",
1759 static const struct tounicode_tests
1763 WCHAR chr
; /* if vk is 0, lookup vk using this char */
1765 WCHAR expect_buf
[4];
1768 { 'A', 0, 0, 1, {'a',0}},
1769 { 'A', ctrl
, 0, 1, {1, 0}},
1770 { 'A', shift
|ctrl
, 0, 1, {1, 0}},
1771 { VK_TAB
, ctrl
, 0, 0, {0}},
1772 { VK_TAB
, shift
|ctrl
, 0, 0, {0}},
1773 { VK_RETURN
, ctrl
, 0, 1, {'\n', 0}},
1774 { VK_RETURN
, shift
|ctrl
, 0, 0, {0}},
1775 { '4', ctrl
, 0, 0, {0}},
1776 { '4', shift
|ctrl
, 0, 0, {0}},
1777 { 0, ctrl
, '!', 0, {0}},
1778 { 0, ctrl
, '\"', 0, {0}},
1779 { 0, ctrl
, '#', 0, {0}},
1780 { 0, ctrl
, '$', 0, {0}},
1781 { 0, ctrl
, '%', 0, {0}},
1782 { 0, ctrl
, '\'', 0, {0}},
1783 { 0, ctrl
, '(', 0, {0}},
1784 { 0, ctrl
, ')', 0, {0}},
1785 { 0, ctrl
, '*', 0, {0}},
1786 { 0, ctrl
, '+', 0, {0}},
1787 { 0, ctrl
, ',', 0, {0}},
1788 { 0, ctrl
, '-', 0, {0}},
1789 { 0, ctrl
, '.', 0, {0}},
1790 { 0, ctrl
, '/', 0, {0}},
1791 { 0, ctrl
, ':', 0, {0}},
1792 { 0, ctrl
, ';', 0, {0}},
1793 { 0, ctrl
, '<', 0, {0}},
1794 { 0, ctrl
, '=', 0, {0}},
1795 { 0, ctrl
, '>', 0, {0}},
1796 { 0, ctrl
, '?', 0, {0}},
1797 { 0, ctrl
, '@', 1, {0}},
1798 { 0, ctrl
, '[', 1, {0x1b}},
1799 { 0, ctrl
, '\\', 1, {0x1c}},
1800 { 0, ctrl
, ']', 1, {0x1d}},
1801 { 0, ctrl
, '^', 1, {0x1e}},
1802 { 0, ctrl
, '_', 1, {0x1f}},
1803 { 0, ctrl
, '`', 0, {0}},
1804 { VK_SPACE
, 0, 0, 1, {' ',0}},
1805 { VK_SPACE
, shift
, 0, 1, {' ',0}},
1806 { VK_SPACE
, ctrl
, 0, 1, {' ',0}},
1809 static void test_ToUnicode(void)
1813 const BYTE SC_RETURN
= 0x1c, SC_TAB
= 0x0f, SC_A
= 0x1e;
1814 const BYTE HIGHEST_BIT
= 0x80;
1816 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
1818 for(i
=0; i
<256; i
++)
1822 SetLastError(0xdeadbeef);
1823 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, state
, wStr
, 4, 0);
1824 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1826 win_skip("ToUnicode is not implemented\n");
1830 ok(ret
== 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret
);
1833 ok(wStr
[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr
[0]);
1834 ok(wStr
[1]==0 || broken(wStr
[1]!=0) /* nt4 */,
1835 "ToUnicode didn't null-terminate the buffer when there was room.\n");
1838 for (i
= 0; i
< ARRAY_SIZE(utests
); i
++)
1840 UINT vk
= utests
[i
].vk
, mod
= utests
[i
].modifiers
, scan
;
1846 if (!us_kbd
) continue;
1847 vk_ret
= VkKeyScanW(utests
[i
].chr
);
1848 if (vk_ret
== -1) continue;
1850 if (vk_ret
& 0x100) mod
|= shift
;
1851 if (vk_ret
& 0x200) mod
|= ctrl
;
1853 scan
= MapVirtualKeyW(vk
, MAPVK_VK_TO_VSC
);
1855 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = (mod
& shift
) ? HIGHEST_BIT
: 0;
1856 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = (mod
& ctrl
) ? HIGHEST_BIT
: 0;
1858 ret
= ToUnicode(vk
, scan
, state
, wStr
, 4, 0);
1859 ok(ret
== utests
[i
].expect_ret
, "%d: got %d expected %d\n", i
, ret
, utests
[i
].expect_ret
);
1861 ok(!lstrcmpW(wStr
, utests
[i
].expect_buf
), "%d: got %s expected %s\n", i
, wine_dbgstr_w(wStr
),
1862 wine_dbgstr_w(utests
[i
].expect_buf
));
1865 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = 0;
1866 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = 0;
1868 ret
= ToUnicode(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0);
1869 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1870 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0);
1871 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1872 ret
= ToUnicode('A', SC_A
, NULL
, wStr
, 4, 0);
1873 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1874 ret
= ToUnicodeEx(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1875 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1876 ret
= ToUnicodeEx(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1877 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1878 ret
= ToUnicodeEx('A', SC_A
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1879 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1882 static void test_ToAscii(void)
1886 const BYTE SC_RETURN
= 0x1c, SC_A
= 0x1e;
1887 const BYTE HIGHEST_BIT
= 0x80;
1890 memset(state
, 0, sizeof(state
));
1893 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1894 ok(ret
== 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret
);
1895 ok(character
== '\r', "ToAscii for Return was %i (expected 13)\n", character
);
1898 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
1899 ok(ret
== 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret
);
1900 ok(character
== 'a', "ToAscii for character 'A' was %i (expected %i)\n", character
, 'a');
1902 state
[VK_CONTROL
] |= HIGHEST_BIT
;
1903 state
[VK_LCONTROL
] |= HIGHEST_BIT
;
1905 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1906 ok(ret
== 1, "ToAscii for CTRL + Return key didn't return 1 (was %i)\n", ret
);
1907 ok(character
== '\n', "ToAscii for CTRL + Return was %i (expected 10)\n", character
);
1910 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
1911 ok(ret
== 1, "ToAscii for CTRL + character 'A' didn't return 1 (was %i)\n", ret
);
1912 ok(character
== 1, "ToAscii for CTRL + character 'A' was %i (expected 1)\n", character
);
1914 state
[VK_SHIFT
] |= HIGHEST_BIT
;
1915 state
[VK_LSHIFT
] |= HIGHEST_BIT
;
1916 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1917 ok(ret
== 0, "ToAscii for CTRL + Shift + Return key didn't return 0 (was %i)\n", ret
);
1919 ret
= ToAscii(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0);
1920 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
1921 ret
= ToAscii('A', SC_A
, NULL
, &character
, 0);
1922 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
1923 ret
= ToAsciiEx(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0, GetKeyboardLayout(0));
1924 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
1925 ret
= ToAsciiEx('A', SC_A
, NULL
, &character
, 0, GetKeyboardLayout(0));
1926 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
1929 static void test_get_async_key_state(void)
1931 /* input value sanity checks */
1932 ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
1933 ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
1936 static void test_keyboard_layout_name(void)
1939 char klid
[KL_NAMELENGTH
];
1941 if (0) /* crashes on native system */
1942 ret
= GetKeyboardLayoutNameA(NULL
);
1944 SetLastError(0xdeadbeef);
1945 ret
= GetKeyboardLayoutNameW(NULL
);
1946 ok(!ret
, "got %d\n", ret
);
1947 ok(GetLastError() == ERROR_NOACCESS
, "got %d\n", GetLastError());
1949 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409) return;
1952 ret
= GetKeyboardLayoutNameA(klid
);
1953 ok(ret
, "GetKeyboardLayoutNameA failed %u\n", GetLastError());
1954 ok(!strcmp(klid
, "00000409"), "expected 00000409, got %s\n", klid
);
1957 static void test_key_names(void)
1962 LONG lparam
= 0x1d << 16;
1964 memset( buffer
, 0xcc, sizeof(buffer
) );
1965 ret
= GetKeyNameTextA( lparam
, buffer
, sizeof(buffer
) );
1966 ok( ret
> 0, "wrong len %u for '%s'\n", ret
, buffer
);
1967 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
1969 memset( buffer
, 0xcc, sizeof(buffer
) );
1971 ret
= GetKeyNameTextA( lparam
, buffer
, prev
);
1972 ok( ret
== prev
- 1, "wrong len %u for '%s'\n", ret
, buffer
);
1973 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
1975 memset( buffer
, 0xcc, sizeof(buffer
) );
1976 ret
= GetKeyNameTextA( lparam
, buffer
, 0 );
1977 ok( ret
== 0, "wrong len %u for '%s'\n", ret
, buffer
);
1978 ok( buffer
[0] == 0, "wrong string '%s'\n", buffer
);
1980 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1981 ret
= GetKeyNameTextW( lparam
, bufferW
, ARRAY_SIZE(bufferW
));
1982 ok( ret
> 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1983 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1985 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1987 ret
= GetKeyNameTextW( lparam
, bufferW
, prev
);
1988 ok( ret
== prev
- 1, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1989 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1991 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1992 ret
= GetKeyNameTextW( lparam
, bufferW
, 0 );
1993 ok( ret
== 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1994 ok( bufferW
[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW
) );
1997 static void simulate_click(BOOL left
, int x
, int y
)
2003 memset(input
, 0, sizeof(input
));
2004 input
[0].type
= INPUT_MOUSE
;
2005 U(input
[0]).mi
.dx
= x
;
2006 U(input
[0]).mi
.dy
= y
;
2007 U(input
[0]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTDOWN
: MOUSEEVENTF_RIGHTDOWN
;
2008 input
[1].type
= INPUT_MOUSE
;
2009 U(input
[1]).mi
.dx
= x
;
2010 U(input
[1]).mi
.dy
= y
;
2011 U(input
[1]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTUP
: MOUSEEVENTF_RIGHTUP
;
2012 events_no
= SendInput(2, input
, sizeof(input
[0]));
2013 ok(events_no
== 2, "SendInput returned %d\n", events_no
);
2016 static BOOL
wait_for_message( MSG
*msg
)
2022 ret
= PeekMessageA(msg
, 0, 0, 0, PM_REMOVE
);
2025 if (msg
->message
== WM_PAINT
) DispatchMessageA(msg
);
2028 else if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, 100, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
2030 if (!ret
) msg
->message
= 0;
2034 static BOOL
wait_for_event(HANDLE event
, int timeout
)
2036 DWORD end_time
= GetTickCount() + timeout
;
2040 if(MsgWaitForMultipleObjects(1, &event
, FALSE
, timeout
, QS_ALLINPUT
) == WAIT_OBJECT_0
)
2042 while(PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
2043 DispatchMessageA(&msg
);
2044 timeout
= end_time
- GetTickCount();
2045 }while(timeout
> 0);
2050 static WNDPROC def_static_proc
;
2051 static DWORD hittest_no
;
2052 static LRESULT WINAPI
static_hook_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
2054 if (msg
== WM_NCHITTEST
)
2056 /* break infinite hittest loop */
2057 if(hittest_no
> 50) return HTCLIENT
;
2061 return def_static_proc(hwnd
, msg
, wp
, lp
);
2071 static DWORD WINAPI
create_static_win(void *arg
)
2073 struct thread_data
*thread_data
= arg
;
2076 win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2077 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2078 ok(win
!= 0, "CreateWindow failed\n");
2079 def_static_proc
= (void*)SetWindowLongPtrA(win
,
2080 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
2081 thread_data
->win
= win
;
2083 SetEvent(thread_data
->start_event
);
2084 wait_for_event(thread_data
->end_event
, 5000);
2088 static void get_dc_region(RECT
*region
, HWND hwnd
, DWORD flags
)
2094 hdc
= GetDCEx(hwnd
, 0, flags
);
2095 ok(hdc
!= NULL
, "GetDCEx failed\n");
2096 hregion
= CreateRectRgn(40, 40, 60, 60);
2097 ok(hregion
!= NULL
, "CreateRectRgn failed\n");
2098 GetRandomRgn(hdc
, hregion
, SYSRGN
);
2099 region_type
= GetRgnBox(hregion
, region
);
2100 ok(region_type
== SIMPLEREGION
, "expected SIMPLEREGION, got %d\n", region_type
);
2101 DeleteObject(hregion
);
2102 ReleaseDC(hwnd
, hdc
);
2105 static void test_Input_mouse(void)
2107 BOOL got_button_down
, got_button_up
;
2108 HWND hwnd
, button_win
, static_win
;
2109 struct thread_data thread_data
;
2120 SetLastError(0xdeadbeef);
2121 ret
= GetCursorPos(NULL
);
2122 ok(!ret
, "GetCursorPos succeed\n");
2123 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_NOACCESS
, "error %u\n", GetLastError());
2125 SetLastError(0xdeadbeef);
2126 ret
= GetCursorPos(&pt_org
);
2127 ok(ret
, "GetCursorPos failed\n");
2128 ok(GetLastError() == 0xdeadbeef, "error %u\n", GetLastError());
2130 button_win
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
2131 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2132 ok(button_win
!= 0, "CreateWindow failed\n");
2135 hwnd
= WindowFromPoint(pt
);
2136 if (hwnd
!= button_win
)
2138 skip("there's another window covering test window\n");
2139 DestroyWindow(button_win
);
2143 /* simple button click test */
2144 simulate_click(TRUE
, 150, 150);
2145 got_button_down
= got_button_up
= FALSE
;
2146 while (wait_for_message(&msg
))
2148 DispatchMessageA(&msg
);
2150 if (msg
.message
== WM_LBUTTONDOWN
)
2152 got_button_down
= TRUE
;
2154 else if (msg
.message
== WM_LBUTTONUP
)
2156 got_button_up
= TRUE
;
2160 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2161 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2163 /* click through HTTRANSPARENT child window */
2164 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_CHILD
,
2165 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
2166 ok(static_win
!= 0, "CreateWindow failed\n");
2167 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
2168 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
2169 simulate_click(FALSE
, 150, 150);
2171 got_button_down
= got_button_up
= FALSE
;
2172 while (wait_for_message(&msg
))
2174 DispatchMessageA(&msg
);
2176 if (msg
.message
== WM_RBUTTONDOWN
)
2178 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2179 got_button_down
= TRUE
;
2181 else if (msg
.message
== WM_RBUTTONUP
)
2183 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2184 got_button_up
= TRUE
;
2188 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2189 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
2190 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
2191 DestroyWindow(static_win
);
2193 /* click through HTTRANSPARENT top-level window */
2194 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2195 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2196 ok(static_win
!= 0, "CreateWindow failed\n");
2197 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
2198 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
2199 simulate_click(TRUE
, 150, 150);
2201 got_button_down
= got_button_up
= FALSE
;
2202 while (wait_for_message(&msg
))
2204 DispatchMessageA(&msg
);
2206 if (msg
.message
== WM_LBUTTONDOWN
)
2208 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2209 got_button_down
= TRUE
;
2211 else if (msg
.message
== WM_LBUTTONUP
)
2213 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2214 got_button_up
= TRUE
;
2218 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2219 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2220 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2221 DestroyWindow(static_win
);
2223 /* click on HTTRANSPARENT top-level window that belongs to other thread */
2224 thread_data
.start_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2225 ok(thread_data
.start_event
!= NULL
, "CreateEvent failed\n");
2226 thread_data
.end_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2227 ok(thread_data
.end_event
!= NULL
, "CreateEvent failed\n");
2228 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, NULL
);
2229 ok(thread
!= NULL
, "CreateThread failed\n");
2231 got_button_down
= got_button_up
= FALSE
;
2232 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
2233 simulate_click(FALSE
, 150, 150);
2234 while (wait_for_message(&msg
))
2236 DispatchMessageA(&msg
);
2238 if (msg
.message
== WM_RBUTTONDOWN
)
2239 got_button_down
= TRUE
;
2240 else if (msg
.message
== WM_RBUTTONUP
)
2241 got_button_up
= TRUE
;
2243 SetEvent(thread_data
.end_event
);
2244 WaitForSingleObject(thread
, INFINITE
);
2245 CloseHandle(thread
);
2246 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2247 ok(!got_button_down
, "unexpected WM_RBUTTONDOWN message\n");
2248 ok(!got_button_up
, "unexpected WM_RBUTTONUP message\n");
2250 /* click on HTTRANSPARENT top-level window that belongs to other thread,
2251 * thread input queues are attached */
2252 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, &thread_id
);
2253 ok(thread
!= NULL
, "CreateThread failed\n");
2255 got_button_down
= got_button_up
= FALSE
;
2256 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
2257 ok(AttachThreadInput(thread_id
, GetCurrentThreadId(), TRUE
),
2258 "AttachThreadInput failed\n");
2259 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2260 SetWindowPos(thread_data
.win
, button_win
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2261 simulate_click(TRUE
, 150, 150);
2262 while (wait_for_message(&msg
))
2264 DispatchMessageA(&msg
);
2266 if (msg
.message
== WM_LBUTTONDOWN
)
2267 got_button_down
= TRUE
;
2268 else if (msg
.message
== WM_LBUTTONUP
)
2269 got_button_up
= TRUE
;
2271 SetEvent(thread_data
.end_event
);
2272 WaitForSingleObject(thread
, INFINITE
);
2273 todo_wine
ok(hittest_no
> 50, "expected loop with WM_NCHITTEST messages\n");
2274 ok(!got_button_down
, "unexpected WM_LBUTTONDOWN message\n");
2275 ok(!got_button_up
, "unexpected WM_LBUTTONUP message\n");
2277 /* click after SetCapture call */
2278 hwnd
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
2279 0, 0, 100, 100, 0, NULL
, NULL
, NULL
);
2280 ok(hwnd
!= 0, "CreateWindow failed\n");
2281 SetCapture(button_win
);
2282 got_button_down
= got_button_up
= FALSE
;
2283 simulate_click(FALSE
, 50, 50);
2284 while (wait_for_message(&msg
))
2286 DispatchMessageA(&msg
);
2288 if (msg
.message
== WM_RBUTTONDOWN
)
2290 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2291 got_button_down
= TRUE
;
2293 else if (msg
.message
== WM_RBUTTONUP
)
2295 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2296 got_button_up
= TRUE
;
2300 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
2301 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
2302 DestroyWindow(hwnd
);
2304 /* click on child window after SetCapture call */
2305 hwnd
= CreateWindowA("button", "button2", WS_VISIBLE
| WS_CHILD
,
2306 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
2307 ok(hwnd
!= 0, "CreateWindow failed\n");
2308 got_button_down
= got_button_up
= FALSE
;
2309 simulate_click(TRUE
, 150, 150);
2310 while (wait_for_message(&msg
))
2312 DispatchMessageA(&msg
);
2314 if (msg
.message
== WM_LBUTTONDOWN
)
2316 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2317 got_button_down
= TRUE
;
2319 else if (msg
.message
== WM_LBUTTONUP
)
2321 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2322 got_button_up
= TRUE
;
2326 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2327 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2328 DestroyWindow(hwnd
);
2329 ok(ReleaseCapture(), "ReleaseCapture failed\n");
2332 wclass
.lpfnWndProc
= WndProc
;
2333 wclass
.cbClsExtra
= 0;
2334 wclass
.cbWndExtra
= 0;
2335 wclass
.hInstance
= GetModuleHandleA(NULL
);
2336 wclass
.hIcon
= LoadIconA(0, (LPCSTR
)IDI_APPLICATION
);
2337 wclass
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
2338 wclass
.hbrBackground
= CreateSolidBrush(RGB(128, 128, 128));
2339 wclass
.lpszMenuName
= NULL
;
2340 wclass
.lpszClassName
= "InputLayeredTestClass";
2341 RegisterClassA( &wclass
);
2343 /* click through layered window with alpha channel / color key */
2344 hwnd
= CreateWindowA(wclass
.lpszClassName
, "InputLayeredTest",
2345 WS_VISIBLE
| WS_POPUP
, 100, 100, 100, 100, button_win
, NULL
, NULL
, NULL
);
2346 ok(hwnd
!= NULL
, "CreateWindowEx failed\n");
2348 static_win
= CreateWindowA("static", "Title", WS_VISIBLE
| WS_CHILD
,
2349 10, 10, 20, 20, hwnd
, NULL
, NULL
, NULL
);
2350 ok(static_win
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
2352 SetWindowPos(hwnd
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
);
2353 SetWindowLongA(hwnd
, GWL_EXSTYLE
, GetWindowLongA(hwnd
, GWL_EXSTYLE
) | WS_EX_LAYERED
);
2354 ret
= SetLayeredWindowAttributes(hwnd
, 0, 255, LWA_ALPHA
);
2355 ok(ret
, "SetLayeredWindowAttributes failed\n");
2356 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2359 if (pGetWindowRgnBox
)
2361 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2362 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2365 get_dc_region(®ion
, hwnd
, DCX_PARENTCLIP
);
2366 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2367 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2368 get_dc_region(®ion
, hwnd
, DCX_WINDOW
| DCX_USESTYLE
);
2369 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2370 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2371 get_dc_region(®ion
, hwnd
, DCX_USESTYLE
);
2372 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2373 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2374 get_dc_region(®ion
, static_win
, DCX_PARENTCLIP
);
2375 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2376 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2377 get_dc_region(®ion
, static_win
, DCX_WINDOW
| DCX_USESTYLE
);
2378 ok(region
.left
== 110 && region
.top
== 110 && region
.right
== 130 && region
.bottom
== 130,
2379 "expected region (110,110)-(130,130), got %s\n", wine_dbgstr_rect(®ion
));
2380 get_dc_region(®ion
, static_win
, DCX_USESTYLE
);
2381 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2382 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2384 got_button_down
= got_button_up
= FALSE
;
2385 simulate_click(TRUE
, 150, 150);
2386 while (wait_for_message(&msg
))
2388 DispatchMessageA(&msg
);
2390 if (msg
.message
== WM_LBUTTONDOWN
)
2392 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2393 got_button_down
= TRUE
;
2395 else if (msg
.message
== WM_LBUTTONUP
)
2397 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2398 got_button_up
= TRUE
;
2402 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2403 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2405 ret
= SetLayeredWindowAttributes(hwnd
, 0, 0, LWA_ALPHA
);
2406 ok(ret
, "SetLayeredWindowAttributes failed\n");
2407 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2410 if (pGetWindowRgnBox
)
2412 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2413 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2416 got_button_down
= got_button_up
= FALSE
;
2417 simulate_click(TRUE
, 150, 150);
2418 while (wait_for_message(&msg
))
2420 DispatchMessageA(&msg
);
2422 if (msg
.message
== WM_LBUTTONDOWN
)
2424 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2425 got_button_down
= TRUE
;
2427 else if (msg
.message
== WM_LBUTTONUP
)
2429 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2430 got_button_up
= TRUE
;
2434 ok(got_button_down
|| broken(!got_button_down
), "expected WM_LBUTTONDOWN message\n");
2435 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2437 ret
= SetLayeredWindowAttributes(hwnd
, RGB(0, 255, 0), 255, LWA_ALPHA
| LWA_COLORKEY
);
2438 ok(ret
, "SetLayeredWindowAttributes failed\n");
2439 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2442 if (pGetWindowRgnBox
)
2444 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2445 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2448 got_button_down
= got_button_up
= FALSE
;
2449 simulate_click(TRUE
, 150, 150);
2450 while (wait_for_message(&msg
))
2452 DispatchMessageA(&msg
);
2454 if (msg
.message
== WM_LBUTTONDOWN
)
2456 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2457 got_button_down
= TRUE
;
2459 else if (msg
.message
== WM_LBUTTONUP
)
2461 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2462 got_button_up
= TRUE
;
2466 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2467 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2469 ret
= SetLayeredWindowAttributes(hwnd
, RGB(128, 128, 128), 0, LWA_COLORKEY
);
2470 ok(ret
, "SetLayeredWindowAttributes failed\n");
2471 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2474 if (pGetWindowRgnBox
)
2476 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2477 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2480 got_button_down
= got_button_up
= FALSE
;
2481 simulate_click(TRUE
, 150, 150);
2482 while (wait_for_message(&msg
))
2484 DispatchMessageA(&msg
);
2486 if (msg
.message
== WM_LBUTTONDOWN
)
2489 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2490 got_button_down
= TRUE
;
2492 else if (msg
.message
== WM_LBUTTONUP
)
2495 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2496 got_button_up
= TRUE
;
2500 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2501 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2503 SetWindowLongA(hwnd
, GWL_EXSTYLE
, GetWindowLongA(hwnd
, GWL_EXSTYLE
) & ~WS_EX_LAYERED
);
2504 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2507 if (pGetWindowRgnBox
)
2509 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2510 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2513 got_button_down
= got_button_up
= FALSE
;
2514 simulate_click(TRUE
, 150, 150);
2515 while (wait_for_message(&msg
))
2517 DispatchMessageA(&msg
);
2519 if (msg
.message
== WM_LBUTTONDOWN
)
2521 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2522 got_button_down
= TRUE
;
2524 else if (msg
.message
== WM_LBUTTONUP
)
2526 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2527 got_button_up
= TRUE
;
2531 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2532 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2534 hregion
= CreateRectRgn(0, 0, 10, 10);
2535 ok(hregion
!= NULL
, "CreateRectRgn failed\n");
2536 ret
= SetWindowRgn(hwnd
, hregion
, TRUE
);
2537 ok(ret
, "SetWindowRgn failed\n");
2538 DeleteObject(hregion
);
2539 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2542 if (pGetWindowRgnBox
)
2544 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2545 ok(region_type
== SIMPLEREGION
, "expected SIMPLEREGION, got %d\n", region_type
);
2548 got_button_down
= got_button_up
= FALSE
;
2549 simulate_click(TRUE
, 150, 150);
2550 while (wait_for_message(&msg
))
2552 DispatchMessageA(&msg
);
2554 if (msg
.message
== WM_LBUTTONDOWN
)
2556 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2557 got_button_down
= TRUE
;
2559 else if (msg
.message
== WM_LBUTTONUP
)
2561 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2562 got_button_up
= TRUE
;
2566 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2567 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2569 DestroyWindow(static_win
);
2570 DestroyWindow(hwnd
);
2571 SetCursorPos(pt_org
.x
, pt_org
.y
);
2573 CloseHandle(thread_data
.start_event
);
2574 CloseHandle(thread_data
.end_event
);
2575 DestroyWindow(button_win
);
2579 static LRESULT WINAPI
MsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2581 if (message
== WM_USER
+1)
2583 HWND hwnd
= (HWND
)lParam
;
2584 ok(GetFocus() == hwnd
, "thread expected focus %p, got %p\n", hwnd
, GetFocus());
2585 ok(GetActiveWindow() == hwnd
, "thread expected active %p, got %p\n", hwnd
, GetActiveWindow());
2587 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2600 static DWORD WINAPI
thread_proc(void *param
)
2603 struct wnd_event
*wnd_event
= param
;
2606 if (wnd_event
->wait_event
)
2608 ok(WaitForSingleObject(wnd_event
->wait_event
, INFINITE
) == WAIT_OBJECT_0
,
2609 "WaitForSingleObject failed\n");
2610 CloseHandle(wnd_event
->wait_event
);
2613 if (wnd_event
->attach_from
)
2615 ret
= AttachThreadInput(wnd_event
->attach_from
, GetCurrentThreadId(), TRUE
);
2616 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2619 if (wnd_event
->attach_to
)
2621 ret
= AttachThreadInput(GetCurrentThreadId(), wnd_event
->attach_to
, TRUE
);
2622 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2625 wnd_event
->hwnd
= CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW
,
2626 100, 100, 200, 200, 0, 0, 0, NULL
);
2627 ok(wnd_event
->hwnd
!= 0, "Failed to create overlapped window\n");
2629 if (wnd_event
->setWindows
)
2631 SetFocus(wnd_event
->hwnd
);
2632 SetActiveWindow(wnd_event
->hwnd
);
2635 SetEvent(wnd_event
->start_event
);
2637 while (GetMessageA(&msg
, 0, 0, 0))
2639 TranslateMessage(&msg
);
2640 DispatchMessageA(&msg
);
2646 static void test_attach_input(void)
2651 struct wnd_event wnd_event
;
2655 cls
.lpfnWndProc
= MsgCheckProcA
;
2658 cls
.hInstance
= GetModuleHandleA(0);
2660 cls
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
2661 cls
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2662 cls
.lpszMenuName
= NULL
;
2663 cls
.lpszClassName
= "TestWindowClass";
2664 if(!RegisterClassA(&cls
)) return;
2666 wnd_event
.wait_event
= NULL
;
2667 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2668 wnd_event
.attach_from
= 0;
2669 wnd_event
.attach_to
= 0;
2670 wnd_event
.setWindows
= FALSE
;
2671 if (!wnd_event
.start_event
)
2673 win_skip("skipping interthread message test under win9x\n");
2677 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2678 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2680 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2681 CloseHandle(wnd_event
.start_event
);
2683 ourWnd
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
2684 0, 0, 0, 0, 0, 0, 0, NULL
);
2685 ok(ourWnd
!= 0, "failed to create ourWnd window\n");
2687 Wnd2
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
2688 0, 0, 0, 0, 0, 0, 0, NULL
);
2689 ok(Wnd2
!= 0, "failed to create Wnd2 window\n");
2692 SetActiveWindow(ourWnd
);
2694 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2695 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2697 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2698 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2700 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
2702 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2703 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2704 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2705 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2707 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2709 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2710 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2712 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2713 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2714 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
2716 SetActiveWindow(Wnd2
);
2718 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2719 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2721 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
2723 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2724 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2725 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2726 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2728 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2730 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2731 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2733 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2734 CloseHandle(hThread
);
2736 wnd_event
.wait_event
= NULL
;
2737 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2738 wnd_event
.attach_from
= 0;
2739 wnd_event
.attach_to
= 0;
2740 wnd_event
.setWindows
= TRUE
;
2742 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2743 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2745 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2746 CloseHandle(wnd_event
.start_event
);
2749 SetActiveWindow(ourWnd
);
2751 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2752 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2754 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
2755 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
2757 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2759 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2760 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2762 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
2763 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
2765 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2767 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2768 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2770 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
2771 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
2773 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2776 SetActiveWindow(Wnd2
);
2777 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2778 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2780 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
2782 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2783 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2785 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2786 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2788 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2790 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2791 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2793 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2794 CloseHandle(hThread
);
2796 wnd_event
.wait_event
= CreateEventW(NULL
, 0, 0, NULL
);
2797 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2798 wnd_event
.attach_from
= 0;
2799 wnd_event
.attach_to
= 0;
2800 wnd_event
.setWindows
= TRUE
;
2802 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2803 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2805 SetLastError(0xdeadbeef);
2806 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2807 ok(!ret
, "AttachThreadInput succeeded\n");
2808 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2809 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2811 SetLastError(0xdeadbeef);
2812 ret
= AttachThreadInput(tid
, GetCurrentThreadId(), TRUE
);
2813 ok(!ret
, "AttachThreadInput succeeded\n");
2814 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2815 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2817 SetEvent(wnd_event
.wait_event
);
2819 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2820 CloseHandle(wnd_event
.start_event
);
2822 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2823 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2825 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2826 CloseHandle(hThread
);
2828 wnd_event
.wait_event
= NULL
;
2829 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2830 wnd_event
.attach_from
= GetCurrentThreadId();
2831 wnd_event
.attach_to
= 0;
2832 wnd_event
.setWindows
= FALSE
;
2835 SetActiveWindow(ourWnd
);
2837 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2838 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2840 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2841 CloseHandle(wnd_event
.start_event
);
2843 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2844 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2846 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2847 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2849 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2850 CloseHandle(hThread
);
2852 wnd_event
.wait_event
= NULL
;
2853 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2854 wnd_event
.attach_from
= 0;
2855 wnd_event
.attach_to
= GetCurrentThreadId();
2856 wnd_event
.setWindows
= FALSE
;
2859 SetActiveWindow(ourWnd
);
2861 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2862 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2864 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2865 CloseHandle(wnd_event
.start_event
);
2867 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2868 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2870 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2871 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2873 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2874 CloseHandle(hThread
);
2875 DestroyWindow(ourWnd
);
2876 DestroyWindow(Wnd2
);
2879 static DWORD WINAPI
get_key_state_thread(void *arg
)
2881 HANDLE
*semaphores
= arg
;
2884 ReleaseSemaphore(semaphores
[0], 1, NULL
);
2885 result
= WaitForSingleObject(semaphores
[1], 1000);
2886 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2888 result
= GetKeyState('X');
2889 ok((result
& 0x8000) || broken(!(result
& 0x8000)), /* > Win 2003 */
2890 "expected that highest bit is set, got %x\n", result
);
2892 ReleaseSemaphore(semaphores
[0], 1, NULL
);
2893 result
= WaitForSingleObject(semaphores
[1], 1000);
2894 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2896 result
= GetKeyState('X');
2897 ok(!(result
& 0x8000), "expected that highest bit is unset, got %x\n", result
);
2902 static void test_GetKeyState(void)
2904 HANDLE semaphores
[2];
2909 semaphores
[0] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
2910 ok(semaphores
[0] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
2911 semaphores
[1] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
2912 ok(semaphores
[1] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
2914 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
2915 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
2916 ok(hwnd
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
2918 thread
= CreateThread(NULL
, 0, get_key_state_thread
, semaphores
, 0, NULL
);
2919 ok(thread
!= NULL
, "CreateThread failed %u\n", GetLastError());
2920 result
= WaitForSingleObject(semaphores
[0], 1000);
2921 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2923 SetForegroundWindow(hwnd
);
2925 keybd_event('X', 0, 0, 0);
2927 ReleaseSemaphore(semaphores
[1], 1, NULL
);
2928 result
= WaitForSingleObject(semaphores
[0], 1000);
2929 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2931 keybd_event('X', 0, KEYEVENTF_KEYUP
, 0);
2933 ReleaseSemaphore(semaphores
[1], 1, NULL
);
2934 result
= WaitForSingleObject(thread
, 1000);
2935 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2936 CloseHandle(thread
);
2938 DestroyWindow(hwnd
);
2939 CloseHandle(semaphores
[0]);
2940 CloseHandle(semaphores
[1]);
2943 static void test_OemKeyScan(void)
2945 DWORD ret
, expect
, vkey
, scan
;
2949 for (oem
= 0; oem
< 0x200; oem
++)
2951 ret
= OemKeyScan( oem
);
2953 oem_char
= LOBYTE( oem
);
2954 /* OemKeyScan returns -1 for any character that cannot be mapped,
2955 * whereas OemToCharBuff changes unmappable characters to question
2956 * marks. The ASCII characters 0-127, including the real question mark
2957 * character, are all mappable and are the same in all OEM codepages. */
2958 if (!OemToCharBuffW( &oem_char
, &wchr
, 1 ) || (wchr
== '?' && oem_char
< 0))
2962 vkey
= VkKeyScanW( wchr
);
2963 scan
= MapVirtualKeyW( LOBYTE( vkey
), MAPVK_VK_TO_VSC
);
2970 expect
= vkey
| scan
;
2973 ok( ret
== expect
, "%04x: got %08x expected %08x\n", oem
, ret
, expect
);
2977 static INPUT_MESSAGE_SOURCE expect_src
;
2979 static LRESULT WINAPI
msg_source_proc( HWND hwnd
, UINT message
, WPARAM wp
, LPARAM lp
)
2981 INPUT_MESSAGE_SOURCE source
;
2984 ok( pGetCurrentInputMessageSource( &source
), "GetCurrentInputMessageSource failed\n" );
2992 case WM_LBUTTONDOWN
:
2994 case WM_RBUTTONDOWN
:
2996 ok( source
.deviceType
== expect_src
.deviceType
|| /* also accept system-generated WM_MOUSEMOVE */
2997 (message
== WM_MOUSEMOVE
&& source
.deviceType
== IMDT_UNAVAILABLE
),
2998 "%x: wrong deviceType %x/%x\n", message
, source
.deviceType
, expect_src
.deviceType
);
2999 ok( source
.originId
== expect_src
.originId
||
3000 (message
== WM_MOUSEMOVE
&& source
.originId
== IMO_SYSTEM
),
3001 "%x: wrong originId %x/%x\n", message
, source
.originId
, expect_src
.originId
);
3002 SendMessageA( hwnd
, WM_USER
, 0, 0 );
3003 PostMessageA( hwnd
, WM_USER
, 0, 0 );
3004 if (PeekMessageW( &msg
, hwnd
, WM_USER
, WM_USER
, PM_REMOVE
)) DispatchMessageW( &msg
);
3005 ok( source
.deviceType
== expect_src
.deviceType
|| /* also accept system-generated WM_MOUSEMOVE */
3006 (message
== WM_MOUSEMOVE
&& source
.deviceType
== IMDT_UNAVAILABLE
),
3007 "%x: wrong deviceType %x/%x\n", message
, source
.deviceType
, expect_src
.deviceType
);
3008 ok( source
.originId
== expect_src
.originId
||
3009 (message
== WM_MOUSEMOVE
&& source
.originId
== IMO_SYSTEM
),
3010 "%x: wrong originId %x/%x\n", message
, source
.originId
, expect_src
.originId
);
3013 ok( source
.deviceType
== IMDT_UNAVAILABLE
, "%x: wrong deviceType %x\n",
3014 message
, source
.deviceType
);
3015 ok( source
.originId
== 0, "%x: wrong originId %x\n", message
, source
.originId
);
3019 return DefWindowProcA( hwnd
, message
, wp
, lp
);
3022 static void test_input_message_source(void)
3025 TEST_INPUT inputs
[2];
3031 cls
.lpfnWndProc
= msg_source_proc
;
3034 cls
.hInstance
= GetModuleHandleA(0);
3036 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
3037 cls
.hbrBackground
= 0;
3038 cls
.lpszMenuName
= NULL
;
3039 cls
.lpszClassName
= "message source class";
3040 RegisterClassA(&cls
);
3041 hwnd
= CreateWindowA( cls
.lpszClassName
, "test", WS_OVERLAPPED
, 0, 0, 100, 100,
3043 ShowWindow( hwnd
, SW_SHOWNORMAL
);
3044 UpdateWindow( hwnd
);
3045 SetForegroundWindow( hwnd
);
3048 inputs
[0].type
= INPUT_KEYBOARD
;
3049 inputs
[0].u
.ki
.dwExtraInfo
= 0;
3050 inputs
[0].u
.ki
.time
= 0;
3051 inputs
[0].u
.ki
.wVk
= 0;
3052 inputs
[0].u
.ki
.wScan
= 0x3c0;
3053 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
3054 inputs
[1] = inputs
[0];
3055 inputs
[1].u
.ki
.dwFlags
|= KEYEVENTF_KEYUP
;
3057 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
3058 expect_src
.originId
= IMO_UNAVAILABLE
;
3059 SendMessageA( hwnd
, WM_KEYDOWN
, 0, 0 );
3060 SendMessageA( hwnd
, WM_MOUSEMOVE
, 0, 0 );
3062 SendInput( 2, (INPUT
*)inputs
, sizeof(INPUT
) );
3063 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
3065 expect_src
.deviceType
= IMDT_KEYBOARD
;
3066 expect_src
.originId
= IMO_INJECTED
;
3067 TranslateMessage( &msg
);
3068 DispatchMessageW( &msg
);
3070 GetWindowRect( hwnd
, &rc
);
3071 simulate_click( TRUE
, (rc
.left
+ rc
.right
) / 2, (rc
.top
+ rc
.bottom
) / 2 );
3072 simulate_click( FALSE
, (rc
.left
+ rc
.right
) / 2 + 1, (rc
.top
+ rc
.bottom
) / 2 + 1 );
3073 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
3075 expect_src
.deviceType
= IMDT_MOUSE
;
3076 expect_src
.originId
= IMO_INJECTED
;
3077 TranslateMessage( &msg
);
3078 DispatchMessageW( &msg
);
3081 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
3082 expect_src
.originId
= IMO_UNAVAILABLE
;
3083 SendMessageA( hwnd
, WM_KEYDOWN
, 0, 0 );
3084 SendMessageA( hwnd
, WM_LBUTTONDOWN
, 0, 0 );
3085 PostMessageA( hwnd
, WM_KEYUP
, 0, 0 );
3086 PostMessageA( hwnd
, WM_LBUTTONUP
, 0, 0 );
3087 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
3089 TranslateMessage( &msg
);
3090 DispatchMessageW( &msg
);
3093 expect_src
.deviceType
= IMDT_UNAVAILABLE
;
3094 expect_src
.originId
= IMO_SYSTEM
;
3095 SetCursorPos( (rc
.left
+ rc
.right
) / 2 - 1, (rc
.top
+ rc
.bottom
) / 2 - 1 );
3096 while (PeekMessageW( &msg
, hwnd
, 0, 0, PM_REMOVE
))
3098 TranslateMessage( &msg
);
3099 DispatchMessageW( &msg
);
3102 DestroyWindow( hwnd
);
3103 UnregisterClassA( cls
.lpszClassName
, GetModuleHandleA(0) );
3106 static void test_GetPointerType(void)
3109 POINTER_INPUT_TYPE type
= -1;
3112 SetLastError(0xdeadbeef);
3113 ret
= pGetPointerType(id
, NULL
);
3114 ok(!ret
, "GetPointerType should have failed.\n");
3115 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3116 "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError());
3118 SetLastError(0xdeadbeef);
3119 ret
= pGetPointerType(id
, &type
);
3120 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3121 "expected error ERROR_INVALID_PARAMETER, got %u.\n", GetLastError());
3122 ok(!ret
, "GetPointerType failed, got type %d for %u.\n", type
, id
);
3123 ok(type
== -1, " type %d\n", type
);
3126 ret
= pGetPointerType(id
, &type
);
3127 ok(ret
, "GetPointerType failed, got type %d for %u.\n", type
, id
);
3128 ok(type
== PT_MOUSE
, " type %d\n", type
);
3131 static void test_GetKeyboardLayoutList(void)
3135 ULONG_PTR baselayout
;
3138 baselayout
= GetUserDefaultLCID();
3139 langid
= PRIMARYLANGID(LANGIDFROMLCID(baselayout
));
3140 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
3141 baselayout
= MAKELONG( baselayout
, 0xe001 ); /* IME */
3143 baselayout
|= baselayout
<< 16;
3145 cnt
= GetKeyboardLayoutList(0, NULL
);
3146 /* Most users will not have more than a few keyboard layouts installed at a time. */
3147 ok(cnt
> 0 && cnt
< 10, "Layout count %d\n", cnt
);
3150 layouts
= HeapAlloc(GetProcessHeap(), 0, sizeof(*layouts
) * cnt
);
3152 cnt2
= GetKeyboardLayoutList(cnt
, layouts
);
3153 ok(cnt
== cnt2
, "wrong value %d!=%d\n", cnt
, cnt2
);
3154 for(cnt
= 0; cnt
< cnt2
; cnt
++)
3156 if(layouts
[cnt
] == (HKL
)baselayout
)
3159 ok(cnt
< cnt2
, "Didnt find current keyboard\n");
3161 HeapFree(GetProcessHeap(), 0, layouts
);
3169 init_function_pointers();
3170 GetCursorPos( &pos
);
3172 test_Input_blackbox();
3173 test_Input_whitebox();
3174 test_Input_unicode();
3177 test_mouse_ll_hook();
3181 test_get_async_key_state();
3182 test_keyboard_layout_name();
3184 test_attach_input();
3187 test_GetRawInputData();
3188 test_GetKeyboardLayoutList();
3190 if(pGetMouseMovePointsEx
)
3191 test_GetMouseMovePointsEx();
3193 win_skip("GetMouseMovePointsEx is not available\n");
3195 if(pGetRawInputDeviceList
)
3196 test_GetRawInputDeviceList();
3198 win_skip("GetRawInputDeviceList is not available\n");
3200 if (pGetCurrentInputMessageSource
)
3201 test_input_message_source();
3203 win_skip("GetCurrentInputMessageSource is not available\n");
3205 SetCursorPos( pos
.x
, pos
.y
);
3208 test_GetPointerType();
3210 win_skip("GetPointerType is not available\n");