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 /* ugly ros hack to bypass desktop crapiness */ 197 if(!CreateTestThread(6, L"ThreadTestDesktop")) return FALSE; 198 199 /* create thread3(different desktop) */ 200 if(!CreateTestThread(3, L"ThreadTestDesktop")) return FALSE; 201 202 /* create thread4(different desktop) */ 203 if(!CreateTestThread(4, L"ThreadTestDesktop")) return FALSE; 204 205 return TRUE; 206 } 207 208 static void cleanup_attachments() 209 { 210 int i,j; 211 BOOL ret; 212 213 for(i = 0; i< 4; i++) 214 { 215 for(j = 0; j< 4; j++) 216 { 217 ret = AttachThreadInput(data[i].tid,data[j].tid, FALSE); 218 ok(ret==0, "expected AttachThreadInput to fail\n"); 219 } 220 } 221 } 222 223 224 225 226 /* 227 * The actual tests 228 */ 229 230 void Test_SimpleParameters() 231 { 232 BOOL ret; 233 /* FIXME: acording to msdn xp doesn't set last error but vista+ does*/ 234 235 /* test wrong thread */ 236 ret = AttachThreadInput( 0, 1, TRUE); 237 ok(ret==0, "expected AttachThreadInput to fail\n"); 238 239 /* test same thread */ 240 ret = AttachThreadInput( data[1].tid, data[1].tid, TRUE); 241 ok(ret==0, "expected AttachThreadInput to fail\n"); 242 243 /* try to attach to a thread on another desktop*/ 244 ret = AttachThreadInput( data[2].tid,data[3].tid, TRUE); 245 ok(ret==0, "expected AttachThreadInput to fail\n"); 246 if(ret == 1 ) 247 AttachThreadInput( data[2].tid,data[3].tid, FALSE); 248 249 /* test other desktop to this */ 250 ret = AttachThreadInput( data[3].tid,data[2].tid, TRUE); 251 ok(ret==0, "expected AttachThreadInput to fail\n"); 252 if(ret == 1 ) 253 AttachThreadInput( data[3].tid,data[2].tid, FALSE); 254 255 /* attach two threads that are both in ThreadTestDesktop */ 256 { 257 /* Attach thread 3 and 4 */ 258 ret = AttachThreadInput( data[3].tid,data[4].tid, TRUE); 259 ok(ret==1, "expected AttachThreadInput to succeed\n"); 260 261 /* cleanup previous attachment */ 262 ret = AttachThreadInput( data[3].tid,data[4].tid, FALSE); 263 ok(ret==1, "expected AttachThreadInput to succeed\n"); 264 } 265 266 { 267 /* Attach thread 1 and 2 */ 268 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE); 269 ok(ret==1, "expected AttachThreadInput to succeed\n"); 270 271 /* attach already attached*/ 272 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE); 273 ok(ret==1, "expected AttachThreadInput to succeed\n"); 274 275 /* attach in the opposite order */ 276 ret = AttachThreadInput( data[2].tid,data[1].tid, TRUE); 277 ok(ret==1, "expected AttachThreadInput to succeed\n"); 278 279 /* Now try to detach 0 from 1 */ 280 ret = AttachThreadInput( data[0].tid,data[1].tid, FALSE); 281 ok(ret==0, "expected AttachThreadInput to fail\n"); 282 283 /* also try to detach 3 from 2 */ 284 ret = AttachThreadInput( data[3].tid,data[2].tid, FALSE); 285 ok(ret==0, "expected AttachThreadInput to fail\n"); 286 287 /* cleanup previous attachment */ 288 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE); 289 ok(ret==1, "expected AttachThreadInput to succeed\n"); 290 291 ret = AttachThreadInput( data[2].tid,data[1].tid, FALSE); 292 ok(ret==1, "expected AttachThreadInput to succeed\n"); 293 294 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE); 295 ok(ret==1, "expected AttachThreadInput to succeed\n"); 296 } 297 298 /* test triple attach */ 299 { 300 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE); 301 ok(ret==1, "expected AttachThreadInput to succeed\n"); 302 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE); 303 ok(ret==1, "expected AttachThreadInput to succeed\n"); 304 305 /* try to detach 2 and 0 */ 306 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE); 307 ok(ret==0, "expected AttachThreadInput to fail\n"); 308 ret = AttachThreadInput( data[2].tid, data[0].tid, FALSE); 309 ok(ret==0, "expected AttachThreadInput to fail\n"); 310 311 /* try to to attach 0 to 2. it works! */ 312 ret = AttachThreadInput( data[0].tid, data[2].tid, TRUE); 313 ok(ret==1, "expected AttachThreadInput to succeed\n"); 314 315 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE); 316 ok(ret==1, "expected AttachThreadInput to succeed\n"); 317 318 /* detach in inverse order */ 319 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE); 320 ok(ret==1, "expected AttachThreadInput to succeed\n"); 321 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE); 322 ok(ret==1, "expected AttachThreadInput to succeed\n"); 323 } 324 325 /* test detaching in thread cleanup */ 326 { 327 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE); 328 ok(ret==1, "expected AttachThreadInput to succeed\n"); 329 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE); 330 ok(ret==1, "expected AttachThreadInput to succeed\n"); 331 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE); 332 ok(ret==1, "expected AttachThreadInput to succeed\n"); 333 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE); 334 ok(ret==1, "expected AttachThreadInput to succeed\n"); 335 336 TerminateThread(data[1].hThread, 0); 337 338 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE); 339 ok(ret==0, "expected AttachThreadInput to fail\n"); 340 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE); 341 ok(ret==0, "expected AttachThreadInput to fail\n"); 342 343 /* Create Thread1 again */ 344 CreateTestThread(1, NULL); 345 } 346 347 } 348 349 void Test_Focus() //Focus Active Capture Foreground Capture 350 { 351 BOOL ret; 352 353 trace("Thread hWnd0 0x%p hWnd1 0x%p\n",data[0].hWnd, data[1].hWnd); 354 /* Window 1 is in the foreground */ 355 SetForegroundWindow(data[1].hWnd); 356 SetActiveWindow(data[0].hWnd); 357 FlushMessages(); 358 359 EXPECT_FOREGROUND(data[1].hWnd); 360 EXPECT_ACTIVE(data[0].hWnd); 361 362 /* attach thread 0 to 1 */ 363 { 364 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE); 365 ok(ret==1, "expected AttachThreadInput to succeed\n"); 366 FlushMessages(); 367 368 EXPECT_FOREGROUND(data[1].hWnd); 369 EXPECT_ACTIVE(data[1].hWnd); 370 371 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE); 372 ok(ret==1, "expected AttachThreadInput to succeed\n"); 373 } 374 375 EXPECT_FOREGROUND(data[1].hWnd); 376 EXPECT_ACTIVE(0); 377 378 SetForegroundWindow(data[1].hWnd); 379 SetActiveWindow(data[0].hWnd); 380 FlushMessages(); 381 382 EXPECT_FOREGROUND(data[1].hWnd); 383 EXPECT_ACTIVE(data[0].hWnd); 384 385 /* attach thread 1 to 0 */ 386 { 387 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE); 388 ok(ret==1, "expected AttachThreadInput to succeed\n"); 389 FlushMessages(); 390 391 EXPECT_FOREGROUND(data[1].hWnd); 392 EXPECT_ACTIVE(data[1].hWnd); 393 394 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE); 395 ok(ret==1, "expected AttachThreadInput to succeed\n"); 396 } 397 398 /* Window 0 is in the foreground */ 399 SetForegroundWindow(data[0].hWnd); 400 SetActiveWindow(data[1].hWnd); 401 FlushMessages(); 402 403 EXPECT_FOREGROUND(data[0].hWnd); 404 EXPECT_ACTIVE(data[0].hWnd); 405 406 /* attach thread 0 to 1 */ 407 { 408 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE); 409 ok(ret==1, "expected AttachThreadInput to succeed\n"); 410 FlushMessages(); 411 412 EXPECT_FOREGROUND(data[0].hWnd); 413 EXPECT_ACTIVE(data[0].hWnd); 414 415 SetForegroundWindow(data[0].hWnd); 416 SetActiveWindow(data[1].hWnd); 417 FlushMessages(); 418 419 EXPECT_FOREGROUND(data[1].hWnd); 420 EXPECT_ACTIVE(data[1].hWnd); 421 422 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE); 423 ok(ret==1, "expected AttachThreadInput to succeed\n"); 424 } 425 426 EXPECT_FOREGROUND(data[1].hWnd); 427 EXPECT_ACTIVE(0); 428 429 SetForegroundWindow(data[0].hWnd); 430 SetActiveWindow(data[1].hWnd); 431 FlushMessages(); 432 433 EXPECT_FOREGROUND(data[0].hWnd); 434 EXPECT_ACTIVE(data[0].hWnd); 435 436 /* attach thread 1 to 0 */ 437 { 438 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE); 439 ok(ret==1, "expected AttachThreadInput to succeed\n"); 440 FlushMessages(); 441 442 EXPECT_FOREGROUND(data[0].hWnd); 443 EXPECT_ACTIVE(data[0].hWnd); 444 445 SetForegroundWindow(data[0].hWnd); 446 SetActiveWindow(data[1].hWnd); 447 FlushMessages(); 448 449 EXPECT_FOREGROUND(data[1].hWnd); 450 EXPECT_ACTIVE(data[1].hWnd); 451 452 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE); 453 ok(ret==1, "expected AttachThreadInput to succeed\n"); 454 } 455 } 456 457 /* test some functions like PostMessage and SendMessage that shouldn't be affected */ 458 void Test_UnaffectedMessages() 459 { 460 BOOL ret; 461 LRESULT res; 462 463 EMPTY_CACHE_(&data[0].cache); 464 EMPTY_CACHE_(&data[1].cache); 465 466 /* test that messages posted before and after attachment are unaffected 467 and that we don't receive a meassage from a window we shouldn't */ 468 PostMessage(data[0].hWnd, WM_USER, 0,0); 469 PostMessage(data[1].hWnd, WM_USER, 1,0); 470 471 { 472 MSG_ENTRY Thread0_chain[]={ 473 {0,WM_USER, POST, 0, 0}, 474 {0,WM_USER, POST, 2, 0}, 475 {0,0}}; 476 MSG_ENTRY Thread1_chain[]={ 477 {1,WM_USER, POST, 1, 0}, 478 {1,WM_USER, POST, 3, 0}, 479 {0,0}}; 480 481 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE); 482 ok(ret==1, "expected AttachThreadInput to succeed\n"); 483 484 PostMessage(data[0].hWnd, WM_USER, 2,0); 485 PostMessage(data[1].hWnd, WM_USER, 3,0); 486 487 FlushMessages(); 488 Sleep(100); 489 490 COMPARE_CACHE_(&data[0].cache, Thread0_chain); 491 COMPARE_CACHE_(&data[1].cache, Thread1_chain); 492 493 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE); 494 ok(ret==1, "expected AttachThreadInput to succeed\n"); 495 } 496 497 /* test messages send to the wrong thread */ 498 res = SendMessageTimeout(data[0].hWnd, WM_USER, 0,0, SMTO_NORMAL, 1000, NULL); 499 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n"); 500 res = SendMessageTimeout(data[1].hWnd, WM_USER, 1,0, SMTO_NORMAL, 1000, NULL); 501 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n"); 502 503 { 504 MSG_ENTRY Thread0_chain[]={ 505 {0,WM_USER, SENT, 0, 0}, 506 {0,WM_USER, SENT, 2, 0}, 507 {0,0}}; 508 MSG_ENTRY Thread1_chain[]={ 509 {1,WM_USER, SENT, 1, 0}, 510 {1,WM_USER, SENT, 3, 0}, 511 {1,WM_MOUSEMOVE, SENT, 0, 0}, 512 {0,0}}; 513 514 ret = AttachThreadInput( data[2].tid, data[1].tid , TRUE); 515 ok(ret==1, "expected AttachThreadInput to succeed\n"); 516 517 res = SendMessageTimeout(data[0].hWnd, WM_USER, 2,0, SMTO_NORMAL, 1000, NULL); 518 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n"); 519 res = SendMessageTimeout(data[1].hWnd, WM_USER, 3,0, SMTO_NORMAL, 1000, NULL); 520 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n"); 521 522 /* Try to send a fake input message */ 523 res = SendMessageTimeout(data[1].hWnd, WM_MOUSEMOVE, 0,0, SMTO_NORMAL, 1000, NULL); 524 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n"); 525 526 COMPARE_CACHE_(&data[0].cache, Thread0_chain); 527 COMPARE_CACHE_(&data[1].cache, Thread1_chain); 528 529 ret = AttachThreadInput( data[2].tid, data[1].tid , FALSE); 530 ok(ret==1, "expected AttachThreadInput to succeed\n"); 531 } 532 533 /* todo: test keyboard layout that shouldn't be affected */ 534 } 535 536 void Test_SendInput() 537 { 538 MSG_ENTRY Thread1_chain[]={ 539 {1,WM_KEYDOWN, POST, VK_SHIFT, 0}, 540 {1,WM_KEYUP, POST, VK_SHIFT, 0}, 541 {0,0}}; 542 MSG_ENTRY Thread0_chain[]={ 543 {0,WM_KEYDOWN, POST, VK_SHIFT, 0}, 544 {0,WM_KEYUP, POST, VK_SHIFT, 0}, 545 {0,0}}; 546 547 BOOL ret; 548 549 //trace("Thread hWnd0 0x%p hWnd1 0x%p\n",data[0].hWnd, data[1].hWnd); 550 551 /* First try sending input without attaching. It will go to the foreground */ 552 { 553 SetForegroundWindow(data[1].hWnd); 554 SetActiveWindow(data[0].hWnd); 555 556 ok(GetForegroundWindow() == data[1].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow()); 557 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow()); 558 559 FlushMessages(); 560 EMPTY_CACHE_(&data[0].cache); 561 EMPTY_CACHE_(&data[1].cache); 562 563 keybd_event(VK_SHIFT, 0,0,0); 564 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0); 565 Sleep(100); 566 FlushMessages(); 567 568 COMPARE_CACHE_(&data[0].cache, empty_chain); 569 COMPARE_CACHE_(&data[1].cache, Thread1_chain); 570 } 571 572 /* Next attach and send input. It will go to the same thread as before */ 573 { // from to 574 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE); 575 ok(ret==1, "expected AttachThreadInput to succeed\n"); 576 577 FlushMessages(); 578 EMPTY_CACHE_(&data[0].cache); 579 EMPTY_CACHE_(&data[1].cache); 580 581 keybd_event(VK_SHIFT, 0,0,0); 582 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0); 583 Sleep(100); 584 FlushMessages(); 585 586 COMPARE_CACHE_(&data[0].cache, empty_chain); 587 COMPARE_CACHE_(&data[1].cache, Thread1_chain); 588 } 589 590 /* Now set foreground and active again. Input will go to thread 0 */ 591 { 592 SetForegroundWindow(data[1].hWnd); 593 SetActiveWindow(data[0].hWnd); 594 FlushMessages(); 595 596 ok(GetForegroundWindow() == data[0].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow()); 597 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow()); 598 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 foreground and active again. Input will go to thread 0 */ 633 { 634 SetForegroundWindow(data[1].hWnd); 635 SetActiveWindow(data[0].hWnd); 636 FlushMessages(); 637 638 ok(GetForegroundWindow() == data[0].hWnd, "wrong foreground got 0x%p\n",GetForegroundWindow()); 639 ok(GetActiveWindow() == data[0].hWnd, "wrong active got 0x%p\n",GetActiveWindow()); 640 641 EMPTY_CACHE_(&data[0].cache); 642 EMPTY_CACHE_(&data[1].cache); 643 644 keybd_event(VK_SHIFT, 0,0,0); 645 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0); 646 Sleep(100); 647 FlushMessages(); 648 649 COMPARE_CACHE_(&data[0].cache, Thread0_chain); 650 COMPARE_CACHE_(&data[1].cache, empty_chain); 651 652 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE); 653 ok(ret==1, "expected AttachThreadInput to succeed\n"); 654 } 655 } 656 657 START_TEST(AttachThreadInput) 658 { 659 if(!InitThreads()) 660 return; 661 662 Test_SimpleParameters(); 663 cleanup_attachments(); 664 Test_Focus(); 665 cleanup_attachments(); 666 Test_UnaffectedMessages(); 667 cleanup_attachments(); 668 Test_SendInput(); 669 cleanup_attachments(); 670 671 if(hMouseHookLL) 672 UnhookWindowsHookEx(hMouseHookLL); 673 if(hKbdHookLL) 674 UnhookWindowsHookEx(hKbdHookLL); 675 676 /* Stop all threads and exit gratefully */ 677 PostThreadMessage(data[1].tid, WM_QUIT,0,0); 678 PostThreadMessage(data[2].tid, WM_QUIT,0,0); 679 PostThreadMessage(data[3].tid, WM_QUIT,0,0); 680 PostThreadMessage(data[4].tid, WM_QUIT,0,0); 681 } 682 683