user32/tests: Restructure the DDE end-to-end tests to make it easier to add new cases.
[wine] / dlls / user32 / tests / input.c
1 /* Test Key event to Key message translation
2  *
3  * Copyright 2003 Rein Klazes
4  *
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.
9  *
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.
14  *
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
18  */
19
20 /* test whether the right type of messages:
21  * WM_KEYUP/DOWN vs WM_SYSKEYUP/DOWN  are sent in case of combined
22  * keystrokes.
23  *
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 */
29
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 */
33
34 /* TODO:
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
40  *    offers a nice way.
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
43  *    if it is a problem.
44  *
45  */
46
47 #define _WIN32_WINNT 0x401
48 #define _WIN32_IE 0x0500
49
50 #include <stdarg.h>
51 #include <assert.h>
52
53 #include "windef.h"
54 #include "winbase.h"
55 #include "winuser.h"
56
57 #include "wine/test.h"
58
59 /* globals */
60 static HWND hWndTest;
61 static LONG timetag = 0x10000000;
62
63 static struct {
64     LONG last_key_down;
65     LONG last_key_up;
66     LONG last_syskey_down;
67     LONG last_syskey_up;
68     LONG last_char;
69     LONG last_syschar;
70     LONG last_hook_down;
71     LONG last_hook_up;
72     LONG last_hook_syskey_down;
73     LONG last_hook_syskey_up;
74     BOOL expect_alt;
75     BOOL sendinput_broken;
76 } key_status;
77
78 static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
79 static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD);
80
81 #define MAXKEYEVENTS 12
82 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
83                                        and only one message */
84
85 /* keyboard message names, sorted as their value */
86 static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR",
87     "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"};
88
89 /* keyevents, add more as needed */
90 typedef enum KEVtag
91 {  ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV;
92 /* matching VK's */
93 static const int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL};
94 /* matching scan codes */
95 static const int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D };
96 /* matching updown events */
97 static const int GETFLAGS[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP};
98 /* matching descriptions */
99 static const char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"};
100
101 /* The MSVC headers ignore our NONAMELESSUNION requests so we have to define our own type */
102 typedef struct
103 {
104     DWORD type;
105     union
106     {
107         MOUSEINPUT      mi;
108         KEYBDINPUT      ki;
109         HARDWAREINPUT   hi;
110     } u;
111 } TEST_INPUT;
112
113 #define ADDTOINPUTS(kev) \
114 inputs[evtctr].type = INPUT_KEYBOARD; \
115     ((TEST_INPUT*)inputs)[evtctr].u.ki.wVk = GETVKEY[ kev]; \
116     ((TEST_INPUT*)inputs)[evtctr].u.ki.wScan = GETSCAN[ kev]; \
117     ((TEST_INPUT*)inputs)[evtctr].u.ki.dwFlags = GETFLAGS[ kev]; \
118     ((TEST_INPUT*)inputs)[evtctr].u.ki.dwExtraInfo = 0; \
119     ((TEST_INPUT*)inputs)[evtctr].u.ki.time = ++timetag; \
120     if( kev) evtctr++;
121
122 typedef struct {
123     UINT    message;
124     WPARAM  wParam;
125     LPARAM  lParam;
126 } KMSG;
127
128 /*******************************************
129  * add new test sets here
130  * the software will make all combinations of the
131  * keyevent defined here
132  */
133 static const struct {
134     int nrkev;
135     KEV keydwn[MAXKEYEVENTS];
136     KEV keyup[MAXKEYEVENTS];
137 } testkeyset[]= {
138     { 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}},
139     { 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}},
140     { 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}},
141     { 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}},
142     { 0 } /* mark the end */
143 };
144
145 /**********************adapted from input.c **********************************/
146
147 static BYTE InputKeyStateTable[256];
148 static BYTE AsyncKeyStateTable[256];
149 static BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
150                          or a WM_KEYUP message */
151
152 static void init_function_pointers(void)
153 {
154     HMODULE hdll = GetModuleHandleA("user32");
155
156 #define GET_PROC(func) \
157     p ## func = (void*)GetProcAddress(hdll, #func); \
158     if(!p ## func) \
159       trace("GetProcAddress(%s) failed\n", #func);
160
161     GET_PROC(SendInput)
162     GET_PROC(GetMouseMovePointsEx)
163
164 #undef GET_PROC
165 }
166
167 static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam )
168 {
169     UINT message;
170     int VKey = GETVKEY[kev];
171     WORD flags;
172
173     flags = LOBYTE(GETSCAN[kev]);
174     if (GETFLAGS[kev] & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED;
175
176     if (GETFLAGS[kev] & KEYEVENTF_KEYUP )
177     {
178         message = WM_KEYUP;
179         if( (InputKeyStateTable[VK_MENU] & 0x80) && (
180                 (VKey == VK_MENU) || (VKey == VK_CONTROL) ||
181                  !(InputKeyStateTable[VK_CONTROL] & 0x80))) {
182             if(  TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
183                     (VKey != VK_MENU)) /* <ALT>-down...<something else>-up */
184                 message = WM_SYSKEYUP;
185                 TrackSysKey = 0;
186         }
187         InputKeyStateTable[VKey] &= ~0x80;
188         flags |= KF_REPEAT | KF_UP;
189     }
190     else
191     {
192         if (InputKeyStateTable[VKey] & 0x80) flags |= KF_REPEAT;
193         if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01;
194         InputKeyStateTable[VKey] |= 0x80;
195         AsyncKeyStateTable[VKey] |= 0x80;
196
197         message = WM_KEYDOWN;
198         if( (InputKeyStateTable[VK_MENU] & 0x80) &&
199                 !(InputKeyStateTable[VK_CONTROL] & 0x80)) {
200             message = WM_SYSKEYDOWN;
201             TrackSysKey = VKey;
202         }
203     }
204
205     if (InputKeyStateTable[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
206
207     if( plParam) *plParam = MAKELPARAM( 1, flags );
208     if( pwParam) *pwParam = VKey;
209     return message;
210 }
211
212 /****************************** end copy input.c ****************************/
213
214 /*
215  * . prepare the keyevents for SendInputs
216  * . calculate the "expected" messages
217  * . Send the events to our window
218  * . retrieve the messages from the input queue
219  * . verify
220  */
221 static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] )
222 {
223     INPUT inputs[MAXKEYEVENTS];
224     KMSG expmsg[MAXKEYEVENTS];
225     MSG msg;
226     char buf[100];
227     UINT evtctr=0;
228     int kmctr, i;
229
230     buf[0]='\0';
231     TrackSysKey=0; /* see input.c */
232     for( i = 0; i < MAXKEYEVENTS; i++) {
233         ADDTOINPUTS(td[i])
234         strcat(buf, getdesc[td[i]]);
235         if(td[i])
236             expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam)); /* see queue_kbd_event() */
237         else
238             expmsg[i].message = 0;
239     }
240     for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++)
241         ;
242     assert( evtctr <= MAXKEYEVENTS );
243     assert( evtctr == pSendInput(evtctr, &inputs[0], sizeof(INPUT)));
244     i = 0;
245     if (winetest_debug > 1)
246         trace("======== key stroke sequence #%d: %s =============\n",
247             seqnr + 1, buf);
248     while( PeekMessage(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) {
249         if (winetest_debug > 1)
250             trace("message[%d] %-15s wParam %04lx lParam %08lx time %x\n", i,
251                   MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time);
252         if( i < kmctr ) {
253             ok( msg.message == expmsg[i].message &&
254                 msg.wParam == expmsg[i].wParam &&
255                 msg.lParam == expmsg[i].lParam,
256                 "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n",
257                 seqnr, i, msg.message, msg.wParam, msg.lParam,
258                 MSGNAME[(expmsg[i]).message - WM_KEYFIRST], expmsg[i].wParam, expmsg[i].lParam );
259         }
260         i++;
261     }
262     if (winetest_debug > 1)
263         trace("%d messages retrieved\n", i);
264     if (!i && kmctr)
265     {
266         skip( "simulated keyboard input doesn't work\n" );
267         return FALSE;
268     }
269     ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr);
270     return TRUE;
271 }
272
273 /* test all combinations of the specified key events */
274 static BOOL TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] )
275 {
276     int i,j,k,l,m,n;
277     static int count=0;
278     KEV kbuf[MAXKEYEVENTS];
279     assert( nrkev==2 || nrkev==3);
280     for(i=0;i<MAXKEYEVENTS;i++) kbuf[i]=0;
281     /* two keys involved gives 4 test cases */
282     if(nrkev==2) {
283         for(i=0;i<nrkev;i++) {
284             for(j=0;j<nrkev;j++) {
285                 kbuf[0] = kevdwn[i];
286                 kbuf[1] = kevdwn[1-i];
287                 kbuf[2] = kevup[j];
288                 kbuf[3] = kevup[1-j];
289                 if (!do_test( hWnd, count++, kbuf)) return FALSE;
290             }
291         }
292     }
293     /* three keys involved gives 36 test cases */
294     if(nrkev==3){
295         for(i=0;i<nrkev;i++){
296             for(j=0;j<nrkev;j++){
297                 if(j==i) continue;
298                 for(k=0;k<nrkev;k++){
299                     if(k==i || k==j) continue;
300                     for(l=0;l<nrkev;l++){
301                         for(m=0;m<nrkev;m++){
302                             if(m==l) continue;
303                             for(n=0;n<nrkev;n++){
304                                 if(n==l ||n==m) continue;
305                                 kbuf[0] = kevdwn[i];
306                                 kbuf[1] = kevdwn[j];
307                                 kbuf[2] = kevdwn[k];
308                                 kbuf[3] = kevup[l];
309                                 kbuf[4] = kevup[m];
310                                 kbuf[5] = kevup[n];
311                                 if (!do_test( hWnd, count++, kbuf)) return FALSE;
312                             }
313                         }
314                     }
315                 }
316             }
317         }
318     }
319     return TRUE;
320 }
321
322 /* test each set specified in the global testkeyset array */
323 static void TestSysKeys( HWND hWnd)
324 {
325     int i;
326     for(i=0; testkeyset[i].nrkev;i++)
327         if (!TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn, testkeyset[i].keyup)) break;
328 }
329
330 static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam,
331         LPARAM lParam )
332 {
333     return DefWindowProcA( hWnd, msg, wParam, lParam );
334 }
335
336 static void test_Input_whitebox(void)
337 {
338     MSG msg;
339     WNDCLASSA  wclass;
340     HANDLE hInstance = GetModuleHandleA( NULL );
341
342     wclass.lpszClassName = "InputSysKeyTestClass";
343     wclass.style         = CS_HREDRAW | CS_VREDRAW;
344     wclass.lpfnWndProc   = WndProc;
345     wclass.hInstance     = hInstance;
346     wclass.hIcon         = LoadIconA( 0, IDI_APPLICATION );
347     wclass.hCursor       = LoadCursorA( NULL, IDC_ARROW );
348     wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
349     wclass.lpszMenuName = 0;
350     wclass.cbClsExtra    = 0;
351     wclass.cbWndExtra    = 0;
352     RegisterClassA( &wclass );
353     /* create the test window that will receive the keystrokes */
354     hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest",
355                               WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
356                               NULL, NULL, hInstance, NULL);
357     assert( hWndTest );
358     ShowWindow( hWndTest, SW_SHOW);
359     SetWindowPos( hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
360     SetForegroundWindow( hWndTest );
361     UpdateWindow( hWndTest);
362
363     /* flush pending messages */
364     while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
365
366     SetFocus( hWndTest );
367     TestSysKeys( hWndTest );
368     DestroyWindow(hWndTest);
369 }
370
371 /* try to make sure pending X events have been processed before continuing */
372 static void empty_message_queue(void)
373 {
374     MSG msg;
375     int diff = 200;
376     int min_timeout = 50;
377     DWORD time = GetTickCount() + diff;
378
379     while (diff > 0)
380     {
381         if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
382         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
383         {
384             TranslateMessage(&msg);
385             DispatchMessage(&msg);
386         }
387         diff = time - GetTickCount();
388     }
389 }
390
391 struct transition_s {
392     WORD wVk;
393     BYTE before_state;
394     BYTE optional;
395 };
396
397 typedef enum {
398     sent=0x1,
399     posted=0x2,
400     parent=0x4,
401     wparam=0x8,
402     lparam=0x10,
403     defwinproc=0x20,
404     beginpaint=0x40,
405     optional=0x80,
406     hook=0x100,
407     winevent_hook=0x200
408 } msg_flags_t;
409
410 struct message {
411     UINT message;          /* the WM_* code */
412     msg_flags_t flags;     /* message props */
413     WPARAM wParam;         /* expected value of wParam */
414     LPARAM lParam;         /* expected value of lParam */
415 };
416
417 struct sendinput_test_s {
418     WORD wVk;
419     DWORD dwFlags;
420     BOOL _todo_wine;
421     struct transition_s expected_transitions[MAXKEYEVENTS+1];
422     struct message expected_messages[MAXKEYMESSAGES+1];
423 } sendinput_test[] = {
424     /* test ALT+F */
425     /* 0 */
426     {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
427         {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}},
428     {'F', 0, 0, {{'F', 0x00}, {0}},
429         {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN},
430         {WM_SYSCHAR},
431         {WM_SYSCOMMAND}, {0}}},
432     {'F', KEYEVENTF_KEYUP, 0, {{'F', 0x80}, {0}},
433         {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
434     {VK_LMENU, KEYEVENTF_KEYUP, 0, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
435         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
436
437     /* test CTRL+O */
438     /* 4 */
439     {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
440         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
441     {'O', 0, 0, {{'O', 0x00}, {0}},
442         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
443     {'O', KEYEVENTF_KEYUP, 0, {{'O', 0x80}, {0}},
444         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
445     {VK_LCONTROL, KEYEVENTF_KEYUP, 0, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
446         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
447
448     /* test ALT+CTRL+X */
449     /* 8 */
450     {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
451         {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}},
452     {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
453         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
454     {'X', 0, 0, {{'X', 0x00}, {0}},
455         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
456     {'X', KEYEVENTF_KEYUP, 0, {{'X', 0x80}, {0}},
457         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
458     {VK_LCONTROL, KEYEVENTF_KEYUP, 0, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
459         {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}},
460     {VK_LMENU, KEYEVENTF_KEYUP, 0, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
461         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
462
463     /* test SHIFT+A */
464     /* 14 */
465     {VK_LSHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
466         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
467     {'A', 0, 0, {{'A', 0x00}, {0}},
468         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}},
469     {'A', KEYEVENTF_KEYUP, 0, {{'A', 0x80}, {0}},
470         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
471     {VK_LSHIFT, KEYEVENTF_KEYUP, 0, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
472         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
473     /* test L-SHIFT & R-SHIFT: */
474     /* RSHIFT == LSHIFT */
475     /* 18 */
476     {VK_RSHIFT, 0, 0,
477      /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
478        {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}},
479         {{WM_KEYDOWN, hook|wparam, VK_RSHIFT},
480         {WM_KEYDOWN}, {0}}},
481     {VK_RSHIFT, KEYEVENTF_KEYUP, 0,
482        {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}},
483         {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT},
484         {WM_KEYUP}, {0}}},
485
486     /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
487     /* 20 */
488     {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, 0,
489         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
490         {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED},
491         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
492     {VK_LSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
493         {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
494         {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED},
495         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
496     /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
497     /* 22 */
498     {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0,
499         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
500         {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
501         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
502     {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
503         {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
504         {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
505         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
506
507     /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
508        win2k  - sends to hook whatever we generated here
509        winXP+ - Attempts to convert key to L/R key but not always correct
510     */
511     /* SHIFT == LSHIFT */
512     /* 24 */
513     {VK_SHIFT, 0, 0,
514         {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
515         {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0},
516         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
517     {VK_SHIFT, KEYEVENTF_KEYUP, 0,
518         {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
519         {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP},
520         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
521     /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
522     /* 26 */
523     {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, 0,
524         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
525         {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED},
526         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
527     {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
528         {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
529         {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED},
530         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
531
532     /* test L-CONTROL & R-CONTROL: */
533     /* RCONTROL == LCONTROL */
534     /* 28 */
535     {VK_RCONTROL, 0, 0,
536         {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
537         {{WM_KEYDOWN, hook|wparam, VK_RCONTROL},
538         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
539     {VK_RCONTROL, KEYEVENTF_KEYUP, 0,
540         {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
541         {{WM_KEYUP, hook|wparam, VK_RCONTROL},
542         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
543     /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
544     /* 30 */
545     {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, 0,
546         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
547         {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED},
548         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
549     {VK_LCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
550         {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
551         {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED},
552         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
553     /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
554     /* 32 */
555     {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, 0,
556         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
557         {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED},
558         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
559     {VK_RCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
560         {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
561         {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED},
562         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
563     /* CONTROL == LCONTROL */
564     /* 34 */
565     {VK_CONTROL, 0, 0,
566         {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
567         {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/},
568         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
569     {VK_CONTROL, KEYEVENTF_KEYUP, 0,
570         {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
571         {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/},
572         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
573     /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
574     /* 36 */
575     {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, 0,
576         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
577         {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED},
578         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
579     {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
580         {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
581         {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED},
582         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
583
584     /* test L-MENU & R-MENU: */
585     /* RMENU == LMENU */
586     /* 38 */
587     {VK_RMENU, 0, 0,
588         {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
589         {{WM_SYSKEYDOWN, hook|wparam|optional, VK_LCONTROL},
590         {WM_SYSKEYDOWN, hook|wparam, VK_RMENU},
591         {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
592         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
593     {VK_RMENU, KEYEVENTF_KEYUP, 1,
594         {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
595         {{WM_KEYUP, hook|wparam|optional, VK_LCONTROL},
596         {WM_KEYUP, hook|wparam, VK_RMENU},
597         {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
598         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
599         {WM_SYSCOMMAND, optional}, {0}}},
600     /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
601     /* 40 */
602     {VK_LMENU, KEYEVENTF_EXTENDEDKEY, 0,
603         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
604         {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED},
605         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
606     {VK_LMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1,
607         {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}},
608         {{WM_KEYUP, hook|wparam|lparam, VK_LMENU, LLKHF_UP|LLKHF_EXTENDED},
609         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
610         {WM_SYSCOMMAND}, {0}}},
611     /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
612     /* 42 */
613     {VK_RMENU, KEYEVENTF_EXTENDEDKEY, 0,
614         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
615         {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_LCONTROL, 0},
616         {WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED},
617         {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0},
618         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
619     {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1,
620         {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
621         {{WM_KEYUP, hook|wparam|lparam|optional, VK_LCONTROL, LLKHF_UP},
622         {WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED},
623         {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP},
624         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
625         {WM_SYSCOMMAND, optional}, {0}}},
626     /* MENU == LMENU */
627     /* 44 */
628     {VK_MENU, 0, 0,
629         {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
630         {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/},
631         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
632     {VK_MENU, KEYEVENTF_KEYUP, 1,
633         {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
634         {{WM_KEYUP, hook/*|wparam, VK_MENU*/},
635         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
636         {WM_SYSCOMMAND}, {0}}},
637     /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
638     /* 46 */
639     {VK_MENU, KEYEVENTF_EXTENDEDKEY, 0,
640         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}},
641         {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_CONTROL, 0},
642         {WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED},
643         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
644     {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1,
645         {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}},
646         {{WM_KEYUP, hook|wparam|lparam|optional, VK_CONTROL, LLKHF_UP},
647         {WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED},
648         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
649         {WM_SYSCOMMAND}, {0}}},
650
651     /* test LSHIFT & RSHIFT */
652     /* 48 */
653     {VK_LSHIFT, 0, 0,
654         {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
655         {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0},
656         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
657     {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0,
658         {{VK_RSHIFT, 0x00}, {0}},
659         {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
660         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
661     {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
662         {{VK_RSHIFT, 0x80}, {0}},
663         {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
664         {WM_KEYUP, optional}, {0}}},
665     {VK_LSHIFT, KEYEVENTF_KEYUP, 0,
666         {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
667         {{WM_KEYUP, hook|wparam, VK_LSHIFT},
668         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
669
670     {0, 0, 0, {{0}}, {{0}}} /* end */
671 };
672
673 static struct message sent_messages[MAXKEYMESSAGES];
674 static UINT sent_messages_cnt;
675
676 /* Verify that only specified key state transitions occur */
677 static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_test_s *test)
678 {
679     int i, failcount = 0;
680     struct transition_s *t = test->expected_transitions;
681     UINT actual_cnt = 0;
682     const struct message *expected = test->expected_messages;
683
684     while (t->wVk) {
685         int matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80)
686                        && (ks2[t->wVk]&0x80) == (~t->before_state&0x80));
687
688         if (!matched && !t->optional && test->_todo_wine)
689         {
690             failcount++;
691             todo_wine {
692                 ok(matched, "%2d (%x/%x): %02x from %02x -> %02x "
693                    "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
694                    t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
695                    ~t->before_state&0x80);
696             }
697         } else {
698             ok(matched || t->optional, "%2d (%x/%x): %02x from %02x -> %02x "
699                "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
700                t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
701                ~t->before_state&0x80);
702         }
703         ks2[t->wVk] = ks1[t->wVk]; /* clear the match */
704         t++;
705     }
706     for (i = 0; i < 256; i++)
707         if (ks2[i] != ks1[i] && test->_todo_wine)
708         {
709             failcount++;
710             todo_wine
711                 ok(FALSE, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
712                    id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
713         }
714         else
715             ok(ks2[i] == ks1[i], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
716                id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
717
718     while (expected->message && actual_cnt < sent_messages_cnt)
719     {
720         const struct message *actual = &sent_messages[actual_cnt];
721
722         if (expected->message == actual->message)
723         {
724             if (expected->flags & wparam)
725             {
726                 if ((expected->flags & optional) && (expected->wParam != actual->wParam))
727                 {
728                     expected++;
729                     continue;
730                 }
731                 if (expected->wParam != actual->wParam && test->_todo_wine)
732                 {
733                     failcount++;
734                     todo_wine
735                         ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
736                            id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
737                 }
738                 else
739                     ok(expected->wParam == actual->wParam,
740                        "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
741                        id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
742             }
743             if (expected->flags & lparam)
744             {
745                 if (expected->lParam != actual->lParam && test->_todo_wine)
746                 {
747                     failcount++;
748                     todo_wine
749                         ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
750                            id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
751                 }
752                 else
753                     ok(expected->lParam == actual->lParam,
754                        "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
755                        id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
756             }
757             ok((expected->flags & hook) == (actual->flags & hook),
758                "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
759                id, test->wVk, test->dwFlags, expected->message);
760
761         }
762         else if (expected->flags & optional)
763         {
764             expected++;
765             continue;
766         }
767         /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */
768         else if ((expected->flags & hook) &&
769                  (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
770                  (actual->message == expected->message - 4))
771         {
772             ok((expected->flags & hook) == (actual->flags & hook),
773                "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
774                id, test->wVk, test->dwFlags, expected->message);
775         }
776         /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP
777          * instead of SYSKEYDOWN/UP to the WNDPROC */
778         else if (test->wVk == VK_RMENU && !(expected->flags & hook) &&
779                  (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) &&
780                  (actual->message == expected->message - 4))
781         {
782             ok(expected->wParam == actual->wParam && expected->lParam == actual->lParam,
783                "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
784                id, test->wVk, test->dwFlags, expected->message, actual->message);
785         }
786         else if (test->_todo_wine)
787         {
788             failcount++;
789             todo_wine
790             ok(FALSE,
791                "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
792                id, test->wVk, test->dwFlags, expected->message, actual->message);
793         }
794         else
795             ok(FALSE,
796                "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
797                id, test->wVk, test->dwFlags, expected->message, actual->message);
798
799         actual_cnt++;
800         expected++;
801     }
802     /* skip all optional trailing messages */
803     while (expected->message && (expected->flags & optional))
804         expected++;
805
806
807     if (expected->message || actual_cnt < sent_messages_cnt)
808     {
809         if (test->_todo_wine)
810         {
811             failcount++;
812             todo_wine
813                 ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
814                    id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
815         }
816         else
817             ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
818                id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
819     }
820
821     if( test->_todo_wine && !failcount) /* succeeded yet marked todo */
822         todo_wine
823             ok(TRUE, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags);
824
825     sent_messages_cnt = 0;
826 }
827
828 /* WndProc2 checks that we get at least the messages specified */
829 static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam,
830                                    LPARAM lParam)
831 {
832     if (winetest_debug > 1) trace("MSG:  %8x W:%8lx L:%8lx\n", Msg, wParam, lParam);
833
834     if (Msg != WM_PAINT &&
835         Msg != WM_NCPAINT &&
836         Msg != WM_SYNCPAINT &&
837         Msg != WM_ERASEBKGND &&
838         Msg != WM_NCHITTEST &&
839         Msg != WM_GETTEXT &&
840         Msg != WM_GETICON &&
841         Msg != WM_IME_SELECT &&
842         Msg != WM_DEVICECHANGE &&
843         Msg != WM_TIMECHANGE)
844     {
845         ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
846         if (sent_messages_cnt < MAXKEYMESSAGES)
847         {
848             sent_messages[sent_messages_cnt].message = Msg;
849             sent_messages[sent_messages_cnt].flags = 0;
850             sent_messages[sent_messages_cnt].wParam = wParam;
851             sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED);
852         }
853     }
854     return DefWindowProc(hWnd, Msg, wParam, lParam);
855 }
856
857 static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam)
858 {
859     KBDLLHOOKSTRUCT *hook_info = (KBDLLHOOKSTRUCT *)lparam;
860
861     if (code == HC_ACTION)
862     {
863         ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n");
864         if (sent_messages_cnt < MAXKEYMESSAGES)
865         {
866             sent_messages[sent_messages_cnt].message = wparam;
867             sent_messages[sent_messages_cnt].flags = hook;
868             sent_messages[sent_messages_cnt].wParam = hook_info->vkCode;
869             sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED);
870         }
871
872 if(0) /* For some reason not stable on Wine */
873 {
874         if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN)
875             ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %x should be up\n", hook_info->vkCode);
876         else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP)
877             ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %x should be down\n", hook_info->vkCode);
878 }
879
880         if (winetest_debug > 1)
881             trace("Hook:   w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam,
882                   hook_info->vkCode, hook_info->scanCode, hook_info->flags, hook_info->dwExtraInfo);
883     }
884     return CallNextHookEx( 0, code, wparam, lparam );
885 }
886 static void test_Input_blackbox(void)
887 {
888     TEST_INPUT i;
889     int ii;
890     BYTE ks1[256], ks2[256];
891     LONG_PTR prevWndProc;
892     HWND window;
893     HHOOK hook;
894
895     if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409)
896     {
897         skip("Skipping Input_blackbox test on non-US keyboard\n");
898         return;
899     }
900     window = CreateWindow("Static", NULL, WS_POPUP|WS_HSCROLL|WS_VSCROLL
901         |WS_VISIBLE, 0, 0, 200, 60, NULL, NULL,
902         NULL, NULL);
903     ok(window != NULL, "error: %d\n", (int) GetLastError());
904     SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
905     SetForegroundWindow( window );
906
907     if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0)))
908     {
909         DestroyWindow(window);
910         win_skip("WH_KEYBOARD_LL is not supported\n");
911         return;
912     }
913
914     /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets
915      * key state set by SendInput(). */
916     empty_message_queue();
917
918     prevWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, (LONG_PTR) WndProc2);
919     ok(prevWndProc != 0 || (prevWndProc == 0 && GetLastError() == 0),
920        "error: %d\n", (int) GetLastError());
921
922     i.type = INPUT_KEYBOARD;
923     i.u.ki.time = 0;
924     i.u.ki.dwExtraInfo = 0;
925
926     for (ii = 0; ii < sizeof(sendinput_test)/sizeof(struct sendinput_test_s)-1;
927          ii++) {
928         GetKeyboardState(ks1);
929         i.u.ki.wScan = ii+1 /* useful for debugging */;
930         i.u.ki.dwFlags = sendinput_test[ii].dwFlags;
931         i.u.ki.wVk = sendinput_test[ii].wVk;
932         pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT));
933         empty_message_queue();
934         GetKeyboardState(ks2);
935         if (!ii && sent_messages_cnt <= 1 && !memcmp( ks1, ks2, sizeof(ks1) ))
936         {
937             win_skip( "window doesn't receive the queued input\n" );
938             /* release the key */
939             i.u.ki.dwFlags |= KEYEVENTF_KEYUP;
940             pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT));
941             break;
942         }
943         compare_and_check(ii, ks1, ks2, &sendinput_test[ii]);
944     }
945
946     empty_message_queue();
947     DestroyWindow(window);
948     UnhookWindowsHookEx(hook);
949 }
950
951 static void reset_key_status(void)
952 {
953     key_status.last_key_down = -1;
954     key_status.last_key_up = -1;
955     key_status.last_syskey_down = -1;
956     key_status.last_syskey_up = -1;
957     key_status.last_char = -1;
958     key_status.last_syschar = -1;
959     key_status.last_hook_down = -1;
960     key_status.last_hook_up = -1;
961     key_status.last_hook_syskey_down = -1;
962     key_status.last_hook_syskey_up = -1;
963     key_status.expect_alt = FALSE;
964     key_status.sendinput_broken = FALSE;
965 }
966
967 static void test_unicode_keys(HWND hwnd, HHOOK hook)
968 {
969     TEST_INPUT inputs[2];
970     MSG msg;
971
972     /* init input data that never changes */
973     inputs[1].type = inputs[0].type = INPUT_KEYBOARD;
974     inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0;
975     inputs[1].u.ki.time = inputs[0].u.ki.time = 0;
976
977     /* pressing & releasing a single unicode character */
978     inputs[0].u.ki.wVk = 0;
979     inputs[0].u.ki.wScan = 0x3c0;
980     inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE;
981
982     reset_key_status();
983     pSendInput(1, (INPUT*)inputs, sizeof(INPUT));
984     while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
985         if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
986             TranslateMessage(&msg);
987         }
988         DispatchMessageW(&msg);
989     }
990     if(!key_status.sendinput_broken){
991         ok(key_status.last_key_down == VK_PACKET,
992             "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_down);
993         ok(key_status.last_char == 0x3c0,
994             "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status.last_char);
995         if(hook)
996             ok(key_status.last_hook_down == 0x3c0,
997                 "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_down);
998     }
999
1000     inputs[1].u.ki.wVk = 0;
1001     inputs[1].u.ki.wScan = 0x3c0;
1002     inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1003
1004     reset_key_status();
1005     pSendInput(1, (INPUT*)(inputs+1), sizeof(INPUT));
1006     while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1007         if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){
1008             TranslateMessage(&msg);
1009         }
1010         DispatchMessageW(&msg);
1011     }
1012     if(!key_status.sendinput_broken){
1013         ok(key_status.last_key_up == VK_PACKET,
1014             "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up);
1015         if(hook)
1016             ok(key_status.last_hook_up == 0x3c0,
1017                 "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_up);
1018     }
1019
1020     /* holding alt, pressing & releasing a unicode character, releasing alt */
1021     inputs[0].u.ki.wVk = VK_LMENU;
1022     inputs[0].u.ki.wScan = 0;
1023     inputs[0].u.ki.dwFlags = 0;
1024
1025     inputs[1].u.ki.wVk = 0;
1026     inputs[1].u.ki.wScan = 0x3041;
1027     inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE;
1028
1029     reset_key_status();
1030     key_status.expect_alt = TRUE;
1031     pSendInput(2, (INPUT*)inputs, sizeof(INPUT));
1032     while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1033         if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1034             TranslateMessage(&msg);
1035         }
1036         DispatchMessageW(&msg);
1037     }
1038     if(!key_status.sendinput_broken){
1039         ok(key_status.last_syskey_down == VK_PACKET,
1040             "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_syskey_down);
1041         ok(key_status.last_syschar == 0x3041,
1042             "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status.last_syschar);
1043         if(hook)
1044             ok(key_status.last_hook_syskey_down == 0x3041,
1045                 "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_syskey_down);
1046     }
1047
1048     inputs[1].u.ki.wVk = 0;
1049     inputs[1].u.ki.wScan = 0x3041;
1050     inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1051
1052     inputs[0].u.ki.wVk = VK_LMENU;
1053     inputs[0].u.ki.wScan = 0;
1054     inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
1055
1056     reset_key_status();
1057     key_status.expect_alt = TRUE;
1058     pSendInput(2, (INPUT*)inputs, sizeof(INPUT));
1059     while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){
1060         if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){
1061             TranslateMessage(&msg);
1062         }
1063         DispatchMessageW(&msg);
1064     }
1065     if(!key_status.sendinput_broken){
1066         ok(key_status.last_key_up == VK_PACKET,
1067             "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up);
1068         if(hook)
1069             ok(key_status.last_hook_up == 0x3041,
1070                 "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_up);
1071     }
1072 }
1073
1074 static LRESULT CALLBACK unicode_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam,
1075         LPARAM lParam )
1076 {
1077     switch(msg){
1078     case WM_KEYDOWN:
1079         key_status.last_key_down = wParam;
1080         break;
1081     case WM_SYSKEYDOWN:
1082         key_status.last_syskey_down = wParam;
1083         break;
1084     case WM_KEYUP:
1085         key_status.last_key_up = wParam;
1086         break;
1087     case WM_SYSKEYUP:
1088         key_status.last_syskey_up = wParam;
1089         break;
1090     case WM_CHAR:
1091         key_status.last_char = wParam;
1092         break;
1093     case WM_SYSCHAR:
1094         key_status.last_syschar = wParam;
1095         break;
1096     }
1097     return DefWindowProcW(hWnd, msg, wParam, lParam);
1098 }
1099
1100 static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lParam)
1101 {
1102     if(nCode == HC_ACTION){
1103         LPKBDLLHOOKSTRUCT info = (LPKBDLLHOOKSTRUCT)lParam;
1104         if(!info->vkCode){
1105             key_status.sendinput_broken = TRUE;
1106             win_skip("SendInput doesn't support unicode on this platform\n");
1107         }else{
1108             if(key_status.expect_alt){
1109                 ok(info->vkCode == VK_LMENU, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU, info->vkCode);
1110                 key_status.expect_alt = FALSE;
1111             }else
1112                 ok(info->vkCode == VK_PACKET, "vkCode should have been VK_PACKET[0x%04x], was: 0x%x\n", VK_PACKET, info->vkCode);
1113         }
1114         switch(wParam){
1115         case WM_KEYDOWN:
1116             key_status.last_hook_down = info->scanCode;
1117             break;
1118         case WM_KEYUP:
1119             key_status.last_hook_up = info->scanCode;
1120             break;
1121         case WM_SYSKEYDOWN:
1122             key_status.last_hook_syskey_down = info->scanCode;
1123             break;
1124         case WM_SYSKEYUP:
1125             key_status.last_hook_syskey_up = info->scanCode;
1126             break;
1127         }
1128     }
1129     return CallNextHookEx(NULL, nCode, wParam, lParam);
1130 }
1131
1132 static void test_Input_unicode(void)
1133 {
1134     WCHAR classNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1135         'K','e','y','T','e','s','t','C','l','a','s','s',0};
1136     WCHAR windowNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e',
1137         'K','e','y','T','e','s','t',0};
1138     MSG msg;
1139     WNDCLASSW wclass;
1140     HANDLE hInstance = GetModuleHandleW(NULL);
1141     HHOOK hook;
1142
1143     wclass.lpszClassName = classNameW;
1144     wclass.style         = CS_HREDRAW | CS_VREDRAW;
1145     wclass.lpfnWndProc   = unicode_wnd_proc;
1146     wclass.hInstance     = hInstance;
1147     wclass.hIcon         = LoadIcon(0, IDI_APPLICATION);
1148     wclass.hCursor       = LoadCursor( NULL, IDC_ARROW);
1149     wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1150     wclass.lpszMenuName  = 0;
1151     wclass.cbClsExtra    = 0;
1152     wclass.cbWndExtra    = 0;
1153     if(!RegisterClassW(&wclass)){
1154         win_skip("Unicode functions not supported\n");
1155         return;
1156     }
1157     /* create the test window that will receive the keystrokes */
1158     hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW,
1159                              WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100,
1160                              NULL, NULL, hInstance, NULL);
1161
1162     assert(hWndTest);
1163     assert(IsWindowUnicode(hWndTest));
1164
1165     hook = SetWindowsHookExW(WH_KEYBOARD_LL, llkbd_unicode_hook, GetModuleHandleW(NULL), 0);
1166     if(!hook)
1167         win_skip("unable to set WH_KEYBOARD_LL hook\n");
1168
1169     ShowWindow(hWndTest, SW_SHOW);
1170     SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
1171     SetForegroundWindow(hWndTest);
1172     UpdateWindow(hWndTest);
1173
1174     /* flush pending messages */
1175     while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
1176
1177     SetFocus(hWndTest);
1178
1179     test_unicode_keys(hWndTest, hook);
1180
1181     if(hook)
1182         UnhookWindowsHookEx(hook);
1183     DestroyWindow(hWndTest);
1184 }
1185
1186 static void test_keynames(void)
1187 {
1188     int i, len;
1189     char buff[256];
1190
1191     for (i = 0; i < 512; i++)
1192     {
1193         strcpy(buff, "----");
1194         len = GetKeyNameTextA(i << 16, buff, sizeof(buff));
1195         ok(len || !buff[0], "%d: Buffer is not zeroed\n", i);
1196     }
1197 }
1198
1199 static POINT pt_old, pt_new;
1200 static BOOL clipped;
1201 #define STEP 3
1202
1203 static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam )
1204 {
1205     MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1206     POINT pt, pt1;
1207
1208     if (code == HC_ACTION)
1209     {
1210         /* This is our new cursor position */
1211         pt_new = hook->pt;
1212         /* Should return previous position */
1213         GetCursorPos(&pt);
1214         ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1215
1216         /* Should set new position until hook chain is finished. */
1217         pt.x = pt_old.x + STEP;
1218         pt.y = pt_old.y + STEP;
1219         SetCursorPos(pt.x, pt.y);
1220         GetCursorPos(&pt1);
1221         if (clipped)
1222             ok(pt1.x == pt_old.x && pt1.y == pt_old.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y);
1223         else
1224             ok(pt1.x == pt.x && pt1.y == pt.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y);
1225     }
1226     return CallNextHookEx( 0, code, wparam, lparam );
1227 }
1228
1229 static LRESULT CALLBACK hook_proc2( int code, WPARAM wparam, LPARAM lparam )
1230 {
1231     MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
1232     POINT pt;
1233
1234     if (code == HC_ACTION)
1235     {
1236         ok(hook->pt.x == pt_new.x && hook->pt.y == pt_new.y,
1237            "Wrong hook coords: (%d %d) != (%d,%d)\n", hook->pt.x, hook->pt.y, pt_new.x, pt_new.y);
1238
1239         /* Should match position set above */
1240         GetCursorPos(&pt);
1241         if (clipped)
1242             ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1243         else
1244             ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%d,%d)\n", pt.x, pt.y);
1245     }
1246     return CallNextHookEx( 0, code, wparam, lparam );
1247 }
1248
1249 static void test_mouse_ll_hook(void)
1250 {
1251     HWND hwnd;
1252     HHOOK hook1, hook2;
1253     POINT pt_org, pt;
1254     RECT rc;
1255
1256     GetCursorPos(&pt_org);
1257     hwnd = CreateWindow("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1258                         10, 10, 200, 200, NULL, NULL, NULL, NULL);
1259     SetCursorPos(100, 100);
1260
1261     if (!(hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0)))
1262     {
1263         win_skip( "cannot set MOUSE_LL hook\n" );
1264         goto done;
1265     }
1266     hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0);
1267
1268     GetCursorPos(&pt_old);
1269     mouse_event(MOUSEEVENTF_MOVE, -STEP,  0, 0, 0);
1270     GetCursorPos(&pt_old);
1271     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);
1272     mouse_event(MOUSEEVENTF_MOVE, +STEP,  0, 0, 0);
1273     GetCursorPos(&pt_old);
1274     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);
1275     mouse_event(MOUSEEVENTF_MOVE,  0, -STEP, 0, 0);
1276     GetCursorPos(&pt_old);
1277     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);
1278     mouse_event(MOUSEEVENTF_MOVE,  0, +STEP, 0, 0);
1279     GetCursorPos(&pt_old);
1280     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);
1281
1282     SetRect(&rc, 50, 50, 151, 151);
1283     ClipCursor(&rc);
1284     clipped = TRUE;
1285
1286     SetCursorPos(40, 40);
1287     GetCursorPos(&pt_old);
1288     ok(pt_old.x == 50 && pt_old.y == 50, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1289     SetCursorPos(160, 160);
1290     GetCursorPos(&pt_old);
1291     ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1292     mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0);
1293     GetCursorPos(&pt_old);
1294     ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y);
1295
1296     clipped = FALSE;
1297     pt_new.x = pt_new.y = 150;
1298     ClipCursor(NULL);
1299     UnhookWindowsHookEx(hook1);
1300
1301     /* Now check that mouse buttons do not change mouse position
1302        if we don't have MOUSEEVENTF_MOVE flag specified. */
1303
1304     /* We reusing the same hook callback, so make it happy */
1305     pt_old.x = pt_new.x - STEP;
1306     pt_old.y = pt_new.y - STEP;
1307     mouse_event(MOUSEEVENTF_LEFTUP, 123, 456, 0, 0);
1308     GetCursorPos(&pt);
1309     ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1310     mouse_event(MOUSEEVENTF_RIGHTUP, 456, 123, 0, 0);
1311     GetCursorPos(&pt);
1312     ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1313
1314     mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 123, 456, 0, 0);
1315     GetCursorPos(&pt);
1316     ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1317     mouse_event(MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE, 456, 123, 0, 0);
1318     GetCursorPos(&pt);
1319     ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y);
1320
1321     UnhookWindowsHookEx(hook2);
1322 done:
1323     DestroyWindow(hwnd);
1324     SetCursorPos(pt_org.x, pt_org.y);
1325 }
1326
1327 static void test_GetMouseMovePointsEx(void)
1328 {
1329 #define BUFLIM  64
1330 #define MYERROR 0xdeadbeef
1331     int count, retval;
1332     MOUSEMOVEPOINT in;
1333     MOUSEMOVEPOINT out[200];
1334     POINT point;
1335
1336     /* Get a valid content for the input struct */
1337     if(!GetCursorPos(&point)) {
1338         skip("GetCursorPos() failed with error %u\n", GetLastError());
1339         return;
1340     }
1341     memset(&in, 0, sizeof(MOUSEMOVEPOINT));
1342     in.x = point.x;
1343     in.y = point.y;
1344
1345     /* test first parameter
1346      * everything different than sizeof(MOUSEMOVEPOINT)
1347      * is expected to fail with ERROR_INVALID_PARAMETER
1348      */
1349     SetLastError(MYERROR);
1350     retval = pGetMouseMovePointsEx(0, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1351     if (retval == ERROR_INVALID_PARAMETER)
1352     {
1353         win_skip( "GetMouseMovePointsEx broken on WinME\n" );
1354         return;
1355     }
1356     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1357     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1358        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1359
1360     SetLastError(MYERROR);
1361     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1362     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1363     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1364        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1365
1366     SetLastError(MYERROR);
1367     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1368     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1369     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1370        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1371
1372     /* test second and third parameter
1373      */
1374     SetLastError(MYERROR);
1375     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1376     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1377     ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR,
1378        "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1379
1380     SetLastError(MYERROR);
1381     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1382     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1383     ok(ERROR_NOACCESS == GetLastError(),
1384        "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1385
1386     SetLastError(MYERROR);
1387     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1388     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1389     ok(ERROR_NOACCESS == GetLastError(),
1390        "expected error ERROR_NOACCESS, got %u\n", GetLastError());
1391
1392     SetLastError(MYERROR);
1393     count = 0;
1394     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, count, GMMP_USE_DISPLAY_POINTS);
1395     if (retval == -1)
1396         ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1397     else
1398         ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1399
1400     /* test fourth parameter
1401      * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER
1402      */
1403     SetLastError(MYERROR);
1404     count = -1;
1405     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1406     ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1407     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1408        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1409
1410     SetLastError(MYERROR);
1411     count = 0;
1412     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1413     if (retval == -1)
1414         ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1415     else
1416         ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1417
1418     SetLastError(MYERROR);
1419     count = BUFLIM;
1420     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
1421     if (retval == -1)
1422         ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError());
1423     else
1424         ok((0 <= retval) && (retval <= count), "expected GetMouseMovePointsEx to succeed, got %d\n", retval);
1425
1426     SetLastError(MYERROR);
1427     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1428     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1429     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1430        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1431
1432     /* it was not possible to force an error with the fifth parameter on win2k */
1433
1434     /* test combinations of wrong parameters to see which error wins */
1435     SetLastError(MYERROR);
1436     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1437     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1438     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1439        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1440
1441     SetLastError(MYERROR);
1442     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
1443     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1444     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1445        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1446
1447     SetLastError(MYERROR);
1448     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1449     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1450     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1451        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1452
1453     SetLastError(MYERROR);
1454     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
1455     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
1456     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
1457        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1458
1459 #undef BUFLIM
1460 #undef MYERROR
1461 }
1462
1463 static void test_key_map(void)
1464 {
1465     HKL kl = GetKeyboardLayout(0);
1466     UINT kL, kR, s, sL;
1467     int i;
1468     static const UINT numpad_collisions[][2] = {
1469         { VK_NUMPAD0, VK_INSERT },
1470         { VK_NUMPAD1, VK_END },
1471         { VK_NUMPAD2, VK_DOWN },
1472         { VK_NUMPAD3, VK_NEXT },
1473         { VK_NUMPAD4, VK_LEFT },
1474         { VK_NUMPAD6, VK_RIGHT },
1475         { VK_NUMPAD7, VK_HOME },
1476         { VK_NUMPAD8, VK_UP },
1477         { VK_NUMPAD9, VK_PRIOR },
1478     };
1479
1480     s  = MapVirtualKeyEx(VK_SHIFT,  MAPVK_VK_TO_VSC, kl);
1481     ok(s != 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
1482     sL = MapVirtualKeyEx(VK_LSHIFT, MAPVK_VK_TO_VSC, kl);
1483     ok(s == sL || broken(sL == 0), /* win9x */
1484        "%x != %x\n", s, sL);
1485
1486     kL = MapVirtualKeyEx(0x2a, MAPVK_VSC_TO_VK, kl);
1487     ok(kL == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL);
1488     kR = MapVirtualKeyEx(0x36, MAPVK_VSC_TO_VK, kl);
1489     ok(kR == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR);
1490
1491     kL = MapVirtualKeyEx(0x2a, MAPVK_VSC_TO_VK_EX, kl);
1492     ok(kL == VK_LSHIFT || broken(kL == 0), /* win9x */
1493        "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL);
1494     kR = MapVirtualKeyEx(0x36, MAPVK_VSC_TO_VK_EX, kl);
1495     ok(kR == VK_RSHIFT || broken(kR == 0), /* win9x */
1496        "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR);
1497
1498     /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
1499     for (i = 0; i < sizeof(numpad_collisions)/sizeof(numpad_collisions[0]); i++)
1500     {
1501         UINT numpad_scan = MapVirtualKeyEx(numpad_collisions[i][0],  MAPVK_VK_TO_VSC, kl);
1502         UINT other_scan  = MapVirtualKeyEx(numpad_collisions[i][1],  MAPVK_VK_TO_VSC, kl);
1503
1504         /* do they really collide for this layout? */
1505         if (numpad_scan && other_scan == numpad_scan)
1506         {
1507             UINT vkey = MapVirtualKeyEx(numpad_scan, MAPVK_VSC_TO_VK, kl);
1508             ok(vkey != numpad_collisions[i][0],
1509                "Got numpad vKey %x for scan code %x when there was another choice\n",
1510                vkey, numpad_scan);
1511         }
1512     }
1513 }
1514
1515 static void test_ToUnicode(void)
1516 {
1517     WCHAR wStr[2];
1518     BYTE state[256];
1519     const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f;
1520     const BYTE HIGHEST_BIT = 0x80;
1521     int i, ret;
1522     for(i=0; i<256; i++)
1523         state[i]=0;
1524
1525     SetLastError(0xdeadbeef);
1526     ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
1527     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1528     {
1529         win_skip("ToUnicode is not implemented\n");
1530         return;
1531     }
1532
1533     ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret);
1534     if(ret == 1)
1535         ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]);
1536     state[VK_CONTROL] |= HIGHEST_BIT;
1537     state[VK_LCONTROL] |= HIGHEST_BIT;
1538
1539     ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0);
1540     ok(ret == 0, "ToUnicode for CTRL + Tab didn't return 0 (was %i)\n", ret);
1541
1542     ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
1543     ok(ret == 1, "ToUnicode for CTRL + Return didn't return 1 (was %i)\n", ret);
1544     if(ret == 1)
1545         ok(wStr[0]=='\n', "ToUnicode for CTRL + Return was %i (expected 10)\n", wStr[0]);
1546
1547     state[VK_SHIFT] |= HIGHEST_BIT;
1548     state[VK_LSHIFT] |= HIGHEST_BIT;
1549     ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0);
1550     ok(ret == 0, "ToUnicode for CTRL + SHIFT + Tab didn't return 0 (was %i)\n", ret);
1551     ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
1552     todo_wine ok(ret == 0, "ToUnicode for CTRL + SHIFT + Return didn't return 0 (was %i)\n", ret);
1553 }
1554
1555 static void test_get_async_key_state(void)
1556 {
1557     /* input value sanity checks */
1558     ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n");
1559     ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n");
1560 }
1561
1562 static void test_keyboard_layout_name(void)
1563 {
1564     BOOL ret;
1565     char klid[KL_NAMELENGTH];
1566
1567     if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) return;
1568
1569     klid[0] = 0;
1570     ret = GetKeyboardLayoutNameA(klid);
1571     ok(ret, "GetKeyboardLayoutNameA failed %u\n", GetLastError());
1572     ok(!strcmp(klid, "00000409"), "expected 00000409, got %s\n", klid);
1573 }
1574
1575 START_TEST(input)
1576 {
1577     init_function_pointers();
1578
1579     if (pSendInput)
1580     {
1581         test_Input_blackbox();
1582         test_Input_whitebox();
1583         test_Input_unicode();
1584     }
1585     else win_skip("SendInput is not available\n");
1586
1587     test_keynames();
1588     test_mouse_ll_hook();
1589     test_key_map();
1590     test_ToUnicode();
1591     test_get_async_key_state();
1592     test_keyboard_layout_name();
1593
1594     if(pGetMouseMovePointsEx)
1595         test_GetMouseMovePointsEx();
1596     else
1597         win_skip("GetMouseMovePointsEx is not available\n");
1598 }