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