1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for AttachThreadInput
5 * PROGRAMMERS: Giannis Adamopoulos
6 */
7
8 #include "precomp.h"
9
10 typedef struct {
11 DWORD tid;
12 HANDLE hThread;
13 HWND hWnd;
14 WCHAR* Desktop;
15 HANDLE StartEvent;
16 HANDLE QueueStatusEvent;
17 DWORD LastQueueStatus;
18
19 MSG_CACHE cache;
20 } THREAD_DATA;
21
22 static THREAD_DATA data[6];
23 static HHOOK hMouseHookLL = NULL;
24 static HHOOK hKbdHookLL = NULL;
25
26
27 #define EXPECT_FOREGROUND(expected) ok(GetForegroundWindow() == expected, \
28 "Expected hwnd%d at the foreground, got hwnd%d\n", \
29 get_iwnd(expected), get_iwnd(GetForegroundWindow()));
30
31 #define EXPECT_ACTIVE(expected) ok(GetActiveWindow() == expected, \
32 "Expected hwnd%d to be active, got hwnd%d\n", \
33 get_iwnd(expected), get_iwnd(GetActiveWindow()));
34
35 /*
36 * Helper functions
37 */
38
get_iwnd(HWND hWnd)39 static int get_iwnd(HWND hWnd)
40 {
41 if(hWnd == data[0].hWnd) return 0;
42 else if(hWnd == data[1].hWnd) return 1;
43 else if(hWnd == data[2].hWnd) return 2;
44 else if(hWnd == data[3].hWnd) return 3;
45 else if(hWnd == data[4].hWnd) return 4;
46 else return -1;
47 }
48
TestProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)49 LRESULT CALLBACK TestProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
50 {
51 int iwnd = get_iwnd(hWnd);
52
53 if(iwnd >= 0 && message > 0 && message < WM_APP && message != WM_TIMER)
54 record_message(&data[iwnd].cache, iwnd, message, SENT, wParam,0);
55
56 return DefWindowProc(hWnd, message, wParam, lParam);
57 }
58
FlushMessages()59 static void FlushMessages()
60 {
61 MSG msg;
62 LRESULT res;
63
64 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
65 {
66 int iwnd = get_iwnd(msg.hwnd);
67 if( iwnd >= 0 && msg.message > 0 && msg.message < WM_APP && msg.message != WM_TIMER)
68 record_message(&data[0].cache, iwnd, msg.message, POST, msg.wParam,0);
69 DispatchMessageA( &msg );
70 }
71
72 /* Use SendMessage to sync with the other queues */
73 res = SendMessageTimeout(data[1].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
74 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
75 res = SendMessageTimeout(data[2].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
76 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
77 res = SendMessageTimeout(data[3].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
78 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
79 res = SendMessageTimeout(data[4].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
80 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
81 }
82
thread_proc(void * param)83 static DWORD WINAPI thread_proc(void *param)
84 {
85 THREAD_DATA* current_data = (THREAD_DATA*)param;
86 MSG msg;
87 HDESK hdesk = NULL;
88 int iwnd;
89
90 if(current_data->Desktop)
91 {
92 hdesk = CreateDesktopW(current_data->Desktop, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
93 SetThreadDesktop(hdesk);
94 }
95
96 /* create test window */
97 current_data->hWnd = CreateWindowW(L"TestClass", L"test", WS_OVERLAPPEDWINDOW,
98 100, 100, 500, 500, NULL, NULL, 0, NULL);
99 SetEvent( current_data->StartEvent );
100
101 iwnd = get_iwnd(current_data->hWnd);
102
103 /* Use MsgWaitForMultipleObjects to let the thread process apcs */
104 while( GetMessage(&msg, 0,0,0) )
105 {
106 if(msg.message > 0 && msg.message < WM_APP && msg.message != WM_TIMER )
107 record_message(&data[iwnd].cache, iwnd, msg.message, POST, msg.wParam,0);
108 DispatchMessage(&msg);
109 }
110
111 if(hdesk)
112 CloseDesktop(hdesk);
113
114 return 0;
115 }
116
CreateTestThread(int i,WCHAR * Desktop)117 BOOL CreateTestThread(int i, WCHAR* Desktop)
118 {
119 DWORD ret;
120
121 data[i].StartEvent = CreateEventW(NULL, 0, 0, NULL);
122 data[i].Desktop = Desktop;
123 data[i].hThread = CreateThread(NULL, 0, thread_proc, &data[i], 0, &data[i].tid);
124 if(!data[i].hThread) goto fail;
125 ret = WaitForSingleObject(data[i].StartEvent, 1000);
126 CloseHandle(data[i].StartEvent);
127 if(ret == WAIT_TIMEOUT)
128 {
129 fail:
130 win_skip("child thread failed to initialize\n");
131 return FALSE;
132 }
133 return TRUE;
134 }
135
MouseLLHookProc(int nCode,WPARAM wParam,LPARAM lParam)136 static LRESULT CALLBACK MouseLLHookProc(int nCode, WPARAM wParam, LPARAM lParam)
137 {
138 LRESULT ret;
139 MSLLHOOKSTRUCT* params = (MSLLHOOKSTRUCT*) lParam;
140
141 ret = CallNextHookEx(hMouseHookLL, nCode, wParam, lParam);
142
143 if((params->flags & LLKHF_INJECTED) == 0)
144 return TRUE;
145
146 return ret;
147 }
148
KbdLLHookProc(int nCode,WPARAM wParam,LPARAM lParam)149 LRESULT CALLBACK KbdLLHookProc(int nCode, WPARAM wParam, LPARAM lParam)
150 {
151 LRESULT ret;
152 KBDLLHOOKSTRUCT* params = (KBDLLHOOKSTRUCT*) lParam;
153
154 ret = CallNextHookEx(hMouseHookLL, nCode, wParam, lParam);
155
156 if((params->flags & LLKHF_INJECTED) == 0)
157 return TRUE;
158
159 return ret;
160 }
161
InitThreads()162 BOOLEAN InitThreads()
163 {
164 /* Create a LL hook that drops any physical keyboard and mouse action
165 and prevent the user from interfering with the test results */
166 if(!IsDebuggerPresent())
167 {
168 hMouseHookLL = SetWindowsHookExW(WH_MOUSE_LL, MouseLLHookProc, GetModuleHandleW( NULL ), 0);
169 ok(hMouseHookLL!=NULL,"failed to set hook\n");
170 hKbdHookLL = SetWindowsHookExW(WH_KEYBOARD_LL, KbdLLHookProc, GetModuleHandleW( NULL ), 0);
171 ok(hKbdHookLL!=NULL,"failed to set hook\n");
172 }
173
174 /* create test clases */
175 RegisterSimpleClass(TestProc, L"TestClass");
176
177 memset(&data[0], 0, sizeof(data[0]));
178
179 data[0].tid = GetCurrentThreadId();
180
181 /* create test window */
182 data[0].hWnd = CreateWindowW(L"TestClass", L"test", WS_OVERLAPPEDWINDOW,
183 100, 100, 500, 500, NULL, NULL, 0, NULL);
184 if(!data[0].hWnd)
185 {
186 win_skip("CreateWindowW failed\n");
187 return FALSE;
188 }
189
190 /* create thread1(same desktop) */
191 if(!CreateTestThread(1, NULL)) return FALSE;
192
193 /* create thread2(same desktop) */
194 if(!CreateTestThread(2, NULL)) return FALSE;
195
196 /* create thread3(different desktop) */
197 if(!CreateTestThread(3, L"ThreadTestDesktop")) return FALSE;
198
199 /* create thread4(different desktop) */
200 if(!CreateTestThread(4, L"ThreadTestDesktop")) return FALSE;
201
202 return TRUE;
203 }
204
cleanup_attachments()205 static void cleanup_attachments()
206 {
207 int i,j;
208 BOOL ret;
209
210 for(i = 0; i< 4; i++)
211 {
212 for(j = 0; j< 4; j++)
213 {
214 ret = AttachThreadInput(data[i].tid,data[j].tid, FALSE);
215 ok(ret==0, "expected AttachThreadInput to fail\n");
216 }
217 }
218 }
219
220
221
222
223 /*
224 * The actual tests
225 */
226
Test_SimpleParameters()227 void Test_SimpleParameters()
228 {
229 BOOL ret;
230 /* FIXME: acording to msdn xp doesn't set last error but vista+ does*/
231
232 /* test wrong thread */
233 ret = AttachThreadInput( 0, 1, TRUE);
234 ok(ret==0, "expected AttachThreadInput to fail\n");
235
236 /* test same thread */
237 ret = AttachThreadInput( data[1].tid, data[1].tid, TRUE);
238 ok(ret==0, "expected AttachThreadInput to fail\n");
239
240 /* try to attach to a thread on another desktop*/
241 ret = AttachThreadInput( data[2].tid,data[3].tid, TRUE);
242 ok(ret==0, "expected AttachThreadInput to fail\n");
243 if(ret == 1 )
244 AttachThreadInput( data[2].tid,data[3].tid, FALSE);
245
246 /* test other desktop to this */
247 ret = AttachThreadInput( data[3].tid,data[2].tid, TRUE);
248 ok(ret==0, "expected AttachThreadInput to fail\n");
249 if(ret == 1 )
250 AttachThreadInput( data[3].tid,data[2].tid, FALSE);
251
252 /* attach two threads that are both in ThreadTestDesktop */
253 {
254 /* Attach thread 3 and 4 */
255 ret = AttachThreadInput( data[3].tid,data[4].tid, TRUE);
256 ok(ret==1, "expected AttachThreadInput to succeed\n");
257
258 /* cleanup previous attachment */
259 ret = AttachThreadInput( data[3].tid,data[4].tid, FALSE);
260 ok(ret==1, "expected AttachThreadInput to succeed\n");
261 }
262
263 {
264 /* Attach thread 1 and 2 */
265 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE);
266 ok(ret==1, "expected AttachThreadInput to succeed\n");
267
268 /* attach already attached*/
269 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE);
270 ok(ret==1, "expected AttachThreadInput to succeed\n");
271
272 /* attach in the opposite order */
273 ret = AttachThreadInput( data[2].tid,data[1].tid, TRUE);
274 ok(ret==1, "expected AttachThreadInput to succeed\n");
275
276 /* Now try to detach 0 from 1 */
277 ret = AttachThreadInput( data[0].tid,data[1].tid, FALSE);
278 ok(ret==0, "expected AttachThreadInput to fail\n");
279
280 /* also try to detach 3 from 2 */
281 ret = AttachThreadInput( data[3].tid,data[2].tid, FALSE);
282 ok(ret==0, "expected AttachThreadInput to fail\n");
283
284 /* cleanup previous attachment */
285 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE);
286 ok(ret==1, "expected AttachThreadInput to succeed\n");
287
288 ret = AttachThreadInput( data[2].tid,data[1].tid, FALSE);
289 ok(ret==1, "expected AttachThreadInput to succeed\n");
290
291 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE);
292 ok(ret==1, "expected AttachThreadInput to succeed\n");
293 }
294
295 /* test triple attach */
296 {
297 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
298 ok(ret==1, "expected AttachThreadInput to succeed\n");
299 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
300 ok(ret==1, "expected AttachThreadInput to succeed\n");
301
302 /* try to detach 2 and 0 */
303 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE);
304 ok(ret==0, "expected AttachThreadInput to fail\n");
305 ret = AttachThreadInput( data[2].tid, data[0].tid, FALSE);
306 ok(ret==0, "expected AttachThreadInput to fail\n");
307
308 /* try to to attach 0 to 2. it works! */
309 ret = AttachThreadInput( data[0].tid, data[2].tid, TRUE);
310 ok(ret==1, "expected AttachThreadInput to succeed\n");
311
312 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE);
313 ok(ret==1, "expected AttachThreadInput to succeed\n");
314
315 /* detach in inverse order */
316 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE);
317 ok(ret==1, "expected AttachThreadInput to succeed\n");
318 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE);
319 ok(ret==1, "expected AttachThreadInput to succeed\n");
320 }
321
322 /* test detaching in thread cleanup */
323 {
324 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
325 ok(ret==1, "expected AttachThreadInput to succeed\n");
326 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
327 ok(ret==1, "expected AttachThreadInput to succeed\n");
328 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
329 ok(ret==1, "expected AttachThreadInput to succeed\n");
330 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
331 ok(ret==1, "expected AttachThreadInput to succeed\n");
332
333 TerminateThread(data[1].hThread, 0);
334
335 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE);
336 ok(ret==0, "expected AttachThreadInput to fail\n");
337 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE);
338 ok(ret==0, "expected AttachThreadInput to fail\n");
339
340 /* Create Thread1 again */
341 CreateTestThread(1, NULL);
342 }
343
344 }
345
Test_Focus()346 void Test_Focus() //Focus Active Capture Foreground Capture
347 {
348 BOOL ret;
349
350 trace("Thread hWnd0 0x%p hWnd1 0x%p\n",data[0].hWnd, data[1].hWnd);
351 /* Window 1 is in the foreground */
352 SetForegroundWindow(data[1].hWnd);
353 SetActiveWindow(data[0].hWnd);
354 FlushMessages();
355
356 EXPECT_FOREGROUND(data[1].hWnd);
357 EXPECT_ACTIVE(data[0].hWnd);
358
359 /* attach thread 0 to 1 */
360 {
361 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
362 ok(ret==1, "expected AttachThreadInput to succeed\n");
363 FlushMessages();
364
365 EXPECT_FOREGROUND(data[1].hWnd);
366 EXPECT_ACTIVE(data[1].hWnd);
367
368 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
369 ok(ret==1, "expected AttachThreadInput to succeed\n");
370 }
371
372 EXPECT_FOREGROUND(data[1].hWnd);
373 EXPECT_ACTIVE(0);
374
375 SetForegroundWindow(data[1].hWnd);
376 SetActiveWindow(data[0].hWnd);
377 FlushMessages();
378
379 EXPECT_FOREGROUND(data[1].hWnd);
380 EXPECT_ACTIVE(data[0].hWnd);
381
382 /* attach thread 1 to 0 */
383 {
384 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
385 ok(ret==1, "expected AttachThreadInput to succeed\n");
386 FlushMessages();
387
388 EXPECT_FOREGROUND(data[1].hWnd);
389 EXPECT_ACTIVE(data[1].hWnd);
390
391 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
392 ok(ret==1, "expected AttachThreadInput to succeed\n");
393 }
394
395 /* Window 0 is in the foreground */
396 SetForegroundWindow(data[0].hWnd);
397 SetActiveWindow(data[1].hWnd);
398 FlushMessages();
399
400 EXPECT_FOREGROUND(data[0].hWnd);
401 EXPECT_ACTIVE(data[0].hWnd);
402
403 /* attach thread 0 to 1 */
404 {
405 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
406 ok(ret==1, "expected AttachThreadInput to succeed\n");
407 FlushMessages();
408
409 EXPECT_FOREGROUND(data[0].hWnd);
410 EXPECT_ACTIVE(data[0].hWnd);
411
412 SetForegroundWindow(data[0].hWnd);
413 SetActiveWindow(data[1].hWnd);
414 FlushMessages();
415
416 EXPECT_FOREGROUND(data[1].hWnd);
417 EXPECT_ACTIVE(data[1].hWnd);
418
419 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
420 ok(ret==1, "expected AttachThreadInput to succeed\n");
421 }
422
423 EXPECT_FOREGROUND(data[1].hWnd);
424 EXPECT_ACTIVE(0);
425
426 SetForegroundWindow(data[0].hWnd);
427 SetActiveWindow(data[1].hWnd);
428 FlushMessages();
429
430 EXPECT_FOREGROUND(data[0].hWnd);
431 EXPECT_ACTIVE(data[0].hWnd);
432
433 /* attach thread 1 to 0 */
434 {
435 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
436 ok(ret==1, "expected AttachThreadInput to succeed\n");
437 FlushMessages();
438
439 EXPECT_FOREGROUND(data[0].hWnd);
440 EXPECT_ACTIVE(data[0].hWnd);
441
442 SetForegroundWindow(data[0].hWnd);
443 SetActiveWindow(data[1].hWnd);
444 FlushMessages();
445
446 EXPECT_FOREGROUND(data[1].hWnd);
447 EXPECT_ACTIVE(data[1].hWnd);
448
449 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
450 ok(ret==1, "expected AttachThreadInput to succeed\n");
451 }
452 }
453
454 /* test some functions like PostMessage and SendMessage that shouldn't be affected */
Test_UnaffectedMessages()455 void Test_UnaffectedMessages()
456 {
457 BOOL ret;
458 LRESULT res;
459
460 EMPTY_CACHE_(&data[0].cache);
461 EMPTY_CACHE_(&data[1].cache);
462
463 /* test that messages posted before and after attachment are unaffected
464 and that we don't receive a meassage from a window we shouldn't */
465 PostMessage(data[0].hWnd, WM_USER, 0,0);
466 PostMessage(data[1].hWnd, WM_USER, 1,0);
467
468 {
469 MSG_ENTRY Thread0_chain[]={
470 {0,WM_USER, POST, 0, 0},
471 {0,WM_USER, POST, 2, 0},
472 {0,0}};
473 MSG_ENTRY Thread1_chain[]={
474 {1,WM_USER, POST, 1, 0},
475 {1,WM_USER, POST, 3, 0},
476 {0,0}};
477
478 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
479 ok(ret==1, "expected AttachThreadInput to succeed\n");
480
481 PostMessage(data[0].hWnd, WM_USER, 2,0);
482 PostMessage(data[1].hWnd, WM_USER, 3,0);
483
484 FlushMessages();
485 Sleep(100);
486
487 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
488 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
489
490 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
491 ok(ret==1, "expected AttachThreadInput to succeed\n");
492 }
493
494 /* test messages send to the wrong thread */
495 res = SendMessageTimeout(data[0].hWnd, WM_USER, 0,0, SMTO_NORMAL, 1000, NULL);
496 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
497 res = SendMessageTimeout(data[1].hWnd, WM_USER, 1,0, SMTO_NORMAL, 1000, NULL);
498 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
499
500 {
501 MSG_ENTRY Thread0_chain[]={
502 {0,WM_USER, SENT, 0, 0},
503 {0,WM_USER, SENT, 2, 0},
504 {0,0}};
505 MSG_ENTRY Thread1_chain[]={
506 {1,WM_USER, SENT, 1, 0},
507 {1,WM_USER, SENT, 3, 0},
508 {1,WM_MOUSEMOVE, SENT, 0, 0},
509 {0,0}};
510
511 ret = AttachThreadInput( data[2].tid, data[1].tid , TRUE);
512 ok(ret==1, "expected AttachThreadInput to succeed\n");
513
514 res = SendMessageTimeout(data[0].hWnd, WM_USER, 2,0, SMTO_NORMAL, 1000, NULL);
515 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
516 res = SendMessageTimeout(data[1].hWnd, WM_USER, 3,0, SMTO_NORMAL, 1000, NULL);
517 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
518
519 /* Try to send a fake input message */
520 res = SendMessageTimeout(data[1].hWnd, WM_MOUSEMOVE, 0,0, SMTO_NORMAL, 1000, NULL);
521 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
522
523 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
524 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
525
526 ret = AttachThreadInput( data[2].tid, data[1].tid , FALSE);
527 ok(ret==1, "expected AttachThreadInput to succeed\n");
528 }
529
530 /* todo: test keyboard layout that shouldn't be affected */
531 }
532
Test_SendInput()533 void Test_SendInput()
534 {
535 MSG_ENTRY Thread1_chain[]={
536 {1,WM_KEYDOWN, POST, VK_SHIFT, 0},
537 {1,WM_KEYUP, POST, VK_SHIFT, 0},
538 {0,0}};
539 MSG_ENTRY Thread0_chain[]={
540 {0,WM_KEYDOWN, POST, VK_SHIFT, 0},
541 {0,WM_KEYUP, POST, VK_SHIFT, 0},
542 {0,0}};
543
544 BOOL ret;
545
546 //trace("Thread hWnd0 0x%p hWnd1 0x%p\n",data[0].hWnd, data[1].hWnd);
547
548 /* First try sending input without attaching. It will go to the foreground */
549 {
550 SetForegroundWindow(data[1].hWnd);
551 SetActiveWindow(data[0].hWnd);
552
553 ok(GetForegroundWindow() == data[1].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow());
554 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow());
555
556 FlushMessages();
557 EMPTY_CACHE_(&data[0].cache);
558 EMPTY_CACHE_(&data[1].cache);
559
560 keybd_event(VK_SHIFT, 0,0,0);
561 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
562 Sleep(100);
563 FlushMessages();
564
565 COMPARE_CACHE_(&data[0].cache, empty_chain);
566 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
567 }
568
569 /* Next attach and send input. It will go to the same thread as before */
570 { // from to
571 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
572 ok(ret==1, "expected AttachThreadInput to succeed\n");
573
574 FlushMessages();
575 EMPTY_CACHE_(&data[0].cache);
576 EMPTY_CACHE_(&data[1].cache);
577
578 keybd_event(VK_SHIFT, 0,0,0);
579 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
580 Sleep(100);
581 FlushMessages();
582
583 COMPARE_CACHE_(&data[0].cache, empty_chain);
584 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
585 }
586
587 /* Now set foreground and active again. Input will go to thread 0 */
588 {
589 SetForegroundWindow(data[1].hWnd);
590 SetActiveWindow(data[0].hWnd);
591 FlushMessages();
592
593 ok(GetForegroundWindow() == data[0].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow());
594 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow());
595
596 EMPTY_CACHE_(&data[0].cache);
597 EMPTY_CACHE_(&data[1].cache);
598
599 keybd_event(VK_SHIFT, 0,0,0);
600 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
601 Sleep(100);
602 FlushMessages();
603
604 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
605 COMPARE_CACHE_(&data[1].cache, empty_chain);
606
607 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
608 ok(ret==1, "expected AttachThreadInput to succeed\n");
609 }
610
611 /* Attach in the opposite order and send input */
612 {
613 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
614 ok(ret==1, "expected AttachThreadInput to succeed\n");
615
616 FlushMessages();
617 EMPTY_CACHE_(&data[0].cache);
618 EMPTY_CACHE_(&data[1].cache);
619
620 keybd_event(VK_SHIFT, 0,0,0);
621 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
622 Sleep(100);
623 FlushMessages();
624
625 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
626 COMPARE_CACHE_(&data[1].cache, empty_chain);
627 }
628
629 /* Now set foreground and active again. Input will go to thread 0 */
630 {
631 SetForegroundWindow(data[1].hWnd);
632 SetActiveWindow(data[0].hWnd);
633 FlushMessages();
634
635 ok(GetForegroundWindow() == data[0].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow());
636 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow());
637
638 EMPTY_CACHE_(&data[0].cache);
639 EMPTY_CACHE_(&data[1].cache);
640
641 keybd_event(VK_SHIFT, 0,0,0);
642 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
643 Sleep(100);
644 FlushMessages();
645
646 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
647 COMPARE_CACHE_(&data[1].cache, empty_chain);
648
649 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
650 ok(ret==1, "expected AttachThreadInput to succeed\n");
651 }
652 }
653
START_TEST(AttachThreadInput)654 START_TEST(AttachThreadInput)
655 {
656 if(!InitThreads())
657 return;
658
659 Test_SimpleParameters();
660 cleanup_attachments();
661 Test_Focus();
662 cleanup_attachments();
663 Test_UnaffectedMessages();
664 cleanup_attachments();
665 Test_SendInput();
666 cleanup_attachments();
667
668 if(hMouseHookLL)
669 UnhookWindowsHookEx(hMouseHookLL);
670 if(hKbdHookLL)
671 UnhookWindowsHookEx(hKbdHookLL);
672
673 /* Stop all threads and exit gratefully */
674 PostThreadMessage(data[1].tid, WM_QUIT,0,0);
675 PostThreadMessage(data[2].tid, WM_QUIT,0,0);
676 PostThreadMessage(data[3].tid, WM_QUIT,0,0);
677 PostThreadMessage(data[4].tid, WM_QUIT,0,0);
678 }
679
680