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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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