1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Input Method Editor and Input Method Manager support 5 * FILE: win32ss/user/ntuser/ime.c 6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 8 */ 9 10 #include <win32k.h> 11 #include <jpnvkeys.h> 12 13 DBG_DEFAULT_CHANNEL(UserMisc); 14 15 #define INVALID_THREAD_ID ((ULONG)-1) 16 #define INVALID_HOTKEY ((UINT)-1) 17 #define MOD_KEYS (MOD_CONTROL | MOD_SHIFT | MOD_ALT | MOD_WIN) 18 #define MOD_LEFT_RIGHT (MOD_LEFT | MOD_RIGHT) 19 20 #define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) 21 #define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT) 22 #define LANGID_KOREAN MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN) 23 #define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) 24 #define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 25 26 HIMC ghIMC = NULL; 27 BOOL gfImeOpen = (BOOL)-1; 28 DWORD gdwImeConversion = (DWORD)-1; 29 BOOL gfIMEShowStatus = (BOOL)-1; 30 31 typedef struct tagIMEHOTKEY 32 { 33 struct tagIMEHOTKEY *pNext; 34 DWORD dwHotKeyId; 35 UINT uVirtualKey; 36 UINT uModifiers; 37 HKL hKL; 38 } IMEHOTKEY, *PIMEHOTKEY; 39 40 PIMEHOTKEY gpImeHotKeyList = NULL; // Win: gpImeHotKeyListHeader 41 LCID glcidSystem = 0; // Win: glcidSystem 42 43 // Win: GetAppImeCompatFlags 44 DWORD FASTCALL IntGetImeCompatFlags(PTHREADINFO pti) 45 { 46 if (!pti) 47 pti = PsGetCurrentThreadWin32Thread(); 48 49 return pti->ppi->dwImeCompatFlags; 50 } 51 52 // Win: GetLangIdMatchLevel 53 UINT FASTCALL IntGetImeHotKeyLanguageScore(HKL hKL, LANGID HotKeyLangId) 54 { 55 LCID lcid; 56 57 if (HotKeyLangId == LANGID_NEUTRAL || HotKeyLangId == LOWORD(hKL)) 58 return 3; 59 60 _SEH2_TRY 61 { 62 lcid = NtCurrentTeb()->CurrentLocale; 63 } 64 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 65 { 66 ERR("%p\n", NtCurrentTeb()); 67 lcid = MAKELCID(LANGID_NEUTRAL, SORT_DEFAULT); 68 } 69 _SEH2_END; 70 71 if (HotKeyLangId == LANGIDFROMLCID(lcid)) 72 return 2; 73 74 if (glcidSystem == 0) 75 ZwQueryDefaultLocale(FALSE, &glcidSystem); 76 77 if (HotKeyLangId == LANGIDFROMLCID(glcidSystem)) 78 return 1; 79 80 return 0; 81 } 82 83 // Win: GetActiveHKL 84 HKL FASTCALL IntGetActiveKeyboardLayout(VOID) 85 { 86 PTHREADINFO pti; 87 88 if (gpqForeground && gpqForeground->spwndActive) 89 { 90 pti = gpqForeground->spwndActive->head.pti; 91 if (pti && pti->KeyboardLayout) 92 return pti->KeyboardLayout->hkl; 93 } 94 95 return UserGetKeyboardLayout(0); 96 } 97 98 // Win: GetHotKeyLangID 99 static LANGID FASTCALL IntGetImeHotKeyLangId(DWORD dwHotKeyId) 100 { 101 #define IME_CHOTKEY 0x10 102 #define IME_JHOTKEY 0x30 103 #define IME_KHOTKEY 0x50 104 #define IME_THOTKEY 0x70 105 #define IME_XHOTKEY 0x90 106 static const LANGID s_array[] = 107 { 108 /* 0x00 */ (WORD)-1, 109 /* 0x10 */ LANGID_CHINESE_SIMPLIFIED, 110 /* 0x20 */ LANGID_CHINESE_SIMPLIFIED, 111 /* 0x30 */ LANGID_JAPANESE, 112 /* 0x40 */ LANGID_JAPANESE, 113 /* 0x50 */ LANGID_KOREAN, 114 /* 0x60 */ LANGID_KOREAN, 115 /* 0x70 */ LANGID_CHINESE_TRADITIONAL, 116 /* 0x80 */ LANGID_CHINESE_TRADITIONAL 117 }; 118 119 if (IME_CHOTKEY <= dwHotKeyId && dwHotKeyId < IME_XHOTKEY) 120 return s_array[(dwHotKeyId & 0xF0) >> 4]; 121 return LANGID_NEUTRAL; 122 } 123 124 // Win: AddImeHotKey 125 static VOID FASTCALL IntAddImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 126 { 127 PIMEHOTKEY pNode; 128 129 if (!*ppList) 130 { 131 *ppList = pHotKey; 132 return; 133 } 134 135 for (pNode = *ppList; pNode; pNode = pNode->pNext) 136 { 137 if (!pNode->pNext) 138 { 139 pNode->pNext = pHotKey; 140 return; 141 } 142 } 143 } 144 145 // Win: FindImeHotKeyByID 146 static PIMEHOTKEY FASTCALL IntGetImeHotKeyById(PIMEHOTKEY pList, DWORD dwHotKeyId) 147 { 148 PIMEHOTKEY pNode; 149 for (pNode = pList; pNode; pNode = pNode->pNext) 150 { 151 if (pNode->dwHotKeyId == dwHotKeyId) 152 return pNode; 153 } 154 return NULL; 155 } 156 157 // Win: FindImeHotKeyByKeyWithLang 158 static PIMEHOTKEY APIENTRY 159 IntGetImeHotKeyByKeyAndLang(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, 160 UINT uVirtualKey, LANGID TargetLangId) 161 { 162 PIMEHOTKEY pNode; 163 LANGID LangID; 164 UINT uModifiers; 165 166 for (pNode = pList; pNode; pNode = pNode->pNext) 167 { 168 if (pNode->uVirtualKey != uVirtualKey) 169 continue; 170 171 LangID = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 172 if (LangID != TargetLangId && LangID != 0) 173 continue; 174 175 uModifiers = pNode->uModifiers; 176 if (uModifiers & MOD_IGNORE_ALL_MODIFIER) 177 return pNode; 178 179 if ((uModifiers & MOD_KEYS) != uModKeys) 180 continue; 181 182 if ((uModifiers & uLeftRight) || (uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 183 return pNode; 184 } 185 186 return NULL; 187 } 188 189 // Win: DeleteImeHotKey 190 static VOID FASTCALL IntDeleteImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 191 { 192 PIMEHOTKEY pNode; 193 194 if (*ppList == pHotKey) 195 { 196 *ppList = pHotKey->pNext; 197 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 198 return; 199 } 200 201 for (pNode = *ppList; pNode; pNode = pNode->pNext) 202 { 203 if (pNode->pNext == pHotKey) 204 { 205 pNode->pNext = pHotKey->pNext; 206 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 207 return; 208 } 209 } 210 } 211 212 // Win: FindImeHotKeyByKey 213 PIMEHOTKEY 214 IntGetImeHotKeyByKey(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, UINT uVirtualKey) 215 { 216 PIMEHOTKEY pNode, ret = NULL; 217 PTHREADINFO pti = GetW32ThreadInfo(); 218 LANGID LangId; 219 HKL hKL = IntGetActiveKeyboardLayout(); 220 BOOL fKorean = (PRIMARYLANGID(LOWORD(hKL)) == LANG_KOREAN); 221 UINT nScore, nMaxScore = 0; 222 223 for (pNode = pList; pNode; pNode = pNode->pNext) 224 { 225 if (pNode->uVirtualKey != uVirtualKey) 226 continue; 227 228 if ((pNode->uModifiers & MOD_IGNORE_ALL_MODIFIER)) 229 { 230 ; 231 } 232 else if ((pNode->uModifiers & MOD_KEYS) != uModKeys) 233 { 234 continue; 235 } 236 else if ((pNode->uModifiers & uLeftRight) || 237 (pNode->uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 238 { 239 ; 240 } 241 else 242 { 243 continue; 244 } 245 246 LangId = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 247 nScore = IntGetImeHotKeyLanguageScore(hKL, LangId); 248 if (nScore >= 3) 249 return pNode; 250 251 if (fKorean) 252 continue; 253 254 if (nScore == 0) 255 { 256 if (pNode->dwHotKeyId == IME_CHOTKEY_IME_NONIME_TOGGLE || 257 pNode->dwHotKeyId == IME_THOTKEY_IME_NONIME_TOGGLE) 258 { 259 if (LOWORD(pti->hklPrev) == LangId) 260 return pNode; 261 } 262 } 263 264 if (nMaxScore < nScore) 265 { 266 nMaxScore = nScore; 267 ret = pNode; 268 } 269 } 270 271 return ret; 272 } 273 274 // Win: CheckImeHotKey 275 PIMEHOTKEY IntCheckImeHotKey(PUSER_MESSAGE_QUEUE MessageQueue, UINT uVirtualKey, LPARAM lParam) 276 { 277 PIMEHOTKEY pHotKey; 278 UINT uModifiers; 279 BOOL bKeyUp = (lParam & 0x80000000); 280 const BYTE *KeyState = MessageQueue->afKeyState; 281 static UINT s_uKeyUpVKey = 0; 282 283 if (bKeyUp) 284 { 285 if (s_uKeyUpVKey != uVirtualKey) 286 { 287 s_uKeyUpVKey = 0; 288 return NULL; 289 } 290 291 s_uKeyUpVKey = 0; 292 } 293 294 uModifiers = 0; 295 if (IS_KEY_DOWN(KeyState, VK_LSHIFT)) uModifiers |= (MOD_SHIFT | MOD_LEFT); 296 if (IS_KEY_DOWN(KeyState, VK_RSHIFT)) uModifiers |= (MOD_SHIFT | MOD_RIGHT); 297 if (IS_KEY_DOWN(KeyState, VK_LCONTROL)) uModifiers |= (MOD_CONTROL | MOD_LEFT); 298 if (IS_KEY_DOWN(KeyState, VK_RCONTROL)) uModifiers |= (MOD_CONTROL | MOD_RIGHT); 299 if (IS_KEY_DOWN(KeyState, VK_LMENU)) uModifiers |= (MOD_ALT | MOD_LEFT); 300 if (IS_KEY_DOWN(KeyState, VK_RMENU)) uModifiers |= (MOD_ALT | MOD_RIGHT); 301 302 pHotKey = IntGetImeHotKeyByKey(gpImeHotKeyList, 303 (uModifiers & MOD_KEYS), 304 (uModifiers & MOD_LEFT_RIGHT), 305 uVirtualKey); 306 if (pHotKey) 307 { 308 if (bKeyUp) 309 { 310 if (pHotKey->uModifiers & MOD_ON_KEYUP) 311 return pHotKey; 312 } 313 else 314 { 315 if (pHotKey->uModifiers & MOD_ON_KEYUP) 316 s_uKeyUpVKey = uVirtualKey; 317 else 318 return pHotKey; 319 } 320 } 321 322 return NULL; 323 } 324 325 // Win: FreeImeHotKeys 326 VOID FASTCALL IntFreeImeHotKeys(VOID) 327 { 328 PIMEHOTKEY pNode, pNext; 329 for (pNode = gpImeHotKeyList; pNode; pNode = pNext) 330 { 331 pNext = pNode->pNext; 332 ExFreePoolWithTag(pNode, USERTAG_IMEHOTKEY); 333 } 334 gpImeHotKeyList = NULL; 335 } 336 337 // Win: SetImeHotKey 338 static BOOL APIENTRY 339 IntSetImeHotKey(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL hKL, DWORD dwAction) 340 { 341 PIMEHOTKEY pNode; 342 LANGID LangId; 343 344 switch (dwAction) 345 { 346 case SETIMEHOTKEY_DELETE: 347 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); /* Find hotkey by ID */ 348 if (!pNode) 349 { 350 ERR("dwHotKeyId: 0x%lX\n", dwHotKeyId); 351 return FALSE; 352 } 353 354 IntDeleteImeHotKey(&gpImeHotKeyList, pNode); /* Delete it */ 355 return TRUE; 356 357 case SETIMEHOTKEY_ADD: 358 if (LOWORD(uVirtualKey) == VK_PACKET) /* In case of VK_PACKET */ 359 return FALSE; 360 361 LangId = IntGetImeHotKeyLangId(dwHotKeyId); 362 if (LangId == LANGID_KOREAN) 363 return FALSE; /* Korean can't add IME hotkeys */ 364 365 /* Find hotkey by key and language */ 366 pNode = IntGetImeHotKeyByKeyAndLang(gpImeHotKeyList, 367 (uModifiers & MOD_KEYS), 368 (uModifiers & MOD_LEFT_RIGHT), 369 uVirtualKey, LangId); 370 if (pNode == NULL) /* If not found */ 371 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); /* Find by ID */ 372 373 if (pNode) /* Already exists */ 374 { 375 pNode->uModifiers = uModifiers; 376 pNode->uVirtualKey = uVirtualKey; 377 pNode->hKL = hKL; 378 return TRUE; 379 } 380 381 /* Allocate new hotkey */ 382 pNode = ExAllocatePoolWithTag(PagedPool, sizeof(IMEHOTKEY), USERTAG_IMEHOTKEY); 383 if (!pNode) 384 return FALSE; 385 386 /* Populate */ 387 pNode->pNext = NULL; 388 pNode->dwHotKeyId = dwHotKeyId; 389 pNode->uModifiers = uModifiers; 390 pNode->uVirtualKey = uVirtualKey; 391 pNode->hKL = hKL; 392 IntAddImeHotKey(&gpImeHotKeyList, pNode); /* Add it */ 393 return TRUE; 394 395 case SETIMEHOTKEY_INITIALIZE: 396 IntFreeImeHotKeys(); /* Delete all the IME hotkeys */ 397 return TRUE; 398 399 default: 400 ERR("0x%lX\n", dwAction); 401 return FALSE; 402 } 403 } 404 405 BOOL NTAPI 406 NtUserGetImeHotKey(DWORD dwHotKeyId, LPUINT lpuModifiers, LPUINT lpuVirtualKey, LPHKL lphKL) 407 { 408 PIMEHOTKEY pNode = NULL; 409 410 UserEnterExclusive(); 411 412 _SEH2_TRY 413 { 414 ProbeForWrite(lpuModifiers, sizeof(UINT), 1); 415 ProbeForWrite(lpuVirtualKey, sizeof(UINT), 1); 416 if (lphKL) 417 ProbeForWrite(lphKL, sizeof(HKL), 1); 418 } 419 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 420 { 421 ERR("%p, %p, %p\n", lpuModifiers, lpuVirtualKey, lphKL); 422 _SEH2_YIELD(goto Quit); 423 } 424 _SEH2_END; 425 426 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 427 if (!pNode) 428 goto Quit; 429 430 _SEH2_TRY 431 { 432 *lpuModifiers = pNode->uModifiers; 433 *lpuVirtualKey = pNode->uVirtualKey; 434 if (lphKL) 435 *lphKL = pNode->hKL; 436 } 437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 438 { 439 ERR("%p, %p, %p, %p\n", pNode, lpuModifiers, lpuVirtualKey, lphKL); 440 pNode = NULL; 441 } 442 _SEH2_END; 443 444 Quit: 445 UserLeave(); 446 return !!pNode; 447 } 448 449 BOOL 450 NTAPI 451 NtUserSetImeHotKey( 452 DWORD dwHotKeyId, 453 UINT uModifiers, 454 UINT uVirtualKey, 455 HKL hKL, 456 DWORD dwAction) 457 { 458 BOOL ret; 459 UserEnterExclusive(); 460 ret = IntSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, dwAction); 461 UserLeave(); 462 return ret; 463 } 464 465 DWORD 466 NTAPI 467 NtUserCheckImeHotKey(UINT uVirtualKey, LPARAM lParam) 468 { 469 PIMEHOTKEY pNode; 470 DWORD ret = INVALID_HOTKEY; 471 472 UserEnterExclusive(); 473 474 if (!gpqForeground || !IS_IMM_MODE()) 475 goto Quit; 476 477 pNode = IntCheckImeHotKey(gpqForeground, uVirtualKey, lParam); 478 if (pNode) 479 ret = pNode->dwHotKeyId; 480 481 Quit: 482 UserLeave(); 483 return ret; 484 } 485 486 // Win: GetTopLevelWindow 487 PWND FASTCALL IntGetTopLevelWindow(PWND pwnd) 488 { 489 if (!pwnd) 490 return NULL; 491 492 while (pwnd->style & WS_CHILD) 493 pwnd = pwnd->spwndParent; 494 495 return pwnd; 496 } 497 498 // Win: AssociateInputContext 499 HIMC FASTCALL IntAssociateInputContext(PWND pWnd, PIMC pImc) 500 { 501 HIMC hOldImc = pWnd->hImc; 502 pWnd->hImc = (pImc ? UserHMGetHandle(pImc) : NULL); 503 return hOldImc; 504 } 505 506 DWORD 507 NTAPI 508 NtUserSetThreadLayoutHandles(HKL hNewKL, HKL hOldKL) 509 { 510 PTHREADINFO pti; 511 PKL pOldKL, pNewKL; 512 513 UserEnterExclusive(); 514 515 pti = GetW32ThreadInfo(); 516 pOldKL = pti->KeyboardLayout; 517 if (pOldKL && pOldKL->hkl != hOldKL) 518 goto Quit; 519 520 pNewKL = UserHklToKbl(hNewKL); 521 if (!pNewKL) 522 goto Quit; 523 524 if (IS_IME_HKL(hNewKL) != IS_IME_HKL(hOldKL)) 525 pti->hklPrev = hOldKL; 526 527 UserAssignmentLock((PVOID*)&pti->KeyboardLayout, pNewKL); 528 pti->pClientInfo->hKL = pNewKL->hkl; 529 530 Quit: 531 UserLeave(); 532 return 0; 533 } 534 535 // Win: BuildHimcList 536 DWORD FASTCALL UserBuildHimcList(PTHREADINFO pti, DWORD dwCount, HIMC *phList) 537 { 538 PIMC pIMC; 539 DWORD dwRealCount = 0; 540 541 if (pti) 542 { 543 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 544 { 545 if (dwRealCount < dwCount) 546 phList[dwRealCount] = UserHMGetHandle(pIMC); 547 548 ++dwRealCount; 549 } 550 } 551 else 552 { 553 for (pti = gptiCurrent->ppi->ptiList; pti; pti = pti->ptiSibling) 554 { 555 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 556 { 557 if (dwRealCount < dwCount) 558 phList[dwRealCount] = UserHMGetHandle(pIMC); 559 560 ++dwRealCount; 561 } 562 } 563 } 564 565 return dwRealCount; 566 } 567 568 // Win: xxxImmProcessKey 569 UINT FASTCALL 570 IntImmProcessKey(PUSER_MESSAGE_QUEUE MessageQueue, PWND pWnd, UINT uMsg, 571 WPARAM wParam, LPARAM lParam) 572 { 573 UINT uVirtualKey, ret = 0; 574 DWORD dwHotKeyId; 575 PKL pKL; 576 PIMC pIMC = NULL; 577 PIMEHOTKEY pImeHotKey; 578 HKL hKL; 579 HWND hWnd; 580 581 ASSERT_REFS_CO(pWnd); 582 583 switch (uMsg) 584 { 585 case WM_KEYDOWN: 586 case WM_KEYUP: 587 case WM_SYSKEYDOWN: 588 case WM_SYSKEYUP: 589 break; 590 591 default: 592 return 0; 593 } 594 595 hWnd = UserHMGetHandle(pWnd); 596 pKL = pWnd->head.pti->KeyboardLayout; 597 if (!pKL) 598 return 0; 599 600 uVirtualKey = LOBYTE(wParam); 601 pImeHotKey = IntCheckImeHotKey(MessageQueue, uVirtualKey, lParam); 602 if (pImeHotKey) 603 { 604 dwHotKeyId = pImeHotKey->dwHotKeyId; 605 hKL = pImeHotKey->hKL; 606 } 607 else 608 { 609 dwHotKeyId = INVALID_HOTKEY; 610 hKL = NULL; 611 } 612 613 if (IME_HOTKEY_DSWITCH_FIRST <= dwHotKeyId && dwHotKeyId <= IME_HOTKEY_DSWITCH_LAST) 614 { 615 if (pKL->hkl != hKL) 616 { 617 UserPostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, 618 ((pKL->dwFontSigs & gSystemFS) ? INPUTLANGCHANGE_SYSCHARSET : 0), 619 (LPARAM)hKL); 620 } 621 622 if (IntGetImeCompatFlags(pWnd->head.pti) & 0x800000) 623 return 0; 624 625 return IPHK_HOTKEY; 626 } 627 628 if (!IS_IMM_MODE()) 629 return 0; 630 631 if (dwHotKeyId == INVALID_HOTKEY) 632 { 633 if (!pKL->piiex) 634 return 0; 635 636 if (pWnd->hImc) 637 pIMC = UserGetObject(gHandleTable, pWnd->hImc, TYPE_INPUTCONTEXT); 638 if (!pIMC) 639 return 0; 640 641 if ((lParam & 0x80000000) && 642 (pKL->piiex->ImeInfo.fdwProperty & IME_PROP_IGNORE_UPKEYS)) 643 { 644 return 0; 645 } 646 647 switch (uVirtualKey) 648 { 649 case VK_DBE_CODEINPUT: 650 case VK_DBE_ENTERCONFIGMODE: 651 case VK_DBE_ENTERWORDREGISTERMODE: 652 case VK_DBE_HIRAGANA: 653 case VK_DBE_KATAKANA: 654 case VK_DBE_NOCODEINPUT: 655 case VK_DBE_NOROMAN: 656 case VK_DBE_ROMAN: 657 break; 658 659 default: 660 { 661 if (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) 662 { 663 if (uVirtualKey != VK_MENU && uVirtualKey != VK_F10) 664 return 0; 665 } 666 667 if (!(pKL->piiex->ImeInfo.fdwProperty & IME_PROP_NEED_ALTKEY)) 668 { 669 if (uVirtualKey == VK_MENU || (lParam & 0x20000000)) 670 return 0; 671 } 672 break; 673 } 674 } 675 } 676 677 if (LOBYTE(uVirtualKey) == VK_PACKET) 678 uVirtualKey = MAKELONG(wParam, GetW32ThreadInfo()->wchInjected); 679 680 ret = co_IntImmProcessKey(hWnd, pKL->hkl, uVirtualKey, lParam, dwHotKeyId); 681 682 if (IntGetImeCompatFlags(pWnd->head.pti) & 0x800000) 683 ret &= ~IPHK_HOTKEY; 684 685 return ret; 686 } 687 688 NTSTATUS 689 NTAPI 690 NtUserBuildHimcList(DWORD dwThreadId, DWORD dwCount, HIMC *phList, LPDWORD pdwCount) 691 { 692 NTSTATUS ret = STATUS_UNSUCCESSFUL; 693 DWORD dwRealCount; 694 PTHREADINFO pti; 695 696 UserEnterExclusive(); 697 698 if (!IS_IMM_MODE()) 699 { 700 ERR("!IS_IMM_MODE()\n"); 701 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 702 goto Quit; 703 } 704 705 if (dwThreadId == 0) 706 { 707 pti = gptiCurrent; 708 } 709 else if (dwThreadId == INVALID_THREAD_ID) 710 { 711 pti = NULL; 712 } 713 else 714 { 715 pti = IntTID2PTI(UlongToHandle(dwThreadId)); 716 if (!pti || !pti->rpdesk) 717 goto Quit; 718 } 719 720 _SEH2_TRY 721 { 722 ProbeForWrite(phList, dwCount * sizeof(HIMC), 1); 723 ProbeForWrite(pdwCount, sizeof(DWORD), 1); 724 *pdwCount = dwRealCount = UserBuildHimcList(pti, dwCount, phList); 725 } 726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 727 { 728 ERR("%p, %p\n", phList, pdwCount); 729 _SEH2_YIELD(goto Quit); 730 } 731 _SEH2_END; 732 733 if (dwCount < dwRealCount) 734 ret = STATUS_BUFFER_TOO_SMALL; 735 else 736 ret = STATUS_SUCCESS; 737 738 Quit: 739 UserLeave(); 740 return ret; 741 } 742 743 // Win: SetConvMode 744 static VOID FASTCALL UserSetImeConversionKeyState(PTHREADINFO pti, DWORD dwConversion) 745 { 746 HKL hKL; 747 LANGID LangID; 748 LPBYTE KeyState; 749 BOOL bAlphaNumeric, bKatakana, bHiragana, bFullShape, bRoman, bCharCode; 750 751 if (!pti->KeyboardLayout) 752 return; 753 754 hKL = pti->KeyboardLayout->hkl; 755 LangID = LOWORD(hKL); 756 KeyState = pti->MessageQueue->afKeyState; 757 758 switch (PRIMARYLANGID(LangID)) 759 { 760 case LANG_JAPANESE: 761 bAlphaNumeric = !(dwConversion & IME_CMODE_NATIVE); 762 bKatakana = !bAlphaNumeric && (dwConversion & IME_CMODE_KATAKANA); 763 bHiragana = !bAlphaNumeric && !(dwConversion & IME_CMODE_KATAKANA); 764 SET_KEY_DOWN(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 765 SET_KEY_LOCKED(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 766 SET_KEY_DOWN(KeyState, VK_DBE_HIRAGANA, bHiragana); 767 SET_KEY_LOCKED(KeyState, VK_DBE_HIRAGANA, bHiragana); 768 SET_KEY_DOWN(KeyState, VK_DBE_KATAKANA, bKatakana); 769 SET_KEY_LOCKED(KeyState, VK_DBE_KATAKANA, bKatakana); 770 771 bFullShape = (dwConversion & IME_CMODE_FULLSHAPE); 772 SET_KEY_DOWN(KeyState, VK_DBE_DBCSCHAR, bFullShape); 773 SET_KEY_LOCKED(KeyState, VK_DBE_DBCSCHAR, bFullShape); 774 SET_KEY_DOWN(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 775 SET_KEY_LOCKED(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 776 777 bRoman = (dwConversion & IME_CMODE_ROMAN); 778 SET_KEY_DOWN(KeyState, VK_DBE_ROMAN, bRoman); 779 SET_KEY_LOCKED(KeyState, VK_DBE_ROMAN, bRoman); 780 SET_KEY_DOWN(KeyState, VK_DBE_NOROMAN, !bRoman); 781 SET_KEY_LOCKED(KeyState, VK_DBE_NOROMAN, !bRoman); 782 783 bCharCode = (dwConversion & IME_CMODE_CHARCODE); 784 SET_KEY_DOWN(KeyState, VK_DBE_CODEINPUT, bCharCode); 785 SET_KEY_LOCKED(KeyState, VK_DBE_CODEINPUT, bCharCode); 786 SET_KEY_DOWN(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 787 SET_KEY_LOCKED(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 788 break; 789 790 case LANG_KOREAN: 791 SET_KEY_LOCKED(KeyState, VK_HANGUL, (dwConversion & IME_CMODE_NATIVE)); 792 SET_KEY_LOCKED(KeyState, VK_JUNJA, (dwConversion & IME_CMODE_FULLSHAPE)); 793 SET_KEY_LOCKED(KeyState, VK_HANJA, (dwConversion & IME_CMODE_HANJACONVERT)); 794 break; 795 796 default: 797 break; 798 } 799 } 800 801 DWORD 802 NTAPI 803 NtUserNotifyIMEStatus(HWND hwnd, BOOL fOpen, DWORD dwConversion) 804 { 805 PWND pwnd; 806 PTHREADINFO pti; 807 HKL hKL; 808 809 UserEnterExclusive(); 810 811 if (!IS_IMM_MODE()) 812 { 813 ERR("!IS_IMM_MODE()\n"); 814 goto Quit; 815 } 816 817 pwnd = ValidateHwndNoErr(hwnd); 818 if (!pwnd) 819 goto Quit; 820 821 pti = pwnd->head.pti; 822 if (!pti || !gptiForeground) 823 goto Quit; 824 if (pti != gptiForeground && pti->MessageQueue != gptiForeground->MessageQueue) 825 goto Quit; 826 if (ghIMC == pwnd->hImc && gfImeOpen == !!fOpen && gdwImeConversion == dwConversion) 827 goto Quit; 828 829 ghIMC = pwnd->hImc; 830 if (ghIMC) 831 { 832 gfImeOpen = !!fOpen; 833 gdwImeConversion = dwConversion; 834 UserSetImeConversionKeyState(pti, (fOpen ? dwConversion : IME_CMODE_ALPHANUMERIC)); 835 } 836 837 if (ISITHOOKED(WH_SHELL)) 838 { 839 hKL = (pti->KeyboardLayout ? pti->KeyboardLayout->hkl : NULL); 840 co_HOOK_CallHooks(WH_SHELL, HSHELL_LANGUAGE, (WPARAM)hwnd, (LPARAM)hKL); 841 } 842 843 // TODO: 844 845 Quit: 846 UserLeave(); 847 return 0; 848 } 849 850 BOOL 851 NTAPI 852 NtUserDisableThreadIme( 853 DWORD dwThreadID) 854 { 855 PTHREADINFO pti, ptiCurrent; 856 PPROCESSINFO ppi; 857 BOOL ret = FALSE; 858 859 UserEnterExclusive(); 860 861 if (!IS_IMM_MODE()) 862 { 863 ERR("!IS_IMM_MODE()\n"); 864 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 865 goto Quit; 866 } 867 868 ptiCurrent = GetW32ThreadInfo(); 869 870 if (dwThreadID == INVALID_THREAD_ID) 871 { 872 ppi = ptiCurrent->ppi; 873 ppi->W32PF_flags |= W32PF_DISABLEIME; 874 875 Retry: 876 for (pti = ppi->ptiList; pti; pti = pti->ptiSibling) 877 { 878 pti->TIF_flags |= TIF_DISABLEIME; 879 880 if (pti->spwndDefaultIme) 881 { 882 co_UserDestroyWindow(pti->spwndDefaultIme); 883 pti->spwndDefaultIme = NULL; 884 goto Retry; /* The contents of ppi->ptiList may be changed. */ 885 } 886 } 887 } 888 else 889 { 890 if (dwThreadID == 0) 891 { 892 pti = ptiCurrent; 893 } 894 else 895 { 896 pti = IntTID2PTI(UlongToHandle(dwThreadID)); 897 898 /* The thread needs to reside in the current process. */ 899 if (!pti || pti->ppi != ptiCurrent->ppi) 900 goto Quit; 901 } 902 903 pti->TIF_flags |= TIF_DISABLEIME; 904 905 if (pti->spwndDefaultIme) 906 { 907 co_UserDestroyWindow(pti->spwndDefaultIme); 908 pti->spwndDefaultIme = NULL; 909 } 910 } 911 912 ret = TRUE; 913 914 Quit: 915 UserLeave(); 916 return ret; 917 } 918 919 DWORD 920 NTAPI 921 NtUserGetAppImeLevel(HWND hWnd) 922 { 923 DWORD ret = 0; 924 PWND pWnd; 925 PTHREADINFO pti; 926 927 UserEnterShared(); 928 929 pWnd = ValidateHwndNoErr(hWnd); 930 if (!pWnd) 931 goto Quit; 932 933 if (!IS_IMM_MODE()) 934 { 935 ERR("!IS_IMM_MODE()\n"); 936 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 937 goto Quit; 938 } 939 940 pti = PsGetCurrentThreadWin32Thread(); 941 if (pWnd->head.pti->ppi == pti->ppi) 942 ret = (DWORD)(ULONG_PTR)UserGetProp(pWnd, AtomImeLevel, TRUE); 943 944 Quit: 945 UserLeave(); 946 return ret; 947 } 948 949 // Win: GetImeInfoEx 950 BOOL FASTCALL 951 UserGetImeInfoEx( 952 _Inout_ PWINSTATION_OBJECT pWinSta, 953 _Inout_ PIMEINFOEX pInfoEx, 954 _In_ IMEINFOEXCLASS SearchType) 955 { 956 PKL pkl, pklHead; 957 958 if (!pWinSta || !gspklBaseLayout) 959 return FALSE; 960 961 pkl = pklHead = gspklBaseLayout; 962 963 /* Find the matching entry from the list and get info */ 964 if (SearchType == ImeInfoExKeyboardLayout) 965 { 966 do 967 { 968 if (pInfoEx->hkl == pkl->hkl) 969 { 970 if (!pkl->piiex) 971 { 972 ERR("!pkl->piiex at %p\n", pkl->hkl); 973 break; 974 } 975 976 *pInfoEx = *pkl->piiex; 977 return TRUE; 978 } 979 980 pkl = pkl->pklNext; 981 } while (pkl != pklHead); 982 } 983 else if (SearchType == ImeInfoExImeFileName) 984 { 985 do 986 { 987 if (pkl->piiex && 988 _wcsnicmp(pkl->piiex->wszImeFile, pInfoEx->wszImeFile, 989 RTL_NUMBER_OF(pkl->piiex->wszImeFile)) == 0) 990 { 991 *pInfoEx = *pkl->piiex; 992 return TRUE; 993 } 994 995 pkl = pkl->pklNext; 996 } while (pkl != pklHead); 997 } 998 else 999 { 1000 ERR("SearchType: %d\n", SearchType); 1001 } 1002 1003 return FALSE; 1004 } 1005 1006 BOOL 1007 NTAPI 1008 NtUserGetImeInfoEx( 1009 PIMEINFOEX pImeInfoEx, 1010 IMEINFOEXCLASS SearchType) 1011 { 1012 IMEINFOEX ImeInfoEx; 1013 BOOL ret = FALSE; 1014 PWINSTATION_OBJECT pWinSta; 1015 1016 UserEnterShared(); 1017 1018 if (!IS_IMM_MODE()) 1019 { 1020 ERR("!IS_IMM_MODE()\n"); 1021 goto Quit; 1022 } 1023 1024 _SEH2_TRY 1025 { 1026 ProbeForRead(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1027 ImeInfoEx = *pImeInfoEx; 1028 } 1029 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1030 { 1031 ERR("%p\n", pImeInfoEx); 1032 _SEH2_YIELD(goto Quit); 1033 } 1034 _SEH2_END; 1035 1036 pWinSta = IntGetProcessWindowStation(NULL); 1037 ret = UserGetImeInfoEx(pWinSta, &ImeInfoEx, SearchType); 1038 if (!ret) 1039 goto Quit; 1040 1041 _SEH2_TRY 1042 { 1043 ProbeForWrite(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1044 *pImeInfoEx = ImeInfoEx; 1045 } 1046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1047 { 1048 ERR("%p\n", pImeInfoEx); 1049 ret = FALSE; 1050 } 1051 _SEH2_END; 1052 1053 Quit: 1054 UserLeave(); 1055 return ret; 1056 } 1057 1058 BOOL 1059 NTAPI 1060 NtUserSetAppImeLevel(HWND hWnd, DWORD dwLevel) 1061 { 1062 BOOL ret = FALSE; 1063 PWND pWnd; 1064 PTHREADINFO pti; 1065 1066 UserEnterExclusive(); 1067 1068 if (!IS_IMM_MODE()) 1069 { 1070 ERR("!IS_IMM_MODE()\n"); 1071 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1072 goto Quit; 1073 } 1074 1075 pWnd = ValidateHwndNoErr(hWnd); 1076 if (!pWnd) 1077 goto Quit; 1078 1079 pti = PsGetCurrentThreadWin32Thread(); 1080 if (pWnd->head.pti->ppi == pti->ppi) 1081 ret = UserSetProp(pWnd, AtomImeLevel, (HANDLE)(ULONG_PTR)dwLevel, TRUE); 1082 1083 Quit: 1084 UserLeave(); 1085 return ret; 1086 } 1087 1088 // Win: SetImeInfoEx 1089 BOOL FASTCALL 1090 UserSetImeInfoEx( 1091 _Inout_ PWINSTATION_OBJECT pWinSta, 1092 _Inout_ PIMEINFOEX pImeInfoEx) 1093 { 1094 PKL pklHead, pkl; 1095 1096 if (!pWinSta || !gspklBaseLayout) 1097 return FALSE; 1098 1099 pkl = pklHead = gspklBaseLayout; 1100 1101 do 1102 { 1103 if (pkl->hkl != pImeInfoEx->hkl) 1104 { 1105 pkl = pkl->pklNext; 1106 continue; 1107 } 1108 1109 if (!pkl->piiex) 1110 { 1111 ERR("!pkl->piiex at %p\n", pkl->hkl); 1112 return FALSE; 1113 } 1114 1115 if (!pkl->piiex->fLoadFlag) 1116 *pkl->piiex = *pImeInfoEx; 1117 1118 return TRUE; 1119 } while (pkl != pklHead); 1120 1121 return FALSE; 1122 } 1123 1124 BOOL 1125 NTAPI 1126 NtUserSetImeInfoEx(PIMEINFOEX pImeInfoEx) 1127 { 1128 BOOL ret = FALSE; 1129 IMEINFOEX ImeInfoEx; 1130 PWINSTATION_OBJECT pWinSta; 1131 1132 UserEnterExclusive(); 1133 1134 if (!IS_IMM_MODE()) 1135 { 1136 ERR("!IS_IMM_MODE()\n"); 1137 goto Quit; 1138 } 1139 1140 _SEH2_TRY 1141 { 1142 ProbeForRead(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1143 ImeInfoEx = *pImeInfoEx; 1144 } 1145 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1146 { 1147 ERR("%p\n", pImeInfoEx); 1148 _SEH2_YIELD(goto Quit); 1149 } 1150 _SEH2_END; 1151 1152 pWinSta = IntGetProcessWindowStation(NULL); 1153 ret = UserSetImeInfoEx(pWinSta, &ImeInfoEx); 1154 1155 Quit: 1156 UserLeave(); 1157 return ret; 1158 } 1159 1160 // Choose the preferred owner of the IME window. 1161 // Win: ImeSetFutureOwner 1162 VOID FASTCALL IntImeSetFutureOwner(PWND pImeWnd, PWND pwndOwner) 1163 { 1164 PWND pwndNode, pwndNextOwner, pwndParent, pwndSibling; 1165 PTHREADINFO pti = pImeWnd->head.pti; 1166 1167 if (!pwndOwner || (pwndOwner->style & WS_CHILD)) // invalid owner 1168 return; 1169 1170 // Get the top-level owner of the same thread 1171 for (pwndNode = pwndOwner; ; pwndNode = pwndNextOwner) 1172 { 1173 pwndNextOwner = pwndNode->spwndOwner; 1174 if (!pwndNextOwner || pwndNextOwner->head.pti != pti) 1175 break; 1176 } 1177 1178 // Don't choose the IME-like windows and the bottom-most windows unless necessary. 1179 if (IS_WND_IMELIKE(pwndNode) || 1180 ((pwndNode->state2 & WNDS2_BOTTOMMOST) && !(pwndOwner->state2 & WNDS2_BOTTOMMOST))) 1181 { 1182 pwndNode = pwndOwner; 1183 } 1184 1185 pwndParent = pwndNode->spwndParent; 1186 if (!pwndParent || pwndOwner != pwndNode) 1187 { 1188 WndSetOwner(pImeWnd, pwndNode); 1189 return; 1190 } 1191 1192 for (pwndSibling = pwndParent->spwndChild; pwndSibling; pwndSibling = pwndSibling->spwndNext) 1193 { 1194 if (pwndNode->head.pti != pwndSibling->head.pti) 1195 continue; 1196 1197 if (IS_WND_MENU(pwndSibling) || IS_WND_IMELIKE(pwndSibling)) 1198 continue; 1199 1200 if (pwndSibling->state2 & WNDS2_INDESTROY) 1201 continue; 1202 1203 if (pwndNode == pwndSibling || (pwndSibling->style & WS_CHILD)) 1204 continue; 1205 1206 if (pwndSibling->spwndOwner == NULL || 1207 pwndSibling->head.pti != pwndSibling->spwndOwner->head.pti) 1208 { 1209 pwndNode = pwndSibling; 1210 break; 1211 } 1212 } 1213 1214 WndSetOwner(pImeWnd, pwndNode); 1215 } 1216 1217 // Get the last non-IME-like top-most window on the desktop. 1218 // Win: GetLastTopMostWindowNoIME 1219 PWND FASTCALL IntGetLastTopMostWindowNoIME(PWND pImeWnd) 1220 { 1221 PWND pwndNode, pwndOwner, pwndLastTopMost = NULL; 1222 BOOL bFound; 1223 1224 pwndNode = UserGetDesktopWindow(); 1225 if (!pwndNode || pwndNode->spwndChild == NULL) 1226 return NULL; 1227 1228 for (pwndNode = pwndNode->spwndChild; 1229 pwndNode && (pwndNode->ExStyle & WS_EX_TOPMOST); 1230 pwndNode = pwndNode->spwndNext) 1231 { 1232 bFound = FALSE; 1233 1234 if (IS_WND_IMELIKE(pwndNode)) // An IME-like window 1235 { 1236 // Search the IME window from owners 1237 for (pwndOwner = pwndNode; pwndOwner; pwndOwner = pwndOwner->spwndOwner) 1238 { 1239 if (pImeWnd == pwndOwner) 1240 { 1241 bFound = TRUE; 1242 break; 1243 } 1244 } 1245 } 1246 1247 if (!bFound) 1248 pwndLastTopMost = pwndNode; 1249 } 1250 1251 return pwndLastTopMost; 1252 } 1253 1254 // Adjust the ordering of the windows around the IME window. 1255 // Win: ImeSetTopMost 1256 VOID FASTCALL IntImeSetTopMost(PWND pImeWnd, BOOL bTopMost, PWND pwndInsertBefore) 1257 { 1258 PWND pwndParent, pwndChild, pwndNode, pwndNext, pwndInsertAfter = NULL; 1259 PWND pwndInsertAfterSave; 1260 1261 pwndParent = pImeWnd->spwndParent; 1262 if (!pwndParent) 1263 return; 1264 1265 pwndChild = pwndParent->spwndChild; 1266 1267 if (!bTopMost) 1268 { 1269 // Calculate pwndInsertAfter 1270 pwndInsertAfter = IntGetLastTopMostWindowNoIME(pImeWnd); 1271 if (pwndInsertBefore) 1272 { 1273 for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = pwndNode->spwndNext) 1274 { 1275 if (pwndNode->spwndNext == pwndInsertBefore) 1276 break; 1277 1278 if (pwndNode == pImeWnd) 1279 return; 1280 } 1281 1282 if (!pwndNode) 1283 return; 1284 1285 pwndInsertAfter = pwndNode; 1286 } 1287 1288 // Adjust pwndInsertAfter if the owner is bottom-most 1289 if (pImeWnd->spwndOwner->state2 & WNDS2_BOTTOMMOST) 1290 { 1291 for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = pwndNode->spwndNext) 1292 { 1293 if (pwndNode == pImeWnd->spwndOwner) 1294 break; 1295 1296 if (!IS_WND_IMELIKE(pwndNode)) 1297 pwndInsertAfter = pwndNode; 1298 } 1299 } 1300 } 1301 1302 pwndInsertAfterSave = pwndInsertAfter; 1303 1304 while (pwndChild) 1305 { 1306 pwndNext = pwndChild->spwndNext; 1307 1308 // If pwndChild is a good IME-like window, ... 1309 if (IS_WND_IMELIKE(pwndChild) && pwndChild != pwndInsertAfter && 1310 pwndChild->head.pti == pImeWnd->head.pti) 1311 { 1312 // Find pImeWnd from the owners 1313 for (pwndNode = pwndChild; pwndNode; pwndNode = pwndNode->spwndOwner) 1314 { 1315 if (pwndNode != pImeWnd) 1316 continue; 1317 1318 // Adjust the ordering and the linking 1319 IntUnlinkWindow(pwndChild); 1320 1321 if (bTopMost) 1322 pwndChild->ExStyle |= WS_EX_TOPMOST; 1323 else 1324 pwndChild->ExStyle &= ~WS_EX_TOPMOST; 1325 1326 if (!pwndInsertAfter) 1327 IntLinkHwnd(pwndChild, HWND_TOP); 1328 else 1329 IntLinkHwnd(pwndChild, UserHMGetHandle(pwndInsertAfter)); 1330 1331 // Update the preferred position 1332 pwndInsertAfter = pwndChild; 1333 break; 1334 } 1335 } 1336 1337 // Get the next child, with ignoring pwndInsertAfterSave 1338 pwndChild = pwndNext; 1339 if (pwndChild && pwndChild == pwndInsertAfterSave && pwndInsertAfter) 1340 pwndChild = pwndInsertAfter->spwndNext; 1341 } 1342 } 1343 1344 // Make the IME window top-most if necessary. 1345 // Win: ImeCheckTopmost 1346 VOID FASTCALL IntImeCheckTopmost(PWND pImeWnd) 1347 { 1348 BOOL bTopMost; 1349 PWND pwndOwner = pImeWnd->spwndOwner, pwndInsertBefore = NULL; 1350 1351 if (!pwndOwner) 1352 return; 1353 1354 if (pImeWnd->head.pti != gptiForeground) 1355 pwndInsertBefore = pwndOwner; 1356 1357 bTopMost = !!(pwndOwner->ExStyle & WS_EX_TOPMOST); 1358 IntImeSetTopMost(pImeWnd, bTopMost, pwndInsertBefore); 1359 } 1360 1361 BOOL NTAPI 1362 NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus) 1363 { 1364 BOOL ret = FALSE; 1365 PWND pImeWnd, pwndFocus, pwndTopLevel, pwndNode, pwndActive; 1366 PTHREADINFO ptiIme; 1367 1368 UserEnterExclusive(); 1369 1370 if (!IS_IMM_MODE()) 1371 { 1372 ERR("!IS_IMM_MODE()\n"); 1373 goto Quit; 1374 } 1375 1376 pImeWnd = ValidateHwndNoErr(hImeWnd); 1377 if (!pImeWnd || pImeWnd->fnid != FNID_IME) 1378 goto Quit; 1379 1380 pwndFocus = ValidateHwndNoErr(hwndFocus); 1381 if (pwndFocus) 1382 { 1383 if (IS_WND_IMELIKE(pwndFocus)) 1384 goto Quit; 1385 1386 pwndTopLevel = IntGetTopLevelWindow(pwndFocus); 1387 1388 for (pwndNode = pwndTopLevel; pwndNode; pwndNode = pwndNode->spwndOwner) 1389 { 1390 if (pwndNode->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 1391 { 1392 pwndTopLevel = NULL; 1393 break; 1394 } 1395 } 1396 1397 WndSetOwner(pImeWnd, pwndTopLevel); 1398 IntImeCheckTopmost(pImeWnd); 1399 } 1400 else 1401 { 1402 ptiIme = pImeWnd->head.pti; 1403 pwndActive = ptiIme->MessageQueue->spwndActive; 1404 1405 if (!pwndActive || pwndActive != pImeWnd->spwndOwner) 1406 { 1407 if (pwndActive && ptiIme == pwndActive->head.pti && !IS_WND_IMELIKE(pwndActive)) 1408 { 1409 WndSetOwner(pImeWnd, pwndActive); 1410 } 1411 else 1412 { 1413 IntImeSetFutureOwner(pImeWnd, pImeWnd->spwndOwner); 1414 } 1415 1416 IntImeCheckTopmost(pImeWnd); 1417 } 1418 } 1419 1420 ret = TRUE; 1421 1422 Quit: 1423 UserLeave(); 1424 return ret; 1425 } 1426 1427 PVOID 1428 AllocInputContextObject(PDESKTOP pDesk, 1429 PTHREADINFO pti, 1430 SIZE_T Size, 1431 PVOID* HandleOwner) 1432 { 1433 PTHRDESKHEAD ObjHead; 1434 1435 ASSERT(Size > sizeof(*ObjHead)); 1436 ASSERT(pti != NULL); 1437 1438 if (!pDesk) 1439 pDesk = pti->rpdesk; 1440 1441 ObjHead = DesktopHeapAlloc(pDesk, Size); 1442 if (!ObjHead) 1443 return NULL; 1444 1445 RtlZeroMemory(ObjHead, Size); 1446 1447 ObjHead->pSelf = ObjHead; 1448 ObjHead->rpdesk = pDesk; 1449 ObjHead->pti = pti; 1450 IntReferenceThreadInfo(pti); 1451 *HandleOwner = pti; 1452 pti->ppi->UserHandleCount++; 1453 1454 return ObjHead; 1455 } 1456 1457 VOID UserFreeInputContext(PVOID Object) 1458 { 1459 PTHRDESKHEAD ObjHead = Object; 1460 PDESKTOP pDesk = ObjHead->rpdesk; 1461 PIMC pNode, pIMC = Object; 1462 PTHREADINFO pti; 1463 1464 if (!pIMC) 1465 return; 1466 1467 // Remove pIMC from the list except spDefaultImc 1468 pti = pIMC->head.pti; 1469 for (pNode = pti->spDefaultImc; pNode; pNode = pNode->pImcNext) 1470 { 1471 if (pNode->pImcNext == pIMC) 1472 { 1473 pNode->pImcNext = pIMC->pImcNext; 1474 break; 1475 } 1476 } 1477 1478 DesktopHeapFree(pDesk, Object); 1479 1480 pti->ppi->UserHandleCount--; 1481 IntDereferenceThreadInfo(pti); 1482 } 1483 1484 BOOLEAN UserDestroyInputContext(PVOID Object) 1485 { 1486 PIMC pIMC = Object; 1487 if (!pIMC) 1488 return TRUE; 1489 1490 UserMarkObjectDestroy(pIMC); 1491 UserDeleteObject(UserHMGetHandle(pIMC), TYPE_INPUTCONTEXT); 1492 return TRUE; 1493 } 1494 1495 // Win: DestroyInputContext 1496 BOOL IntDestroyInputContext(PIMC pIMC) 1497 { 1498 HIMC hIMC = UserHMGetHandle(pIMC); 1499 PTHREADINFO pti = pIMC->head.pti; 1500 PWND pwndChild; 1501 PWINDOWLIST pwl; 1502 HWND *phwnd; 1503 PWND pWnd; 1504 1505 if (pti != gptiCurrent) 1506 { 1507 EngSetLastError(ERROR_ACCESS_DENIED); 1508 return FALSE; 1509 } 1510 1511 if (pIMC == pti->spDefaultImc) 1512 { 1513 EngSetLastError(ERROR_INVALID_PARAMETER); 1514 return FALSE; 1515 } 1516 1517 pwndChild = pti->rpdesk->pDeskInfo->spwnd->spwndChild; 1518 pwl = IntBuildHwndList(pwndChild, IACE_LIST | IACE_CHILDREN, pti); 1519 if (pwl) 1520 { 1521 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1522 { 1523 pWnd = UserGetObjectNoErr(gHandleTable, *phwnd, TYPE_WINDOW); 1524 if (pWnd && pWnd->hImc == hIMC) 1525 IntAssociateInputContext(pWnd, pti->spDefaultImc); 1526 } 1527 1528 IntFreeHwndList(pwl); 1529 } 1530 1531 UserDeleteObject(hIMC, TYPE_INPUTCONTEXT); 1532 return TRUE; 1533 } 1534 1535 BOOL NTAPI NtUserDestroyInputContext(HIMC hIMC) 1536 { 1537 BOOL ret = FALSE; 1538 PIMC pIMC; 1539 1540 UserEnterExclusive(); 1541 1542 if (!IS_IMM_MODE()) 1543 { 1544 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1545 goto Quit; 1546 } 1547 1548 pIMC = UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1549 if (pIMC) 1550 ret = IntDestroyInputContext(pIMC); 1551 1552 Quit: 1553 UserLeave(); 1554 return ret; 1555 } 1556 1557 // Win: CreateInputContext 1558 PIMC FASTCALL UserCreateInputContext(ULONG_PTR dwClientImcData) 1559 { 1560 PIMC pIMC; 1561 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1562 PDESKTOP pdesk = pti->rpdesk; 1563 1564 if (!IS_IMM_MODE() || (pti->TIF_flags & TIF_DISABLEIME)) // Disabled? 1565 { 1566 ERR("IME is disabled\n"); 1567 return NULL; 1568 } 1569 1570 if (!pdesk) // No desktop? 1571 return NULL; 1572 1573 // pti->spDefaultImc should be already set if non-first time. 1574 if (dwClientImcData && !pti->spDefaultImc) 1575 return NULL; 1576 1577 // Create an input context user object. 1578 pIMC = UserCreateObject(gHandleTable, pdesk, pti, NULL, TYPE_INPUTCONTEXT, sizeof(IMC)); 1579 if (!pIMC) 1580 return NULL; 1581 1582 // Release the extra reference (UserCreateObject added 2 references). 1583 UserDereferenceObject(pIMC); 1584 ASSERT(pIMC->head.cLockObj == 1); 1585 1586 if (dwClientImcData) // Non-first time. 1587 { 1588 // Insert pIMC to the second position (non-default) of the list. 1589 pIMC->pImcNext = pti->spDefaultImc->pImcNext; 1590 pti->spDefaultImc->pImcNext = pIMC; 1591 } 1592 else // First time. It's the default IMC. 1593 { 1594 // Add the first one (default) to the list. 1595 UserAssignmentLock((PVOID*)&pti->spDefaultImc, pIMC); 1596 pIMC->pImcNext = NULL; 1597 ASSERT(pIMC->head.cLockObj == 2); // UserAssignmentUnlock'ed at ExitThreadCallback 1598 } 1599 1600 pIMC->dwClientImcData = dwClientImcData; // Set it. 1601 return pIMC; 1602 } 1603 1604 HIMC 1605 NTAPI 1606 NtUserCreateInputContext(ULONG_PTR dwClientImcData) 1607 { 1608 PIMC pIMC; 1609 HIMC ret = NULL; 1610 1611 UserEnterExclusive(); 1612 1613 if (!IS_IMM_MODE()) 1614 { 1615 ERR("!IS_IMM_MODE()\n"); 1616 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1617 goto Quit; 1618 } 1619 1620 if (!dwClientImcData) 1621 { 1622 EngSetLastError(ERROR_INVALID_PARAMETER); 1623 goto Quit; 1624 } 1625 1626 pIMC = UserCreateInputContext(dwClientImcData); 1627 if (pIMC) 1628 ret = UserHMGetHandle(pIMC); 1629 1630 Quit: 1631 UserLeave(); 1632 return ret; 1633 } 1634 1635 // Win: AssociateInputContextEx 1636 DWORD FASTCALL IntAssociateInputContextEx(PWND pWnd, PIMC pIMC, DWORD dwFlags) 1637 { 1638 DWORD ret = 0; 1639 PWINDOWLIST pwl; 1640 BOOL bIgnoreNullImc = (dwFlags & IACE_IGNORENOCONTEXT); 1641 PTHREADINFO pti = pWnd->head.pti; 1642 PWND pwndTarget, pwndFocus = pti->MessageQueue->spwndFocus; 1643 HWND *phwnd; 1644 HIMC hIMC; 1645 1646 if (dwFlags & IACE_DEFAULT) 1647 { 1648 pIMC = pti->spDefaultImc; 1649 } 1650 else 1651 { 1652 if (pIMC && pti != pIMC->head.pti) 1653 return 2; 1654 } 1655 1656 if (pWnd->head.pti->ppi != GetW32ThreadInfo()->ppi || 1657 (pIMC && pIMC->head.rpdesk != pWnd->head.rpdesk)) 1658 { 1659 return 2; 1660 } 1661 1662 if ((dwFlags & IACE_CHILDREN) && pWnd->spwndChild) 1663 { 1664 pwl = IntBuildHwndList(pWnd->spwndChild, IACE_CHILDREN | IACE_LIST, pti); 1665 if (pwl) 1666 { 1667 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1668 { 1669 pwndTarget = ValidateHwndNoErr(*phwnd); 1670 if (!pwndTarget) 1671 continue; 1672 1673 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1674 if (pwndTarget->hImc == hIMC || (bIgnoreNullImc && !pwndTarget->hImc)) 1675 continue; 1676 1677 IntAssociateInputContext(pwndTarget, pIMC); 1678 if (pwndTarget == pwndFocus) 1679 ret = 1; 1680 } 1681 1682 IntFreeHwndList(pwl); 1683 } 1684 } 1685 1686 if (!bIgnoreNullImc || pWnd->hImc) 1687 { 1688 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1689 if (pWnd->hImc != hIMC) 1690 { 1691 IntAssociateInputContext(pWnd, pIMC); 1692 if (pWnd == pwndFocus) 1693 ret = 1; 1694 } 1695 } 1696 1697 return ret; 1698 } 1699 1700 DWORD 1701 NTAPI 1702 NtUserAssociateInputContext(HWND hWnd, HIMC hIMC, DWORD dwFlags) 1703 { 1704 DWORD ret = 2; 1705 PWND pWnd; 1706 PIMC pIMC; 1707 1708 UserEnterExclusive(); 1709 1710 if (!IS_IMM_MODE()) 1711 { 1712 ERR("!IS_IMM_MODE()\n"); 1713 goto Quit; 1714 } 1715 1716 pWnd = ValidateHwndNoErr(hWnd); 1717 if (!pWnd) 1718 goto Quit; 1719 1720 pIMC = (hIMC ? UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT) : NULL); 1721 ret = IntAssociateInputContextEx(pWnd, pIMC, dwFlags); 1722 1723 Quit: 1724 UserLeave(); 1725 return ret; 1726 } 1727 1728 // Win: UpdateInputContext 1729 BOOL FASTCALL UserUpdateInputContext(PIMC pIMC, DWORD dwType, DWORD_PTR dwValue) 1730 { 1731 PTHREADINFO pti = GetW32ThreadInfo(); 1732 PTHREADINFO ptiIMC = pIMC->head.pti; 1733 1734 if (pti->ppi != ptiIMC->ppi) // Different process? 1735 return FALSE; 1736 1737 switch (dwType) 1738 { 1739 case UIC_CLIENTIMCDATA: 1740 if (pIMC->dwClientImcData) 1741 return FALSE; // Already set 1742 1743 pIMC->dwClientImcData = dwValue; 1744 break; 1745 1746 case UIC_IMEWINDOW: 1747 if (!ValidateHwndNoErr((HWND)dwValue)) 1748 return FALSE; // Invalid HWND 1749 1750 pIMC->hImeWnd = (HWND)dwValue; 1751 break; 1752 1753 default: 1754 return FALSE; 1755 } 1756 1757 return TRUE; 1758 } 1759 1760 BOOL 1761 NTAPI 1762 NtUserUpdateInputContext( 1763 HIMC hIMC, 1764 DWORD dwType, 1765 DWORD_PTR dwValue) 1766 { 1767 PIMC pIMC; 1768 BOOL ret = FALSE; 1769 1770 UserEnterExclusive(); 1771 1772 if (!IS_IMM_MODE()) 1773 { 1774 ERR("!IS_IMM_MODE()\n"); 1775 goto Quit; 1776 } 1777 1778 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1779 if (!pIMC) 1780 goto Quit; 1781 1782 ret = UserUpdateInputContext(pIMC, dwType, dwValue); 1783 1784 Quit: 1785 UserLeave(); 1786 return ret; 1787 } 1788 1789 DWORD_PTR 1790 NTAPI 1791 NtUserQueryInputContext(HIMC hIMC, DWORD dwType) 1792 { 1793 PIMC pIMC; 1794 PTHREADINFO ptiIMC; 1795 DWORD_PTR ret = 0; 1796 1797 UserEnterExclusive(); 1798 1799 if (!IS_IMM_MODE()) 1800 { 1801 ERR("!IS_IMM_MODE()\n"); 1802 goto Quit; 1803 } 1804 1805 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1806 if (!pIMC) 1807 goto Quit; 1808 1809 ptiIMC = pIMC->head.pti; 1810 1811 switch (dwType) 1812 { 1813 case QIC_INPUTPROCESSID: 1814 ret = (DWORD_PTR)PsGetThreadProcessId(ptiIMC->pEThread); 1815 break; 1816 1817 case QIC_INPUTTHREADID: 1818 ret = (DWORD_PTR)PsGetThreadId(ptiIMC->pEThread); 1819 break; 1820 1821 case QIC_DEFAULTWINDOWIME: 1822 if (ptiIMC->spwndDefaultIme) 1823 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spwndDefaultIme); 1824 break; 1825 1826 case QIC_DEFAULTIMC: 1827 if (ptiIMC->spDefaultImc) 1828 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spDefaultImc); 1829 break; 1830 } 1831 1832 Quit: 1833 UserLeave(); 1834 return ret; 1835 } 1836 1837 // Searchs a non-IME-related window of the same thread of pwndTarget, 1838 // other than pwndTarget, around pwndParent. Returns TRUE if found. 1839 // 1840 // Win: IsChildSameThread 1841 BOOL IntFindNonImeRelatedWndOfSameThread(PWND pwndParent, PWND pwndTarget) 1842 { 1843 PWND pwnd, pwndOwner, pwndNode; 1844 PTHREADINFO ptiTarget = pwndTarget->head.pti; 1845 1846 // For all the children of pwndParent, ... 1847 for (pwnd = pwndParent->spwndChild; pwnd; pwnd = pwnd->spwndNext) 1848 { 1849 if (pwnd == pwndTarget || pwnd->head.pti != ptiTarget || IS_WND_MENU(pwnd)) 1850 continue; 1851 1852 if (!IS_WND_CHILD(pwnd)) 1853 { 1854 // Check if any IME-like owner. 1855 BOOL bFound1 = FALSE; 1856 for (pwndOwner = pwnd; pwndOwner; pwndOwner = pwndOwner->spwndOwner) 1857 { 1858 if (IS_WND_IMELIKE(pwndOwner)) 1859 { 1860 bFound1 = TRUE; 1861 break; 1862 } 1863 } 1864 if (bFound1) 1865 continue; // Skip if any IME-like owner. 1866 } 1867 1868 pwndNode = pwnd; 1869 1870 if (IS_WND_CHILD(pwndNode)) 1871 { 1872 // Check if any same-thread IME-like ancestor. 1873 BOOL bFound2 = FALSE; 1874 for (; IS_WND_CHILD(pwndNode); pwndNode = pwndNode->spwndParent) 1875 { 1876 if (pwndNode->head.pti != ptiTarget) 1877 break; 1878 1879 if (IS_WND_IMELIKE(pwndNode)) 1880 { 1881 bFound2 = TRUE; 1882 break; 1883 } 1884 } 1885 if (bFound2) 1886 continue; 1887 // Now, pwndNode is non-child or non-same-thread window. 1888 } 1889 1890 if (!IS_WND_CHILD(pwndNode)) // pwndNode is non-child 1891 { 1892 // Check if any same-thread IME-like owner. 1893 BOOL bFound3 = FALSE; 1894 for (; pwndNode; pwndNode = pwndNode->spwndOwner) 1895 { 1896 if (pwndNode->head.pti != ptiTarget) 1897 break; 1898 1899 if (IS_WND_IMELIKE(pwndNode)) 1900 { 1901 bFound3 = TRUE; 1902 break; 1903 } 1904 } 1905 if (bFound3) 1906 continue; 1907 } 1908 1909 return TRUE; 1910 } 1911 1912 return FALSE; 1913 } 1914 1915 // Determines whether the target window needs the IME window. 1916 // Win: WantImeWindow(pwndParent, pwndTarget) 1917 BOOL FASTCALL IntWantImeWindow(PWND pwndTarget) 1918 { 1919 PDESKTOP rpdesk; 1920 PWINSTATION_OBJECT rpwinstaParent; 1921 PWND pwndNode, pwndParent = pwndTarget->spwndParent; 1922 1923 if (gptiCurrent->TIF_flags & TIF_DISABLEIME) 1924 return FALSE; 1925 1926 if (IS_WND_IMELIKE(pwndTarget)) 1927 return FALSE; 1928 1929 if (pwndTarget->fnid == FNID_DESKTOP || pwndTarget->fnid == FNID_MESSAGEWND) 1930 return FALSE; 1931 1932 if (pwndTarget->state & WNDS_SERVERSIDEWINDOWPROC) 1933 return FALSE; 1934 1935 rpdesk = pwndTarget->head.rpdesk; 1936 if (!rpdesk) 1937 return FALSE; 1938 1939 rpwinstaParent = rpdesk->rpwinstaParent; 1940 if (!rpwinstaParent || (rpwinstaParent->Flags & WSS_NOIO)) 1941 return FALSE; 1942 1943 for (pwndNode = pwndParent; pwndNode; pwndNode = pwndNode->spwndParent) 1944 { 1945 if (rpdesk != pwndNode->head.rpdesk) 1946 break; 1947 1948 if (pwndNode == rpdesk->spwndMessage) 1949 return FALSE; 1950 } 1951 1952 return TRUE; 1953 } 1954 1955 // Create the default IME window for the target window. 1956 // Win: xxxCreateDefaultImeWindow(pwndTarget, ATOM, hInst) 1957 PWND FASTCALL co_IntCreateDefaultImeWindow(PWND pwndTarget, HINSTANCE hInst) 1958 { 1959 LARGE_UNICODE_STRING WindowName; 1960 UNICODE_STRING ClassName; 1961 PWND pImeWnd; 1962 PIMEUI pimeui; 1963 CREATESTRUCTW Cs; 1964 USER_REFERENCE_ENTRY Ref; 1965 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1966 HANDLE pid = PsGetThreadProcessId(pti->pEThread); 1967 1968 if (!(pti->spDefaultImc) && pid == gpidLogon) 1969 UserCreateInputContext(0); 1970 1971 if (!(pti->spDefaultImc) || IS_WND_IMELIKE(pwndTarget) || !(pti->rpdesk->pheapDesktop)) 1972 return NULL; 1973 1974 if (IS_WND_CHILD(pwndTarget) && !(pwndTarget->style & WS_VISIBLE) && 1975 pwndTarget->spwndParent->head.pti->ppi != pti->ppi) 1976 { 1977 return NULL; 1978 } 1979 1980 RtlInitLargeUnicodeString(&WindowName, L"Default IME", 0); 1981 1982 ClassName.Buffer = (PWCH)(ULONG_PTR)gpsi->atomSysClass[ICLS_IME]; 1983 ClassName.Length = 0; 1984 ClassName.MaximumLength = 0; 1985 1986 UserRefObjectCo(pwndTarget, &Ref); 1987 1988 RtlZeroMemory(&Cs, sizeof(Cs)); 1989 Cs.style = WS_POPUP | WS_DISABLED; 1990 Cs.hInstance = hInst; 1991 Cs.hwndParent = UserHMGetHandle(pwndTarget); 1992 Cs.lpszName = WindowName.Buffer; 1993 Cs.lpszClass = ClassName.Buffer; 1994 1995 // NOTE: LARGE_UNICODE_STRING is compatible to LARGE_STRING. 1996 pImeWnd = co_UserCreateWindowEx(&Cs, &ClassName, (PLARGE_STRING)&WindowName, NULL, WINVER); 1997 if (pImeWnd) 1998 { 1999 pimeui = ((PIMEWND)pImeWnd)->pimeui; 2000 _SEH2_TRY 2001 { 2002 ProbeForWrite(pimeui, sizeof(IMEUI), 1); 2003 pimeui->fDefault = TRUE; 2004 if (IS_WND_CHILD(pwndTarget) && pwndTarget->spwndParent->head.pti != pti) 2005 pimeui->fChildThreadDef = TRUE; 2006 } 2007 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2008 { 2009 ERR("%p\n", pimeui); 2010 } 2011 _SEH2_END; 2012 } 2013 2014 UserDerefObjectCo(pwndTarget); 2015 return pImeWnd; 2016 } 2017 2018 // Determines whether the system can destroy the default IME window for the target child window. 2019 // Win: ImeCanDestroyDefIMEforChild 2020 BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget) 2021 { 2022 PWND pwndNode; 2023 PIMEUI pimeui; 2024 IMEUI SafeImeUI; 2025 2026 pimeui = ((PIMEWND)pImeWnd)->pimeui; 2027 if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1) 2028 return FALSE; 2029 2030 // Check IMEUI.fChildThreadDef 2031 _SEH2_TRY 2032 { 2033 ProbeForRead(pimeui, sizeof(IMEUI), 1); 2034 SafeImeUI = *pimeui; 2035 if (!SafeImeUI.fChildThreadDef) 2036 return FALSE; 2037 } 2038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2039 { 2040 ERR("%p\n", pimeui); 2041 } 2042 _SEH2_END; 2043 2044 // The parent of pwndTarget is NULL or of the same thread of pwndTarget? 2045 if (pwndTarget->spwndParent == NULL || 2046 pwndTarget->head.pti == pwndTarget->spwndParent->head.pti) 2047 { 2048 return FALSE; 2049 } 2050 2051 for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndParent) 2052 { 2053 if (pwndNode == pwndNode->head.rpdesk->pDeskInfo->spwnd) 2054 break; 2055 2056 if (IntFindNonImeRelatedWndOfSameThread(pwndNode->spwndParent, pwndTarget)) 2057 return FALSE; 2058 } 2059 2060 return TRUE; 2061 } 2062 2063 // Determines whether the system can destroy the default IME window for the non-child target window. 2064 // Win: ImeCanDestroyDefIME 2065 BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget) 2066 { 2067 PWND pwndNode; 2068 PIMEUI pimeui; 2069 IMEUI SafeImeUI; 2070 2071 pimeui = ((PIMEWND)pImeWnd)->pimeui; 2072 if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1) 2073 return FALSE; 2074 2075 // Check IMEUI.fDestroy 2076 _SEH2_TRY 2077 { 2078 ProbeForRead(pimeui, sizeof(IMEUI), 1); 2079 SafeImeUI = *pimeui; 2080 if (SafeImeUI.fDestroy) 2081 return FALSE; 2082 } 2083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2084 { 2085 ERR("%p\n", pimeui); 2086 } 2087 _SEH2_END; 2088 2089 // Any ancestor of pImeWnd is pwndTarget? 2090 if (pImeWnd->spwndOwner) 2091 { 2092 for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode = pwndNode->spwndOwner) 2093 { 2094 if (pwndNode == pwndTarget) 2095 break; 2096 } 2097 2098 if (!pwndNode) 2099 return FALSE; 2100 } 2101 2102 // Any ancestor of pwndTarget is IME-like? 2103 for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndOwner) 2104 { 2105 if (IS_WND_IMELIKE(pwndNode)) 2106 return FALSE; 2107 } 2108 2109 // Adjust the ordering and top-mode status 2110 IntImeSetFutureOwner(pImeWnd, pwndTarget); 2111 for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode = pwndNode->spwndNext) 2112 { 2113 if (pwndNode == pImeWnd) 2114 break; 2115 } 2116 if (pwndNode == pImeWnd) 2117 IntImeCheckTopmost(pImeWnd); 2118 2119 // Is the owner of pImeWnd NULL or pwndTarget? 2120 if (pImeWnd->spwndOwner && pwndTarget != pImeWnd->spwndOwner) 2121 return FALSE; 2122 2123 WndSetOwner(pImeWnd, NULL); 2124 return TRUE; 2125 } 2126 2127 // Update IMEUI.fShowStatus flags and Send the WM_IME_NOTIFY messages. 2128 // Win: xxxCheckImeShowStatus 2129 BOOL FASTCALL IntCheckImeShowStatus(PWND pwndIme, PTHREADINFO pti) 2130 { 2131 BOOL ret = FALSE, bDifferent; 2132 PWINDOWLIST pwl; 2133 HWND *phwnd; 2134 PWND pwndNode, pwndIMC; 2135 PTHREADINFO ptiCurrent = GetW32ThreadInfo(); 2136 PIMEUI pimeui; 2137 IMEUI SafeImeUI; 2138 2139 if (pwndIme->state2 & WNDS2_INDESTROY) 2140 return FALSE; 2141 2142 // Build a window list 2143 pwl = IntBuildHwndList(pwndIme->spwndParent->spwndChild, IACE_LIST, NULL); 2144 if (!pwl) 2145 return FALSE; 2146 2147 ret = TRUE; 2148 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 2149 { 2150 pwndNode = ValidateHwndNoErr(*phwnd); 2151 2152 if (!pwndNode || pwndIme == pwndNode) 2153 continue; 2154 2155 if (pwndNode->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME] || 2156 (pwndNode->state2 & WNDS2_INDESTROY)) 2157 { 2158 continue; 2159 } 2160 2161 pimeui = ((PIMEWND)pwndNode)->pimeui; 2162 if (!pimeui || pimeui == (PIMEUI)-1) 2163 continue; 2164 2165 if (pti && pti != pwndNode->head.pti) 2166 continue; 2167 2168 // Attach to the process if necessary 2169 bDifferent = FALSE; 2170 if (pwndNode->head.pti->ppi != ptiCurrent->ppi) 2171 { 2172 KeAttachProcess(&(pwndNode->head.pti->ppi->peProcess->Pcb)); 2173 bDifferent = TRUE; 2174 } 2175 2176 // Get pwndIMC and update IMEUI.fShowStatus flag 2177 _SEH2_TRY 2178 { 2179 ProbeForWrite(pimeui, sizeof(IMEUI), 1); 2180 SafeImeUI = *pimeui; 2181 if (SafeImeUI.fShowStatus) 2182 { 2183 pwndIMC = ValidateHwndNoErr(pimeui->hwndIMC); 2184 if (pwndIMC) 2185 pimeui->fShowStatus = FALSE; 2186 } 2187 else 2188 { 2189 pwndIMC = NULL; 2190 } 2191 } 2192 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2193 { 2194 ERR("%p\n", pimeui); 2195 pwndIMC = NULL; 2196 } 2197 _SEH2_END; 2198 2199 // Detach from the process if necessary 2200 if (bDifferent) 2201 KeDetachProcess(); 2202 2203 // Send the WM_IME_NOTIFY message 2204 if (pwndIMC && pwndIMC->head.pti && !(pwndIMC->head.pti->TIF_flags & TIF_INCLEANUP)) 2205 { 2206 HWND hImeWnd; 2207 USER_REFERENCE_ENTRY Ref; 2208 2209 UserRefObjectCo(pwndIMC, &Ref); 2210 2211 hImeWnd = UserHMGetHandle(pwndIMC); 2212 co_IntSendMessage(hImeWnd, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0); 2213 2214 UserDerefObjectCo(pwndIMC); 2215 } 2216 } 2217 2218 // Free the window list 2219 IntFreeHwndList(pwl); 2220 return ret; 2221 } 2222 2223 // Send a UI message. 2224 LRESULT FASTCALL 2225 IntSendMessageToUI(PTHREADINFO ptiIME, PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam) 2226 { 2227 PWND pwndUI; 2228 LRESULT ret = 0; 2229 IMEUI SafeImeUI; 2230 BOOL bDifferent = FALSE; 2231 USER_REFERENCE_ENTRY Ref; 2232 2233 // Attach to the process if necessary 2234 if (ptiIME != GetW32ThreadInfo()) 2235 { 2236 bDifferent = TRUE; 2237 KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb)); 2238 } 2239 2240 // Get the pwndUI 2241 _SEH2_TRY 2242 { 2243 ProbeForRead(pimeui, sizeof(IMEUI), 1); 2244 SafeImeUI = *pimeui; 2245 pwndUI = ValidateHwndNoErr(SafeImeUI.hwndUI); 2246 } 2247 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2248 { 2249 ERR("%p\n", pimeui); 2250 pwndUI = NULL; 2251 } 2252 _SEH2_END; 2253 2254 if (!pwndUI) 2255 goto Quit; 2256 2257 // Increment the recursion count of the IME procedure. 2258 // See also ImeWndProc_common of user32. 2259 _SEH2_TRY 2260 { 2261 ProbeForWrite(&pimeui->nCntInIMEProc, sizeof(LONG), 1); 2262 InterlockedIncrement(&pimeui->nCntInIMEProc); 2263 } 2264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2265 { 2266 ERR("%p\n", pimeui); 2267 _SEH2_YIELD(goto Quit); 2268 } 2269 _SEH2_END; 2270 2271 // Detach from the process if necessary 2272 if (bDifferent) 2273 KeDetachProcess(); 2274 2275 UserRefObjectCo(pwndUI, &Ref); 2276 ret = co_IntSendMessage(UserHMGetHandle(pwndUI), uMsg, wParam, lParam); 2277 UserDerefObjectCo(pwndUI); 2278 2279 // Attach to the process if necessary 2280 if (bDifferent) 2281 KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb)); 2282 2283 // Decrement the recursion count of the IME procedure 2284 _SEH2_TRY 2285 { 2286 ProbeForWrite(&pimeui->nCntInIMEProc, sizeof(LONG), 1); 2287 InterlockedDecrement(&pimeui->nCntInIMEProc); 2288 } 2289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2290 { 2291 ERR("%p\n", pimeui); 2292 _SEH2_YIELD(goto Quit); 2293 } 2294 _SEH2_END; 2295 2296 Quit: 2297 // Detach from the process if necessary 2298 if (bDifferent) 2299 KeDetachProcess(); 2300 2301 return ret; 2302 } 2303 2304 // Send the open status notification. 2305 // Win: xxxSendOpenStatusNotify 2306 VOID FASTCALL 2307 IntSendOpenStatusNotify(PTHREADINFO ptiIME, PIMEUI pimeui, PWND pWnd, BOOL bOpen) 2308 { 2309 WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW); 2310 PTHREADINFO ptiWnd = pWnd->head.pti; 2311 USER_REFERENCE_ENTRY Ref; 2312 2313 if (ptiWnd->dwExpWinVer >= WINVER_WINNT4 && pWnd->hImc) 2314 { 2315 UserRefObjectCo(pWnd, &Ref); 2316 co_IntSendMessage(UserHMGetHandle(pWnd), WM_IME_NOTIFY, wParam, 0); 2317 UserDerefObjectCo(pWnd); 2318 } 2319 else 2320 { 2321 IntSendMessageToUI(ptiIME, pimeui, WM_IME_NOTIFY, wParam, 0); 2322 } 2323 } 2324 2325 // Update the IME status and send a notification. 2326 VOID FASTCALL IntNotifyImeShowStatus(PWND pImeWnd) 2327 { 2328 PIMEUI pimeui; 2329 PWND pWnd; 2330 PTHREADINFO pti, ptiIME; 2331 BOOL bShow, bSendNotify = FALSE; 2332 IMEUI SafeImeUI; 2333 2334 if (!IS_IMM_MODE() || (pImeWnd->state2 & WNDS2_INDESTROY)) 2335 return; 2336 2337 pti = PsGetCurrentThreadWin32Thread(); 2338 ptiIME = pImeWnd->head.pti; 2339 2340 // Attach to the process if necessary 2341 if (pti != ptiIME) 2342 KeAttachProcess(&(ptiIME->ppi->peProcess->Pcb)); 2343 2344 // Get an IMEUI and check whether hwndIMC is valid and update fShowStatus 2345 _SEH2_TRY 2346 { 2347 ProbeForWrite(pImeWnd, sizeof(IMEWND), 1); 2348 pimeui = ((PIMEWND)pImeWnd)->pimeui; 2349 SafeImeUI = *pimeui; 2350 2351 bShow = (gfIMEShowStatus == TRUE) && SafeImeUI.fCtrlShowStatus; 2352 2353 pWnd = ValidateHwndNoErr(SafeImeUI.hwndIMC); 2354 if (!pWnd) 2355 pWnd = ptiIME->MessageQueue->spwndFocus; 2356 2357 if (pWnd) 2358 { 2359 bSendNotify = TRUE; 2360 pimeui->fShowStatus = bShow; 2361 } 2362 } 2363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2364 { 2365 ERR("%p, %p\n", pImeWnd, pimeui); 2366 2367 if (pti != ptiIME) 2368 KeDetachProcess(); 2369 2370 _SEH2_YIELD(return); 2371 } 2372 _SEH2_END; 2373 2374 // Detach from the process if necessary 2375 if (pti != ptiIME) 2376 KeDetachProcess(); 2377 2378 if (bSendNotify) 2379 IntSendOpenStatusNotify(ptiIME, &SafeImeUI, pWnd, bShow); 2380 2381 if (!(pImeWnd->state2 & WNDS2_INDESTROY)) 2382 IntCheckImeShowStatus(pImeWnd, NULL); 2383 } 2384 2385 // Win: xxxBroadcastImeShowStatusChange 2386 BOOL FASTCALL IntBroadcastImeShowStatusChange(PWND pImeWnd, BOOL bShow) 2387 { 2388 if (gfIMEShowStatus == bShow || !IS_IMM_MODE()) 2389 return TRUE; 2390 2391 gfIMEShowStatus = bShow; 2392 IntNotifyImeShowStatus(pImeWnd); 2393 return TRUE; 2394 } 2395 2396 /* Win: xxxCheckImeShowStatusInThread */ 2397 VOID FASTCALL IntCheckImeShowStatusInThread(PWND pImeWnd) 2398 { 2399 if (IS_IMM_MODE() && !(pImeWnd->state2 & WNDS2_INDESTROY)) 2400 IntCheckImeShowStatus(pImeWnd, pImeWnd->head.pti); 2401 } 2402 2403 /* EOF */ 2404