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