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
48 #define _WIN32_WINNT 0x401
49 #define _WIN32_IE 0x0500
61 #include "wine/test.h"
64 #include <reactos/undocuser.h>
69 static LONG timetag
= 0x10000000;
74 LONG last_syskey_down
;
80 LONG last_hook_syskey_down
;
81 LONG last_hook_syskey_up
;
83 BOOL sendinput_broken
;
86 static UINT (WINAPI
*pSendInput
) (UINT
, INPUT
*, size_t);
87 static int (WINAPI
*pGetMouseMovePointsEx
) (UINT
, LPMOUSEMOVEPOINT
, LPMOUSEMOVEPOINT
, int, DWORD
);
88 static UINT (WINAPI
*pGetRawInputDeviceList
) (PRAWINPUTDEVICELIST
, PUINT
, UINT
);
89 static int (WINAPI
*pGetWindowRgnBox
)(HWND
, LPRECT
);
91 #define MAXKEYEVENTS 12
92 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
93 and only one message */
95 /* keyboard message names, sorted as their value */
96 static const char *MSGNAME
[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
97 "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
99 /* keyevents, add more as needed */
101 { ALTDOWN
= 1, ALTUP
, XDOWN
, XUP
, SHIFTDOWN
, SHIFTUP
, CTRLDOWN
, CTRLUP
} KEV
;
103 static const int GETVKEY
[]={0, VK_MENU
, VK_MENU
, 'X', 'X', VK_SHIFT
, VK_SHIFT
, VK_CONTROL
, VK_CONTROL
};
104 /* matching scan codes */
105 static const int GETSCAN
[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
106 /* matching updown events */
107 static const int GETFLAGS
[]={0, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
, 0, KEYEVENTF_KEYUP
};
108 /* matching descriptions */
109 static const char *getdesc
[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
111 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
123 #define ADDTOINPUTS(kev) \
124 inputs[evtctr].type = INPUT_KEYBOARD; \
125 ((TEST_INPUT*)inputs)[evtctr].u.ki.wVk = GETVKEY[ kev]; \
126 ((TEST_INPUT*)inputs)[evtctr].u.ki.wScan = GETSCAN[ kev]; \
127 ((TEST_INPUT*)inputs)[evtctr].u.ki.dwFlags = GETFLAGS[ kev]; \
128 ((TEST_INPUT*)inputs)[evtctr].u.ki.dwExtraInfo = 0; \
129 ((TEST_INPUT*)inputs)[evtctr].u.ki.time = ++timetag; \
138 /*******************************************
139 * add new test sets here
140 * the software will make all combinations of the
141 * keyevent defined here
143 static const struct {
145 KEV keydwn
[MAXKEYEVENTS
];
146 KEV keyup
[MAXKEYEVENTS
];
148 { 2, { ALTDOWN
, XDOWN
}, { ALTUP
, XUP
}},
149 { 3, { ALTDOWN
, XDOWN
, SHIFTDOWN
}, { ALTUP
, XUP
, SHIFTUP
}},
150 { 3, { ALTDOWN
, XDOWN
, CTRLDOWN
}, { ALTUP
, XUP
, CTRLUP
}},
151 { 3, { SHIFTDOWN
, XDOWN
, CTRLDOWN
}, { SHIFTUP
, XUP
, CTRLUP
}},
152 { 0 } /* mark the end */
155 /**********************adapted from input.c **********************************/
157 static BYTE InputKeyStateTable
[256];
158 static BYTE AsyncKeyStateTable
[256];
159 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
160 or a WM_KEYUP message */
162 static void init_function_pointers(void)
164 HMODULE hdll
= GetModuleHandleA("user32");
166 #define GET_PROC(func) \
167 p ## func = (void*)GetProcAddress(hdll, #func); \
169 trace("GetProcAddress(%s) failed\n", #func);
172 GET_PROC(GetMouseMovePointsEx
)
173 GET_PROC(GetRawInputDeviceList
)
174 GET_PROC(GetWindowRgnBox
)
179 static int KbdMessage( KEV kev
, WPARAM
*pwParam
, LPARAM
*plParam
)
182 int VKey
= GETVKEY
[kev
];
185 flags
= LOBYTE(GETSCAN
[kev
]);
186 if (GETFLAGS
[kev
] & KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
188 if (GETFLAGS
[kev
] & KEYEVENTF_KEYUP
)
191 if( (InputKeyStateTable
[VK_MENU
] & 0x80) && (
192 (VKey
== VK_MENU
) || (VKey
== VK_CONTROL
) ||
193 !(InputKeyStateTable
[VK_CONTROL
] & 0x80))) {
194 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
195 (VKey
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
196 message
= WM_SYSKEYUP
;
199 InputKeyStateTable
[VKey
] &= ~0x80;
200 flags
|= KF_REPEAT
| KF_UP
;
204 if (InputKeyStateTable
[VKey
] & 0x80) flags
|= KF_REPEAT
;
205 if (!(InputKeyStateTable
[VKey
] & 0x80)) InputKeyStateTable
[VKey
] ^= 0x01;
206 InputKeyStateTable
[VKey
] |= 0x80;
207 AsyncKeyStateTable
[VKey
] |= 0x80;
209 message
= WM_KEYDOWN
;
210 if( (InputKeyStateTable
[VK_MENU
] & 0x80) &&
211 !(InputKeyStateTable
[VK_CONTROL
] & 0x80)) {
212 message
= WM_SYSKEYDOWN
;
217 if (InputKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
219 if( plParam
) *plParam
= MAKELPARAM( 1, flags
);
220 if( pwParam
) *pwParam
= VKey
;
224 /****************************** end copy input.c ****************************/
227 * . prepare the keyevents for SendInputs
228 * . calculate the "expected" messages
229 * . Send the events to our window
230 * . retrieve the messages from the input queue
233 static BOOL
do_test( HWND hwnd
, int seqnr
, const KEV td
[] )
235 INPUT inputs
[MAXKEYEVENTS
];
236 KMSG expmsg
[MAXKEYEVENTS
];
243 TrackSysKey
=0; /* see input.c */
244 for( i
= 0; i
< MAXKEYEVENTS
; i
++) {
246 strcat(buf
, getdesc
[td
[i
]]);
248 expmsg
[i
].message
= KbdMessage(td
[i
], &(expmsg
[i
].wParam
), &(expmsg
[i
].lParam
));
250 expmsg
[i
].message
= 0;
252 for( kmctr
= 0; kmctr
< MAXKEYEVENTS
&& expmsg
[kmctr
].message
; kmctr
++)
254 ok( evtctr
<= MAXKEYEVENTS
, "evtctr is above MAXKEYEVENTS\n" );
255 if( evtctr
!= pSendInput(evtctr
, &inputs
[0], sizeof(INPUT
)))
256 ok (FALSE
, "SendInput failed to send some events\n");
258 if (winetest_debug
> 1)
259 trace("======== key stroke sequence #%d: %s =============\n",
261 while( PeekMessageA(&msg
,hwnd
,WM_KEYFIRST
,WM_KEYLAST
,PM_REMOVE
) ) {
262 if (winetest_debug
> 1)
263 trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i
,
264 MSGNAME
[msg
.message
- WM_KEYFIRST
], msg
.wParam
, msg
.lParam
, msg
.time
);
266 ok( msg
.message
== expmsg
[i
].message
&&
267 msg
.wParam
== expmsg
[i
].wParam
&&
268 msg
.lParam
== expmsg
[i
].lParam
,
269 "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n",
270 seqnr
, i
, msg
.message
, msg
.wParam
, msg
.lParam
,
271 MSGNAME
[(expmsg
[i
]).message
- WM_KEYFIRST
], expmsg
[i
].wParam
, expmsg
[i
].lParam
);
275 if (winetest_debug
> 1)
276 trace("%d messages retrieved\n", i
);
279 skip( "simulated keyboard input doesn't work\n" );
282 ok( i
== kmctr
, "message count is wrong: got %d expected: %d\n", i
, kmctr
);
286 /* test all combinations of the specified key events */
287 static BOOL
TestASet( HWND hWnd
, int nrkev
, const KEV kevdwn
[], const KEV kevup
[] )
291 KEV kbuf
[MAXKEYEVENTS
];
292 assert( nrkev
==2 || nrkev
==3);
293 for(i
=0;i
<MAXKEYEVENTS
;i
++) kbuf
[i
]=0;
294 /* two keys involved gives 4 test cases */
296 for(i
=0;i
<nrkev
;i
++) {
297 for(j
=0;j
<nrkev
;j
++) {
299 kbuf
[1] = kevdwn
[1-i
];
301 kbuf
[3] = kevup
[1-j
];
302 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
306 /* three keys involved gives 36 test cases */
308 for(i
=0;i
<nrkev
;i
++){
309 for(j
=0;j
<nrkev
;j
++){
311 for(k
=0;k
<nrkev
;k
++){
312 if(k
==i
|| k
==j
) continue;
313 for(l
=0;l
<nrkev
;l
++){
314 for(m
=0;m
<nrkev
;m
++){
316 for(n
=0;n
<nrkev
;n
++){
317 if(n
==l
||n
==m
) continue;
324 if (!do_test( hWnd
, count
++, kbuf
)) return FALSE
;
335 /* test each set specified in the global testkeyset array */
336 static void TestSysKeys( HWND hWnd
)
339 for(i
=0; testkeyset
[i
].nrkev
;i
++)
340 if (!TestASet( hWnd
, testkeyset
[i
].nrkev
, testkeyset
[i
].keydwn
, testkeyset
[i
].keyup
)) break;
343 static LRESULT CALLBACK
WndProc( HWND hWnd
, UINT msg
, WPARAM wParam
,
346 return DefWindowProcA( hWnd
, msg
, wParam
, lParam
);
349 static void test_Input_whitebox(void)
353 HANDLE hInstance
= GetModuleHandleA( NULL
);
355 wclass
.lpszClassName
= "InputSysKeyTestClass";
356 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
357 wclass
.lpfnWndProc
= WndProc
;
358 wclass
.hInstance
= hInstance
;
359 wclass
.hIcon
= LoadIconA( 0, (LPCSTR
)IDI_APPLICATION
);
360 wclass
.hCursor
= LoadCursorA( NULL
, (LPCSTR
)IDC_ARROW
);
361 wclass
.hbrBackground
= (HBRUSH
)( COLOR_WINDOW
+ 1 );
362 wclass
.lpszMenuName
= 0;
363 wclass
.cbClsExtra
= 0;
364 wclass
.cbWndExtra
= 0;
365 RegisterClassA( &wclass
);
366 /* create the test window that will receive the keystrokes */
367 hWndTest
= CreateWindowA( wclass
.lpszClassName
, "InputSysKeyTest",
368 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
369 NULL
, NULL
, hInstance
, NULL
);
371 ShowWindow( hWndTest
, SW_SHOW
);
372 SetWindowPos( hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
373 SetForegroundWindow( hWndTest
);
374 UpdateWindow( hWndTest
);
376 /* flush pending messages */
377 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
379 SetFocus( hWndTest
);
380 TestSysKeys( hWndTest
);
381 DestroyWindow(hWndTest
);
384 static inline BOOL
is_keyboard_message( UINT message
)
386 return (message
>= WM_KEYFIRST
&& message
<= WM_KEYLAST
);
389 static inline BOOL
is_mouse_message( UINT message
)
391 return (message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
);
394 /* try to make sure pending X events have been processed before continuing */
395 static void empty_message_queue(void)
399 int min_timeout
= 50;
400 DWORD time
= GetTickCount() + diff
;
404 if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
405 while (PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
407 if (is_keyboard_message(msg
.message
) || is_mouse_message(msg
.message
))
408 ok(msg
.time
!= 0, "message %#x has time set to 0\n", msg
.message
);
410 TranslateMessage(&msg
);
411 DispatchMessageA(&msg
);
413 diff
= time
- GetTickCount();
417 struct transition_s
{
437 UINT message
; /* the WM_* code */
438 msg_flags_t flags
; /* message props */
439 WPARAM wParam
; /* expected value of wParam */
440 LPARAM lParam
; /* expected value of lParam */
443 static const struct sendinput_test_s
{
447 struct transition_s expected_transitions
[MAXKEYEVENTS
+1];
448 struct message expected_messages
[MAXKEYMESSAGES
+1];
449 } sendinput_test
[] = {
452 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
453 {{WM_SYSKEYDOWN
, hook
|wparam
, VK_LMENU
}, {WM_SYSKEYDOWN
}, {0}}},
454 {'F', 0, FALSE
, {{'F', 0x00}, {0}},
455 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
},
457 {WM_SYSCOMMAND
}, {0}}},
458 {'F', KEYEVENTF_KEYUP
, FALSE
, {{'F', 0x80}, {0}},
459 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
460 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
461 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
465 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
466 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
467 {'O', 0, FALSE
, {{'O', 0x00}, {0}},
468 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
469 {'O', KEYEVENTF_KEYUP
, FALSE
, {{'O', 0x80}, {0}},
470 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
471 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
472 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
474 /* test ALT+CTRL+X */
476 {VK_LMENU
, 0, FALSE
, {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
477 {{WM_SYSKEYDOWN
, hook
}, {WM_SYSKEYDOWN
}, {0}}},
478 {VK_LCONTROL
, 0, FALSE
, {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
479 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
480 {'X', 0, FALSE
, {{'X', 0x00}, {0}},
481 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
482 {'X', KEYEVENTF_KEYUP
, FALSE
, {{'X', 0x80}, {0}},
483 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
484 {VK_LCONTROL
, KEYEVENTF_KEYUP
, FALSE
, {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
485 {{WM_SYSKEYUP
, hook
}, {WM_SYSKEYUP
}, {0}}},
486 {VK_LMENU
, KEYEVENTF_KEYUP
, FALSE
, {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
487 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
491 {VK_LSHIFT
, 0, FALSE
, {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
492 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {0}}},
493 {'A', 0, FALSE
, {{'A', 0x00}, {0}},
494 {{WM_KEYDOWN
, hook
}, {WM_KEYDOWN
}, {WM_CHAR
}, {0}}},
495 {'A', KEYEVENTF_KEYUP
, FALSE
, {{'A', 0x80}, {0}},
496 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
497 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
, {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
498 {{WM_KEYUP
, hook
}, {WM_KEYUP
}, {0}}},
499 /* test L-SHIFT & R-SHIFT: */
500 /* RSHIFT == LSHIFT */
502 {VK_RSHIFT
, 0, FALSE
,
503 /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
504 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00, TRUE
}, {VK_RSHIFT
, 0x00, TRUE
}, {0}},
505 {{WM_KEYDOWN
, hook
|wparam
, VK_RSHIFT
},
507 {VK_RSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
508 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80, TRUE
}, {VK_RSHIFT
, 0x80, TRUE
}, {0}},
509 {{WM_KEYUP
, hook
, hook
|wparam
, VK_RSHIFT
},
512 /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
514 {VK_LSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
515 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
516 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_EXTENDED
},
517 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
518 {VK_LSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
519 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
520 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
521 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
522 /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
524 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
525 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
526 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
527 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
528 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
529 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
530 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
531 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
533 /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
534 win2k - sends to hook whatever we generated here
535 winXP+ - Attempts to convert key to L/R key but not always correct
537 /* SHIFT == LSHIFT */
540 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
541 {{WM_KEYDOWN
, hook
/* |wparam */|lparam
, VK_SHIFT
, 0},
542 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
543 {VK_SHIFT
, KEYEVENTF_KEYUP
, FALSE
,
544 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
545 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
},
546 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
547 /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
549 {VK_SHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
550 {{VK_SHIFT
, 0x00}, {VK_RSHIFT
, 0x00}, {0}},
551 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_EXTENDED
},
552 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
553 {VK_SHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
554 {{VK_SHIFT
, 0x80}, {VK_RSHIFT
, 0x80}, {0}},
555 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_SHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
556 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
558 /* test L-CONTROL & R-CONTROL: */
559 /* RCONTROL == LCONTROL */
561 {VK_RCONTROL
, 0, FALSE
,
562 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
563 {{WM_KEYDOWN
, hook
|wparam
, VK_RCONTROL
},
564 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
565 {VK_RCONTROL
, KEYEVENTF_KEYUP
, FALSE
,
566 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
567 {{WM_KEYUP
, hook
|wparam
, VK_RCONTROL
},
568 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
569 /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
571 {VK_LCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
572 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
573 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_EXTENDED
},
574 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
575 {VK_LCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
576 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
577 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
578 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
579 /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
581 {VK_RCONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
582 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
583 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_EXTENDED
},
584 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
585 {VK_RCONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
586 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
587 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RCONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
588 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
589 /* CONTROL == LCONTROL */
591 {VK_CONTROL
, 0, FALSE
,
592 {{VK_CONTROL
, 0x00}, {VK_LCONTROL
, 0x00}, {0}},
593 {{WM_KEYDOWN
, hook
/*|wparam, VK_CONTROL*/},
594 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, 0}, {0}}},
595 {VK_CONTROL
, KEYEVENTF_KEYUP
, FALSE
,
596 {{VK_CONTROL
, 0x80}, {VK_LCONTROL
, 0x80}, {0}},
597 {{WM_KEYUP
, hook
/*|wparam, VK_CONTROL*/},
598 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
}, {0}}},
599 /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
601 {VK_CONTROL
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
602 {{VK_CONTROL
, 0x00}, {VK_RCONTROL
, 0x00}, {0}},
603 {{WM_KEYDOWN
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_EXTENDED
},
604 {WM_KEYDOWN
, wparam
|lparam
, VK_CONTROL
, KF_EXTENDED
}, {0}}},
605 {VK_CONTROL
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
606 {{VK_CONTROL
, 0x80}, {VK_RCONTROL
, 0x80}, {0}},
607 {{WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_CONTROL
, LLKHF_UP
|LLKHF_EXTENDED
},
608 {WM_KEYUP
, wparam
|lparam
, VK_CONTROL
, KF_UP
|KF_EXTENDED
}, {0}}},
610 /* test L-MENU & R-MENU: */
614 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
615 {{WM_SYSKEYDOWN
, hook
|wparam
|optional
, VK_LCONTROL
},
616 {WM_SYSKEYDOWN
, hook
|wparam
, VK_RMENU
},
617 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
618 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
619 {VK_RMENU
, KEYEVENTF_KEYUP
, TRUE
,
620 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
621 {{WM_KEYUP
, hook
|wparam
|optional
, VK_LCONTROL
},
622 {WM_KEYUP
, hook
|wparam
, VK_RMENU
},
623 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
624 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
625 {WM_SYSCOMMAND
, optional
}, {0}}},
626 /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
628 {VK_LMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
629 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {0}},
630 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_EXTENDED
},
631 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
632 {VK_LMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
633 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {0}},
634 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_LMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
635 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
636 {WM_SYSCOMMAND
}, {0}}},
637 /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
639 {VK_RMENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
640 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
641 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, 0},
642 {WM_SYSKEYDOWN
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_EXTENDED
},
643 {WM_KEYDOWN
, wparam
|lparam
|optional
, VK_CONTROL
, 0},
644 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
645 {VK_RMENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
646 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
647 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_LCONTROL
, LLKHF_UP
},
648 {WM_KEYUP
, hook
|wparam
|lparam
, VK_RMENU
, LLKHF_UP
|LLKHF_EXTENDED
},
649 {WM_SYSKEYUP
, wparam
|lparam
|optional
, VK_CONTROL
, KF_UP
},
650 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
651 {WM_SYSCOMMAND
, optional
}, {0}}},
655 {{VK_MENU
, 0x00}, {VK_LMENU
, 0x00}, {0}},
656 {{WM_SYSKEYDOWN
, hook
/*|wparam, VK_MENU*/},
657 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, 0}, {0}}},
658 {VK_MENU
, KEYEVENTF_KEYUP
, TRUE
,
659 {{VK_MENU
, 0x80}, {VK_LMENU
, 0x80}, {0}},
660 {{WM_KEYUP
, hook
/*|wparam, VK_MENU*/},
661 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
},
662 {WM_SYSCOMMAND
}, {0}}},
663 /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
665 {VK_MENU
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
666 {{VK_MENU
, 0x00}, {VK_RMENU
, 0x00}, {VK_CONTROL
, 0x00, 1}, {VK_LCONTROL
, 0x01, 1}, {0}},
667 {{WM_SYSKEYDOWN
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, 0},
668 {WM_SYSKEYDOWN
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_EXTENDED
},
669 {WM_SYSKEYDOWN
, wparam
|lparam
, VK_MENU
, KF_EXTENDED
}, {0}}},
670 {VK_MENU
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, TRUE
,
671 {{VK_MENU
, 0x80}, {VK_RMENU
, 0x80}, {VK_CONTROL
, 0x81, 1}, {VK_LCONTROL
, 0x80, 1}, {0}},
672 {{WM_KEYUP
, hook
|wparam
|lparam
|optional
, VK_CONTROL
, LLKHF_UP
},
673 {WM_KEYUP
, hook
/*|wparam*/|lparam
, VK_MENU
, LLKHF_UP
|LLKHF_EXTENDED
},
674 {WM_SYSKEYUP
, wparam
|lparam
, VK_MENU
, KF_UP
|KF_EXTENDED
},
675 {WM_SYSCOMMAND
}, {0}}},
677 /* test LSHIFT & RSHIFT */
679 {VK_LSHIFT
, 0, FALSE
,
680 {{VK_SHIFT
, 0x00}, {VK_LSHIFT
, 0x00}, {0}},
681 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_LSHIFT
, 0},
682 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
683 {VK_RSHIFT
, KEYEVENTF_EXTENDEDKEY
, FALSE
,
684 {{VK_RSHIFT
, 0x00}, {0}},
685 {{WM_KEYDOWN
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_EXTENDED
},
686 {WM_KEYDOWN
, wparam
|lparam
, VK_SHIFT
, 0}, {0}}},
687 {VK_RSHIFT
, KEYEVENTF_KEYUP
| KEYEVENTF_EXTENDEDKEY
, FALSE
,
688 {{VK_RSHIFT
, 0x80}, {0}},
689 {{WM_KEYUP
, hook
|wparam
|lparam
, VK_RSHIFT
, LLKHF_UP
|LLKHF_EXTENDED
},
690 {WM_KEYUP
, optional
}, {0}}},
691 {VK_LSHIFT
, KEYEVENTF_KEYUP
, FALSE
,
692 {{VK_SHIFT
, 0x80}, {VK_LSHIFT
, 0x80}, {0}},
693 {{WM_KEYUP
, hook
|wparam
, VK_LSHIFT
},
694 {WM_KEYUP
, wparam
|lparam
, VK_SHIFT
, KF_UP
}, {0}}},
696 {0, 0, FALSE
, {{0}}, {{0}}} /* end */
699 static struct message sent_messages
[MAXKEYMESSAGES
];
700 static UINT sent_messages_cnt
;
702 /* Verify that only specified key state transitions occur */
703 static void compare_and_check(int id
, BYTE
*ks1
, BYTE
*ks2
, const struct sendinput_test_s
*test
)
705 int i
, failcount
= 0;
706 const struct transition_s
*t
= test
->expected_transitions
;
708 const struct message
*expected
= test
->expected_messages
;
711 BOOL matched
= ((ks1
[t
->wVk
]&0x80) == (t
->before_state
&0x80)
712 && (ks2
[t
->wVk
]&0x80) == (~t
->before_state
&0x80));
714 if (!matched
&& !t
->optional
&& test
->_todo_wine
)
718 ok(matched
, "%2d (%x/%x): %02x from %02x -> %02x "
719 "instead of %02x -> %02x\n", id
, test
->wVk
, test
->dwFlags
,
720 t
->wVk
, ks1
[t
->wVk
]&0x80, ks2
[t
->wVk
]&0x80, t
->before_state
,
721 ~t
->before_state
&0x80);
724 ok(matched
|| t
->optional
, "%2d (%x/%x): %02x from %02x -> %02x "
725 "instead of %02x -> %02x\n", id
, test
->wVk
, test
->dwFlags
,
726 t
->wVk
, ks1
[t
->wVk
]&0x80, ks2
[t
->wVk
]&0x80, t
->before_state
,
727 ~t
->before_state
&0x80);
729 ks2
[t
->wVk
] = ks1
[t
->wVk
]; /* clear the match */
732 for (i
= 0; i
< 256; i
++)
733 if (ks2
[i
] != ks1
[i
] && test
->_todo_wine
)
737 ok(FALSE
, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
738 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
741 ok(ks2
[i
] == ks1
[i
], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
742 id
, test
->wVk
, test
->dwFlags
, i
, ks1
[i
], ks2
[i
]);
744 while (expected
->message
&& actual_cnt
< sent_messages_cnt
)
746 const struct message
*actual
= &sent_messages
[actual_cnt
];
748 if (expected
->message
== actual
->message
)
750 if (expected
->flags
& wparam
)
752 if ((expected
->flags
& optional
) && (expected
->wParam
!= actual
->wParam
))
757 if (expected
->wParam
!= actual
->wParam
&& test
->_todo_wine
)
761 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
762 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
765 ok(expected
->wParam
== actual
->wParam
,
766 "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
767 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->wParam
, actual
->wParam
);
769 if (expected
->flags
& lparam
)
771 if (expected
->lParam
!= actual
->lParam
&& test
->_todo_wine
)
775 ok(FALSE
, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
776 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
779 ok(expected
->lParam
== actual
->lParam
,
780 "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
781 id
, test
->wVk
, test
->dwFlags
, expected
->message
, expected
->lParam
, actual
->lParam
);
783 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
784 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
785 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
788 else if (expected
->flags
& optional
)
793 /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
794 else if ((expected
->flags
& hook
) &&
795 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
796 (actual
->message
== expected
->message
- 4))
798 ok((expected
->flags
& hook
) == (actual
->flags
& hook
),
799 "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
800 id
, test
->wVk
, test
->dwFlags
, expected
->message
);
802 /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
803 * instead of SYSKEYDOWN/UP to the WNDPROC */
804 else if (test
->wVk
== VK_RMENU
&& !(expected
->flags
& hook
) &&
805 (expected
->message
== WM_SYSKEYDOWN
|| expected
->message
== WM_SYSKEYUP
) &&
806 (actual
->message
== expected
->message
- 4))
808 ok(expected
->wParam
== actual
->wParam
&& expected
->lParam
== actual
->lParam
,
809 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
810 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
812 else if (test
->_todo_wine
)
817 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
818 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
822 "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
823 id
, test
->wVk
, test
->dwFlags
, expected
->message
, actual
->message
);
828 /* skip all optional trailing messages */
829 while (expected
->message
&& (expected
->flags
& optional
))
833 if (expected
->message
|| actual_cnt
< sent_messages_cnt
)
835 if (test
->_todo_wine
)
839 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
840 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
843 ok(FALSE
, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
844 id
, test
->wVk
, test
->dwFlags
, expected
->message
, sent_messages
[actual_cnt
].message
);
847 if( test
->_todo_wine
&& !failcount
) /* succeeded yet marked todo */
849 ok(TRUE
, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id
, test
->wVk
, test
->dwFlags
);
851 sent_messages_cnt
= 0;
854 /* WndProc2 checks that we get at least the messages specified */
855 static LRESULT CALLBACK
WndProc2(HWND hWnd
, UINT Msg
, WPARAM wParam
,
858 if (winetest_debug
> 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg
, wParam
, lParam
);
860 if (Msg
!= WM_PAINT
&&
862 Msg
!= WM_SYNCPAINT
&&
863 Msg
!= WM_ERASEBKGND
&&
864 Msg
!= WM_NCHITTEST
&&
867 Msg
!= WM_IME_SELECT
&&
868 Msg
!= WM_DEVICECHANGE
&&
869 Msg
!= WM_TIMECHANGE
)
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
;
921 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409)
923 skip("Skipping Input_blackbox test on non-US keyboard\n");
926 window
= CreateWindowA("Static", NULL
, WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
927 |WS_VISIBLE
, 0, 0, 200, 60, NULL
, NULL
,
929 ok(window
!= NULL
, "error: %d\n", (int) GetLastError());
930 SetWindowPos( window
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
931 SetForegroundWindow( window
);
933 if (!(hook
= SetWindowsHookExA(WH_KEYBOARD_LL
, hook_proc
, GetModuleHandleA( NULL
), 0)))
935 DestroyWindow(window
);
936 win_skip("WH_KEYBOARD_LL is not supported\n");
940 /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
941 * key state set by SendInput(). */
942 empty_message_queue();
944 prevWndProc
= SetWindowLongPtrA(window
, GWLP_WNDPROC
, (LONG_PTR
) WndProc2
);
945 ok(prevWndProc
!= 0 || GetLastError() == 0, "error: %d\n", (int) GetLastError());
947 i
.type
= INPUT_KEYBOARD
;
949 i
.u
.ki
.dwExtraInfo
= 0;
951 for (ii
= 0; ii
< sizeof(sendinput_test
)/sizeof(struct sendinput_test_s
)-1;
953 GetKeyboardState(ks1
);
954 i
.u
.ki
.wScan
= ii
+1 /* useful for debugging */;
955 i
.u
.ki
.dwFlags
= sendinput_test
[ii
].dwFlags
;
956 i
.u
.ki
.wVk
= sendinput_test
[ii
].wVk
;
957 pSendInput(1, (INPUT
*)&i
, sizeof(TEST_INPUT
));
958 empty_message_queue();
959 GetKeyboardState(ks2
);
960 if (!ii
&& sent_messages_cnt
<= 1 && !memcmp( ks1
, ks2
, sizeof(ks1
) ))
962 win_skip( "window doesn't receive the queued input\n" );
963 /* release the key */
964 i
.u
.ki
.dwFlags
|= KEYEVENTF_KEYUP
;
965 pSendInput(1, (INPUT
*)&i
, sizeof(TEST_INPUT
));
968 compare_and_check(ii
, ks1
, ks2
, &sendinput_test
[ii
]);
971 empty_message_queue();
972 DestroyWindow(window
);
973 UnhookWindowsHookEx(hook
);
976 static void reset_key_status(void)
978 key_status
.last_key_down
= -1;
979 key_status
.last_key_up
= -1;
980 key_status
.last_syskey_down
= -1;
981 key_status
.last_syskey_up
= -1;
982 key_status
.last_char
= -1;
983 key_status
.last_syschar
= -1;
984 key_status
.last_hook_down
= -1;
985 key_status
.last_hook_up
= -1;
986 key_status
.last_hook_syskey_down
= -1;
987 key_status
.last_hook_syskey_up
= -1;
988 key_status
.expect_alt
= FALSE
;
989 key_status
.sendinput_broken
= FALSE
;
992 static void test_unicode_keys(HWND hwnd
, HHOOK hook
)
994 TEST_INPUT inputs
[2];
997 /* init input data that never changes */
998 inputs
[1].type
= inputs
[0].type
= INPUT_KEYBOARD
;
999 inputs
[1].u
.ki
.dwExtraInfo
= inputs
[0].u
.ki
.dwExtraInfo
= 0;
1000 inputs
[1].u
.ki
.time
= inputs
[0].u
.ki
.time
= 0;
1002 /* pressing & releasing a single unicode character */
1003 inputs
[0].u
.ki
.wVk
= 0;
1004 inputs
[0].u
.ki
.wScan
= 0x3c0;
1005 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1008 pSendInput(1, (INPUT
*)inputs
, sizeof(INPUT
));
1009 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1010 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1011 TranslateMessage(&msg
);
1013 DispatchMessageW(&msg
);
1015 if(!key_status
.sendinput_broken
){
1016 ok(key_status
.last_key_down
== VK_PACKET
,
1017 "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_down
);
1018 ok(key_status
.last_char
== 0x3c0,
1019 "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status
.last_char
);
1021 ok(key_status
.last_hook_down
== 0x3c0,
1022 "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_down
);
1025 inputs
[1].u
.ki
.wVk
= 0;
1026 inputs
[1].u
.ki
.wScan
= 0x3c0;
1027 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1030 pSendInput(1, (INPUT
*)(inputs
+1), sizeof(INPUT
));
1031 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1032 if(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_PACKET
){
1033 TranslateMessage(&msg
);
1035 DispatchMessageW(&msg
);
1037 if(!key_status
.sendinput_broken
){
1038 ok(key_status
.last_key_up
== VK_PACKET
,
1039 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1041 ok(key_status
.last_hook_up
== 0x3c0,
1042 "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status
.last_hook_up
);
1045 /* holding alt, pressing & releasing a unicode character, releasing alt */
1046 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1047 inputs
[0].u
.ki
.wScan
= 0;
1048 inputs
[0].u
.ki
.dwFlags
= 0;
1050 inputs
[1].u
.ki
.wVk
= 0;
1051 inputs
[1].u
.ki
.wScan
= 0x3041;
1052 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
;
1055 key_status
.expect_alt
= TRUE
;
1056 pSendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1057 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1058 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1059 TranslateMessage(&msg
);
1061 DispatchMessageW(&msg
);
1063 if(!key_status
.sendinput_broken
){
1064 ok(key_status
.last_syskey_down
== VK_PACKET
,
1065 "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_syskey_down
);
1066 ok(key_status
.last_syschar
== 0x3041,
1067 "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status
.last_syschar
);
1069 ok(key_status
.last_hook_syskey_down
== 0x3041,
1070 "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_syskey_down
);
1073 inputs
[1].u
.ki
.wVk
= 0;
1074 inputs
[1].u
.ki
.wScan
= 0x3041;
1075 inputs
[1].u
.ki
.dwFlags
= KEYEVENTF_UNICODE
| KEYEVENTF_KEYUP
;
1077 inputs
[0].u
.ki
.wVk
= VK_LMENU
;
1078 inputs
[0].u
.ki
.wScan
= 0;
1079 inputs
[0].u
.ki
.dwFlags
= KEYEVENTF_KEYUP
;
1082 key_status
.expect_alt
= TRUE
;
1083 pSendInput(2, (INPUT
*)inputs
, sizeof(INPUT
));
1084 while(PeekMessageW(&msg
, hwnd
, 0, 0, PM_REMOVE
)){
1085 if(msg
.message
== WM_SYSKEYDOWN
&& msg
.wParam
== VK_PACKET
){
1086 TranslateMessage(&msg
);
1088 DispatchMessageW(&msg
);
1090 if(!key_status
.sendinput_broken
){
1091 ok(key_status
.last_key_up
== VK_PACKET
,
1092 "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET
, key_status
.last_key_up
);
1094 ok(key_status
.last_hook_up
== 0x3041,
1095 "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status
.last_hook_up
);
1099 static LRESULT CALLBACK
unicode_wnd_proc( HWND hWnd
, UINT msg
, WPARAM wParam
,
1104 key_status
.last_key_down
= wParam
;
1107 key_status
.last_syskey_down
= wParam
;
1110 key_status
.last_key_up
= wParam
;
1113 key_status
.last_syskey_up
= wParam
;
1116 key_status
.last_char
= wParam
;
1119 key_status
.last_syschar
= wParam
;
1122 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1125 static LRESULT CALLBACK
llkbd_unicode_hook(int nCode
, WPARAM wParam
, LPARAM lParam
)
1127 if(nCode
== HC_ACTION
){
1128 LPKBDLLHOOKSTRUCT info
= (LPKBDLLHOOKSTRUCT
)lParam
;
1130 key_status
.sendinput_broken
= TRUE
;
1131 win_skip("SendInput doesn't support unicode on this platform\n");
1133 if(key_status
.expect_alt
){
1134 ok(info
->vkCode
== VK_LMENU
, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU
, info
->vkCode
);
1135 key_status
.expect_alt
= FALSE
;
1137 ok(info
->vkCode
== VK_PACKET
, "vkCode should have been VK_PACKET[0x%04x], was: 0x%x\n", VK_PACKET
, info
->vkCode
);
1141 key_status
.last_hook_down
= info
->scanCode
;
1144 key_status
.last_hook_up
= info
->scanCode
;
1147 key_status
.last_hook_syskey_down
= info
->scanCode
;
1150 key_status
.last_hook_syskey_up
= info
->scanCode
;
1154 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
1157 static void test_Input_unicode(void)
1159 WCHAR classNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1160 'K','e','y','T','e','s','t','C','l','a','s','s',0};
1161 WCHAR windowNameW
[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1162 'K','e','y','T','e','s','t',0};
1165 HANDLE hInstance
= GetModuleHandleW(NULL
);
1167 HMODULE hModuleImm32
;
1168 BOOL (WINAPI
*pImmDisableIME
)(DWORD
);
1170 wclass
.lpszClassName
= classNameW
;
1171 wclass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1172 wclass
.lpfnWndProc
= unicode_wnd_proc
;
1173 wclass
.hInstance
= hInstance
;
1174 wclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_APPLICATION
);
1175 wclass
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
1176 wclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1177 wclass
.lpszMenuName
= 0;
1178 wclass
.cbClsExtra
= 0;
1179 wclass
.cbWndExtra
= 0;
1180 if(!RegisterClassW(&wclass
)){
1181 win_skip("Unicode functions not supported\n");
1185 hModuleImm32
= LoadLibraryA("imm32.dll");
1187 pImmDisableIME
= (void *)GetProcAddress(hModuleImm32
, "ImmDisableIME");
1191 pImmDisableIME
= NULL
;
1192 FreeLibrary(hModuleImm32
);
1194 /* create the test window that will receive the keystrokes */
1195 hWndTest
= CreateWindowW(wclass
.lpszClassName
, windowNameW
,
1196 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0, 100, 100,
1197 NULL
, NULL
, hInstance
, NULL
);
1200 assert(IsWindowUnicode(hWndTest
));
1202 hook
= SetWindowsHookExW(WH_KEYBOARD_LL
, llkbd_unicode_hook
, GetModuleHandleW(NULL
), 0);
1204 win_skip("unable to set WH_KEYBOARD_LL hook\n");
1206 ShowWindow(hWndTest
, SW_SHOW
);
1207 SetWindowPos(hWndTest
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
1208 SetForegroundWindow(hWndTest
);
1209 UpdateWindow(hWndTest
);
1211 /* flush pending messages */
1212 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageW(&msg
);
1216 test_unicode_keys(hWndTest
, hook
);
1219 UnhookWindowsHookEx(hook
);
1220 DestroyWindow(hWndTest
);
1223 static void test_keynames(void)
1228 for (i
= 0; i
< 512; i
++)
1230 strcpy(buff
, "----");
1231 len
= GetKeyNameTextA(i
<< 16, buff
, sizeof(buff
));
1232 ok(len
|| !buff
[0], "%d: Buffer is not zeroed\n", i
);
1236 static POINT pt_old
, pt_new
;
1237 static BOOL clipped
;
1240 static LRESULT CALLBACK
hook_proc1( int code
, WPARAM wparam
, LPARAM lparam
)
1242 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1245 if (code
== HC_ACTION
)
1247 /* This is our new cursor position */
1249 /* Should return previous position */
1251 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1253 /* Should set new position until hook chain is finished. */
1254 pt
.x
= pt_old
.x
+ STEP
;
1255 pt
.y
= pt_old
.y
+ STEP
;
1256 SetCursorPos(pt
.x
, pt
.y
);
1259 ok(pt1
.x
== pt_old
.x
&& pt1
.y
== pt_old
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1261 ok(pt1
.x
== pt
.x
&& pt1
.y
== pt
.y
, "Wrong set pos: (%d,%d)\n", pt1
.x
, pt1
.y
);
1263 return CallNextHookEx( 0, code
, wparam
, lparam
);
1266 static LRESULT CALLBACK
hook_proc2( int code
, WPARAM wparam
, LPARAM lparam
)
1268 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
1271 if (code
== HC_ACTION
)
1273 ok(hook
->pt
.x
== pt_new
.x
&& hook
->pt
.y
== pt_new
.y
,
1274 "Wrong hook coords: (%d %d) != (%d,%d)\n", hook
->pt
.x
, hook
->pt
.y
, pt_new
.x
, pt_new
.y
);
1276 /* Should match position set above */
1279 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1281 ok(pt
.x
== pt_old
.x
+STEP
&& pt
.y
== pt_old
.y
+STEP
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1283 return CallNextHookEx( 0, code
, wparam
, lparam
);
1286 static LRESULT CALLBACK
hook_proc3( int code
, WPARAM wparam
, LPARAM lparam
)
1290 if (code
== HC_ACTION
)
1292 /* MSLLHOOKSTRUCT does not seem to be reliable and contains different data on each run. */
1294 ok(pt
.x
== pt_old
.x
&& pt
.y
== pt_old
.y
, "GetCursorPos: (%d,%d)\n", pt
.x
, pt
.y
);
1296 return CallNextHookEx( 0, code
, wparam
, lparam
);
1299 static void test_mouse_ll_hook(void)
1306 GetCursorPos(&pt_org
);
1307 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
1308 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
1309 SetCursorPos(100, 100);
1311 if (!(hook2
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc2
, GetModuleHandleA(0), 0)))
1313 win_skip( "cannot set MOUSE_LL hook\n" );
1316 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc1
, GetModuleHandleA(0), 0);
1318 GetCursorPos(&pt_old
);
1319 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, 0, 0, 0);
1320 GetCursorPos(&pt_old
);
1321 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
);
1322 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, 0, 0, 0);
1323 GetCursorPos(&pt_old
);
1324 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
);
1325 mouse_event(MOUSEEVENTF_MOVE
, 0, -STEP
, 0, 0);
1326 GetCursorPos(&pt_old
);
1327 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
);
1328 mouse_event(MOUSEEVENTF_MOVE
, 0, +STEP
, 0, 0);
1329 GetCursorPos(&pt_old
);
1330 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
);
1332 SetRect(&rc
, 50, 50, 151, 151);
1336 SetCursorPos(40, 40);
1337 GetCursorPos(&pt_old
);
1338 ok(pt_old
.x
== 50 && pt_old
.y
== 50, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1339 SetCursorPos(160, 160);
1340 GetCursorPos(&pt_old
);
1341 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1342 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1343 GetCursorPos(&pt_old
);
1344 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_new
.x
, pt_new
.y
);
1347 pt_new
.x
= pt_new
.y
= 150;
1349 UnhookWindowsHookEx(hook1
);
1351 /* Now check that mouse buttons do not change mouse position
1352 if we don't have MOUSEEVENTF_MOVE flag specified. */
1354 /* We reusing the same hook callback, so make it happy */
1355 pt_old
.x
= pt_new
.x
- STEP
;
1356 pt_old
.y
= pt_new
.y
- STEP
;
1357 mouse_event(MOUSEEVENTF_LEFTUP
, 123, 456, 0, 0);
1359 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1360 mouse_event(MOUSEEVENTF_RIGHTUP
, 456, 123, 0, 0);
1362 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1364 mouse_event(MOUSEEVENTF_LEFTUP
| MOUSEEVENTF_ABSOLUTE
, 123, 456, 0, 0);
1366 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1367 mouse_event(MOUSEEVENTF_RIGHTUP
| MOUSEEVENTF_ABSOLUTE
, 456, 123, 0, 0);
1369 ok(pt
.x
== pt_new
.x
&& pt
.y
== pt_new
.y
, "Position changed: (%d,%d)\n", pt
.x
, pt
.y
);
1371 UnhookWindowsHookEx(hook2
);
1372 hook1
= SetWindowsHookExA(WH_MOUSE_LL
, hook_proc3
, GetModuleHandleA(0), 0);
1374 SetRect(&rc
, 150, 150, 150, 150);
1378 SetCursorPos(140, 140);
1379 GetCursorPos(&pt_old
);
1380 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1381 SetCursorPos(160, 160);
1382 GetCursorPos(&pt_old
);
1384 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1385 mouse_event(MOUSEEVENTF_MOVE
, -STEP
, -STEP
, 0, 0);
1386 GetCursorPos(&pt_old
);
1387 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1388 mouse_event(MOUSEEVENTF_MOVE
, +STEP
, +STEP
, 0, 0);
1389 GetCursorPos(&pt_old
);
1391 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1392 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1393 GetCursorPos(&pt_old
);
1394 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1395 mouse_event(MOUSEEVENTF_MOVE
, 0, 0, 0, 0);
1396 GetCursorPos(&pt_old
);
1398 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1403 SetCursorPos(140, 140);
1404 SetRect(&rc
, 150, 150, 150, 150);
1406 GetCursorPos(&pt_old
);
1407 ok(pt_old
.x
== 150 && pt_old
.y
== 150, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1410 SetCursorPos(160, 160);
1411 SetRect(&rc
, 150, 150, 150, 150);
1413 GetCursorPos(&pt_old
);
1415 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1418 SetCursorPos(150, 150);
1419 SetRect(&rc
, 150, 150, 150, 150);
1421 GetCursorPos(&pt_old
);
1423 ok(pt_old
.x
== 149 && pt_old
.y
== 149, "Wrong new pos: (%d,%d)\n", pt_old
.x
, pt_old
.y
);
1426 UnhookWindowsHookEx(hook1
);
1429 DestroyWindow(hwnd
);
1430 SetCursorPos(pt_org
.x
, pt_org
.y
);
1433 static void test_GetMouseMovePointsEx(void)
1436 #define MYERROR 0xdeadbeef
1439 MOUSEMOVEPOINT out
[200];
1442 /* Get a valid content for the input struct */
1443 if(!GetCursorPos(&point
)) {
1444 win_skip("GetCursorPos() failed with error %u\n", GetLastError());
1447 memset(&in
, 0, sizeof(MOUSEMOVEPOINT
));
1451 /* test first parameter
1452 * everything different than sizeof(MOUSEMOVEPOINT)
1453 * is expected to fail with ERROR_INVALID_PARAMETER
1455 SetLastError(MYERROR
);
1456 retval
= pGetMouseMovePointsEx(0, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1457 if (retval
== ERROR_INVALID_PARAMETER
)
1459 win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1462 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1463 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1464 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1466 SetLastError(MYERROR
);
1467 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1468 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1469 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1470 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1472 SetLastError(MYERROR
);
1473 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)+1, &in
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1474 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1475 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1476 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1478 /* test second and third parameter
1480 SetLastError(MYERROR
);
1481 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1482 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1483 ok(GetLastError() == ERROR_NOACCESS
|| GetLastError() == MYERROR
,
1484 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1486 SetLastError(MYERROR
);
1487 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1488 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1489 ok(ERROR_NOACCESS
== GetLastError(),
1490 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1492 SetLastError(MYERROR
);
1493 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1494 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1495 ok(ERROR_NOACCESS
== GetLastError(),
1496 "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1498 SetLastError(MYERROR
);
1500 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, count
, GMMP_USE_DISPLAY_POINTS
);
1502 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1504 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1506 /* test fourth parameter
1507 * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1509 SetLastError(MYERROR
);
1511 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1512 ok(retval
== count
, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1513 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1514 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1516 SetLastError(MYERROR
);
1518 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1520 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1522 ok(retval
== count
, "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1524 SetLastError(MYERROR
);
1526 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, count
, GMMP_USE_DISPLAY_POINTS
);
1528 ok(GetLastError() == ERROR_POINT_NOT_FOUND
, "unexpected error %u\n", GetLastError());
1530 ok((0 <= retval
) && (retval
<= count
), "expected GetMouseMovePointsEx to succeed, got %d\n", retval
);
1532 SetLastError(MYERROR
);
1533 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, out
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1534 ok(retval
== -1, "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 /* it was not possible to force an error with the fifth parameter on win2k */
1540 /* test combinations of wrong parameters to see which error wins */
1541 SetLastError(MYERROR
);
1542 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, NULL
, out
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1543 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1544 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1545 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1547 SetLastError(MYERROR
);
1548 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
)-1, &in
, NULL
, BUFLIM
, GMMP_USE_DISPLAY_POINTS
);
1549 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1550 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1551 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1553 SetLastError(MYERROR
);
1554 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), NULL
, out
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1555 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1556 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1557 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1559 SetLastError(MYERROR
);
1560 retval
= pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT
), &in
, NULL
, BUFLIM
+1, GMMP_USE_DISPLAY_POINTS
);
1561 ok(retval
== -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval
);
1562 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| GetLastError() == MYERROR
,
1563 "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1569 static void test_GetRawInputDeviceList(void)
1571 RAWINPUTDEVICELIST devices
[32];
1572 UINT ret
, oret
, devcount
, odevcount
;
1575 SetLastError(0xdeadbeef);
1576 ret
= pGetRawInputDeviceList(NULL
, NULL
, 0);
1577 err
= GetLastError();
1578 ok(ret
== -1, "expected -1, got %d\n", ret
);
1579 ok(err
== ERROR_INVALID_PARAMETER
, "expected 87, got %d\n", err
);
1581 SetLastError(0xdeadbeef);
1582 ret
= pGetRawInputDeviceList(NULL
, NULL
, sizeof(devices
[0]));
1583 err
= GetLastError();
1584 ok(ret
== -1, "expected -1, got %d\n", ret
);
1585 ok(err
== ERROR_NOACCESS
, "expected 998, got %d\n", err
);
1588 ret
= pGetRawInputDeviceList(NULL
, &devcount
, sizeof(devices
[0]));
1589 ok(ret
== 0, "expected 0, got %d\n", ret
);
1590 ok(devcount
> 0, "expected non-zero\n");
1592 SetLastError(0xdeadbeef);
1594 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1595 err
= GetLastError();
1596 ok(ret
== -1, "expected -1, got %d\n", ret
);
1597 ok(err
== ERROR_INSUFFICIENT_BUFFER
, "expected 122, got %d\n", err
);
1598 ok(devcount
> 0, "expected non-zero\n");
1600 /* devcount contains now the correct number of devices */
1601 ret
= pGetRawInputDeviceList(devices
, &devcount
, sizeof(devices
[0]));
1602 ok(ret
> 0, "expected non-zero\n");
1604 /* check if variable changes from larger to smaller value */
1605 devcount
= odevcount
= sizeof(devices
) / sizeof(devices
[0]);
1606 oret
= ret
= pGetRawInputDeviceList(devices
, &odevcount
, sizeof(devices
[0]));
1607 ok(ret
> 0, "expected non-zero\n");
1608 ok(devcount
== odevcount
, "expected %d, got %d\n", devcount
, odevcount
);
1609 devcount
= odevcount
;
1610 odevcount
= sizeof(devices
) / sizeof(devices
[0]);
1611 ret
= pGetRawInputDeviceList(NULL
, &odevcount
, sizeof(devices
[0]));
1612 ok(ret
== 0, "expected 0, got %d\n", ret
);
1613 ok(odevcount
== oret
, "expected %d, got %d\n", oret
, odevcount
);
1616 static void test_key_map(void)
1618 HKL kl
= GetKeyboardLayout(0);
1621 static const UINT numpad_collisions
[][2] = {
1622 { VK_NUMPAD0
, VK_INSERT
},
1623 { VK_NUMPAD1
, VK_END
},
1624 { VK_NUMPAD2
, VK_DOWN
},
1625 { VK_NUMPAD3
, VK_NEXT
},
1626 { VK_NUMPAD4
, VK_LEFT
},
1627 { VK_NUMPAD6
, VK_RIGHT
},
1628 { VK_NUMPAD7
, VK_HOME
},
1629 { VK_NUMPAD8
, VK_UP
},
1630 { VK_NUMPAD9
, VK_PRIOR
},
1633 s
= MapVirtualKeyExA(VK_SHIFT
, MAPVK_VK_TO_VSC
, kl
);
1634 ok(s
!= 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
1635 sL
= MapVirtualKeyExA(VK_LSHIFT
, MAPVK_VK_TO_VSC
, kl
);
1636 ok(s
== sL
|| broken(sL
== 0), /* win9x */
1637 "%x != %x\n", s
, sL
);
1639 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK
, kl
);
1640 ok(kL
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL
);
1641 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK
, kl
);
1642 ok(kR
== VK_SHIFT
, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR
);
1644 kL
= MapVirtualKeyExA(0x2a, MAPVK_VSC_TO_VK_EX
, kl
);
1645 ok(kL
== VK_LSHIFT
|| broken(kL
== 0), /* win9x */
1646 "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL
);
1647 kR
= MapVirtualKeyExA(0x36, MAPVK_VSC_TO_VK_EX
, kl
);
1648 ok(kR
== VK_RSHIFT
|| broken(kR
== 0), /* win9x */
1649 "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR
);
1651 /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
1652 for (i
= 0; i
< sizeof(numpad_collisions
)/sizeof(numpad_collisions
[0]); i
++)
1654 UINT numpad_scan
= MapVirtualKeyExA(numpad_collisions
[i
][0], MAPVK_VK_TO_VSC
, kl
);
1655 UINT other_scan
= MapVirtualKeyExA(numpad_collisions
[i
][1], MAPVK_VK_TO_VSC
, kl
);
1657 /* do they really collide for this layout? */
1658 if (numpad_scan
&& other_scan
== numpad_scan
)
1660 UINT vkey
= MapVirtualKeyExA(numpad_scan
, MAPVK_VSC_TO_VK
, kl
);
1661 ok(vkey
!= numpad_collisions
[i
][0],
1662 "Got numpad vKey %x for scan code %x when there was another choice\n",
1671 static const struct tounicode_tests
1675 WCHAR chr
; /* if vk is 0, lookup vk using this char */
1677 WCHAR expect_buf
[4];
1680 { 'A', 0, 0, 1, {'a',0}},
1681 { 'A', ctrl
, 0, 1, {1, 0}},
1682 { 'A', shift
|ctrl
, 0, 1, {1, 0}},
1683 { VK_TAB
, ctrl
, 0, 0, {0}},
1684 { VK_TAB
, shift
|ctrl
, 0, 0, {0}},
1685 { VK_RETURN
, ctrl
, 0, 1, {'\n', 0}},
1686 { VK_RETURN
, shift
|ctrl
, 0, 0, {0}},
1687 { '4', ctrl
, 0, 0, {0}},
1688 { '4', shift
|ctrl
, 0, 0, {0}},
1689 { 0, ctrl
, '!', 0, {0}},
1690 { 0, ctrl
, '\"', 0, {0}},
1691 { 0, ctrl
, '#', 0, {0}},
1692 { 0, ctrl
, '$', 0, {0}},
1693 { 0, ctrl
, '%', 0, {0}},
1694 { 0, ctrl
, '\'', 0, {0}},
1695 { 0, ctrl
, '(', 0, {0}},
1696 { 0, ctrl
, ')', 0, {0}},
1697 { 0, ctrl
, '*', 0, {0}},
1698 { 0, ctrl
, '+', 0, {0}},
1699 { 0, ctrl
, ',', 0, {0}},
1700 { 0, ctrl
, '-', 0, {0}},
1701 { 0, ctrl
, '.', 0, {0}},
1702 { 0, ctrl
, '/', 0, {0}},
1703 { 0, ctrl
, ':', 0, {0}},
1704 { 0, ctrl
, ';', 0, {0}},
1705 { 0, ctrl
, '<', 0, {0}},
1706 { 0, ctrl
, '=', 0, {0}},
1707 { 0, ctrl
, '>', 0, {0}},
1708 { 0, ctrl
, '?', 0, {0}},
1709 { 0, ctrl
, '@', 1, {0}},
1710 { 0, ctrl
, '[', 1, {0x1b}},
1711 { 0, ctrl
, '\\', 1, {0x1c}},
1712 { 0, ctrl
, ']', 1, {0x1d}},
1713 { 0, ctrl
, '^', 1, {0x1e}},
1714 { 0, ctrl
, '_', 1, {0x1f}},
1715 { 0, ctrl
, '`', 0, {0}},
1716 { VK_SPACE
, 0, 0, 1, {' ',0}},
1717 { VK_SPACE
, shift
, 0, 1, {' ',0}},
1718 { VK_SPACE
, ctrl
, 0, 1, {' ',0}},
1721 static void test_ToUnicode(void)
1725 const BYTE SC_RETURN
= 0x1c, SC_TAB
= 0x0f, SC_A
= 0x1e;
1726 const BYTE HIGHEST_BIT
= 0x80;
1728 BOOL us_kbd
= (GetKeyboardLayout(0) == (HKL
)(ULONG_PTR
)0x04090409);
1730 for(i
=0; i
<256; i
++)
1734 SetLastError(0xdeadbeef);
1735 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, state
, wStr
, 4, 0);
1736 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1738 win_skip("ToUnicode is not implemented\n");
1742 ok(ret
== 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret
);
1745 ok(wStr
[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr
[0]);
1746 ok(wStr
[1]==0 || broken(wStr
[1]!=0) /* nt4 */,
1747 "ToUnicode didn't null-terminate the buffer when there was room.\n");
1750 for (i
= 0; i
< sizeof(utests
) / sizeof(utests
[0]); i
++)
1752 UINT vk
= utests
[i
].vk
, mod
= utests
[i
].modifiers
, scan
;
1758 if (!us_kbd
) continue;
1759 vk_ret
= VkKeyScanW(utests
[i
].chr
);
1760 if (vk_ret
== -1) continue;
1762 if (vk_ret
& 0x100) mod
|= shift
;
1763 if (vk_ret
& 0x200) mod
|= ctrl
;
1765 scan
= MapVirtualKeyW(vk
, MAPVK_VK_TO_VSC
);
1767 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = (mod
& shift
) ? HIGHEST_BIT
: 0;
1768 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = (mod
& ctrl
) ? HIGHEST_BIT
: 0;
1770 ret
= ToUnicode(vk
, scan
, state
, wStr
, 4, 0);
1771 ok(ret
== utests
[i
].expect_ret
, "%d: got %d expected %d\n", i
, ret
, utests
[i
].expect_ret
);
1773 ok(!lstrcmpW(wStr
, utests
[i
].expect_buf
), "%d: got %s expected %s\n", i
, wine_dbgstr_w(wStr
),
1774 wine_dbgstr_w(utests
[i
].expect_buf
));
1777 state
[VK_SHIFT
] = state
[VK_LSHIFT
] = 0;
1778 state
[VK_CONTROL
] = state
[VK_LCONTROL
] = 0;
1780 ret
= ToUnicode(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0);
1781 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1782 ret
= ToUnicode(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0);
1783 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1784 ret
= ToUnicode('A', SC_A
, NULL
, wStr
, 4, 0);
1785 ok(ret
== 0, "ToUnicode with NULL keystate didn't return 0 (was %i)\n", ret
);
1786 ret
= ToUnicodeEx(VK_TAB
, SC_TAB
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1787 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1788 ret
= ToUnicodeEx(VK_RETURN
, SC_RETURN
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1789 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1790 ret
= ToUnicodeEx('A', SC_A
, NULL
, wStr
, 4, 0, GetKeyboardLayout(0));
1791 ok(ret
== 0, "ToUnicodeEx with NULL keystate didn't return 0 (was %i)\n", ret
);
1794 static void test_ToAscii(void)
1798 const BYTE SC_RETURN
= 0x1c, SC_A
= 0x1e;
1799 const BYTE HIGHEST_BIT
= 0x80;
1802 memset(state
, 0, sizeof(state
));
1805 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1806 ok(ret
== 1, "ToAscii for Return key didn't return 1 (was %i)\n", ret
);
1807 ok(character
== '\r', "ToAscii for Return was %i (expected 13)\n", character
);
1810 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
1811 ok(ret
== 1, "ToAscii for character 'A' didn't return 1 (was %i)\n", ret
);
1812 ok(character
== 'a', "ToAscii for character 'A' was %i (expected %i)\n", character
, 'a');
1814 state
[VK_CONTROL
] |= HIGHEST_BIT
;
1815 state
[VK_LCONTROL
] |= HIGHEST_BIT
;
1817 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1818 ok(ret
== 1, "ToAscii for CTRL + Return key didn't return 1 (was %i)\n", ret
);
1819 ok(character
== '\n', "ToAscii for CTRL + Return was %i (expected 10)\n", character
);
1822 ret
= ToAscii('A', SC_A
, state
, &character
, 0);
1823 ok(ret
== 1, "ToAscii for CTRL + character 'A' didn't return 1 (was %i)\n", ret
);
1824 ok(character
== 1, "ToAscii for CTRL + character 'A' was %i (expected 1)\n", character
);
1826 state
[VK_SHIFT
] |= HIGHEST_BIT
;
1827 state
[VK_LSHIFT
] |= HIGHEST_BIT
;
1828 ret
= ToAscii(VK_RETURN
, SC_RETURN
, state
, &character
, 0);
1829 ok(ret
== 0, "ToAscii for CTRL + Shift + Return key didn't return 0 (was %i)\n", ret
);
1831 ret
= ToAscii(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0);
1832 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
1833 ret
= ToAscii('A', SC_A
, NULL
, &character
, 0);
1834 ok(ret
== 0, "ToAscii for NULL keystate didn't return 0 (was %i)\n", ret
);
1835 ret
= ToAsciiEx(VK_RETURN
, SC_RETURN
, NULL
, &character
, 0, GetKeyboardLayout(0));
1836 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
1837 ret
= ToAsciiEx('A', SC_A
, NULL
, &character
, 0, GetKeyboardLayout(0));
1838 ok(ret
== 0, "ToAsciiEx for NULL keystate didn't return 0 (was %i)\n", ret
);
1841 static void test_get_async_key_state(void)
1843 /* input value sanity checks */
1844 ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
1845 ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
1848 static void test_keyboard_layout_name(void)
1851 char klid
[KL_NAMELENGTH
];
1853 if (0) /* crashes on native system */
1854 ret
= GetKeyboardLayoutNameA(NULL
);
1856 SetLastError(0xdeadbeef);
1857 ret
= GetKeyboardLayoutNameW(NULL
);
1858 ok(!ret
, "got %d\n", ret
);
1859 ok(GetLastError() == ERROR_NOACCESS
, "got %d\n", GetLastError());
1861 if (GetKeyboardLayout(0) != (HKL
)(ULONG_PTR
)0x04090409) return;
1864 ret
= GetKeyboardLayoutNameA(klid
);
1865 ok(ret
, "GetKeyboardLayoutNameA failed %u\n", GetLastError());
1866 ok(!strcmp(klid
, "00000409"), "expected 00000409, got %s\n", klid
);
1869 static void test_key_names(void)
1874 LONG lparam
= 0x1d << 16;
1876 memset( buffer
, 0xcc, sizeof(buffer
) );
1877 ret
= GetKeyNameTextA( lparam
, buffer
, sizeof(buffer
) );
1878 ok( ret
> 0, "wrong len %u for '%s'\n", ret
, buffer
);
1879 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
1881 memset( buffer
, 0xcc, sizeof(buffer
) );
1883 ret
= GetKeyNameTextA( lparam
, buffer
, prev
);
1884 ok( ret
== prev
- 1, "wrong len %u for '%s'\n", ret
, buffer
);
1885 ok( ret
== strlen(buffer
), "wrong len %u for '%s'\n", ret
, buffer
);
1887 memset( buffer
, 0xcc, sizeof(buffer
) );
1888 ret
= GetKeyNameTextA( lparam
, buffer
, 0 );
1889 ok( ret
== 0, "wrong len %u for '%s'\n", ret
, buffer
);
1890 ok( buffer
[0] == 0, "wrong string '%s'\n", buffer
);
1892 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1893 ret
= GetKeyNameTextW( lparam
, bufferW
, sizeof(bufferW
)/sizeof(WCHAR
) );
1894 ok( ret
> 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1895 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1897 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1899 ret
= GetKeyNameTextW( lparam
, bufferW
, prev
);
1900 ok( ret
== prev
- 1, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1901 ok( ret
== lstrlenW(bufferW
), "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1903 memset( bufferW
, 0xcc, sizeof(bufferW
) );
1904 ret
= GetKeyNameTextW( lparam
, bufferW
, 0 );
1905 ok( ret
== 0, "wrong len %u for %s\n", ret
, wine_dbgstr_w(bufferW
) );
1906 ok( bufferW
[0] == 0xcccc, "wrong string %s\n", wine_dbgstr_w(bufferW
) );
1909 static void simulate_click(BOOL left
, int x
, int y
)
1915 memset(input
, 0, sizeof(input
));
1916 input
[0].type
= INPUT_MOUSE
;
1917 U(input
[0]).mi
.dx
= x
;
1918 U(input
[0]).mi
.dy
= y
;
1919 U(input
[0]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTDOWN
: MOUSEEVENTF_RIGHTDOWN
;
1920 input
[1].type
= INPUT_MOUSE
;
1921 U(input
[1]).mi
.dx
= x
;
1922 U(input
[1]).mi
.dy
= y
;
1923 U(input
[1]).mi
.dwFlags
= left
? MOUSEEVENTF_LEFTUP
: MOUSEEVENTF_RIGHTUP
;
1924 events_no
= SendInput(2, input
, sizeof(input
[0]));
1925 ok(events_no
== 2, "SendInput returned %d\n", events_no
);
1928 static BOOL
wait_for_message( MSG
*msg
)
1934 ret
= PeekMessageA(msg
, 0, 0, 0, PM_REMOVE
);
1937 if (msg
->message
== WM_PAINT
) DispatchMessageA(msg
);
1940 else if (MsgWaitForMultipleObjects(0, NULL
, FALSE
, 100, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
1942 if (!ret
) msg
->message
= 0;
1946 static BOOL
wait_for_event(HANDLE event
, int timeout
)
1948 DWORD end_time
= GetTickCount() + timeout
;
1952 if(MsgWaitForMultipleObjects(1, &event
, FALSE
, timeout
, QS_ALLINPUT
) == WAIT_OBJECT_0
)
1954 while(PeekMessageA(&msg
, 0, 0, 0, PM_REMOVE
))
1955 DispatchMessageA(&msg
);
1956 timeout
= end_time
- GetTickCount();
1957 }while(timeout
> 0);
1962 static WNDPROC def_static_proc
;
1963 static DWORD hittest_no
;
1964 static LRESULT WINAPI
static_hook_proc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1966 if (msg
== WM_NCHITTEST
)
1968 /* break infinite hittest loop */
1969 if(hittest_no
> 50) return HTCLIENT
;
1973 return def_static_proc(hwnd
, msg
, wp
, lp
);
1983 static DWORD WINAPI
create_static_win(void *arg
)
1985 struct thread_data
*thread_data
= arg
;
1988 win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
1989 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
1990 ok(win
!= 0, "CreateWindow failed\n");
1991 def_static_proc
= (void*)SetWindowLongPtrA(win
,
1992 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
1993 thread_data
->win
= win
;
1995 SetEvent(thread_data
->start_event
);
1996 wait_for_event(thread_data
->end_event
, 5000);
2000 static void get_dc_region(RECT
*region
, HWND hwnd
, DWORD flags
)
2006 hdc
= GetDCEx(hwnd
, 0, flags
);
2007 ok(hdc
!= NULL
, "GetDCEx failed\n");
2008 hregion
= CreateRectRgn(40, 40, 60, 60);
2009 ok(hregion
!= NULL
, "CreateRectRgn failed\n");
2010 GetRandomRgn(hdc
, hregion
, SYSRGN
);
2011 region_type
= GetRgnBox(hregion
, region
);
2012 ok(region_type
== SIMPLEREGION
, "expected SIMPLEREGION, got %d\n", region_type
);
2013 DeleteObject(hregion
);
2014 ReleaseDC(hwnd
, hdc
);
2017 static void test_Input_mouse(void)
2019 BOOL got_button_down
, got_button_up
;
2020 HWND hwnd
, button_win
, static_win
;
2021 struct thread_data thread_data
;
2032 SetLastError(0xdeadbeef);
2033 ret
= GetCursorPos(NULL
);
2034 ok(!ret
, "GetCursorPos succeed\n");
2035 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_NOACCESS
, "error %u\n", GetLastError());
2037 SetLastError(0xdeadbeef);
2038 ret
= GetCursorPos(&pt_org
);
2039 ok(ret
, "GetCursorPos failed\n");
2040 ok(GetLastError() == 0xdeadbeef, "error %u\n", GetLastError());
2042 button_win
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
2043 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2044 ok(button_win
!= 0, "CreateWindow failed\n");
2047 hwnd
= WindowFromPoint(pt
);
2048 if (hwnd
!= button_win
)
2050 skip("there's another window covering test window\n");
2051 DestroyWindow(button_win
);
2055 /* simple button click test */
2056 simulate_click(TRUE
, 150, 150);
2057 got_button_down
= got_button_up
= FALSE
;
2058 while (wait_for_message(&msg
))
2060 DispatchMessageA(&msg
);
2062 if (msg
.message
== WM_LBUTTONDOWN
)
2064 got_button_down
= TRUE
;
2066 else if (msg
.message
== WM_LBUTTONUP
)
2068 got_button_up
= TRUE
;
2072 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2073 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2075 /* click through HTTRANSPARENT child window */
2076 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_CHILD
,
2077 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
2078 ok(static_win
!= 0, "CreateWindow failed\n");
2079 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
2080 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
2081 simulate_click(FALSE
, 150, 150);
2083 got_button_down
= got_button_up
= FALSE
;
2084 while (wait_for_message(&msg
))
2086 DispatchMessageA(&msg
);
2088 if (msg
.message
== WM_RBUTTONDOWN
)
2090 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2091 got_button_down
= TRUE
;
2093 else if (msg
.message
== WM_RBUTTONUP
)
2095 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2096 got_button_up
= TRUE
;
2100 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2101 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
2102 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
2103 DestroyWindow(static_win
);
2105 /* click through HTTRANSPARENT top-level window */
2106 static_win
= CreateWindowA("static", "static", WS_VISIBLE
| WS_POPUP
,
2107 100, 100, 100, 100, 0, NULL
, NULL
, NULL
);
2108 ok(static_win
!= 0, "CreateWindow failed\n");
2109 def_static_proc
= (void*)SetWindowLongPtrA(static_win
,
2110 GWLP_WNDPROC
, (LONG_PTR
)static_hook_proc
);
2111 simulate_click(TRUE
, 150, 150);
2113 got_button_down
= got_button_up
= FALSE
;
2114 while (wait_for_message(&msg
))
2116 DispatchMessageA(&msg
);
2118 if (msg
.message
== WM_LBUTTONDOWN
)
2120 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2121 got_button_down
= TRUE
;
2123 else if (msg
.message
== WM_LBUTTONUP
)
2125 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2126 got_button_up
= TRUE
;
2130 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2131 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2132 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2133 DestroyWindow(static_win
);
2135 /* click on HTTRANSPARENT top-level window that belongs to other thread */
2136 thread_data
.start_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2137 ok(thread_data
.start_event
!= NULL
, "CreateEvent failed\n");
2138 thread_data
.end_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
2139 ok(thread_data
.end_event
!= NULL
, "CreateEvent failed\n");
2140 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, NULL
);
2141 ok(thread
!= NULL
, "CreateThread failed\n");
2143 got_button_down
= got_button_up
= FALSE
;
2144 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
2145 simulate_click(FALSE
, 150, 150);
2146 while (wait_for_message(&msg
))
2148 DispatchMessageA(&msg
);
2150 if (msg
.message
== WM_RBUTTONDOWN
)
2151 got_button_down
= TRUE
;
2152 else if (msg
.message
== WM_RBUTTONUP
)
2153 got_button_up
= TRUE
;
2155 SetEvent(thread_data
.end_event
);
2156 WaitForSingleObject(thread
, INFINITE
);
2157 CloseHandle(thread
);
2158 ok(hittest_no
&& hittest_no
<50, "expected WM_NCHITTEST message\n");
2159 ok(!got_button_down
, "unexpected WM_RBUTTONDOWN message\n");
2160 ok(!got_button_up
, "unexpected WM_RBUTTONUP message\n");
2162 /* click on HTTRANSPARENT top-level window that belongs to other thread,
2163 * thread input queues are attached */
2164 thread
= CreateThread(NULL
, 0, create_static_win
, &thread_data
, 0, &thread_id
);
2165 ok(thread
!= NULL
, "CreateThread failed\n");
2167 got_button_down
= got_button_up
= FALSE
;
2168 WaitForSingleObject(thread_data
.start_event
, INFINITE
);
2169 ok(AttachThreadInput(thread_id
, GetCurrentThreadId(), TRUE
),
2170 "AttachThreadInput failed\n");
2171 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2172 SetWindowPos(thread_data
.win
, button_win
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
);
2173 simulate_click(TRUE
, 150, 150);
2174 while (wait_for_message(&msg
))
2176 DispatchMessageA(&msg
);
2178 if (msg
.message
== WM_LBUTTONDOWN
)
2179 got_button_down
= TRUE
;
2180 else if (msg
.message
== WM_LBUTTONUP
)
2181 got_button_up
= TRUE
;
2183 SetEvent(thread_data
.end_event
);
2184 WaitForSingleObject(thread
, INFINITE
);
2185 todo_wine
ok(hittest_no
> 50, "expected loop with WM_NCHITTEST messages\n");
2186 ok(!got_button_down
, "unexpected WM_LBUTTONDOWN message\n");
2187 ok(!got_button_up
, "unexpected WM_LBUTTONUP message\n");
2189 /* click after SetCapture call */
2190 hwnd
= CreateWindowA("button", "button", WS_VISIBLE
| WS_POPUP
,
2191 0, 0, 100, 100, 0, NULL
, NULL
, NULL
);
2192 ok(hwnd
!= 0, "CreateWindow failed\n");
2193 SetCapture(button_win
);
2194 got_button_down
= got_button_up
= FALSE
;
2195 simulate_click(FALSE
, 50, 50);
2196 while (wait_for_message(&msg
))
2198 DispatchMessageA(&msg
);
2200 if (msg
.message
== WM_RBUTTONDOWN
)
2202 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2203 got_button_down
= TRUE
;
2205 else if (msg
.message
== WM_RBUTTONUP
)
2207 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2208 got_button_up
= TRUE
;
2212 ok(got_button_down
, "expected WM_RBUTTONDOWN message\n");
2213 ok(got_button_up
, "expected WM_RBUTTONUP message\n");
2214 DestroyWindow(hwnd
);
2216 /* click on child window after SetCapture call */
2217 hwnd
= CreateWindowA("button", "button2", WS_VISIBLE
| WS_CHILD
,
2218 0, 0, 100, 100, button_win
, NULL
, NULL
, NULL
);
2219 ok(hwnd
!= 0, "CreateWindow failed\n");
2220 got_button_down
= got_button_up
= FALSE
;
2221 simulate_click(TRUE
, 150, 150);
2222 while (wait_for_message(&msg
))
2224 DispatchMessageA(&msg
);
2226 if (msg
.message
== WM_LBUTTONDOWN
)
2228 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2229 got_button_down
= TRUE
;
2231 else if (msg
.message
== WM_LBUTTONUP
)
2233 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2234 got_button_up
= TRUE
;
2238 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2239 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2240 DestroyWindow(hwnd
);
2241 ok(ReleaseCapture(), "ReleaseCapture failed\n");
2244 wclass
.lpfnWndProc
= WndProc
;
2245 wclass
.cbClsExtra
= 0;
2246 wclass
.cbWndExtra
= 0;
2247 wclass
.hInstance
= GetModuleHandleA(NULL
);
2248 wclass
.hIcon
= LoadIconA(0, (LPCSTR
)IDI_APPLICATION
);
2249 wclass
.hCursor
= LoadCursorA(NULL
, (LPCSTR
)IDC_ARROW
);
2250 wclass
.hbrBackground
= CreateSolidBrush(RGB(128, 128, 128));
2251 wclass
.lpszMenuName
= NULL
;
2252 wclass
.lpszClassName
= "InputLayeredTestClass";
2253 RegisterClassA( &wclass
);
2255 /* click through layered window with alpha channel / color key */
2256 hwnd
= CreateWindowA(wclass
.lpszClassName
, "InputLayeredTest",
2257 WS_VISIBLE
| WS_POPUP
, 100, 100, 100, 100, button_win
, NULL
, NULL
, NULL
);
2258 ok(hwnd
!= NULL
, "CreateWindowEx failed\n");
2260 static_win
= CreateWindowA("static", "Title", WS_VISIBLE
| WS_CHILD
,
2261 10, 10, 20, 20, hwnd
, NULL
, NULL
, NULL
);
2262 ok(static_win
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
2264 SetWindowPos(hwnd
, HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
);
2265 SetWindowLongA(hwnd
, GWL_EXSTYLE
, GetWindowLongA(hwnd
, GWL_EXSTYLE
) | WS_EX_LAYERED
);
2266 ret
= SetLayeredWindowAttributes(hwnd
, 0, 255, LWA_ALPHA
);
2267 ok(ret
, "SetLayeredWindowAttributes failed\n");
2268 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2271 if (pGetWindowRgnBox
)
2273 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2274 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2277 got_button_down
= got_button_up
= FALSE
;
2278 simulate_click(TRUE
, 150, 150);
2279 while (wait_for_message(&msg
))
2281 DispatchMessageA(&msg
);
2283 if (msg
.message
== WM_LBUTTONDOWN
)
2285 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2286 got_button_down
= TRUE
;
2288 else if (msg
.message
== WM_LBUTTONUP
)
2290 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2291 got_button_up
= TRUE
;
2295 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2296 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2298 ret
= SetLayeredWindowAttributes(hwnd
, 0, 0, LWA_ALPHA
);
2299 ok(ret
, "SetLayeredWindowAttributes failed\n");
2300 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2303 if (pGetWindowRgnBox
)
2305 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2306 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2309 got_button_down
= got_button_up
= FALSE
;
2310 simulate_click(TRUE
, 150, 150);
2311 while (wait_for_message(&msg
))
2313 DispatchMessageA(&msg
);
2315 if (msg
.message
== WM_LBUTTONDOWN
)
2318 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2319 got_button_down
= TRUE
;
2321 else if (msg
.message
== WM_LBUTTONUP
)
2324 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2325 got_button_up
= TRUE
;
2329 ok(got_button_down
|| broken(!got_button_down
), "expected WM_LBUTTONDOWN message\n");
2330 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2332 ret
= SetLayeredWindowAttributes(hwnd
, RGB(0, 255, 0), 255, LWA_ALPHA
| LWA_COLORKEY
);
2333 ok(ret
, "SetLayeredWindowAttributes failed\n");
2334 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2337 if (pGetWindowRgnBox
)
2339 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2340 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2343 got_button_down
= got_button_up
= FALSE
;
2344 simulate_click(TRUE
, 150, 150);
2345 while (wait_for_message(&msg
))
2347 DispatchMessageA(&msg
);
2349 if (msg
.message
== WM_LBUTTONDOWN
)
2351 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2352 got_button_down
= TRUE
;
2354 else if (msg
.message
== WM_LBUTTONUP
)
2356 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2357 got_button_up
= TRUE
;
2361 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2362 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2364 ret
= SetLayeredWindowAttributes(hwnd
, RGB(128, 128, 128), 0, LWA_COLORKEY
);
2365 ok(ret
, "SetLayeredWindowAttributes failed\n");
2366 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2369 if (pGetWindowRgnBox
)
2371 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2372 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2375 get_dc_region(®ion
, hwnd
, DCX_PARENTCLIP
);
2376 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2377 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2378 get_dc_region(®ion
, hwnd
, DCX_WINDOW
| DCX_USESTYLE
);
2379 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2380 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2381 get_dc_region(®ion
, hwnd
, DCX_USESTYLE
);
2382 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2383 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2384 get_dc_region(®ion
, static_win
, DCX_PARENTCLIP
);
2385 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2386 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2387 get_dc_region(®ion
, static_win
, DCX_WINDOW
| DCX_USESTYLE
);
2388 ok(region
.left
== 110 && region
.top
== 110 && region
.right
== 130 && region
.bottom
== 130,
2389 "expected region (110,110)-(130,130), got %s\n", wine_dbgstr_rect(®ion
));
2390 get_dc_region(®ion
, static_win
, DCX_USESTYLE
);
2391 ok(region
.left
== 100 && region
.top
== 100 && region
.right
== 200 && region
.bottom
== 200,
2392 "expected region (100,100)-(200,200), got %s\n", wine_dbgstr_rect(®ion
));
2394 got_button_down
= got_button_up
= FALSE
;
2395 simulate_click(TRUE
, 150, 150);
2396 while (wait_for_message(&msg
))
2398 DispatchMessageA(&msg
);
2400 if (msg
.message
== WM_LBUTTONDOWN
)
2402 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2403 got_button_down
= TRUE
;
2405 else if (msg
.message
== WM_LBUTTONUP
)
2407 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2408 got_button_up
= TRUE
;
2412 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2413 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2415 SetWindowLongA(hwnd
, GWL_EXSTYLE
, GetWindowLongA(hwnd
, GWL_EXSTYLE
) & ~WS_EX_LAYERED
);
2416 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2419 if (pGetWindowRgnBox
)
2421 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2422 ok(region_type
== ERROR
, "expected ERROR, got %d\n", region_type
);
2425 got_button_down
= got_button_up
= FALSE
;
2426 simulate_click(TRUE
, 150, 150);
2427 while (wait_for_message(&msg
))
2429 DispatchMessageA(&msg
);
2431 if (msg
.message
== WM_LBUTTONDOWN
)
2433 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2434 got_button_down
= TRUE
;
2436 else if (msg
.message
== WM_LBUTTONUP
)
2438 ok(msg
.hwnd
== hwnd
, "msg.hwnd = %p\n", msg
.hwnd
);
2439 got_button_up
= TRUE
;
2443 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2444 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2446 hregion
= CreateRectRgn(0, 0, 10, 10);
2447 ok(hregion
!= NULL
, "CreateRectRgn failed\n");
2448 ret
= SetWindowRgn(hwnd
, hregion
, TRUE
);
2449 ok(ret
, "SetWindowRgn failed\n");
2450 DeleteObject(hregion
);
2451 while (wait_for_message(&msg
)) DispatchMessageA(&msg
);
2454 if (pGetWindowRgnBox
)
2456 region_type
= pGetWindowRgnBox(hwnd
, ®ion
);
2457 ok(region_type
== SIMPLEREGION
, "expected SIMPLEREGION, got %d\n", region_type
);
2460 got_button_down
= got_button_up
= FALSE
;
2461 simulate_click(TRUE
, 150, 150);
2462 while (wait_for_message(&msg
))
2464 DispatchMessageA(&msg
);
2466 if (msg
.message
== WM_LBUTTONDOWN
)
2468 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2469 got_button_down
= TRUE
;
2471 else if (msg
.message
== WM_LBUTTONUP
)
2473 ok(msg
.hwnd
== button_win
, "msg.hwnd = %p\n", msg
.hwnd
);
2474 got_button_up
= TRUE
;
2478 ok(got_button_down
, "expected WM_LBUTTONDOWN message\n");
2479 ok(got_button_up
, "expected WM_LBUTTONUP message\n");
2481 DestroyWindow(static_win
);
2482 DestroyWindow(hwnd
);
2483 SetCursorPos(pt_org
.x
, pt_org
.y
);
2485 CloseHandle(thread_data
.start_event
);
2486 CloseHandle(thread_data
.end_event
);
2487 DestroyWindow(button_win
);
2491 static LRESULT WINAPI
MsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2493 if (message
== WM_USER
+1)
2495 HWND hwnd
= (HWND
)lParam
;
2496 ok(GetFocus() == hwnd
, "thread expected focus %p, got %p\n", hwnd
, GetFocus());
2497 ok(GetActiveWindow() == hwnd
, "thread expected active %p, got %p\n", hwnd
, GetActiveWindow());
2499 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2512 static DWORD WINAPI
thread_proc(void *param
)
2515 struct wnd_event
*wnd_event
= param
;
2518 if (wnd_event
->wait_event
)
2520 ok(WaitForSingleObject(wnd_event
->wait_event
, INFINITE
) == WAIT_OBJECT_0
,
2521 "WaitForSingleObject failed\n");
2522 CloseHandle(wnd_event
->wait_event
);
2525 if (wnd_event
->attach_from
)
2527 ret
= AttachThreadInput(wnd_event
->attach_from
, GetCurrentThreadId(), TRUE
);
2528 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2531 if (wnd_event
->attach_to
)
2533 ret
= AttachThreadInput(GetCurrentThreadId(), wnd_event
->attach_to
, TRUE
);
2534 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2537 wnd_event
->hwnd
= CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW
,
2538 100, 100, 200, 200, 0, 0, 0, NULL
);
2539 ok(wnd_event
->hwnd
!= 0, "Failed to create overlapped window\n");
2541 if (wnd_event
->setWindows
)
2543 SetFocus(wnd_event
->hwnd
);
2544 SetActiveWindow(wnd_event
->hwnd
);
2547 SetEvent(wnd_event
->start_event
);
2549 while (GetMessageA(&msg
, 0, 0, 0))
2551 TranslateMessage(&msg
);
2552 DispatchMessageA(&msg
);
2558 static void test_attach_input(void)
2563 struct wnd_event wnd_event
;
2567 cls
.lpfnWndProc
= MsgCheckProcA
;
2570 cls
.hInstance
= GetModuleHandleA(0);
2572 cls
.hCursor
= LoadCursorW( NULL
, (LPCWSTR
)IDC_ARROW
);
2573 cls
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
2574 cls
.lpszMenuName
= NULL
;
2575 cls
.lpszClassName
= "TestWindowClass";
2576 if(!RegisterClassA(&cls
)) return;
2578 wnd_event
.wait_event
= NULL
;
2579 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2580 wnd_event
.attach_from
= 0;
2581 wnd_event
.attach_to
= 0;
2582 wnd_event
.setWindows
= FALSE
;
2583 if (!wnd_event
.start_event
)
2585 win_skip("skipping interthread message test under win9x\n");
2589 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2590 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2592 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2593 CloseHandle(wnd_event
.start_event
);
2595 ourWnd
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
2596 0, 0, 0, 0, 0, 0, 0, NULL
);
2597 ok(ourWnd
!= 0, "failed to create ourWnd window\n");
2599 Wnd2
= CreateWindowExA(0, "TestWindowClass", NULL
, WS_OVERLAPPEDWINDOW
,
2600 0, 0, 0, 0, 0, 0, 0, NULL
);
2601 ok(Wnd2
!= 0, "failed to create Wnd2 window\n");
2604 SetActiveWindow(ourWnd
);
2606 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2607 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2609 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2610 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2612 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
2614 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2615 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2616 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2617 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2619 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2621 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2622 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2624 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2625 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2626 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)ourWnd
);
2628 SetActiveWindow(Wnd2
);
2630 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2631 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2633 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
2635 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2636 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2637 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2638 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2640 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2642 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2643 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2645 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2646 CloseHandle(hThread
);
2648 wnd_event
.wait_event
= NULL
;
2649 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2650 wnd_event
.attach_from
= 0;
2651 wnd_event
.attach_to
= 0;
2652 wnd_event
.setWindows
= TRUE
;
2654 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2655 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2657 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2658 CloseHandle(wnd_event
.start_event
);
2661 SetActiveWindow(ourWnd
);
2663 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2664 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2666 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
2667 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
2669 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2671 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2672 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2674 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
2675 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
2677 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2679 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2680 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2682 ok(GetActiveWindow() == wnd_event
.hwnd
, "expected active %p, got %p\n", wnd_event
.hwnd
, GetActiveWindow());
2683 ok(GetFocus() == wnd_event
.hwnd
, "expected focus %p, got %p\n", wnd_event
.hwnd
, GetFocus());
2685 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)wnd_event
.hwnd
);
2688 SetActiveWindow(Wnd2
);
2689 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2690 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2692 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, (LPARAM
)Wnd2
);
2694 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, FALSE
);
2695 ok(ret
, "AttachThreadInput error %d\n", GetLastError());
2697 ok(GetActiveWindow() == Wnd2
, "expected active %p, got %p\n", Wnd2
, GetActiveWindow());
2698 ok(GetFocus() == Wnd2
, "expected focus %p, got %p\n", Wnd2
, GetFocus());
2700 SendMessageA(wnd_event
.hwnd
, WM_USER
+1, 0, 0);
2702 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2703 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2705 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2706 CloseHandle(hThread
);
2708 wnd_event
.wait_event
= CreateEventW(NULL
, 0, 0, NULL
);
2709 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2710 wnd_event
.attach_from
= 0;
2711 wnd_event
.attach_to
= 0;
2712 wnd_event
.setWindows
= TRUE
;
2714 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2715 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2717 SetLastError(0xdeadbeef);
2718 ret
= AttachThreadInput(GetCurrentThreadId(), tid
, TRUE
);
2719 ok(!ret
, "AttachThreadInput succeeded\n");
2720 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2721 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2723 SetLastError(0xdeadbeef);
2724 ret
= AttachThreadInput(tid
, GetCurrentThreadId(), TRUE
);
2725 ok(!ret
, "AttachThreadInput succeeded\n");
2726 ok(GetLastError() == ERROR_INVALID_PARAMETER
|| broken(GetLastError() == 0xdeadbeef) /* <= Win XP */,
2727 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2729 SetEvent(wnd_event
.wait_event
);
2731 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2732 CloseHandle(wnd_event
.start_event
);
2734 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2735 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2737 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2738 CloseHandle(hThread
);
2740 wnd_event
.wait_event
= NULL
;
2741 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2742 wnd_event
.attach_from
= GetCurrentThreadId();
2743 wnd_event
.attach_to
= 0;
2744 wnd_event
.setWindows
= FALSE
;
2747 SetActiveWindow(ourWnd
);
2749 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2750 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2752 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2753 CloseHandle(wnd_event
.start_event
);
2755 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2756 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2758 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2759 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2761 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2762 CloseHandle(hThread
);
2764 wnd_event
.wait_event
= NULL
;
2765 wnd_event
.start_event
= CreateEventW(NULL
, 0, 0, NULL
);
2766 wnd_event
.attach_from
= 0;
2767 wnd_event
.attach_to
= GetCurrentThreadId();
2768 wnd_event
.setWindows
= FALSE
;
2771 SetActiveWindow(ourWnd
);
2773 hThread
= CreateThread(NULL
, 0, thread_proc
, &wnd_event
, 0, &tid
);
2774 ok(hThread
!= NULL
, "CreateThread failed, error %d\n", GetLastError());
2776 ok(WaitForSingleObject(wnd_event
.start_event
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2777 CloseHandle(wnd_event
.start_event
);
2779 ok(GetActiveWindow() == ourWnd
, "expected active %p, got %p\n", ourWnd
, GetActiveWindow());
2780 ok(GetFocus() == ourWnd
, "expected focus %p, got %p\n", ourWnd
, GetFocus());
2782 ret
= PostMessageA(wnd_event
.hwnd
, WM_QUIT
, 0, 0);
2783 ok(ret
, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
2785 ok(WaitForSingleObject(hThread
, INFINITE
) == WAIT_OBJECT_0
, "WaitForSingleObject failed\n");
2786 CloseHandle(hThread
);
2787 DestroyWindow(ourWnd
);
2788 DestroyWindow(Wnd2
);
2791 static DWORD WINAPI
get_key_state_thread(void *arg
)
2793 HANDLE
*semaphores
= arg
;
2796 ReleaseSemaphore(semaphores
[0], 1, NULL
);
2797 result
= WaitForSingleObject(semaphores
[1], 1000);
2798 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2800 result
= GetKeyState('X');
2801 ok((result
& 0x8000) || broken(!(result
& 0x8000)), /* > Win 2003 */
2802 "expected that highest bit is set, got %x\n", result
);
2804 ReleaseSemaphore(semaphores
[0], 1, NULL
);
2805 result
= WaitForSingleObject(semaphores
[1], 1000);
2806 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2808 result
= GetKeyState('X');
2809 ok(!(result
& 0x8000), "expected that highest bit is unset, got %x\n", result
);
2814 static void test_GetKeyState(void)
2816 HANDLE semaphores
[2];
2821 semaphores
[0] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
2822 ok(semaphores
[0] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
2823 semaphores
[1] = CreateSemaphoreA(NULL
, 0, 1, NULL
);
2824 ok(semaphores
[1] != NULL
, "CreateSemaphoreA failed %u\n", GetLastError());
2826 hwnd
= CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW
| WS_VISIBLE
,
2827 10, 10, 200, 200, NULL
, NULL
, NULL
, NULL
);
2828 ok(hwnd
!= NULL
, "CreateWindowA failed %u\n", GetLastError());
2830 thread
= CreateThread(NULL
, 0, get_key_state_thread
, semaphores
, 0, NULL
);
2831 ok(thread
!= NULL
, "CreateThread failed %u\n", GetLastError());
2832 result
= WaitForSingleObject(semaphores
[0], 1000);
2833 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2836 keybd_event('X', 0, 0, 0);
2838 ReleaseSemaphore(semaphores
[1], 1, NULL
);
2839 result
= WaitForSingleObject(semaphores
[0], 1000);
2840 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2842 keybd_event('X', 0, KEYEVENTF_KEYUP
, 0);
2844 ReleaseSemaphore(semaphores
[1], 1, NULL
);
2845 result
= WaitForSingleObject(thread
, 1000);
2846 ok(result
== WAIT_OBJECT_0
, "WaitForSingleObject returned %u\n", result
);
2847 CloseHandle(thread
);
2849 DestroyWindow(hwnd
);
2850 CloseHandle(semaphores
[0]);
2851 CloseHandle(semaphores
[1]);
2854 static void test_OemKeyScan(void)
2856 DWORD ret
, expect
, vkey
, scan
;
2860 for (oem
= 0; oem
< 0x200; oem
++)
2862 ret
= OemKeyScan( oem
);
2864 oem_char
= LOBYTE( oem
);
2865 /* OemKeyScan returns -1 for any character that cannot be mapped,
2866 * whereas OemToCharBuff changes unmappable characters to question
2867 * marks. The ASCII characters 0-127, including the real question mark
2868 * character, are all mappable and are the same in all OEM codepages. */
2869 if (!OemToCharBuffW( &oem_char
, &wchr
, 1 ) || (wchr
== '?' && oem_char
< 0))
2873 vkey
= VkKeyScanW( wchr
);
2874 scan
= MapVirtualKeyW( LOBYTE( vkey
), MAPVK_VK_TO_VSC
);
2881 expect
= vkey
| scan
;
2884 ok( ret
== expect
, "%04x: got %08x expected %08x\n", oem
, ret
, expect
);
2890 init_function_pointers();
2894 test_Input_blackbox();
2895 test_Input_whitebox();
2896 test_Input_unicode();
2899 else win_skip("SendInput is not available\n");
2902 test_mouse_ll_hook();
2906 test_get_async_key_state();
2907 test_keyboard_layout_name();
2909 test_attach_input();
2913 if(pGetMouseMovePointsEx
)
2914 test_GetMouseMovePointsEx();
2916 win_skip("GetMouseMovePointsEx is not available\n");
2918 if(pGetRawInputDeviceList
)
2919 test_GetRawInputDeviceList();
2921 win_skip("GetRawInputDeviceList is not available\n");