2003-10-28 01:18:40 +01:00
/* Test Key event to Key message translation
*
* Copyright 2003 Rein Klazes
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
2006-05-18 14:49:52 +02:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2003-10-28 01:18:40 +01:00
*/
/* test whether the right type of messages:
* WM_KEYUP / DOWN vs WM_SYSKEYUP / DOWN are sent in case of combined
* keystrokes .
*
2008-04-22 08:18:14 +02:00
* For instance < ALT > - X can be accomplished by
2003-10-28 01:18:40 +01:00
* the sequence ALT - KEY - DOWN , X - KEY - DOWN , ALT - KEY - UP , X - KEY - UP
* but also X - KEY - DOWN , ALT - KEY - DOWN , X - KEY - UP , ALT - KEY - UP
* Whether a KEY or a SYSKEY message is sent is not always clear , it is
* also not the same in WINNT as in WIN9X */
/* NOTE that there will be test failures under WIN9X
* No applications are known to me that rely on this
* so I don ' t fix it */
/* TODO:
* 1. extend it to the wm_command and wm_syscommand notifications
* 2. add some more tests with special cases like dead keys or right ( alt ) key
* 3. there is some adapted code from input . c in here . Should really
* make that code exactly the same .
* 4. resolve the win9x case when there is a need or the testing frame work
* offers a nice way .
* 5. The test app creates a window , the user should not take the focus
2003-10-28 22:45:30 +01:00
* away during its short existence . I could do something to prevent that
2003-10-28 01:18:40 +01:00
* if it is a problem .
*
*/
# define _WIN32_WINNT 0x401
2008-07-21 21:28:35 +02:00
# define _WIN32_IE 0x0500
2003-10-28 01:18:40 +01:00
2004-10-29 23:27:04 +02:00
# include <stdarg.h>
# include <assert.h>
# include "windef.h"
2003-10-28 01:18:40 +01:00
# include "winbase.h"
# include "winuser.h"
2004-10-29 23:27:04 +02:00
# include "wine/test.h"
2003-10-28 01:18:40 +01:00
/* globals */
2004-10-29 23:27:04 +02:00
static HWND hWndTest ;
2009-04-22 10:25:30 +02:00
static LONG timetag = 0x10000000 ;
2003-10-28 01:18:40 +01:00
2009-08-18 18:29:17 +02:00
static struct {
LONG last_key_down ;
LONG last_key_up ;
LONG last_syskey_down ;
LONG last_syskey_up ;
LONG last_char ;
LONG last_syschar ;
LONG last_hook_down ;
LONG last_hook_up ;
LONG last_hook_syskey_down ;
LONG last_hook_syskey_up ;
BOOL expect_alt ;
} key_status ;
2007-08-15 14:23:45 +02:00
static UINT ( WINAPI * pSendInput ) ( UINT , INPUT * , size_t ) ;
2008-02-16 19:35:22 +01:00
static int ( WINAPI * pGetMouseMovePointsEx ) ( UINT , LPMOUSEMOVEPOINT , LPMOUSEMOVEPOINT , int , DWORD ) ;
2004-05-05 03:07:04 +02:00
2009-01-20 15:07:15 +01:00
# define MAXKEYEVENTS 10
2003-10-28 01:18:40 +01:00
# define MAXKEYMESSAGES MAXKEYEVENTS / * assuming a key event generates one
and only one message */
/* keyboard message names, sorted as their value */
static const char * MSGNAME [ ] = { " WM_KEYDOWN " , " WM_KEYUP " , " WM_CHAR " , " WM_DEADCHAR " ,
" WM_SYSKEYDOWN " , " WM_SYSKEYUP " , " WM_SYSCHAR " , " WM_SYSDEADCHAR " , " WM_KEYLAST " } ;
/* keyevents, add more as needed */
typedef enum KEVtag
{ ALTDOWN = 1 , ALTUP , XDOWN , XUP , SHIFTDOWN , SHIFTUP , CTRLDOWN , CTRLUP } KEV ;
/* matching VK's */
2004-10-29 23:27:04 +02:00
static const int GETVKEY [ ] = { 0 , VK_MENU , VK_MENU , ' X ' , ' X ' , VK_SHIFT , VK_SHIFT , VK_CONTROL , VK_CONTROL } ;
2003-10-28 01:18:40 +01:00
/* matching scan codes */
2004-10-29 23:27:04 +02:00
static const int GETSCAN [ ] = { 0 , 0x38 , 0x38 , 0x2D , 0x2D , 0x2A , 0x2A , 0x1D , 0x1D } ;
2003-10-28 01:18:40 +01:00
/* matching updown events */
2008-04-10 17:59:10 +02:00
static const int GETFLAGS [ ] = { 0 , 0 , KEYEVENTF_KEYUP , 0 , KEYEVENTF_KEYUP , 0 , KEYEVENTF_KEYUP , 0 , KEYEVENTF_KEYUP } ;
2008-04-22 08:18:14 +02:00
/* matching descriptions */
2004-10-29 23:27:04 +02:00
static const char * getdesc [ ] = { " " , " +alt " , " -alt " , " +X " , " -X " , " +shift " , " -shift " , " +ctrl " , " -ctrl " } ;
2003-10-28 01:18:40 +01:00
2004-01-16 03:02:38 +01:00
/* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
typedef struct
{
DWORD type ;
union
{
MOUSEINPUT mi ;
KEYBDINPUT ki ;
HARDWAREINPUT hi ;
} u ;
} TEST_INPUT ;
2003-10-28 01:18:40 +01:00
# define ADDTOINPUTS(kev) \
inputs [ evtctr ] . type = INPUT_KEYBOARD ; \
2004-01-16 03:02:38 +01:00
( ( TEST_INPUT * ) inputs ) [ evtctr ] . u . ki . wVk = GETVKEY [ kev ] ; \
( ( TEST_INPUT * ) inputs ) [ evtctr ] . u . ki . wScan = GETSCAN [ kev ] ; \
2008-04-10 17:59:10 +02:00
( ( TEST_INPUT * ) inputs ) [ evtctr ] . u . ki . dwFlags = GETFLAGS [ kev ] ; \
2004-01-16 03:02:38 +01:00
( ( TEST_INPUT * ) inputs ) [ evtctr ] . u . ki . dwExtraInfo = 0 ; \
( ( TEST_INPUT * ) inputs ) [ evtctr ] . u . ki . time = + + timetag ; \
2003-10-28 01:18:40 +01:00
if ( kev ) evtctr + + ;
typedef struct {
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
} KMSG ;
/*******************************************
* add new test sets here
* the software will make all combinations of the
* keyevent defined here
*/
2004-10-29 23:27:04 +02:00
static const struct {
int nrkev ;
2003-10-28 01:18:40 +01:00
KEV keydwn [ MAXKEYEVENTS ] ;
KEV keyup [ MAXKEYEVENTS ] ;
} testkeyset [ ] = {
{ 2 , { ALTDOWN , XDOWN } , { ALTUP , XUP } } ,
{ 3 , { ALTDOWN , XDOWN , SHIFTDOWN } , { ALTUP , XUP , SHIFTUP } } ,
{ 3 , { ALTDOWN , XDOWN , CTRLDOWN } , { ALTUP , XUP , CTRLUP } } ,
{ 3 , { SHIFTDOWN , XDOWN , CTRLDOWN } , { SHIFTUP , XUP , CTRLUP } } ,
{ 0 } /* mark the end */
} ;
/**********************adapted from input.c **********************************/
2004-10-29 23:27:04 +02:00
static BYTE InputKeyStateTable [ 256 ] ;
static BYTE AsyncKeyStateTable [ 256 ] ;
static BYTE TrackSysKey = 0 ; /* determine whether ALT key up will cause a WM_SYSKEYUP
2003-10-28 01:18:40 +01:00
or a WM_KEYUP message */
2007-08-15 14:23:45 +02:00
static void init_function_pointers ( void )
{
HMODULE hdll = GetModuleHandleA ( " user32 " ) ;
# define GET_PROC(func) \
p # # func = ( void * ) GetProcAddress ( hdll , # func ) ; \
if ( ! p # # func ) \
trace ( " GetProcAddress(%s) failed \n " , # func ) ;
GET_PROC ( SendInput )
2008-02-16 19:35:22 +01:00
GET_PROC ( GetMouseMovePointsEx )
2007-08-15 14:23:45 +02:00
# undef GET_PROC
}
2004-10-29 23:27:04 +02:00
static int KbdMessage ( KEV kev , WPARAM * pwParam , LPARAM * plParam )
2003-10-28 01:18:40 +01:00
{
UINT message ;
int VKey = GETVKEY [ kev ] ;
2008-04-10 17:59:10 +02:00
WORD flags ;
2003-10-28 01:18:40 +01:00
2008-04-10 17:59:10 +02:00
flags = LOBYTE ( GETSCAN [ kev ] ) ;
if ( GETFLAGS [ kev ] & KEYEVENTF_EXTENDEDKEY ) flags | = KF_EXTENDED ;
2003-10-28 01:18:40 +01:00
2008-04-10 17:59:10 +02:00
if ( GETFLAGS [ kev ] & KEYEVENTF_KEYUP )
2003-10-28 01:18:40 +01:00
{
message = WM_KEYUP ;
if ( ( InputKeyStateTable [ VK_MENU ] & 0x80 ) & & (
( VKey = = VK_MENU ) | | ( VKey = = VK_CONTROL ) | |
! ( InputKeyStateTable [ VK_CONTROL ] & 0x80 ) ) ) {
if ( TrackSysKey = = VK_MENU | | /* <ALT>-down/<ALT>-up sequence */
( VKey ! = VK_MENU ) ) /* <ALT>-down...<something else>-up */
message = WM_SYSKEYUP ;
TrackSysKey = 0 ;
}
InputKeyStateTable [ VKey ] & = ~ 0x80 ;
2008-04-10 17:59:10 +02:00
flags | = KF_REPEAT | KF_UP ;
2003-10-28 01:18:40 +01:00
}
else
{
2008-04-10 17:59:10 +02:00
if ( InputKeyStateTable [ VKey ] & 0x80 ) flags | = KF_REPEAT ;
2003-10-28 01:18:40 +01:00
if ( ! ( InputKeyStateTable [ VKey ] & 0x80 ) ) InputKeyStateTable [ VKey ] ^ = 0x01 ;
InputKeyStateTable [ VKey ] | = 0x80 ;
AsyncKeyStateTable [ VKey ] | = 0x80 ;
message = WM_KEYDOWN ;
if ( ( InputKeyStateTable [ VK_MENU ] & 0x80 ) & &
! ( InputKeyStateTable [ VK_CONTROL ] & 0x80 ) ) {
message = WM_SYSKEYDOWN ;
TrackSysKey = VKey ;
}
}
2008-04-10 17:59:10 +02:00
if ( InputKeyStateTable [ VK_MENU ] & 0x80 ) flags | = KF_ALTDOWN ;
2003-10-28 01:18:40 +01:00
2008-04-10 17:59:10 +02:00
if ( plParam ) * plParam = MAKELPARAM ( 1 , flags ) ;
2003-10-28 01:18:40 +01:00
if ( pwParam ) * pwParam = VKey ;
return message ;
}
/****************************** end copy input.c ****************************/
/*
* . prepare the keyevents for SendInputs
* . calculate the " expected " messages
* . Send the events to our window
* . retrieve the messages from the input queue
* . verify
*/
2009-02-20 16:56:07 +01:00
static BOOL do_test ( HWND hwnd , int seqnr , const KEV td [ ] )
2003-10-28 01:18:40 +01:00
{
INPUT inputs [ MAXKEYEVENTS ] ;
KMSG expmsg [ MAXKEYEVENTS ] ;
MSG msg ;
char buf [ 100 ] ;
2004-01-16 03:02:38 +01:00
UINT evtctr = 0 ;
int kmctr , i ;
2004-05-05 03:07:04 +02:00
2003-10-28 01:18:40 +01:00
buf [ 0 ] = ' \0 ' ;
TrackSysKey = 0 ; /* see input.c */
for ( i = 0 ; i < MAXKEYEVENTS ; i + + ) {
ADDTOINPUTS ( td [ i ] )
strcat ( buf , getdesc [ td [ i ] ] ) ;
if ( td [ i ] )
expmsg [ i ] . message = KbdMessage ( td [ i ] , & ( expmsg [ i ] . wParam ) , & ( expmsg [ i ] . lParam ) ) ; /* see queue_kbd_event() */
else
expmsg [ i ] . message = 0 ;
}
for ( kmctr = 0 ; kmctr < MAXKEYEVENTS & & expmsg [ kmctr ] . message ; kmctr + + )
;
assert ( evtctr < = MAXKEYEVENTS ) ;
2007-08-15 14:23:45 +02:00
assert ( evtctr = = pSendInput ( evtctr , & inputs [ 0 ] , sizeof ( INPUT ) ) ) ;
2003-10-28 01:18:40 +01:00
i = 0 ;
2006-12-26 18:05:57 +01:00
if ( winetest_debug > 1 )
trace ( " ======== key stroke sequence #%d: %s ============= \n " ,
2003-10-28 01:18:40 +01:00
seqnr + 1 , buf ) ;
while ( PeekMessage ( & msg , hwnd , WM_KEYFIRST , WM_KEYLAST , PM_REMOVE ) ) {
2006-12-26 18:05:57 +01:00
if ( winetest_debug > 1 )
2007-05-24 16:41:17 +02:00
trace ( " message[%d] %-15s wParam %04lx lParam %08lx time %x \n " , i ,
2006-12-26 18:05:57 +01:00
MSGNAME [ msg . message - WM_KEYFIRST ] , msg . wParam , msg . lParam , msg . time ) ;
2003-10-28 01:18:40 +01:00
if ( i < kmctr ) {
ok ( msg . message = = expmsg [ i ] . message & &
2009-02-24 14:57:51 +01:00
msg . wParam = = expmsg [ i ] . wParam & &
msg . lParam = = expmsg [ i ] . lParam ,
" %u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx \n " ,
seqnr , i , msg . message , msg . wParam , msg . lParam ,
MSGNAME [ ( expmsg [ i ] ) . message - WM_KEYFIRST ] , expmsg [ i ] . wParam , expmsg [ i ] . lParam ) ;
2003-10-28 01:18:40 +01:00
}
i + + ;
}
2006-12-26 18:05:57 +01:00
if ( winetest_debug > 1 )
trace ( " %d messages retrieved \n " , i ) ;
2009-02-20 16:56:07 +01:00
if ( ! i & & kmctr )
{
skip ( " simulated keyboard input doesn't work \n " ) ;
return FALSE ;
}
2004-01-18 23:10:55 +01:00
ok ( i = = kmctr , " message count is wrong: got %d expected: %d \n " , i , kmctr ) ;
2009-02-20 16:56:07 +01:00
return TRUE ;
2003-10-28 01:18:40 +01:00
}
/* test all combinations of the specified key events */
2009-02-20 16:56:07 +01:00
static BOOL TestASet ( HWND hWnd , int nrkev , const KEV kevdwn [ ] , const KEV kevup [ ] )
2003-10-28 01:18:40 +01:00
{
int i , j , k , l , m , n ;
static int count = 0 ;
KEV kbuf [ MAXKEYEVENTS ] ;
assert ( nrkev = = 2 | | nrkev = = 3 ) ;
for ( i = 0 ; i < MAXKEYEVENTS ; i + + ) kbuf [ i ] = 0 ;
/* two keys involved gives 4 test cases */
if ( nrkev = = 2 ) {
for ( i = 0 ; i < nrkev ; i + + ) {
for ( j = 0 ; j < nrkev ; j + + ) {
kbuf [ 0 ] = kevdwn [ i ] ;
kbuf [ 1 ] = kevdwn [ 1 - i ] ;
kbuf [ 2 ] = kevup [ j ] ;
kbuf [ 3 ] = kevup [ 1 - j ] ;
2009-02-20 16:56:07 +01:00
if ( ! do_test ( hWnd , count + + , kbuf ) ) return FALSE ;
2003-10-28 01:18:40 +01:00
}
}
}
/* three keys involved gives 36 test cases */
if ( nrkev = = 3 ) {
for ( i = 0 ; i < nrkev ; i + + ) {
for ( j = 0 ; j < nrkev ; j + + ) {
if ( j = = i ) continue ;
for ( k = 0 ; k < nrkev ; k + + ) {
if ( k = = i | | k = = j ) continue ;
for ( l = 0 ; l < nrkev ; l + + ) {
for ( m = 0 ; m < nrkev ; m + + ) {
if ( m = = l ) continue ;
for ( n = 0 ; n < nrkev ; n + + ) {
if ( n = = l | | n = = m ) continue ;
kbuf [ 0 ] = kevdwn [ i ] ;
kbuf [ 1 ] = kevdwn [ j ] ;
kbuf [ 2 ] = kevdwn [ k ] ;
kbuf [ 3 ] = kevup [ l ] ;
kbuf [ 4 ] = kevup [ m ] ;
kbuf [ 5 ] = kevup [ n ] ;
2009-02-20 16:56:07 +01:00
if ( ! do_test ( hWnd , count + + , kbuf ) ) return FALSE ;
2003-10-28 01:18:40 +01:00
}
}
}
}
}
}
}
2009-02-20 16:56:07 +01:00
return TRUE ;
2003-10-28 01:18:40 +01:00
}
/* test each set specified in the global testkeyset array */
2004-10-29 23:27:04 +02:00
static void TestSysKeys ( HWND hWnd )
2003-10-28 01:18:40 +01:00
{
int i ;
for ( i = 0 ; testkeyset [ i ] . nrkev ; i + + )
2009-02-20 16:56:07 +01:00
if ( ! TestASet ( hWnd , testkeyset [ i ] . nrkev , testkeyset [ i ] . keydwn , testkeyset [ i ] . keyup ) ) break ;
2003-10-28 01:18:40 +01:00
}
static LRESULT CALLBACK WndProc ( HWND hWnd , UINT msg , WPARAM wParam ,
LPARAM lParam )
{
2009-02-19 14:23:49 +01:00
return DefWindowProcA ( hWnd , msg , wParam , lParam ) ;
2003-10-28 01:18:40 +01:00
}
2006-04-12 20:13:46 +02:00
static void test_Input_whitebox ( void )
2003-10-28 01:18:40 +01:00
{
MSG msg ;
WNDCLASSA wclass ;
HANDLE hInstance = GetModuleHandleA ( NULL ) ;
wclass . lpszClassName = " InputSysKeyTestClass " ;
wclass . style = CS_HREDRAW | CS_VREDRAW ;
2004-12-06 12:51:29 +01:00
wclass . lpfnWndProc = WndProc ;
2003-10-28 01:18:40 +01:00
wclass . hInstance = hInstance ;
2009-01-13 10:55:46 +01:00
wclass . hIcon = LoadIconA ( 0 , IDI_APPLICATION ) ;
wclass . hCursor = LoadCursorA ( NULL , IDC_ARROW ) ;
wclass . hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ) ;
2003-10-28 01:18:40 +01:00
wclass . lpszMenuName = 0 ;
wclass . cbClsExtra = 0 ;
wclass . cbWndExtra = 0 ;
2009-02-19 14:23:49 +01:00
RegisterClassA ( & wclass ) ;
2003-10-28 01:18:40 +01:00
/* create the test window that will receive the keystrokes */
2009-02-19 14:23:49 +01:00
hWndTest = CreateWindowA ( wclass . lpszClassName , " InputSysKeyTest " ,
WS_OVERLAPPEDWINDOW , CW_USEDEFAULT , 0 , 100 , 100 ,
NULL , NULL , hInstance , NULL ) ;
assert ( hWndTest ) ;
2003-10-28 01:18:40 +01:00
ShowWindow ( hWndTest , SW_SHOW ) ;
2009-02-19 14:23:49 +01:00
SetWindowPos ( hWndTest , HWND_TOPMOST , 0 , 0 , 0 , 0 , SWP_NOSIZE | SWP_NOMOVE ) ;
SetForegroundWindow ( hWndTest ) ;
2003-10-28 01:18:40 +01:00
UpdateWindow ( hWndTest ) ;
2004-10-29 23:27:04 +02:00
/* flush pending messages */
while ( PeekMessage ( & msg , 0 , 0 , 0 , PM_REMOVE ) ) DispatchMessageA ( & msg ) ;
2009-02-19 14:23:49 +01:00
SetFocus ( hWndTest ) ;
TestSysKeys ( hWndTest ) ;
2004-10-29 23:27:04 +02:00
DestroyWindow ( hWndTest ) ;
2003-10-28 01:18:40 +01:00
}
2006-04-12 20:13:46 +02:00
2008-09-25 16:26:09 +02:00
/* try to make sure pending X events have been processed before continuing */
static void empty_message_queue ( void )
{
2006-04-12 20:13:46 +02:00
MSG msg ;
2008-09-25 16:26:09 +02:00
int diff = 200 ;
int min_timeout = 50 ;
DWORD time = GetTickCount ( ) + diff ;
while ( diff > 0 )
{
if ( MsgWaitForMultipleObjects ( 0 , NULL , FALSE , min_timeout , QS_ALLINPUT ) = = WAIT_TIMEOUT ) break ;
while ( PeekMessage ( & msg , 0 , 0 , 0 , PM_REMOVE ) )
{
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
diff = time - GetTickCount ( ) ;
2006-04-12 20:13:46 +02:00
}
}
struct transition_s {
WORD wVk ;
BYTE before_state ;
2008-09-24 15:37:38 +02:00
BYTE optional ;
2008-04-02 07:13:45 +02:00
} ;
typedef enum {
sent = 0x1 ,
posted = 0x2 ,
parent = 0x4 ,
wparam = 0x8 ,
lparam = 0x10 ,
defwinproc = 0x20 ,
beginpaint = 0x40 ,
optional = 0x80 ,
hook = 0x100 ,
winevent_hook = 0x200
} msg_flags_t ;
struct message {
UINT message ; /* the WM_* code */
msg_flags_t flags ; /* message props */
WPARAM wParam ; /* expected value of wParam */
LPARAM lParam ; /* expected value of lParam */
2006-04-12 20:13:46 +02:00
} ;
struct sendinput_test_s {
WORD wVk ;
DWORD dwFlags ;
2008-04-02 07:13:45 +02:00
BOOL _todo_wine ;
2006-04-12 20:13:46 +02:00
struct transition_s expected_transitions [ MAXKEYEVENTS + 1 ] ;
2008-04-02 07:13:45 +02:00
struct message expected_messages [ MAXKEYMESSAGES + 1 ] ;
2006-04-12 20:13:46 +02:00
} sendinput_test [ ] = {
/* test ALT+F */
2008-09-25 16:26:15 +02:00
/* 0 */
2008-04-02 07:13:45 +02:00
{ VK_LMENU , 0 , 0 , { { VK_MENU , 0x00 } , { VK_LMENU , 0x00 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook | wparam , VK_LMENU } , { WM_SYSKEYDOWN } , { 0 } } } ,
{ ' F ' , 0 , 0 , { { ' F ' , 0x00 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook } , { WM_SYSKEYDOWN } ,
{ WM_SYSCHAR } ,
{ WM_SYSCOMMAND } , { 0 } } } ,
{ ' F ' , KEYEVENTF_KEYUP , 0 , { { ' F ' , 0x80 } , { 0 } } ,
{ { WM_SYSKEYUP , hook } , { WM_SYSKEYUP } , { 0 } } } ,
{ VK_LMENU , KEYEVENTF_KEYUP , 0 , { { VK_MENU , 0x80 } , { VK_LMENU , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
2006-04-12 20:13:46 +02:00
/* test CTRL+O */
2008-09-25 16:26:15 +02:00
/* 4 */
2008-04-02 07:13:45 +02:00
{ VK_LCONTROL , 0 , 0 , { { VK_CONTROL , 0x00 } , { VK_LCONTROL , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { 0 } } } ,
{ ' O ' , 0 , 0 , { { ' O ' , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { WM_CHAR } , { 0 } } } ,
{ ' O ' , KEYEVENTF_KEYUP , 0 , { { ' O ' , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
{ VK_LCONTROL , KEYEVENTF_KEYUP , 0 , { { VK_CONTROL , 0x80 } , { VK_LCONTROL , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
2006-04-12 20:13:46 +02:00
/* test ALT+CTRL+X */
2008-09-25 16:26:15 +02:00
/* 8 */
2008-04-02 07:13:45 +02:00
{ VK_LMENU , 0 , 0 , { { VK_MENU , 0x00 } , { VK_LMENU , 0x00 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook } , { WM_SYSKEYDOWN } , { 0 } } } ,
{ VK_LCONTROL , 0 , 0 , { { VK_CONTROL , 0x00 } , { VK_LCONTROL , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { 0 } } } ,
{ ' X ' , 0 , 0 , { { ' X ' , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { 0 } } } ,
{ ' X ' , KEYEVENTF_KEYUP , 0 , { { ' X ' , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
{ VK_LCONTROL , KEYEVENTF_KEYUP , 0 , { { VK_CONTROL , 0x80 } , { VK_LCONTROL , 0x80 } , { 0 } } ,
{ { WM_SYSKEYUP , hook } , { WM_SYSKEYUP } , { 0 } } } ,
{ VK_LMENU , KEYEVENTF_KEYUP , 0 , { { VK_MENU , 0x80 } , { VK_LMENU , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
2006-04-12 20:13:46 +02:00
/* test SHIFT+A */
2008-09-25 16:26:15 +02:00
/* 14 */
2008-04-02 07:13:45 +02:00
{ VK_LSHIFT , 0 , 0 , { { VK_SHIFT , 0x00 } , { VK_LSHIFT , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { 0 } } } ,
{ ' A ' , 0 , 0 , { { ' A ' , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook } , { WM_KEYDOWN } , { WM_CHAR } , { 0 } } } ,
{ ' A ' , KEYEVENTF_KEYUP , 0 , { { ' A ' , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
{ VK_LSHIFT , KEYEVENTF_KEYUP , 0 , { { VK_SHIFT , 0x80 } , { VK_LSHIFT , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook } , { WM_KEYUP } , { 0 } } } ,
/* test L-SHIFT & R-SHIFT: */
/* RSHIFT == LSHIFT */
2008-09-25 16:26:15 +02:00
/* 18 */
2008-04-02 07:13:45 +02:00
{ VK_RSHIFT , 0 , 0 ,
2008-09-24 15:37:38 +02:00
/* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
{ { VK_SHIFT , 0x00 } , { VK_LSHIFT , 0x00 , TRUE } , { VK_RSHIFT , 0x00 , TRUE } , { 0 } } ,
2008-04-02 07:13:45 +02:00
{ { WM_KEYDOWN , hook | wparam , VK_RSHIFT } ,
{ WM_KEYDOWN } , { 0 } } } ,
{ VK_RSHIFT , KEYEVENTF_KEYUP , 0 ,
2008-09-24 15:37:38 +02:00
{ { VK_SHIFT , 0x80 } , { VK_LSHIFT , 0x80 , TRUE } , { VK_RSHIFT , 0x80 , TRUE } , { 0 } } ,
2008-04-02 07:13:45 +02:00
{ { WM_KEYUP , hook , hook | wparam , VK_RSHIFT } ,
{ WM_KEYUP } , { 0 } } } ,
/* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
2008-09-25 16:26:15 +02:00
/* 20 */
2008-04-02 07:13:45 +02:00
{ VK_LSHIFT , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x00 } , { VK_RSHIFT , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_LSHIFT , LLKHF_EXTENDED } ,
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_LSHIFT , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x80 } , { VK_RSHIFT , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_LSHIFT , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_KEYUP , wparam | lparam , VK_SHIFT , KF_UP } , { 0 } } } ,
/* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
2008-09-25 16:26:15 +02:00
/* 22 */
2008-04-02 07:13:45 +02:00
{ VK_RSHIFT , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x00 } , { VK_RSHIFT , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_RSHIFT , LLKHF_EXTENDED } ,
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_RSHIFT , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x80 } , { VK_RSHIFT , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_RSHIFT , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_KEYUP , wparam | lparam , VK_SHIFT , KF_UP } , { 0 } } } ,
2008-06-02 16:12:26 +02:00
/* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
win2k - sends to hook whatever we generated here
winXP + - Attempts to convert key to L / R key but not always correct
*/
2008-04-02 07:13:45 +02:00
/* SHIFT == LSHIFT */
2008-09-25 16:26:15 +02:00
/* 24 */
2008-04-02 07:13:45 +02:00
{ VK_SHIFT , 0 , 0 ,
{ { VK_SHIFT , 0x00 } , { VK_LSHIFT , 0x00 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYDOWN , hook /* |wparam */ | lparam , VK_SHIFT , 0 } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_SHIFT , KEYEVENTF_KEYUP , 0 ,
{ { VK_SHIFT , 0x80 } , { VK_LSHIFT , 0x80 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYUP , hook /*|wparam*/ | lparam , VK_SHIFT , LLKHF_UP } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYUP , wparam | lparam , VK_SHIFT , KF_UP } , { 0 } } } ,
/* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
2008-09-25 16:26:15 +02:00
/* 26 */
2008-04-02 07:13:45 +02:00
{ VK_SHIFT , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x00 } , { VK_RSHIFT , 0x00 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYDOWN , hook /*|wparam*/ | lparam , VK_SHIFT , LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_SHIFT , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_SHIFT , 0x80 } , { VK_RSHIFT , 0x80 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYUP , hook /*|wparam*/ | lparam , VK_SHIFT , LLKHF_UP | LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYUP , wparam | lparam , VK_SHIFT , KF_UP } , { 0 } } } ,
/* test L-CONTROL & R-CONTROL: */
/* RCONTROL == LCONTROL */
2008-09-25 16:26:15 +02:00
/* 28 */
2008-04-02 07:13:45 +02:00
{ VK_RCONTROL , 0 , 0 ,
{ { VK_CONTROL , 0x00 } , { VK_LCONTROL , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam , VK_RCONTROL } ,
{ WM_KEYDOWN , wparam | lparam , VK_CONTROL , 0 } , { 0 } } } ,
{ VK_RCONTROL , KEYEVENTF_KEYUP , 0 ,
{ { VK_CONTROL , 0x80 } , { VK_LCONTROL , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam , VK_RCONTROL } ,
{ WM_KEYUP , wparam | lparam , VK_CONTROL , KF_UP } , { 0 } } } ,
/* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
2008-09-25 16:26:15 +02:00
/* 30 */
2008-04-02 07:13:45 +02:00
{ VK_LCONTROL , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x00 } , { VK_RCONTROL , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_LCONTROL , LLKHF_EXTENDED } ,
{ WM_KEYDOWN , wparam | lparam , VK_CONTROL , KF_EXTENDED } , { 0 } } } ,
{ VK_LCONTROL , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x80 } , { VK_RCONTROL , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_LCONTROL , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_KEYUP , wparam | lparam , VK_CONTROL , KF_UP | KF_EXTENDED } , { 0 } } } ,
/* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
2008-09-25 16:26:15 +02:00
/* 32 */
2008-04-02 07:13:45 +02:00
{ VK_RCONTROL , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x00 } , { VK_RCONTROL , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_RCONTROL , LLKHF_EXTENDED } ,
{ WM_KEYDOWN , wparam | lparam , VK_CONTROL , KF_EXTENDED } , { 0 } } } ,
{ VK_RCONTROL , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x80 } , { VK_RCONTROL , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_RCONTROL , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_KEYUP , wparam | lparam , VK_CONTROL , KF_UP | KF_EXTENDED } , { 0 } } } ,
/* CONTROL == LCONTROL */
2008-09-25 16:26:15 +02:00
/* 34 */
2008-04-02 07:13:45 +02:00
{ VK_CONTROL , 0 , 0 ,
{ { VK_CONTROL , 0x00 } , { VK_LCONTROL , 0x00 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYDOWN , hook /*|wparam, VK_CONTROL*/ } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYDOWN , wparam | lparam , VK_CONTROL , 0 } , { 0 } } } ,
{ VK_CONTROL , KEYEVENTF_KEYUP , 0 ,
{ { VK_CONTROL , 0x80 } , { VK_LCONTROL , 0x80 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYUP , hook /*|wparam, VK_CONTROL*/ } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYUP , wparam | lparam , VK_CONTROL , KF_UP } , { 0 } } } ,
/* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
2008-09-25 16:26:15 +02:00
/* 36 */
2008-04-02 07:13:45 +02:00
{ VK_CONTROL , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x00 } , { VK_RCONTROL , 0x00 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYDOWN , hook /*|wparam*/ | lparam , VK_CONTROL , LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYDOWN , wparam | lparam , VK_CONTROL , KF_EXTENDED } , { 0 } } } ,
{ VK_CONTROL , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_CONTROL , 0x80 } , { VK_RCONTROL , 0x80 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYUP , hook /*|wparam*/ | lparam , VK_CONTROL , LLKHF_UP | LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_KEYUP , wparam | lparam , VK_CONTROL , KF_UP | KF_EXTENDED } , { 0 } } } ,
/* test L-MENU & R-MENU: */
/* RMENU == LMENU */
2008-09-25 16:26:15 +02:00
/* 38 */
2008-04-02 07:13:45 +02:00
{ VK_RMENU , 0 , 0 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x00 } , { VK_LMENU , 0x00 } , { VK_CONTROL , 0x00 , 1 } , { VK_LCONTROL , 0x01 , 1 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook | wparam | optional , VK_LCONTROL } ,
{ WM_SYSKEYDOWN , hook | wparam , VK_RMENU } ,
2009-05-02 02:11:38 +02:00
{ WM_KEYDOWN , wparam | lparam | optional , VK_CONTROL , 0 } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYDOWN , wparam | lparam , VK_MENU , 0 } , { 0 } } } ,
{ VK_RMENU , KEYEVENTF_KEYUP , 1 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x80 } , { VK_LMENU , 0x80 } , { VK_CONTROL , 0x81 , 1 } , { VK_LCONTROL , 0x80 , 1 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | optional , VK_LCONTROL } ,
{ WM_KEYUP , hook | wparam , VK_RMENU } ,
2009-02-24 14:57:51 +01:00
{ WM_SYSKEYUP , wparam | lparam | optional , VK_CONTROL , KF_UP } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYUP , wparam | lparam , VK_MENU , KF_UP } ,
2009-05-02 02:11:38 +02:00
{ WM_SYSCOMMAND , optional } , { 0 } } } ,
2008-04-02 07:13:45 +02:00
/* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
2008-09-25 16:26:15 +02:00
/* 40 */
2008-04-02 07:13:45 +02:00
{ VK_LMENU , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_MENU , 0x00 } , { VK_RMENU , 0x00 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook | wparam | lparam , VK_LMENU , LLKHF_EXTENDED } ,
{ WM_SYSKEYDOWN , wparam | lparam , VK_MENU , KF_EXTENDED } , { 0 } } } ,
{ VK_LMENU , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 1 ,
{ { VK_MENU , 0x80 } , { VK_RMENU , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_LMENU , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_SYSKEYUP , wparam | lparam , VK_MENU , KF_UP | KF_EXTENDED } ,
{ WM_SYSCOMMAND } , { 0 } } } ,
/* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
2008-09-25 16:26:15 +02:00
/* 42 */
2008-04-02 07:13:45 +02:00
{ VK_RMENU , KEYEVENTF_EXTENDEDKEY , 0 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x00 } , { VK_RMENU , 0x00 } , { VK_CONTROL , 0x00 , 1 } , { VK_LCONTROL , 0x01 , 1 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook | wparam | lparam | optional , VK_LCONTROL , 0 } ,
{ WM_SYSKEYDOWN , hook | wparam | lparam , VK_RMENU , LLKHF_EXTENDED } ,
2009-05-02 02:11:38 +02:00
{ WM_KEYDOWN , wparam | lparam | optional , VK_CONTROL , 0 } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYDOWN , wparam | lparam , VK_MENU , KF_EXTENDED } , { 0 } } } ,
{ VK_RMENU , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 1 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x80 } , { VK_RMENU , 0x80 } , { VK_CONTROL , 0x81 , 1 } , { VK_LCONTROL , 0x80 , 1 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam | optional , VK_LCONTROL , LLKHF_UP } ,
{ WM_KEYUP , hook | wparam | lparam , VK_RMENU , LLKHF_UP | LLKHF_EXTENDED } ,
2009-02-24 14:57:51 +01:00
{ WM_SYSKEYUP , wparam | lparam | optional , VK_CONTROL , KF_UP } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYUP , wparam | lparam , VK_MENU , KF_UP | KF_EXTENDED } ,
2009-05-02 02:11:38 +02:00
{ WM_SYSCOMMAND , optional } , { 0 } } } ,
2008-04-02 07:13:45 +02:00
/* MENU == LMENU */
2008-09-25 16:26:15 +02:00
/* 44 */
2008-04-02 07:13:45 +02:00
{ VK_MENU , 0 , 0 ,
{ { VK_MENU , 0x00 } , { VK_LMENU , 0x00 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_SYSKEYDOWN , hook /*|wparam, VK_MENU*/ } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYDOWN , wparam | lparam , VK_MENU , 0 } , { 0 } } } ,
{ VK_MENU , KEYEVENTF_KEYUP , 1 ,
{ { VK_MENU , 0x80 } , { VK_LMENU , 0x80 } , { 0 } } ,
2008-06-02 16:12:26 +02:00
{ { WM_KEYUP , hook /*|wparam, VK_MENU*/ } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYUP , wparam | lparam , VK_MENU , KF_UP } ,
{ WM_SYSCOMMAND } , { 0 } } } ,
/* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
2008-09-25 16:26:15 +02:00
/* 46 */
2008-04-02 07:13:45 +02:00
{ VK_MENU , KEYEVENTF_EXTENDEDKEY , 0 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x00 } , { VK_RMENU , 0x00 } , { VK_CONTROL , 0x00 , 1 } , { VK_LCONTROL , 0x01 , 1 } , { 0 } } ,
{ { WM_SYSKEYDOWN , hook | wparam | lparam | optional , VK_CONTROL , 0 } ,
{ WM_SYSKEYDOWN , hook /*|wparam*/ | lparam , VK_MENU , LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYDOWN , wparam | lparam , VK_MENU , KF_EXTENDED } , { 0 } } } ,
{ VK_MENU , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 1 ,
2009-02-21 12:56:52 +01:00
{ { VK_MENU , 0x80 } , { VK_RMENU , 0x80 } , { VK_CONTROL , 0x81 , 1 } , { VK_LCONTROL , 0x80 , 1 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam | optional , VK_CONTROL , LLKHF_UP } ,
{ WM_KEYUP , hook /*|wparam*/ | lparam , VK_MENU , LLKHF_UP | LLKHF_EXTENDED } ,
2008-04-02 07:13:45 +02:00
{ WM_SYSKEYUP , wparam | lparam , VK_MENU , KF_UP | KF_EXTENDED } ,
{ WM_SYSCOMMAND } , { 0 } } } ,
/* test LSHIFT & RSHIFT */
2008-09-25 16:26:15 +02:00
/* 48 */
2008-04-02 07:13:45 +02:00
{ VK_LSHIFT , 0 , 0 ,
{ { VK_SHIFT , 0x00 } , { VK_LSHIFT , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_LSHIFT , 0 } ,
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_RSHIFT , KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_RSHIFT , 0x00 } , { 0 } } ,
{ { WM_KEYDOWN , hook | wparam | lparam , VK_RSHIFT , LLKHF_EXTENDED } ,
{ WM_KEYDOWN , wparam | lparam , VK_SHIFT , 0 } , { 0 } } } ,
{ VK_RSHIFT , KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY , 0 ,
{ { VK_RSHIFT , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam | lparam , VK_RSHIFT , LLKHF_UP | LLKHF_EXTENDED } ,
{ WM_KEYUP , optional } , { 0 } } } ,
{ VK_LSHIFT , KEYEVENTF_KEYUP , 0 ,
{ { VK_SHIFT , 0x80 } , { VK_LSHIFT , 0x80 } , { 0 } } ,
{ { WM_KEYUP , hook | wparam , VK_LSHIFT } ,
{ WM_KEYUP , wparam | lparam , VK_SHIFT , KF_UP } , { 0 } } } ,
{ 0 , 0 , 0 , { { 0 } } , { { 0 } } } /* end */
2006-04-12 20:13:46 +02:00
} ;
2008-04-02 07:13:45 +02:00
static struct message sent_messages [ MAXKEYMESSAGES ] ;
static UINT sent_messages_cnt ;
2006-04-12 20:13:46 +02:00
/* Verify that only specified key state transitions occur */
2008-04-02 07:13:45 +02:00
static void compare_and_check ( int id , BYTE * ks1 , BYTE * ks2 , struct sendinput_test_s * test )
{
int i , failcount = 0 ;
struct transition_s * t = test - > expected_transitions ;
UINT actual_cnt = 0 ;
const struct message * expected = test - > expected_messages ;
2006-04-12 20:13:46 +02:00
while ( t - > wVk ) {
int matched = ( ( ks1 [ t - > wVk ] & 0x80 ) = = ( t - > before_state & 0x80 )
& & ( ks2 [ t - > wVk ] & 0x80 ) = = ( ~ t - > before_state & 0x80 ) ) ;
2008-04-02 07:13:45 +02:00
2009-02-21 12:56:52 +01:00
if ( ! matched & & ! t - > optional & & test - > _todo_wine )
2008-04-02 07:13:45 +02:00
{
failcount + + ;
2006-04-12 20:13:46 +02:00
todo_wine {
2008-09-25 16:26:15 +02:00
ok ( matched , " %2d (%x/%x): %02x from %02x -> %02x "
" instead of %02x -> %02x \n " , id , test - > wVk , test - > dwFlags ,
t - > wVk , ks1 [ t - > wVk ] & 0x80 , ks2 [ t - > wVk ] & 0x80 , t - > before_state ,
2006-04-12 20:13:46 +02:00
~ t - > before_state & 0x80 ) ;
}
} else {
2008-09-25 16:26:15 +02:00
ok ( matched | | t - > optional , " %2d (%x/%x): %02x from %02x -> %02x "
" instead of %02x -> %02x \n " , id , test - > wVk , test - > dwFlags ,
t - > wVk , ks1 [ t - > wVk ] & 0x80 , ks2 [ t - > wVk ] & 0x80 , t - > before_state ,
2006-04-12 20:13:46 +02:00
~ t - > before_state & 0x80 ) ;
}
ks2 [ t - > wVk ] = ks1 [ t - > wVk ] ; /* clear the match */
t + + ;
}
for ( i = 0 ; i < 256 ; i + + )
2008-04-02 07:13:45 +02:00
if ( ks2 [ i ] ! = ks1 [ i ] & & test - > _todo_wine )
{
failcount + + ;
todo_wine
2008-09-25 16:26:15 +02:00
ok ( FALSE , " %2d (%x/%x): %02x from %02x -> %02x unexpected \n " ,
id , test - > wVk , test - > dwFlags , i , ks1 [ i ] , ks2 [ i ] ) ;
2008-04-02 07:13:45 +02:00
}
else
2008-09-25 16:26:15 +02:00
ok ( ks2 [ i ] = = ks1 [ i ] , " %2d (%x/%x): %02x from %02x -> %02x unexpected \n " ,
id , test - > wVk , test - > dwFlags , i , ks1 [ i ] , ks2 [ i ] ) ;
2008-04-02 07:13:45 +02:00
while ( expected - > message & & actual_cnt < sent_messages_cnt )
{
const struct message * actual = & sent_messages [ actual_cnt ] ;
if ( expected - > message = = actual - > message )
{
if ( expected - > flags & wparam )
{
2009-02-21 12:56:52 +01:00
if ( ( expected - > flags & optional ) & & ( expected - > wParam ! = actual - > wParam ) )
{
expected + + ;
continue ;
}
2008-04-02 07:13:45 +02:00
if ( expected - > wParam ! = actual - > wParam & & test - > _todo_wine )
{
failcount + + ;
todo_wine
2008-09-25 16:26:15 +02:00
ok ( FALSE , " %2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , expected - > wParam , actual - > wParam ) ;
2008-04-02 07:13:45 +02:00
}
else
ok ( expected - > wParam = = actual - > wParam ,
2008-09-25 16:26:15 +02:00
" %2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , expected - > wParam , actual - > wParam ) ;
2008-04-02 07:13:45 +02:00
}
if ( expected - > flags & lparam )
{
if ( expected - > lParam ! = actual - > lParam & & test - > _todo_wine )
{
failcount + + ;
todo_wine
2008-09-25 16:26:15 +02:00
ok ( FALSE , " %2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , expected - > lParam , actual - > lParam ) ;
2008-04-02 07:13:45 +02:00
}
else
ok ( expected - > lParam = = actual - > lParam ,
2008-09-25 16:26:15 +02:00
" %2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , expected - > lParam , actual - > lParam ) ;
2008-04-02 07:13:45 +02:00
}
2009-02-21 12:56:52 +01:00
ok ( ( expected - > flags & hook ) = = ( actual - > flags & hook ) ,
" %2d (%x/%x): the msg 0x%04x should have been sent by a hook \n " ,
id , test - > wVk , test - > dwFlags , expected - > message ) ;
2008-04-02 07:13:45 +02:00
}
else if ( expected - > flags & optional )
{
expected + + ;
continue ;
}
2009-02-25 23:30:13 +01:00
/* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
else if ( ( expected - > flags & hook ) & &
( expected - > message = = WM_SYSKEYDOWN | | expected - > message = = WM_SYSKEYUP ) & &
( actual - > message = = expected - > message - 4 ) )
{
ok ( ( expected - > flags & hook ) = = ( actual - > flags & hook ) ,
" %2d (%x/%x): the msg 0x%04x should have been sent by a hook \n " ,
id , test - > wVk , test - > dwFlags , expected - > message ) ;
}
2009-05-02 02:11:38 +02:00
/* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
* instead of SYSKEYDOWN / UP to the WNDPROC */
else if ( test - > wVk = = VK_RMENU & & ! ( expected - > flags & hook ) & &
( expected - > message = = WM_SYSKEYDOWN | | expected - > message = = WM_SYSKEYUP ) & &
( actual - > message = = expected - > message - 4 ) )
{
ok ( expected - > wParam = = actual - > wParam & & expected - > lParam = = actual - > lParam ,
" %2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , actual - > message ) ;
}
else if ( test - > _todo_wine )
{
failcount + + ;
todo_wine
ok ( FALSE ,
" %2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , actual - > message ) ;
}
2008-04-02 07:13:45 +02:00
else
ok ( FALSE ,
2008-09-25 16:26:15 +02:00
" %2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , actual - > message ) ;
2008-04-02 07:13:45 +02:00
actual_cnt + + ;
expected + + ;
}
/* skip all optional trailing messages */
while ( expected - > message & & ( expected - > flags & optional ) )
expected + + ;
if ( expected - > message | | actual_cnt < sent_messages_cnt )
{
if ( test - > _todo_wine )
{
failcount + + ;
todo_wine
2008-09-25 16:26:15 +02:00
ok ( FALSE , " %2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , sent_messages [ actual_cnt ] . message ) ;
2008-04-02 07:13:45 +02:00
}
else
2008-09-25 16:26:15 +02:00
ok ( FALSE , " %2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x \n " ,
id , test - > wVk , test - > dwFlags , expected - > message , sent_messages [ actual_cnt ] . message ) ;
2008-04-02 07:13:45 +02:00
}
if ( test - > _todo_wine & & ! failcount ) /* succeeded yet marked todo */
todo_wine
2008-09-25 16:26:15 +02:00
ok ( TRUE , " %2d (%x/%x): marked \" todo_wine \" but succeeds \n " , id , test - > wVk , test - > dwFlags ) ;
2008-04-02 07:13:45 +02:00
sent_messages_cnt = 0 ;
2006-04-12 20:13:46 +02:00
}
/* WndProc2 checks that we get at least the messages specified */
static LRESULT CALLBACK WndProc2 ( HWND hWnd , UINT Msg , WPARAM wParam ,
LPARAM lParam )
{
2008-04-02 07:13:45 +02:00
if ( winetest_debug > 1 ) trace ( " MSG: %8x W:%8lx L:%8lx \n " , Msg , wParam , lParam ) ;
if ( Msg ! = WM_PAINT & &
Msg ! = WM_NCPAINT & &
Msg ! = WM_SYNCPAINT & &
Msg ! = WM_ERASEBKGND & &
Msg ! = WM_NCHITTEST & &
Msg ! = WM_GETTEXT & &
Msg ! = WM_GETICON & &
2009-02-24 14:57:51 +01:00
Msg ! = WM_IME_SELECT & &
2009-06-20 12:19:51 +02:00
Msg ! = WM_DEVICECHANGE & &
Msg ! = WM_TIMECHANGE )
2008-04-02 07:13:45 +02:00
{
2009-01-20 15:07:15 +01:00
ok ( sent_messages_cnt < MAXKEYMESSAGES , " Too many messages \n " ) ;
if ( sent_messages_cnt < MAXKEYMESSAGES )
{
sent_messages [ sent_messages_cnt ] . message = Msg ;
sent_messages [ sent_messages_cnt ] . flags = 0 ;
sent_messages [ sent_messages_cnt ] . wParam = wParam ;
sent_messages [ sent_messages_cnt + + ] . lParam = HIWORD ( lParam ) & ( KF_UP | KF_EXTENDED ) ;
}
2006-04-12 20:13:46 +02:00
}
return DefWindowProc ( hWnd , Msg , wParam , lParam ) ;
}
2008-04-02 07:13:45 +02:00
static LRESULT CALLBACK hook_proc ( int code , WPARAM wparam , LPARAM lparam )
{
KBDLLHOOKSTRUCT * hook_info = ( KBDLLHOOKSTRUCT * ) lparam ;
if ( code = = HC_ACTION )
{
2009-01-20 15:07:15 +01:00
ok ( sent_messages_cnt < MAXKEYMESSAGES , " Too many messages \n " ) ;
if ( sent_messages_cnt < MAXKEYMESSAGES )
{
sent_messages [ sent_messages_cnt ] . message = wparam ;
sent_messages [ sent_messages_cnt ] . flags = hook ;
sent_messages [ sent_messages_cnt ] . wParam = hook_info - > vkCode ;
sent_messages [ sent_messages_cnt + + ] . lParam = hook_info - > flags & ( LLKHF_UP | LLKHF_EXTENDED ) ;
}
2008-04-02 07:13:45 +02:00
if ( 0 ) /* For some reason not stable on Wine */
{
if ( wparam = = WM_KEYDOWN | | wparam = = WM_SYSKEYDOWN )
ok ( ! ( GetAsyncKeyState ( hook_info - > vkCode ) & 0x8000 ) , " key %x should be up \n " , hook_info - > vkCode ) ;
else if ( wparam = = WM_KEYUP | | wparam = = WM_SYSKEYUP )
ok ( GetAsyncKeyState ( hook_info - > vkCode ) & 0x8000 , " key %x should be down \n " , hook_info - > vkCode ) ;
}
if ( winetest_debug > 1 )
trace ( " Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx \n " , wparam ,
hook_info - > vkCode , hook_info - > scanCode , hook_info - > flags , hook_info - > dwExtraInfo ) ;
}
return CallNextHookEx ( 0 , code , wparam , lparam ) ;
}
2006-04-12 20:13:46 +02:00
static void test_Input_blackbox ( void )
{
2006-04-27 10:23:18 +02:00
TEST_INPUT i ;
2006-04-12 20:13:46 +02:00
int ii ;
BYTE ks1 [ 256 ] , ks2 [ 256 ] ;
LONG_PTR prevWndProc ;
HWND window ;
2008-04-02 07:13:45 +02:00
HHOOK hook ;
2007-08-15 14:23:45 +02:00
2006-04-12 20:13:46 +02:00
window = CreateWindow ( " Static " , NULL , WS_POPUP | WS_HSCROLL | WS_VSCROLL
| WS_VISIBLE , 0 , 0 , 200 , 60 , NULL , NULL ,
NULL , NULL ) ;
ok ( window ! = NULL , " error: %d \n " , ( int ) GetLastError ( ) ) ;
2009-02-19 14:23:49 +01:00
SetWindowPos ( window , HWND_TOPMOST , 0 , 0 , 0 , 0 , SWP_NOSIZE | SWP_NOMOVE ) ;
SetForegroundWindow ( window ) ;
2006-04-12 20:13:46 +02:00
2008-04-02 07:13:45 +02:00
hook = SetWindowsHookExA ( WH_KEYBOARD_LL , hook_proc , GetModuleHandleA ( NULL ) , 0 ) ;
2006-04-12 20:13:46 +02:00
/* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
* key state set by SendInput ( ) . */
empty_message_queue ( ) ;
prevWndProc = SetWindowLongPtr ( window , GWLP_WNDPROC , ( LONG_PTR ) WndProc2 ) ;
ok ( prevWndProc ! = 0 | | ( prevWndProc = = 0 & & GetLastError ( ) = = 0 ) ,
" error: %d \n " , ( int ) GetLastError ( ) ) ;
i . type = INPUT_KEYBOARD ;
2006-04-27 10:23:18 +02:00
i . u . ki . time = 0 ;
i . u . ki . dwExtraInfo = 0 ;
2006-04-12 20:13:46 +02:00
for ( ii = 0 ; ii < sizeof ( sendinput_test ) / sizeof ( struct sendinput_test_s ) - 1 ;
ii + + ) {
GetKeyboardState ( ks1 ) ;
2008-04-02 07:13:45 +02:00
i . u . ki . wScan = ii + 1 /* useful for debugging */ ;
2006-04-27 10:23:18 +02:00
i . u . ki . dwFlags = sendinput_test [ ii ] . dwFlags ;
i . u . ki . wVk = sendinput_test [ ii ] . wVk ;
2007-08-15 14:23:45 +02:00
pSendInput ( 1 , ( INPUT * ) & i , sizeof ( TEST_INPUT ) ) ;
2006-04-12 20:13:46 +02:00
empty_message_queue ( ) ;
GetKeyboardState ( ks2 ) ;
2009-02-25 12:24:53 +01:00
if ( ! ii & & sent_messages_cnt < = 1 & & ! memcmp ( ks1 , ks2 , sizeof ( ks1 ) ) )
2009-02-24 14:57:51 +01:00
{
win_skip ( " window doesn't receive the queued input \n " ) ;
2009-02-25 23:30:13 +01:00
/* release the key */
i . u . ki . dwFlags | = KEYEVENTF_KEYUP ;
pSendInput ( 1 , ( INPUT * ) & i , sizeof ( TEST_INPUT ) ) ;
2009-02-24 14:57:51 +01:00
break ;
}
2008-04-02 07:13:45 +02:00
compare_and_check ( ii , ks1 , ks2 , & sendinput_test [ ii ] ) ;
2006-04-12 20:13:46 +02:00
}
2008-04-02 07:13:45 +02:00
empty_message_queue ( ) ;
2006-04-12 20:13:46 +02:00
DestroyWindow ( window ) ;
2008-04-02 07:13:45 +02:00
UnhookWindowsHookEx ( hook ) ;
2006-04-12 20:13:46 +02:00
}
2009-08-18 18:29:17 +02:00
static void reset_key_status ( void )
{
key_status . last_key_down = - 1 ;
key_status . last_key_up = - 1 ;
key_status . last_syskey_down = - 1 ;
key_status . last_syskey_up = - 1 ;
key_status . last_char = - 1 ;
key_status . last_syschar = - 1 ;
key_status . last_hook_down = - 1 ;
key_status . last_hook_up = - 1 ;
key_status . last_hook_syskey_down = - 1 ;
key_status . last_hook_syskey_up = - 1 ;
key_status . expect_alt = FALSE ;
}
static void test_unicode_keys ( HWND hwnd , HHOOK hook )
{
TEST_INPUT inputs [ 2 ] ;
MSG msg ;
/* init input data that never changes */
inputs [ 1 ] . type = inputs [ 0 ] . type = INPUT_KEYBOARD ;
inputs [ 1 ] . u . ki . dwExtraInfo = inputs [ 0 ] . u . ki . dwExtraInfo = 0 ;
inputs [ 1 ] . u . ki . time = inputs [ 0 ] . u . ki . time = 0 ;
/* pressing & releasing a single unicode character */
inputs [ 0 ] . u . ki . wVk = 0 ;
inputs [ 0 ] . u . ki . wScan = 0x3c0 ;
inputs [ 0 ] . u . ki . dwFlags = KEYEVENTF_UNICODE ;
reset_key_status ( ) ;
SendInput ( 1 , ( INPUT * ) inputs , sizeof ( INPUT ) ) ;
while ( PeekMessageW ( & msg , hwnd , 0 , 0 , PM_REMOVE ) ) {
if ( msg . message = = WM_KEYDOWN & & msg . wParam = = VK_PACKET ) {
TranslateMessage ( & msg ) ;
}
DispatchMessageW ( & msg ) ;
}
ok ( key_status . last_key_down = = VK_PACKET ,
" Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x) \n " , VK_PACKET , key_status . last_key_down ) ;
ok ( key_status . last_char = = 0x3c0 ,
" Last char msg wparam should have been 0x3c0 (was: 0x%x) \n " , key_status . last_char ) ;
if ( hook )
ok ( key_status . last_hook_down = = 0x3c0 ,
" Last hookdown msg should have been 0x3c0, was: 0x%x \n " , key_status . last_hook_down ) ;
inputs [ 1 ] . u . ki . wVk = 0 ;
inputs [ 1 ] . u . ki . wScan = 0x3c0 ;
inputs [ 1 ] . u . ki . dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP ;
reset_key_status ( ) ;
SendInput ( 1 , ( INPUT * ) ( inputs + 1 ) , sizeof ( INPUT ) ) ;
while ( PeekMessageW ( & msg , hwnd , 0 , 0 , PM_REMOVE ) ) {
if ( msg . message = = WM_KEYDOWN & & msg . wParam = = VK_PACKET ) {
TranslateMessage ( & msg ) ;
}
DispatchMessageW ( & msg ) ;
}
ok ( key_status . last_key_up = = VK_PACKET ,
" Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x) \n " , VK_PACKET , key_status . last_key_up ) ;
if ( hook )
ok ( key_status . last_hook_up = = 0x3c0 ,
" Last hookup msg should have been 0x3c0, was: 0x%x \n " , key_status . last_hook_up ) ;
/* holding alt, pressing & releasing a unicode character, releasing alt */
inputs [ 0 ] . u . ki . wVk = VK_LMENU ;
inputs [ 0 ] . u . ki . wScan = 0 ;
inputs [ 0 ] . u . ki . dwFlags = 0 ;
inputs [ 1 ] . u . ki . wVk = 0 ;
inputs [ 1 ] . u . ki . wScan = 0x3041 ;
inputs [ 1 ] . u . ki . dwFlags = KEYEVENTF_UNICODE ;
reset_key_status ( ) ;
key_status . expect_alt = TRUE ;
SendInput ( 2 , ( INPUT * ) inputs , sizeof ( INPUT ) ) ;
while ( PeekMessageW ( & msg , hwnd , 0 , 0 , PM_REMOVE ) ) {
if ( msg . message = = WM_SYSKEYDOWN & & msg . wParam = = VK_PACKET ) {
TranslateMessage ( & msg ) ;
}
DispatchMessageW ( & msg ) ;
}
ok ( key_status . last_syskey_down = = VK_PACKET ,
" Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x) \n " , VK_PACKET , key_status . last_syskey_down ) ;
ok ( key_status . last_syschar = = 0x3041 ,
" Last syschar msg should have been 0x3041 (was: 0x%x) \n " , key_status . last_syschar ) ;
if ( hook )
ok ( key_status . last_hook_syskey_down = = 0x3041 ,
" Last hooksysdown msg should have been 0x3041, was: 0x%x \n " , key_status . last_hook_syskey_down ) ;
inputs [ 1 ] . u . ki . wVk = 0 ;
inputs [ 1 ] . u . ki . wScan = 0x3041 ;
inputs [ 1 ] . u . ki . dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP ;
inputs [ 0 ] . u . ki . wVk = VK_LMENU ;
inputs [ 0 ] . u . ki . wScan = 0 ;
inputs [ 0 ] . u . ki . dwFlags = KEYEVENTF_KEYUP ;
reset_key_status ( ) ;
key_status . expect_alt = TRUE ;
SendInput ( 2 , ( INPUT * ) inputs , sizeof ( INPUT ) ) ;
while ( PeekMessageW ( & msg , hwnd , 0 , 0 , PM_REMOVE ) ) {
if ( msg . message = = WM_SYSKEYDOWN & & msg . wParam = = VK_PACKET ) {
TranslateMessage ( & msg ) ;
}
DispatchMessageW ( & msg ) ;
}
ok ( key_status . last_key_up = = VK_PACKET ,
" Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x) \n " , VK_PACKET , key_status . last_key_up ) ;
if ( hook )
ok ( key_status . last_hook_up = = 0x3041 ,
" Last hook up msg should have been 0x3041, was: 0x%x \n " , key_status . last_hook_up ) ;
}
static LRESULT CALLBACK unicode_wnd_proc ( HWND hWnd , UINT msg , WPARAM wParam ,
LPARAM lParam )
{
switch ( msg ) {
case WM_KEYDOWN :
key_status . last_key_down = wParam ;
break ;
case WM_SYSKEYDOWN :
key_status . last_syskey_down = wParam ;
break ;
case WM_KEYUP :
key_status . last_key_up = wParam ;
break ;
case WM_SYSKEYUP :
key_status . last_syskey_up = wParam ;
break ;
case WM_CHAR :
key_status . last_char = wParam ;
break ;
case WM_SYSCHAR :
key_status . last_syschar = wParam ;
break ;
}
return DefWindowProcW ( hWnd , msg , wParam , lParam ) ;
}
static LRESULT CALLBACK llkbd_unicode_hook ( int nCode , WPARAM wParam , LPARAM lParam )
{
if ( nCode = = HC_ACTION ) {
LPKBDLLHOOKSTRUCT info = ( LPKBDLLHOOKSTRUCT ) lParam ;
ok ( info - > vkCode = = VK_PACKET | | ( key_status . expect_alt & & info - > vkCode = = VK_LMENU ) , " vkCode should have been VK_PACKET[%04x], was: %04x \n " , VK_PACKET , info - > vkCode ) ;
key_status . expect_alt = FALSE ;
switch ( wParam ) {
case WM_KEYDOWN :
key_status . last_hook_down = info - > scanCode ;
break ;
case WM_KEYUP :
key_status . last_hook_up = info - > scanCode ;
break ;
case WM_SYSKEYDOWN :
key_status . last_hook_syskey_down = info - > scanCode ;
break ;
case WM_SYSKEYUP :
key_status . last_hook_syskey_up = info - > scanCode ;
break ;
}
}
return CallNextHookEx ( NULL , nCode , wParam , lParam ) ;
}
static void test_Input_unicode ( void )
{
WCHAR classNameW [ ] = { ' I ' , ' n ' , ' p ' , ' u ' , ' t ' , ' U ' , ' n ' , ' i ' , ' c ' , ' o ' , ' d ' , ' e ' ,
' K ' , ' e ' , ' y ' , ' T ' , ' e ' , ' s ' , ' t ' , ' C ' , ' l ' , ' a ' , ' s ' , ' s ' , 0 } ;
WCHAR windowNameW [ ] = { ' I ' , ' n ' , ' p ' , ' u ' , ' t ' , ' U ' , ' n ' , ' i ' , ' c ' , ' o ' , ' d ' , ' e ' ,
' K ' , ' e ' , ' y ' , ' T ' , ' e ' , ' s ' , ' t ' , 0 } ;
MSG msg ;
WNDCLASSW wclass ;
HANDLE hInstance = GetModuleHandleW ( NULL ) ;
HHOOK hook ;
wclass . lpszClassName = classNameW ;
wclass . style = CS_HREDRAW | CS_VREDRAW ;
wclass . lpfnWndProc = unicode_wnd_proc ;
wclass . hInstance = hInstance ;
wclass . hIcon = LoadIcon ( 0 , IDI_APPLICATION ) ;
wclass . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wclass . hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ) ;
wclass . lpszMenuName = 0 ;
wclass . cbClsExtra = 0 ;
wclass . cbWndExtra = 0 ;
2009-08-20 18:43:00 +02:00
if ( ! RegisterClassW ( & wclass ) ) {
win_skip ( " Unicode functions not supported \n " ) ;
return ;
}
2009-08-18 18:29:17 +02:00
/* create the test window that will receive the keystrokes */
hWndTest = CreateWindowW ( wclass . lpszClassName , windowNameW ,
WS_OVERLAPPEDWINDOW , CW_USEDEFAULT , 0 , 100 , 100 ,
NULL , NULL , hInstance , NULL ) ;
assert ( hWndTest ) ;
assert ( IsWindowUnicode ( hWndTest ) ) ;
hook = SetWindowsHookExW ( WH_KEYBOARD_LL , llkbd_unicode_hook , GetModuleHandleW ( NULL ) , 0 ) ;
if ( ! hook )
win_skip ( " unable to set WH_KEYBOARD_LL hook \n " ) ;
ShowWindow ( hWndTest , SW_SHOW ) ;
SetWindowPos ( hWndTest , HWND_TOPMOST , 0 , 0 , 0 , 0 , SWP_NOSIZE | SWP_NOMOVE ) ;
SetForegroundWindow ( hWndTest ) ;
UpdateWindow ( hWndTest ) ;
/* flush pending messages */
while ( PeekMessageW ( & msg , 0 , 0 , 0 , PM_REMOVE ) ) DispatchMessageW ( & msg ) ;
SetFocus ( hWndTest ) ;
test_unicode_keys ( hWndTest , hook ) ;
if ( hook )
UnhookWindowsHookEx ( hook ) ;
DestroyWindow ( hWndTest ) ;
}
2006-07-30 03:28:26 +02:00
static void test_keynames ( void )
{
int i , len ;
char buff [ 256 ] ;
for ( i = 0 ; i < 512 ; i + + )
{
strcpy ( buff , " ---- " ) ;
len = GetKeyNameTextA ( i < < 16 , buff , sizeof ( buff ) ) ;
ok ( len | | ! buff [ 0 ] , " %d: Buffer is not zeroed \n " , i ) ;
}
}
2006-10-09 06:48:26 +02:00
static POINT pt_old , pt_new ;
2007-01-04 20:24:50 +01:00
static BOOL clipped ;
2009-02-25 12:24:53 +01:00
# define STEP 3
2006-10-09 06:48:26 +02:00
static LRESULT CALLBACK hook_proc1 ( int code , WPARAM wparam , LPARAM lparam )
{
MSLLHOOKSTRUCT * hook = ( MSLLHOOKSTRUCT * ) lparam ;
POINT pt , pt1 ;
if ( code = = HC_ACTION )
{
/* This is our new cursor position */
pt_new = hook - > pt ;
/* Should return previous position */
GetCursorPos ( & pt ) ;
ok ( pt . x = = pt_old . x & & pt . y = = pt_old . y , " GetCursorPos: (%d,%d) \n " , pt . x , pt . y ) ;
/* Should set new position until hook chain is finished. */
pt . x = pt_old . x + STEP ;
pt . y = pt_old . y + STEP ;
SetCursorPos ( pt . x , pt . y ) ;
GetCursorPos ( & pt1 ) ;
2007-01-04 20:24:50 +01:00
if ( clipped )
ok ( pt1 . x = = pt_old . x & & pt1 . y = = pt_old . y , " Wrong set pos: (%d,%d) \n " , pt1 . x , pt1 . y ) ;
else
ok ( pt1 . x = = pt . x & & pt1 . y = = pt . y , " Wrong set pos: (%d,%d) \n " , pt1 . x , pt1 . y ) ;
2006-10-09 06:48:26 +02:00
}
return CallNextHookEx ( 0 , code , wparam , lparam ) ;
}
static LRESULT CALLBACK hook_proc2 ( int code , WPARAM wparam , LPARAM lparam )
{
MSLLHOOKSTRUCT * hook = ( MSLLHOOKSTRUCT * ) lparam ;
POINT pt ;
if ( code = = HC_ACTION )
{
ok ( hook - > pt . x = = pt_new . x & & hook - > pt . y = = pt_new . y ,
2006-12-12 23:57:22 +01:00
" Wrong hook coords: (%d %d) != (%d,%d) \n " , hook - > pt . x , hook - > pt . y , pt_new . x , pt_new . y ) ;
2006-10-09 06:48:26 +02:00
/* Should match position set above */
GetCursorPos ( & pt ) ;
2007-01-04 20:24:50 +01:00
if ( clipped )
ok ( pt . x = = pt_old . x & & pt . y = = pt_old . y , " GetCursorPos: (%d,%d) \n " , pt . x , pt . y ) ;
else
ok ( pt . x = = pt_old . x + STEP & & pt . y = = pt_old . y + STEP , " GetCursorPos: (%d,%d) \n " , pt . x , pt . y ) ;
2006-10-09 06:48:26 +02:00
}
return CallNextHookEx ( 0 , code , wparam , lparam ) ;
}
static void test_mouse_ll_hook ( void )
{
HWND hwnd ;
HHOOK hook1 , hook2 ;
2006-12-12 23:57:22 +01:00
POINT pt_org , pt ;
2007-01-04 20:24:50 +01:00
RECT rc ;
2006-10-09 06:48:26 +02:00
GetCursorPos ( & pt_org ) ;
2007-01-04 20:24:50 +01:00
hwnd = CreateWindow ( " static " , " Title " , WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
2006-10-09 06:48:26 +02:00
10 , 10 , 200 , 200 , NULL , NULL , NULL , NULL ) ;
2007-01-04 20:24:50 +01:00
SetCursorPos ( 100 , 100 ) ;
2006-10-09 06:48:26 +02:00
2009-02-25 23:30:13 +01:00
if ( ! ( hook2 = SetWindowsHookExA ( WH_MOUSE_LL , hook_proc2 , GetModuleHandleA ( 0 ) , 0 ) ) )
{
win_skip ( " cannot set MOUSE_LL hook \n " ) ;
goto done ;
}
2006-10-09 06:48:26 +02:00
hook1 = SetWindowsHookExA ( WH_MOUSE_LL , hook_proc1 , GetModuleHandleA ( 0 ) , 0 ) ;
GetCursorPos ( & pt_old ) ;
mouse_event ( MOUSEEVENTF_MOVE , - STEP , 0 , 0 , 0 ) ;
GetCursorPos ( & pt_old ) ;
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 ) ;
mouse_event ( MOUSEEVENTF_MOVE , + STEP , 0 , 0 , 0 ) ;
GetCursorPos ( & pt_old ) ;
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 ) ;
mouse_event ( MOUSEEVENTF_MOVE , 0 , - STEP , 0 , 0 ) ;
GetCursorPos ( & pt_old ) ;
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 ) ;
mouse_event ( MOUSEEVENTF_MOVE , 0 , + STEP , 0 , 0 ) ;
GetCursorPos ( & pt_old ) ;
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 ) ;
2007-01-04 20:24:50 +01:00
SetRect ( & rc , 50 , 50 , 151 , 151 ) ;
ClipCursor ( & rc ) ;
clipped = TRUE ;
SetCursorPos ( 40 , 40 ) ;
GetCursorPos ( & pt_old ) ;
ok ( pt_old . x = = 50 & & pt_old . y = = 50 , " Wrong new pos: (%d,%d) \n " , pt_new . x , pt_new . y ) ;
SetCursorPos ( 160 , 160 ) ;
GetCursorPos ( & pt_old ) ;
ok ( pt_old . x = = 150 & & pt_old . y = = 150 , " Wrong new pos: (%d,%d) \n " , pt_new . x , pt_new . y ) ;
mouse_event ( MOUSEEVENTF_MOVE , + STEP , + STEP , 0 , 0 ) ;
GetCursorPos ( & pt_old ) ;
ok ( pt_old . x = = 150 & & pt_old . y = = 150 , " Wrong new pos: (%d,%d) \n " , pt_new . x , pt_new . y ) ;
clipped = FALSE ;
pt_new . x = pt_new . y = 150 ;
ClipCursor ( NULL ) ;
2006-10-09 06:48:26 +02:00
UnhookWindowsHookEx ( hook1 ) ;
2006-12-12 23:57:22 +01:00
/* Now check that mouse buttons do not change mouse position
if we don ' t have MOUSEEVENTF_MOVE flag specified . */
/* We reusing the same hook callback, so make it happy */
pt_old . x = pt_new . x - STEP ;
pt_old . y = pt_new . y - STEP ;
mouse_event ( MOUSEEVENTF_LEFTUP , 123 , 456 , 0 , 0 ) ;
GetCursorPos ( & pt ) ;
ok ( pt . x = = pt_new . x & & pt . y = = pt_new . y , " Position changed: (%d,%d) \n " , pt . x , pt . y ) ;
mouse_event ( MOUSEEVENTF_RIGHTUP , 456 , 123 , 0 , 0 ) ;
GetCursorPos ( & pt ) ;
ok ( pt . x = = pt_new . x & & pt . y = = pt_new . y , " Position changed: (%d,%d) \n " , pt . x , pt . y ) ;
mouse_event ( MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE , 123 , 456 , 0 , 0 ) ;
GetCursorPos ( & pt ) ;
ok ( pt . x = = pt_new . x & & pt . y = = pt_new . y , " Position changed: (%d,%d) \n " , pt . x , pt . y ) ;
mouse_event ( MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE , 456 , 123 , 0 , 0 ) ;
GetCursorPos ( & pt ) ;
ok ( pt . x = = pt_new . x & & pt . y = = pt_new . y , " Position changed: (%d,%d) \n " , pt . x , pt . y ) ;
2006-10-09 06:48:26 +02:00
UnhookWindowsHookEx ( hook2 ) ;
2009-02-25 23:30:13 +01:00
done :
2006-10-09 06:48:26 +02:00
DestroyWindow ( hwnd ) ;
SetCursorPos ( pt_org . x , pt_org . y ) ;
}
2008-02-16 19:35:22 +01:00
static void test_GetMouseMovePointsEx ( void )
{
# define BUFLIM 64
# define MYERROR 0xdeadbeef
int count , retval ;
MOUSEMOVEPOINT in ;
MOUSEMOVEPOINT out [ 200 ] ;
POINT point ;
/* Get a valid content for the input struct */
if ( ! GetCursorPos ( & point ) ) {
skip ( " GetCursorPos() failed with error %u \n " , GetLastError ( ) ) ;
return ;
}
memset ( & in , 0 , sizeof ( MOUSEMOVEPOINT ) ) ;
in . x = point . x ;
in . y = point . y ;
/* test first parameter
* everything different than sizeof ( MOUSEMOVEPOINT )
* is expected to fail with ERROR_INVALID_PARAMETER
*/
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( 0 , & in , out , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
2009-02-25 23:30:13 +01:00
if ( retval = = ERROR_INVALID_PARAMETER )
{
win_skip ( " GetMouseMovePointsEx broken on WinME \n " ) ;
return ;
}
2008-02-16 19:35:22 +01:00
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) - 1 , & in , out , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) + 1 , & in , out , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
/* test second and third parameter
*/
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , NULL , out , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_NOACCESS | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_NOACCESS, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , NULL , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
ok ( ERROR_NOACCESS = = GetLastError ( ) ,
" expected error ERROR_NOACCESS, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , NULL , NULL , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
ok ( ERROR_NOACCESS = = GetLastError ( ) ,
" expected error ERROR_NOACCESS, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
count = 0 ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , NULL , count , GMMP_USE_DISPLAY_POINTS ) ;
2009-02-25 12:24:53 +01:00
if ( retval = = - 1 )
ok ( GetLastError ( ) = = ERROR_POINT_NOT_FOUND , " unexpected error %u \n " , GetLastError ( ) ) ;
else
ok ( retval = = count , " expected GetMouseMovePointsEx to succeed, got %d \n " , retval ) ;
2008-02-16 19:35:22 +01:00
/* test fourth parameter
* a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
*/
SetLastError ( MYERROR ) ;
count = - 1 ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , out , count , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = count , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
count = 0 ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , out , count , GMMP_USE_DISPLAY_POINTS ) ;
2009-02-25 12:24:53 +01:00
if ( retval = = - 1 )
ok ( GetLastError ( ) = = ERROR_POINT_NOT_FOUND , " unexpected error %u \n " , GetLastError ( ) ) ;
else
ok ( retval = = count , " expected GetMouseMovePointsEx to succeed, got %d \n " , retval ) ;
2008-02-16 19:35:22 +01:00
SetLastError ( MYERROR ) ;
count = BUFLIM ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , out , count , GMMP_USE_DISPLAY_POINTS ) ;
2009-02-25 12:24:53 +01:00
if ( retval = = - 1 )
ok ( GetLastError ( ) = = ERROR_POINT_NOT_FOUND , " unexpected error %u \n " , GetLastError ( ) ) ;
else
ok ( ( 0 < = retval ) & & ( retval < = count ) , " expected GetMouseMovePointsEx to succeed, got %d \n " , retval ) ;
2008-02-16 19:35:22 +01:00
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , out , BUFLIM + 1 , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
/* it was not possible to force an error with the fifth parameter on win2k */
/* test combinations of wrong parameters to see which error wins */
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) - 1 , NULL , out , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) - 1 , & in , NULL , BUFLIM , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , NULL , out , BUFLIM + 1 , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
SetLastError ( MYERROR ) ;
retval = pGetMouseMovePointsEx ( sizeof ( MOUSEMOVEPOINT ) , & in , NULL , BUFLIM + 1 , GMMP_USE_DISPLAY_POINTS ) ;
ok ( retval = = - 1 , " expected GetMouseMovePointsEx to fail, got %d \n " , retval ) ;
2008-09-24 15:37:38 +02:00
ok ( GetLastError ( ) = = ERROR_INVALID_PARAMETER | | GetLastError ( ) = = MYERROR ,
2008-02-16 19:35:22 +01:00
" expected error ERROR_INVALID_PARAMETER, got %u \n " , GetLastError ( ) ) ;
# undef BUFLIM
# undef MYERROR
}
2008-04-27 01:35:50 +02:00
static void test_key_map ( void )
{
HKL kl = GetKeyboardLayout ( 0 ) ;
UINT kL , kR , s , sL ;
2008-05-16 17:37:07 +02:00
int i ;
static const UINT numpad_collisions [ ] [ 2 ] = {
{ VK_NUMPAD0 , VK_INSERT } ,
{ VK_NUMPAD1 , VK_END } ,
{ VK_NUMPAD2 , VK_DOWN } ,
{ VK_NUMPAD3 , VK_NEXT } ,
{ VK_NUMPAD4 , VK_LEFT } ,
{ VK_NUMPAD6 , VK_RIGHT } ,
{ VK_NUMPAD7 , VK_HOME } ,
{ VK_NUMPAD8 , VK_UP } ,
{ VK_NUMPAD9 , VK_PRIOR } ,
} ;
2008-04-27 01:35:50 +02:00
s = MapVirtualKeyEx ( VK_SHIFT , MAPVK_VK_TO_VSC , kl ) ;
ok ( s ! = 0 , " MapVirtualKeyEx(VK_SHIFT) should return non-zero \n " ) ;
sL = MapVirtualKeyEx ( VK_LSHIFT , MAPVK_VK_TO_VSC , kl ) ;
2009-02-24 14:57:51 +01:00
ok ( s = = sL | | broken ( sL = = 0 ) , /* win9x */
" %x != %x \n " , s , sL ) ;
2008-04-27 01:35:50 +02:00
kL = MapVirtualKeyEx ( 0x2a , MAPVK_VSC_TO_VK , kl ) ;
ok ( kL = = VK_SHIFT , " Scan code -> vKey = %x (not VK_SHIFT) \n " , kL ) ;
kR = MapVirtualKeyEx ( 0x36 , MAPVK_VSC_TO_VK , kl ) ;
ok ( kR = = VK_SHIFT , " Scan code -> vKey = %x (not VK_SHIFT) \n " , kR ) ;
kL = MapVirtualKeyEx ( 0x2a , MAPVK_VSC_TO_VK_EX , kl ) ;
2009-02-24 14:57:51 +01:00
ok ( kL = = VK_LSHIFT | | broken ( kL = = 0 ) , /* win9x */
" Scan code -> vKey = %x (not VK_LSHIFT) \n " , kL ) ;
2008-04-27 01:35:50 +02:00
kR = MapVirtualKeyEx ( 0x36 , MAPVK_VSC_TO_VK_EX , kl ) ;
2009-02-24 14:57:51 +01:00
ok ( kR = = VK_RSHIFT | | broken ( kR = = 0 ) , /* win9x */
" Scan code -> vKey = %x (not VK_RSHIFT) \n " , kR ) ;
2008-05-16 17:37:07 +02:00
/* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
for ( i = 0 ; i < sizeof ( numpad_collisions ) / sizeof ( numpad_collisions [ 0 ] ) ; i + + )
{
UINT numpad_scan = MapVirtualKeyEx ( numpad_collisions [ i ] [ 0 ] , MAPVK_VK_TO_VSC , kl ) ;
UINT other_scan = MapVirtualKeyEx ( numpad_collisions [ i ] [ 1 ] , MAPVK_VK_TO_VSC , kl ) ;
/* do they really collide for this layout? */
if ( numpad_scan & & other_scan = = numpad_scan )
{
UINT vkey = MapVirtualKeyEx ( numpad_scan , MAPVK_VSC_TO_VK , kl ) ;
ok ( vkey ! = numpad_collisions [ i ] [ 0 ] ,
" Got numpad vKey %x for scan code %x when there was another choice \n " ,
vkey , numpad_scan ) ;
}
}
2008-04-27 01:35:50 +02:00
}
2008-08-05 14:20:24 +02:00
static void test_ToUnicode ( void )
{
WCHAR wStr [ 2 ] ;
BYTE state [ 256 ] ;
const BYTE SC_RETURN = 0x1c , SC_TAB = 0x0f ;
const BYTE HIGHEST_BIT = 0x80 ;
int i , ret ;
for ( i = 0 ; i < 256 ; i + + )
state [ i ] = 0 ;
SetLastError ( 0xdeadbeef ) ;
ret = ToUnicode ( VK_RETURN , SC_RETURN , state , wStr , 2 , 0 ) ;
if ( ! ret & & GetLastError ( ) = = ERROR_CALL_NOT_IMPLEMENTED )
{
2009-02-23 10:41:03 +01:00
win_skip ( " ToUnicode is not implemented \n " ) ;
2008-08-05 14:20:24 +02:00
return ;
}
ok ( ret = = 1 , " ToUnicode for Return key didn't return 1 (was %i) \n " , ret ) ;
if ( ret = = 1 )
ok ( wStr [ 0 ] = = ' \r ' , " ToUnicode for CTRL + Return was %i (expected 13) \n " , wStr [ 0 ] ) ;
state [ VK_CONTROL ] | = HIGHEST_BIT ;
state [ VK_LCONTROL ] | = HIGHEST_BIT ;
ret = ToUnicode ( VK_TAB , SC_TAB , state , wStr , 2 , 0 ) ;
2009-05-27 19:55:23 +02:00
ok ( ret = = 0 , " ToUnicode for CTRL + Tab didn't return 0 (was %i) \n " , ret ) ;
2008-08-05 14:20:24 +02:00
ret = ToUnicode ( VK_RETURN , SC_RETURN , state , wStr , 2 , 0 ) ;
2008-09-01 17:02:19 +02:00
ok ( ret = = 1 , " ToUnicode for CTRL + Return didn't return 1 (was %i) \n " , ret ) ;
2008-08-05 14:20:24 +02:00
if ( ret = = 1 )
ok ( wStr [ 0 ] = = ' \n ' , " ToUnicode for CTRL + Return was %i (expected 10) \n " , wStr [ 0 ] ) ;
state [ VK_SHIFT ] | = HIGHEST_BIT ;
state [ VK_LSHIFT ] | = HIGHEST_BIT ;
2009-06-01 20:10:21 +02:00
ret = ToUnicode ( VK_TAB , SC_TAB , state , wStr , 2 , 0 ) ;
ok ( ret = = 0 , " ToUnicode for CTRL + SHIFT + Tab didn't return 0 (was %i) \n " , ret ) ;
2008-08-05 14:20:24 +02:00
ret = ToUnicode ( VK_RETURN , SC_RETURN , state , wStr , 2 , 0 ) ;
todo_wine ok ( ret = = 0 , " ToUnicode for CTRL + SHIFT + Return didn't return 0 (was %i) \ n " , ret) ;
}
2008-12-08 20:25:30 +01:00
static void test_get_async_key_state ( void )
{
/* input value sanity checks */
ok ( 0 = = GetAsyncKeyState ( 1000000 ) , " GetAsyncKeyState did not return 0 \n " ) ;
ok ( 0 = = GetAsyncKeyState ( - 1000000 ) , " GetAsyncKeyState did not return 0 \n " ) ;
}
2009-04-14 12:34:37 +02:00
static void test_keyboard_layout_name ( void )
{
BOOL ret ;
char klid [ KL_NAMELENGTH ] ;
if ( GetKeyboardLayout ( 0 ) ! = ( HKL ) ( ULONG_PTR ) 0x04090409 ) return ;
klid [ 0 ] = 0 ;
ret = GetKeyboardLayoutNameA ( klid ) ;
ok ( ret , " GetKeyboardLayoutNameA failed %u \n " , GetLastError ( ) ) ;
ok ( ! strcmp ( klid , " 00000409 " ) , " expected 00000409, got %s \n " , klid ) ;
}
2006-04-12 20:13:46 +02:00
START_TEST ( input )
{
2007-08-15 14:23:45 +02:00
init_function_pointers ( ) ;
2009-02-23 10:41:03 +01:00
if ( pSendInput )
2009-02-21 12:56:52 +01:00
{
test_Input_blackbox ( ) ;
2007-08-15 14:23:45 +02:00
test_Input_whitebox ( ) ;
2009-08-18 18:29:17 +02:00
test_Input_unicode ( ) ;
2009-02-21 12:56:52 +01:00
}
2009-02-23 10:41:03 +01:00
else win_skip ( " SendInput is not available \n " ) ;
2006-07-30 03:28:26 +02:00
test_keynames ( ) ;
2006-10-09 06:48:26 +02:00
test_mouse_ll_hook ( ) ;
2008-04-27 01:35:50 +02:00
test_key_map ( ) ;
2008-08-05 14:20:24 +02:00
test_ToUnicode ( ) ;
2008-12-08 20:25:30 +01:00
test_get_async_key_state ( ) ;
2009-04-14 12:34:37 +02:00
test_keyboard_layout_name ( ) ;
2008-02-16 19:35:22 +01:00
if ( pGetMouseMovePointsEx )
test_GetMouseMovePointsEx ( ) ;
else
2009-02-23 10:41:03 +01:00
win_skip ( " GetMouseMovePointsEx is not available \n " ) ;
2006-04-12 20:13:46 +02:00
}