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 DBG_DEFAULT_CHANNEL(UserMisc); 12 13 #define INVALID_THREAD_ID ((ULONG)-1) 14 #define INVALID_HOTKEY ((UINT)-1) 15 #define MOD_KEYS (MOD_CONTROL | MOD_SHIFT | MOD_ALT | MOD_WIN) 16 #define MOD_LEFT_RIGHT (MOD_LEFT | MOD_RIGHT) 17 18 #define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) 19 #define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT) 20 #define LANGID_KOREAN MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN) 21 #define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) 22 #define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 23 24 #define IS_WND_IMELIKE(pwnd) \ 25 (((pwnd)->pcls->style & CS_IME) || \ 26 ((pwnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])) 27 28 // The special virtual keys for Japanese: Used for key states. 29 // https://www.kthree.co.jp/kihelp/index.html?page=app/vkey&type=html 30 #define VK_DBE_ALPHANUMERIC 0xF0 31 #define VK_DBE_KATAKANA 0xF1 32 #define VK_DBE_HIRAGANA 0xF2 33 #define VK_DBE_SBCSCHAR 0xF3 34 #define VK_DBE_DBCSCHAR 0xF4 35 #define VK_DBE_ROMAN 0xF5 36 #define VK_DBE_NOROMAN 0xF6 37 #define VK_DBE_ENTERWORDREGISTERMODE 0xF7 38 #define VK_DBE_ENTERCONFIGMODE 0xF8 39 #define VK_DBE_FLUSHSTRING 0xF9 40 #define VK_DBE_CODEINPUT 0xFA 41 #define VK_DBE_NOCODEINPUT 0xFB 42 #define VK_DBE_DETERINESTRING 0xFC 43 #define VK_DBE_ENTERDLGCONVERSIONMODE 0xFD 44 45 HIMC ghIMC = NULL; 46 BOOL gfImeOpen = (BOOL)-1; 47 DWORD gdwImeConversion = (DWORD)-1; 48 49 typedef struct tagIMEHOTKEY 50 { 51 struct tagIMEHOTKEY *pNext; 52 DWORD dwHotKeyId; 53 UINT uVirtualKey; 54 UINT uModifiers; 55 HKL hKL; 56 } IMEHOTKEY, *PIMEHOTKEY; 57 58 PIMEHOTKEY gpImeHotKeyList = NULL; 59 LCID glcid = 0; 60 61 DWORD FASTCALL IntGetImeCompatFlags(PTHREADINFO pti) 62 { 63 if (!pti) 64 pti = PsGetCurrentThreadWin32Thread(); 65 66 return pti->ppi->dwImeCompatFlags; 67 } 68 69 UINT FASTCALL IntGetImeHotKeyLanguageScore(HKL hKL, LANGID HotKeyLangId) 70 { 71 LCID lcid; 72 73 if (HotKeyLangId == LANGID_NEUTRAL || HotKeyLangId == LOWORD(hKL)) 74 return 3; 75 76 _SEH2_TRY 77 { 78 lcid = NtCurrentTeb()->CurrentLocale; 79 } 80 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 81 { 82 lcid = MAKELCID(LANGID_NEUTRAL, SORT_DEFAULT); 83 } 84 _SEH2_END; 85 86 if (HotKeyLangId == LANGIDFROMLCID(lcid)) 87 return 2; 88 89 if (glcid == 0) 90 ZwQueryDefaultLocale(FALSE, &glcid); 91 92 if (HotKeyLangId == LANGIDFROMLCID(glcid)) 93 return 1; 94 95 return 0; 96 } 97 98 HKL FASTCALL IntGetActiveKeyboardLayout(VOID) 99 { 100 PTHREADINFO pti; 101 102 if (gpqForeground && gpqForeground->spwndActive) 103 { 104 pti = gpqForeground->spwndActive->head.pti; 105 if (pti && pti->KeyboardLayout) 106 return pti->KeyboardLayout->hkl; 107 } 108 109 return UserGetKeyboardLayout(0); 110 } 111 112 static LANGID FASTCALL IntGetImeHotKeyLangId(DWORD dwHotKeyId) 113 { 114 #define IME_CHOTKEY 0x10 115 #define IME_JHOTKEY 0x30 116 #define IME_KHOTKEY 0x50 117 #define IME_THOTKEY 0x70 118 #define IME_XHOTKEY 0x90 119 static const LANGID s_array[] = 120 { 121 /* 0x00 */ (WORD)-1, 122 /* 0x10 */ LANGID_CHINESE_SIMPLIFIED, 123 /* 0x20 */ LANGID_CHINESE_SIMPLIFIED, 124 /* 0x30 */ LANGID_JAPANESE, 125 /* 0x40 */ LANGID_JAPANESE, 126 /* 0x50 */ LANGID_KOREAN, 127 /* 0x60 */ LANGID_KOREAN, 128 /* 0x70 */ LANGID_CHINESE_TRADITIONAL, 129 /* 0x80 */ LANGID_CHINESE_TRADITIONAL 130 }; 131 132 if (IME_CHOTKEY <= dwHotKeyId && dwHotKeyId < IME_XHOTKEY) 133 return s_array[(dwHotKeyId & 0xF0) >> 4]; 134 return LANGID_NEUTRAL; 135 } 136 137 // Win: AddImeHotKey 138 static VOID FASTCALL IntAddImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 139 { 140 PIMEHOTKEY pNode; 141 142 if (!*ppList) 143 { 144 *ppList = pHotKey; 145 return; 146 } 147 148 for (pNode = *ppList; pNode; pNode = pNode->pNext) 149 { 150 if (!pNode->pNext) 151 { 152 pNode->pNext = pHotKey; 153 return; 154 } 155 } 156 } 157 158 static PIMEHOTKEY FASTCALL IntGetImeHotKeyById(PIMEHOTKEY pList, DWORD dwHotKeyId) 159 { 160 PIMEHOTKEY pNode; 161 for (pNode = pList; pNode; pNode = pNode->pNext) 162 { 163 if (pNode->dwHotKeyId == dwHotKeyId) 164 return pNode; 165 } 166 return NULL; 167 } 168 169 static PIMEHOTKEY APIENTRY 170 IntGetImeHotKeyByKeyAndLang(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, 171 UINT uVirtualKey, LANGID TargetLangId) 172 { 173 PIMEHOTKEY pNode; 174 LANGID LangID; 175 UINT uModifiers; 176 177 for (pNode = pList; pNode; pNode = pNode->pNext) 178 { 179 if (pNode->uVirtualKey != uVirtualKey) 180 continue; 181 182 LangID = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 183 if (LangID != TargetLangId) 184 continue; 185 186 uModifiers = pNode->uModifiers; 187 if (uModifiers & MOD_IGNORE_ALL_MODIFIER) 188 return pNode; 189 190 if ((uModifiers & MOD_KEYS) != uModKeys) 191 continue; 192 193 if ((uModifiers & uLeftRight) || (uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 194 return pNode; 195 } 196 197 return NULL; 198 } 199 200 static VOID FASTCALL IntDeleteImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 201 { 202 PIMEHOTKEY pNode; 203 204 if (*ppList == pHotKey) 205 { 206 *ppList = pHotKey->pNext; 207 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 208 return; 209 } 210 211 for (pNode = *ppList; pNode; pNode = pNode->pNext) 212 { 213 if (pNode->pNext == pHotKey) 214 { 215 pNode->pNext = pHotKey->pNext; 216 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 217 return; 218 } 219 } 220 } 221 222 PIMEHOTKEY 223 IntGetImeHotKeyByKey(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, UINT uVirtualKey) 224 { 225 PIMEHOTKEY pNode, ret = NULL; 226 PTHREADINFO pti = GetW32ThreadInfo(); 227 LANGID LangId; 228 HKL hKL = IntGetActiveKeyboardLayout(); 229 BOOL fKorean = (PRIMARYLANGID(LOWORD(hKL)) == LANG_KOREAN); 230 UINT nScore, nMaxScore = 0; 231 232 for (pNode = pList; pNode; pNode = pNode->pNext) 233 { 234 if (pNode->uVirtualKey != uVirtualKey) 235 continue; 236 237 if ((pNode->uModifiers & MOD_IGNORE_ALL_MODIFIER)) 238 { 239 ; 240 } 241 else if ((pNode->uModifiers & MOD_KEYS) != uModKeys) 242 { 243 continue; 244 } 245 else if ((pNode->uModifiers & uLeftRight) || 246 (pNode->uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 247 { 248 ; 249 } 250 else 251 { 252 continue; 253 } 254 255 LangId = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 256 nScore = IntGetImeHotKeyLanguageScore(hKL, LangId); 257 if (nScore >= 3) 258 return pNode; 259 260 if (fKorean) 261 continue; 262 263 if (nScore == 0) 264 { 265 if (pNode->dwHotKeyId == IME_CHOTKEY_IME_NONIME_TOGGLE || 266 pNode->dwHotKeyId == IME_THOTKEY_IME_NONIME_TOGGLE) 267 { 268 if (LOWORD(pti->hklPrev) == LangId) 269 return pNode; 270 } 271 } 272 273 if (nMaxScore < nScore) 274 { 275 nMaxScore = nScore; 276 ret = pNode; 277 } 278 } 279 280 return ret; 281 } 282 283 // Win: CheckImeHotKey 284 PIMEHOTKEY IntCheckImeHotKey(PUSER_MESSAGE_QUEUE MessageQueue, UINT uVirtualKey, LPARAM lParam) 285 { 286 PIMEHOTKEY pHotKey; 287 UINT uModifiers; 288 BOOL bKeyUp = (lParam & 0x80000000); 289 const BYTE *KeyState = MessageQueue->afKeyState; 290 static UINT s_uKeyUpVKey = 0; 291 292 if (bKeyUp) 293 { 294 if (s_uKeyUpVKey != uVirtualKey) 295 { 296 s_uKeyUpVKey = 0; 297 return NULL; 298 } 299 300 s_uKeyUpVKey = 0; 301 } 302 303 uModifiers = 0; 304 if (IS_KEY_DOWN(KeyState, VK_LSHIFT)) uModifiers |= (MOD_SHIFT | MOD_LEFT); 305 if (IS_KEY_DOWN(KeyState, VK_RSHIFT)) uModifiers |= (MOD_SHIFT | MOD_RIGHT); 306 if (IS_KEY_DOWN(KeyState, VK_LCONTROL)) uModifiers |= (MOD_CONTROL | MOD_LEFT); 307 if (IS_KEY_DOWN(KeyState, VK_RCONTROL)) uModifiers |= (MOD_CONTROL | MOD_RIGHT); 308 if (IS_KEY_DOWN(KeyState, VK_LMENU)) uModifiers |= (MOD_ALT | MOD_LEFT); 309 if (IS_KEY_DOWN(KeyState, VK_RMENU)) uModifiers |= (MOD_ALT | MOD_RIGHT); 310 311 pHotKey = IntGetImeHotKeyByKey(gpImeHotKeyList, 312 (uModifiers & MOD_KEYS), 313 (uModifiers & MOD_LEFT_RIGHT), 314 uVirtualKey); 315 if (pHotKey) 316 { 317 if (bKeyUp) 318 { 319 if (pHotKey->uModifiers & MOD_ON_KEYUP) 320 return pHotKey; 321 } 322 else 323 { 324 if (pHotKey->uModifiers & MOD_ON_KEYUP) 325 s_uKeyUpVKey = uVirtualKey; 326 else 327 return pHotKey; 328 } 329 } 330 331 return NULL; 332 } 333 334 // Win: FreeImeHotKeys 335 VOID FASTCALL IntFreeImeHotKeys(VOID) 336 { 337 PIMEHOTKEY pNode, pNext; 338 for (pNode = gpImeHotKeyList; pNode; pNode = pNext) 339 { 340 pNext = pNode->pNext; 341 ExFreePoolWithTag(pNode, USERTAG_IMEHOTKEY); 342 } 343 gpImeHotKeyList = NULL; 344 } 345 346 // Win: SetImeHotKey 347 static BOOL APIENTRY 348 IntSetImeHotKey(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL hKL, DWORD dwAction) 349 { 350 PIMEHOTKEY pNode; 351 LANGID LangId; 352 353 switch (dwAction) 354 { 355 case SETIMEHOTKEY_DELETE: 356 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 357 if (!pNode) 358 { 359 ERR("dwHotKeyId: 0x%lX\n", dwHotKeyId); 360 return FALSE; 361 } 362 363 IntDeleteImeHotKey(&gpImeHotKeyList, pNode); 364 return TRUE; 365 366 case SETIMEHOTKEY_ADD: 367 if (uVirtualKey == VK_PACKET) 368 return FALSE; 369 370 LangId = IntGetImeHotKeyLangId(dwHotKeyId); 371 if (LangId == LANGID_KOREAN) 372 return FALSE; 373 374 pNode = IntGetImeHotKeyByKeyAndLang(gpImeHotKeyList, 375 (uModifiers & MOD_KEYS), 376 (uModifiers & MOD_LEFT_RIGHT), 377 uVirtualKey, LangId); 378 if (!pNode) 379 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 380 381 if (pNode) 382 { 383 pNode->uModifiers = uModifiers; 384 pNode->uVirtualKey = uVirtualKey; 385 pNode->hKL = hKL; 386 return TRUE; 387 } 388 389 pNode = ExAllocatePoolWithTag(PagedPool, sizeof(IMEHOTKEY), USERTAG_IMEHOTKEY); 390 if (!pNode) 391 return FALSE; 392 393 pNode->pNext = NULL; 394 pNode->dwHotKeyId = dwHotKeyId; 395 pNode->uModifiers = uModifiers; 396 pNode->uVirtualKey = uVirtualKey; 397 pNode->hKL = hKL; 398 IntAddImeHotKey(&gpImeHotKeyList, pNode); 399 return TRUE; 400 401 case SETIMEHOTKEY_DELETEALL: 402 IntFreeImeHotKeys(); 403 return TRUE; 404 405 default: 406 return FALSE; 407 } 408 } 409 410 BOOL NTAPI 411 NtUserGetImeHotKey(DWORD dwHotKeyId, LPUINT lpuModifiers, LPUINT lpuVirtualKey, LPHKL lphKL) 412 { 413 PIMEHOTKEY pNode = NULL; 414 415 UserEnterExclusive(); 416 417 _SEH2_TRY 418 { 419 ProbeForWrite(lpuModifiers, sizeof(UINT), 1); 420 ProbeForWrite(lpuVirtualKey, sizeof(UINT), 1); 421 if (lphKL) 422 ProbeForWrite(lphKL, sizeof(HKL), 1); 423 } 424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 425 { 426 goto Quit; 427 } 428 _SEH2_END; 429 430 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 431 if (!pNode) 432 goto Quit; 433 434 _SEH2_TRY 435 { 436 *lpuModifiers = pNode->uModifiers; 437 *lpuVirtualKey = pNode->uVirtualKey; 438 if (lphKL) 439 *lphKL = pNode->hKL; 440 } 441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 442 { 443 pNode = NULL; 444 } 445 _SEH2_END; 446 447 Quit: 448 UserLeave(); 449 return !!pNode; 450 } 451 452 BOOL 453 NTAPI 454 NtUserSetImeHotKey( 455 DWORD dwHotKeyId, 456 UINT uModifiers, 457 UINT uVirtualKey, 458 HKL hKL, 459 DWORD dwAction) 460 { 461 BOOL ret; 462 UserEnterExclusive(); 463 ret = IntSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, dwAction); 464 UserLeave(); 465 return ret; 466 } 467 468 DWORD 469 NTAPI 470 NtUserCheckImeHotKey(UINT uVirtualKey, LPARAM lParam) 471 { 472 PIMEHOTKEY pNode; 473 DWORD ret = INVALID_HOTKEY; 474 475 UserEnterExclusive(); 476 477 if (!gpqForeground || !IS_IMM_MODE()) 478 goto Quit; 479 480 pNode = IntCheckImeHotKey(gpqForeground, uVirtualKey, lParam); 481 if (pNode) 482 ret = pNode->dwHotKeyId; 483 484 Quit: 485 UserLeave(); 486 return ret; 487 } 488 489 PWND FASTCALL IntGetTopLevelWindow(PWND pwnd) 490 { 491 if (!pwnd) 492 return NULL; 493 494 while (pwnd->style & WS_CHILD) 495 pwnd = pwnd->spwndParent; 496 497 return pwnd; 498 } 499 500 // Win: AssociateInputContext 501 HIMC FASTCALL IntAssociateInputContext(PWND pWnd, PIMC pImc) 502 { 503 HIMC hOldImc = pWnd->hImc; 504 pWnd->hImc = (pImc ? UserHMGetHandle(pImc) : NULL); 505 return hOldImc; 506 } 507 508 DWORD 509 NTAPI 510 NtUserSetThreadLayoutHandles(HKL hNewKL, HKL hOldKL) 511 { 512 PTHREADINFO pti; 513 PKL pOldKL, pNewKL; 514 515 UserEnterExclusive(); 516 517 pti = GetW32ThreadInfo(); 518 pOldKL = pti->KeyboardLayout; 519 if (pOldKL && pOldKL->hkl != hOldKL) 520 goto Quit; 521 522 pNewKL = UserHklToKbl(hNewKL); 523 if (!pNewKL) 524 goto Quit; 525 526 if (IS_IME_HKL(hNewKL) != IS_IME_HKL(hOldKL)) 527 pti->hklPrev = hOldKL; 528 529 pti->KeyboardLayout = pNewKL; 530 531 Quit: 532 UserLeave(); 533 return 0; 534 } 535 536 // Win: BuildHimcList 537 DWORD FASTCALL UserBuildHimcList(PTHREADINFO pti, DWORD dwCount, HIMC *phList) 538 { 539 PIMC pIMC; 540 DWORD dwRealCount = 0; 541 542 if (pti) 543 { 544 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 545 { 546 if (dwRealCount < dwCount) 547 phList[dwRealCount] = UserHMGetHandle(pIMC); 548 549 ++dwRealCount; 550 } 551 } 552 else 553 { 554 for (pti = GetW32ThreadInfo()->ppi->ptiList; pti; pti = pti->ptiSibling) 555 { 556 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 557 { 558 if (dwRealCount < dwCount) 559 phList[dwRealCount] = UserHMGetHandle(pIMC); 560 561 ++dwRealCount; 562 } 563 } 564 } 565 566 return dwRealCount; 567 } 568 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 = GetW32ThreadInfo(); 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 goto Quit; 729 } 730 _SEH2_END; 731 732 if (dwCount < dwRealCount) 733 ret = STATUS_BUFFER_TOO_SMALL; 734 else 735 ret = STATUS_SUCCESS; 736 737 Quit: 738 UserLeave(); 739 return ret; 740 } 741 742 static VOID FASTCALL UserSetImeConversionKeyState(PTHREADINFO pti, DWORD dwConversion) 743 { 744 HKL hKL; 745 LANGID LangID; 746 LPBYTE KeyState; 747 BOOL bAlphaNumeric, bKatakana, bHiragana, bFullShape, bRoman, bCharCode; 748 749 if (!pti->KeyboardLayout) 750 return; 751 752 hKL = pti->KeyboardLayout->hkl; 753 LangID = LOWORD(hKL); 754 KeyState = pti->MessageQueue->afKeyState; 755 756 switch (PRIMARYLANGID(LangID)) 757 { 758 case LANG_JAPANESE: 759 bAlphaNumeric = !(dwConversion & IME_CMODE_NATIVE); 760 bKatakana = !bAlphaNumeric && (dwConversion & IME_CMODE_KATAKANA); 761 bHiragana = !bAlphaNumeric && !(dwConversion & IME_CMODE_KATAKANA); 762 SET_KEY_DOWN(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 763 SET_KEY_LOCKED(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 764 SET_KEY_DOWN(KeyState, VK_DBE_HIRAGANA, bHiragana); 765 SET_KEY_LOCKED(KeyState, VK_DBE_HIRAGANA, bHiragana); 766 SET_KEY_DOWN(KeyState, VK_DBE_KATAKANA, bKatakana); 767 SET_KEY_LOCKED(KeyState, VK_DBE_KATAKANA, bKatakana); 768 769 bFullShape = (dwConversion & IME_CMODE_FULLSHAPE); 770 SET_KEY_DOWN(KeyState, VK_DBE_DBCSCHAR, bFullShape); 771 SET_KEY_LOCKED(KeyState, VK_DBE_DBCSCHAR, bFullShape); 772 SET_KEY_DOWN(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 773 SET_KEY_LOCKED(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 774 775 bRoman = (dwConversion & IME_CMODE_ROMAN); 776 SET_KEY_DOWN(KeyState, VK_DBE_ROMAN, bRoman); 777 SET_KEY_LOCKED(KeyState, VK_DBE_ROMAN, bRoman); 778 SET_KEY_DOWN(KeyState, VK_DBE_NOROMAN, !bRoman); 779 SET_KEY_LOCKED(KeyState, VK_DBE_NOROMAN, !bRoman); 780 781 bCharCode = (dwConversion & IME_CMODE_CHARCODE); 782 SET_KEY_DOWN(KeyState, VK_DBE_CODEINPUT, bCharCode); 783 SET_KEY_LOCKED(KeyState, VK_DBE_CODEINPUT, bCharCode); 784 SET_KEY_DOWN(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 785 SET_KEY_LOCKED(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 786 break; 787 788 case LANG_KOREAN: 789 SET_KEY_LOCKED(KeyState, VK_HANGUL, (dwConversion & IME_CMODE_NATIVE)); 790 SET_KEY_LOCKED(KeyState, VK_JUNJA, (dwConversion & IME_CMODE_FULLSHAPE)); 791 SET_KEY_LOCKED(KeyState, VK_HANJA, (dwConversion & IME_CMODE_HANJACONVERT)); 792 break; 793 794 default: 795 break; 796 } 797 } 798 799 DWORD 800 NTAPI 801 NtUserNotifyIMEStatus(HWND hwnd, BOOL fOpen, DWORD dwConversion) 802 { 803 PWND pwnd; 804 PTHREADINFO pti; 805 HKL hKL; 806 807 UserEnterExclusive(); 808 809 if (!IS_IMM_MODE()) 810 { 811 ERR("!IS_IMM_MODE()\n"); 812 goto Quit; 813 } 814 815 pwnd = ValidateHwndNoErr(hwnd); 816 if (!pwnd) 817 goto Quit; 818 819 pti = pwnd->head.pti; 820 if (!pti || !gptiForeground) 821 goto Quit; 822 if (pti != gptiForeground && pti->MessageQueue != gptiForeground->MessageQueue) 823 goto Quit; 824 if (ghIMC == pwnd->hImc && gfImeOpen == !!fOpen && gdwImeConversion == dwConversion) 825 goto Quit; 826 827 ghIMC = pwnd->hImc; 828 if (ghIMC) 829 { 830 gfImeOpen = !!fOpen; 831 gdwImeConversion = dwConversion; 832 UserSetImeConversionKeyState(pti, (fOpen ? dwConversion : IME_CMODE_ALPHANUMERIC)); 833 } 834 835 if (ISITHOOKED(WH_SHELL)) 836 { 837 hKL = (pti->KeyboardLayout ? pti->KeyboardLayout->hkl : NULL); 838 co_HOOK_CallHooks(WH_SHELL, HSHELL_LANGUAGE, (WPARAM)hwnd, (LPARAM)hKL); 839 } 840 841 // TODO: 842 843 Quit: 844 UserLeave(); 845 return 0; 846 } 847 848 BOOL 849 NTAPI 850 NtUserDisableThreadIme( 851 DWORD dwThreadID) 852 { 853 PTHREADINFO pti, ptiCurrent; 854 PPROCESSINFO ppi; 855 BOOL ret = FALSE; 856 857 UserEnterExclusive(); 858 859 if (!IS_IMM_MODE()) 860 { 861 ERR("!IS_IMM_MODE()\n"); 862 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 863 goto Quit; 864 } 865 866 ptiCurrent = GetW32ThreadInfo(); 867 868 if (dwThreadID == INVALID_THREAD_ID) 869 { 870 ppi = ptiCurrent->ppi; 871 ppi->W32PF_flags |= W32PF_DISABLEIME; 872 873 Retry: 874 for (pti = ppi->ptiList; pti; pti = pti->ptiSibling) 875 { 876 pti->TIF_flags |= TIF_DISABLEIME; 877 878 if (pti->spwndDefaultIme) 879 { 880 co_UserDestroyWindow(pti->spwndDefaultIme); 881 pti->spwndDefaultIme = NULL; 882 goto Retry; /* The contents of ppi->ptiList may be changed. */ 883 } 884 } 885 } 886 else 887 { 888 if (dwThreadID == 0) 889 { 890 pti = ptiCurrent; 891 } 892 else 893 { 894 pti = IntTID2PTI(UlongToHandle(dwThreadID)); 895 896 /* The thread needs to reside in the current process. */ 897 if (!pti || pti->ppi != ptiCurrent->ppi) 898 goto Quit; 899 } 900 901 pti->TIF_flags |= TIF_DISABLEIME; 902 903 if (pti->spwndDefaultIme) 904 { 905 co_UserDestroyWindow(pti->spwndDefaultIme); 906 pti->spwndDefaultIme = NULL; 907 } 908 } 909 910 ret = TRUE; 911 912 Quit: 913 UserLeave(); 914 return ret; 915 } 916 917 DWORD 918 NTAPI 919 NtUserGetAppImeLevel(HWND hWnd) 920 { 921 DWORD ret = 0; 922 PWND pWnd; 923 PTHREADINFO pti; 924 925 UserEnterShared(); 926 927 pWnd = ValidateHwndNoErr(hWnd); 928 if (!pWnd) 929 goto Quit; 930 931 if (!IS_IMM_MODE()) 932 { 933 ERR("!IS_IMM_MODE()\n"); 934 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 935 goto Quit; 936 } 937 938 pti = PsGetCurrentThreadWin32Thread(); 939 if (pWnd->head.pti->ppi == pti->ppi) 940 ret = (DWORD)(ULONG_PTR)UserGetProp(pWnd, AtomImeLevel, TRUE); 941 942 Quit: 943 UserLeave(); 944 return ret; 945 } 946 947 // Win: GetImeInfoEx 948 BOOL FASTCALL UserGetImeInfoEx(LPVOID pUnknown, PIMEINFOEX pInfoEx, IMEINFOEXCLASS SearchType) 949 { 950 PKL pkl, pklHead; 951 952 if (!gspklBaseLayout) 953 return FALSE; 954 955 pkl = pklHead = gspklBaseLayout; 956 957 /* Find the matching entry from the list and get info */ 958 if (SearchType == ImeInfoExKeyboardLayout) 959 { 960 do 961 { 962 if (pInfoEx->hkl == pkl->hkl) 963 { 964 if (!pkl->piiex) 965 break; 966 967 *pInfoEx = *pkl->piiex; 968 return TRUE; 969 } 970 971 pkl = pkl->pklNext; 972 } while (pkl != pklHead); 973 } 974 else if (SearchType == ImeInfoExImeFileName) 975 { 976 do 977 { 978 if (pkl->piiex && 979 _wcsnicmp(pkl->piiex->wszImeFile, pInfoEx->wszImeFile, 980 RTL_NUMBER_OF(pkl->piiex->wszImeFile)) == 0) 981 { 982 *pInfoEx = *pkl->piiex; 983 return TRUE; 984 } 985 986 pkl = pkl->pklNext; 987 } while (pkl != pklHead); 988 } 989 else 990 { 991 /* Do nothing */ 992 } 993 994 return FALSE; 995 } 996 997 BOOL 998 NTAPI 999 NtUserGetImeInfoEx( 1000 PIMEINFOEX pImeInfoEx, 1001 IMEINFOEXCLASS SearchType) 1002 { 1003 IMEINFOEX ImeInfoEx; 1004 BOOL ret = FALSE; 1005 1006 UserEnterShared(); 1007 1008 if (!IS_IMM_MODE()) 1009 { 1010 ERR("!IS_IMM_MODE()\n"); 1011 goto Quit; 1012 } 1013 1014 _SEH2_TRY 1015 { 1016 ProbeForWrite(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1017 ImeInfoEx = *pImeInfoEx; 1018 } 1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1020 { 1021 goto Quit; 1022 } 1023 _SEH2_END; 1024 1025 ret = UserGetImeInfoEx(NULL, &ImeInfoEx, SearchType); 1026 if (!ret) 1027 goto Quit; 1028 1029 _SEH2_TRY 1030 { 1031 *pImeInfoEx = ImeInfoEx; 1032 } 1033 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1034 { 1035 ret = FALSE; 1036 } 1037 _SEH2_END; 1038 1039 Quit: 1040 UserLeave(); 1041 return ret; 1042 } 1043 1044 BOOL 1045 NTAPI 1046 NtUserSetAppImeLevel(HWND hWnd, DWORD dwLevel) 1047 { 1048 BOOL ret = FALSE; 1049 PWND pWnd; 1050 PTHREADINFO pti; 1051 1052 UserEnterExclusive(); 1053 1054 if (!IS_IMM_MODE()) 1055 { 1056 ERR("!IS_IMM_MODE()\n"); 1057 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1058 goto Quit; 1059 } 1060 1061 pWnd = ValidateHwndNoErr(hWnd); 1062 if (!pWnd) 1063 goto Quit; 1064 1065 pti = PsGetCurrentThreadWin32Thread(); 1066 if (pWnd->head.pti->ppi == pti->ppi) 1067 ret = UserSetProp(pWnd, AtomImeLevel, (HANDLE)(ULONG_PTR)dwLevel, TRUE); 1068 1069 Quit: 1070 UserLeave(); 1071 return ret; 1072 } 1073 1074 // Win: SetImeInfoEx 1075 BOOL FASTCALL UserSetImeInfoEx(LPVOID pUnknown, PIMEINFOEX pImeInfoEx) 1076 { 1077 PKL pklHead, pkl; 1078 1079 pkl = pklHead = gspklBaseLayout; 1080 1081 do 1082 { 1083 if (pkl->hkl != pImeInfoEx->hkl) 1084 { 1085 pkl = pkl->pklNext; 1086 continue; 1087 } 1088 1089 if (!pkl->piiex) 1090 return FALSE; 1091 1092 if (!pkl->piiex->fLoadFlag) 1093 *pkl->piiex = *pImeInfoEx; 1094 1095 return TRUE; 1096 } while (pkl != pklHead); 1097 1098 return FALSE; 1099 } 1100 1101 BOOL 1102 NTAPI 1103 NtUserSetImeInfoEx(PIMEINFOEX pImeInfoEx) 1104 { 1105 BOOL ret = FALSE; 1106 IMEINFOEX ImeInfoEx; 1107 1108 UserEnterExclusive(); 1109 1110 if (!IS_IMM_MODE()) 1111 { 1112 ERR("!IS_IMM_MODE()\n"); 1113 goto Quit; 1114 } 1115 1116 _SEH2_TRY 1117 { 1118 ProbeForRead(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1119 ImeInfoEx = *pImeInfoEx; 1120 } 1121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1122 { 1123 goto Quit; 1124 } 1125 _SEH2_END; 1126 1127 ret = UserSetImeInfoEx(NULL, &ImeInfoEx); 1128 1129 Quit: 1130 UserLeave(); 1131 return ret; 1132 } 1133 1134 BOOL NTAPI 1135 NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus) 1136 { 1137 BOOL ret = FALSE; 1138 PWND pImeWnd, pwndFocus, pwndTopLevel, pwnd, pwndActive; 1139 PTHREADINFO ptiIme; 1140 1141 UserEnterExclusive(); 1142 1143 if (!IS_IMM_MODE()) 1144 { 1145 ERR("!IS_IMM_MODE()\n"); 1146 goto Quit; 1147 } 1148 1149 pImeWnd = ValidateHwndNoErr(hImeWnd); 1150 if (!pImeWnd || pImeWnd->fnid != FNID_IME) 1151 goto Quit; 1152 1153 pwndFocus = ValidateHwndNoErr(hwndFocus); 1154 if (pwndFocus) 1155 { 1156 if (IS_WND_IMELIKE(pwndFocus)) 1157 goto Quit; 1158 1159 pwndTopLevel = IntGetTopLevelWindow(pwndFocus); 1160 1161 for (pwnd = pwndTopLevel; pwnd; pwnd = pwnd->spwndOwner) 1162 { 1163 if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 1164 { 1165 pwndTopLevel = NULL; 1166 break; 1167 } 1168 } 1169 1170 pImeWnd->spwndOwner = pwndTopLevel; 1171 // TODO: 1172 } 1173 else 1174 { 1175 ptiIme = pImeWnd->head.pti; 1176 pwndActive = ptiIme->MessageQueue->spwndActive; 1177 1178 if (!pwndActive || pwndActive != pImeWnd->spwndOwner) 1179 { 1180 if (pwndActive && ptiIme == pwndActive->head.pti && !IS_WND_IMELIKE(pwndActive)) 1181 { 1182 pImeWnd->spwndOwner = pwndActive; 1183 } 1184 else 1185 { 1186 // TODO: 1187 } 1188 1189 // TODO: 1190 } 1191 } 1192 1193 ret = TRUE; 1194 1195 Quit: 1196 UserLeave(); 1197 return ret; 1198 } 1199 1200 PVOID 1201 AllocInputContextObject(PDESKTOP pDesk, 1202 PTHREADINFO pti, 1203 SIZE_T Size, 1204 PVOID* HandleOwner) 1205 { 1206 PTHRDESKHEAD ObjHead; 1207 1208 ASSERT(Size > sizeof(*ObjHead)); 1209 ASSERT(pti != NULL); 1210 1211 if (!pDesk) 1212 pDesk = pti->rpdesk; 1213 1214 ObjHead = DesktopHeapAlloc(pDesk, Size); 1215 if (!ObjHead) 1216 return NULL; 1217 1218 RtlZeroMemory(ObjHead, Size); 1219 1220 ObjHead->pSelf = ObjHead; 1221 ObjHead->rpdesk = pDesk; 1222 ObjHead->pti = pti; 1223 IntReferenceThreadInfo(pti); 1224 *HandleOwner = pti; 1225 pti->ppi->UserHandleCount++; 1226 1227 return ObjHead; 1228 } 1229 1230 VOID UserFreeInputContext(PVOID Object) 1231 { 1232 PTHRDESKHEAD ObjHead = Object; 1233 PDESKTOP pDesk = ObjHead->rpdesk; 1234 PIMC pIMC = Object, *ppIMC; 1235 PTHREADINFO pti; 1236 1237 if (!pIMC) 1238 return; 1239 1240 /* Find the IMC in the list and remove it */ 1241 pti = pIMC->head.pti; 1242 for (ppIMC = &pti->spDefaultImc; *ppIMC; ppIMC = &(*ppIMC)->pImcNext) 1243 { 1244 if (*ppIMC == pIMC) 1245 { 1246 *ppIMC = pIMC->pImcNext; 1247 break; 1248 } 1249 } 1250 1251 DesktopHeapFree(pDesk, Object); 1252 1253 pti->ppi->UserHandleCount--; 1254 IntDereferenceThreadInfo(pti); 1255 } 1256 1257 BOOLEAN UserDestroyInputContext(PVOID Object) 1258 { 1259 PIMC pIMC = Object; 1260 1261 if (!pIMC) 1262 return TRUE; 1263 1264 UserMarkObjectDestroy(pIMC); 1265 1266 return UserDeleteObject(UserHMGetHandle(pIMC), TYPE_INPUTCONTEXT); 1267 } 1268 1269 BOOL NTAPI NtUserDestroyInputContext(HIMC hIMC) 1270 { 1271 PIMC pIMC; 1272 BOOL ret = FALSE; 1273 HWND *phwnd; 1274 PWND pWnd; 1275 PWINDOWLIST pwl; 1276 PTHREADINFO pti; 1277 1278 UserEnterExclusive(); 1279 1280 if (!IS_IMM_MODE()) 1281 { 1282 ERR("!IS_IMM_MODE()\n"); 1283 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1284 goto Quit; 1285 } 1286 1287 pIMC = UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1288 if (!pIMC) 1289 goto Quit; 1290 1291 pti = pIMC->head.pti; 1292 if (pti != GetW32ThreadInfo() || pIMC == pti->spDefaultImc) 1293 goto Quit; 1294 1295 UserMarkObjectDestroy(pIMC); 1296 1297 pwl = IntBuildHwndList(pti->rpdesk->pDeskInfo->spwnd->spwndChild, 1298 IACE_CHILDREN | IACE_LIST, pti); 1299 if (pwl) 1300 { 1301 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1302 { 1303 pWnd = ValidateHwndNoErr(*phwnd); 1304 if (!pWnd) 1305 continue; 1306 1307 if (pWnd->hImc == hIMC) 1308 IntAssociateInputContext(pWnd, pti->spDefaultImc); 1309 } 1310 1311 IntFreeHwndList(pwl); 1312 } 1313 1314 ret = UserDeleteObject(hIMC, TYPE_INPUTCONTEXT); 1315 1316 Quit: 1317 UserLeave(); 1318 return ret; 1319 } 1320 1321 // Win: CreateInputContext 1322 PIMC FASTCALL UserCreateInputContext(ULONG_PTR dwClientImcData) 1323 { 1324 PIMC pIMC; 1325 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1326 PDESKTOP pdesk = pti->rpdesk; 1327 1328 if (!IS_IMM_MODE() || (pti->TIF_flags & TIF_DISABLEIME)) // Disabled? 1329 { 1330 ERR("IME is disabled\n"); 1331 return NULL; 1332 } 1333 1334 if (!pdesk) // No desktop? 1335 return NULL; 1336 1337 // pti->spDefaultImc should be already set if non-first time. 1338 if (dwClientImcData && !pti->spDefaultImc) 1339 return NULL; 1340 1341 // Create an input context user object. 1342 pIMC = UserCreateObject(gHandleTable, pdesk, pti, NULL, TYPE_INPUTCONTEXT, sizeof(IMC)); 1343 if (!pIMC) 1344 return NULL; 1345 1346 // Release the extra reference (UserCreateObject added 2 references). 1347 UserDereferenceObject(pIMC); 1348 1349 if (dwClientImcData) // Non-first time. 1350 { 1351 // Insert pIMC to the second position (non-default) of the list. 1352 pIMC->pImcNext = pti->spDefaultImc->pImcNext; 1353 pti->spDefaultImc->pImcNext = pIMC; 1354 } 1355 else // First time. It's the default IMC. 1356 { 1357 // Add the first one (default) to the list. 1358 pti->spDefaultImc = pIMC; 1359 pIMC->pImcNext = NULL; 1360 } 1361 1362 pIMC->dwClientImcData = dwClientImcData; // Set it. 1363 return pIMC; 1364 } 1365 1366 HIMC 1367 NTAPI 1368 NtUserCreateInputContext(ULONG_PTR dwClientImcData) 1369 { 1370 PIMC pIMC; 1371 HIMC ret = NULL; 1372 1373 if (!dwClientImcData) 1374 return NULL; 1375 1376 UserEnterExclusive(); 1377 1378 if (!IS_IMM_MODE()) 1379 { 1380 ERR("!IS_IMM_MODE()\n"); 1381 goto Quit; 1382 } 1383 1384 pIMC = UserCreateInputContext(dwClientImcData); 1385 if (pIMC) 1386 ret = UserHMGetHandle(pIMC); 1387 1388 Quit: 1389 UserLeave(); 1390 return ret; 1391 } 1392 1393 // Win: AssociateInputContextEx 1394 DWORD FASTCALL IntAssociateInputContextEx(PWND pWnd, PIMC pIMC, DWORD dwFlags) 1395 { 1396 DWORD ret = 0; 1397 PWINDOWLIST pwl; 1398 BOOL bIgnoreNullImc = (dwFlags & IACE_IGNORENOCONTEXT); 1399 PTHREADINFO pti = pWnd->head.pti; 1400 PWND pwndTarget, pwndFocus = pti->MessageQueue->spwndFocus; 1401 HWND *phwnd; 1402 HIMC hIMC; 1403 1404 if (dwFlags & IACE_DEFAULT) 1405 { 1406 pIMC = pti->spDefaultImc; 1407 } 1408 else 1409 { 1410 if (pIMC && pti != pIMC->head.pti) 1411 return 2; 1412 } 1413 1414 if (pWnd->head.pti->ppi != GetW32ThreadInfo()->ppi || 1415 (pIMC && pIMC->head.rpdesk != pWnd->head.rpdesk)) 1416 { 1417 return 2; 1418 } 1419 1420 if ((dwFlags & IACE_CHILDREN) && pWnd->spwndChild) 1421 { 1422 pwl = IntBuildHwndList(pWnd->spwndChild, IACE_CHILDREN | IACE_LIST, pti); 1423 if (pwl) 1424 { 1425 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1426 { 1427 pwndTarget = ValidateHwndNoErr(*phwnd); 1428 if (!pwndTarget) 1429 continue; 1430 1431 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1432 if (pwndTarget->hImc == hIMC || (bIgnoreNullImc && !pwndTarget->hImc)) 1433 continue; 1434 1435 IntAssociateInputContext(pwndTarget, pIMC); 1436 if (pwndTarget == pwndFocus) 1437 ret = 1; 1438 } 1439 1440 IntFreeHwndList(pwl); 1441 } 1442 } 1443 1444 if (!bIgnoreNullImc || pWnd->hImc) 1445 { 1446 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1447 if (pWnd->hImc != hIMC) 1448 { 1449 IntAssociateInputContext(pWnd, pIMC); 1450 if (pWnd == pwndFocus) 1451 ret = 1; 1452 } 1453 } 1454 1455 return ret; 1456 } 1457 1458 DWORD 1459 NTAPI 1460 NtUserAssociateInputContext(HWND hWnd, HIMC hIMC, DWORD dwFlags) 1461 { 1462 DWORD ret = 2; 1463 PWND pWnd; 1464 PIMC pIMC; 1465 1466 UserEnterExclusive(); 1467 1468 if (!IS_IMM_MODE()) 1469 { 1470 ERR("!IS_IMM_MODE()\n"); 1471 goto Quit; 1472 } 1473 1474 pWnd = ValidateHwndNoErr(hWnd); 1475 if (!pWnd) 1476 goto Quit; 1477 1478 pIMC = (hIMC ? UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT) : NULL); 1479 ret = IntAssociateInputContextEx(pWnd, pIMC, dwFlags); 1480 1481 Quit: 1482 UserLeave(); 1483 return ret; 1484 } 1485 1486 BOOL FASTCALL UserUpdateInputContext(PIMC pIMC, DWORD dwType, DWORD_PTR dwValue) 1487 { 1488 PTHREADINFO pti = GetW32ThreadInfo(); 1489 PTHREADINFO ptiIMC = pIMC->head.pti; 1490 1491 if (pti->ppi != ptiIMC->ppi) // Different process? 1492 return FALSE; 1493 1494 switch (dwType) 1495 { 1496 case UIC_CLIENTIMCDATA: 1497 if (pIMC->dwClientImcData) 1498 return FALSE; // Already set 1499 1500 pIMC->dwClientImcData = dwValue; 1501 break; 1502 1503 case UIC_IMEWINDOW: 1504 if (!ValidateHwndNoErr((HWND)dwValue)) 1505 return FALSE; // Invalid HWND 1506 1507 pIMC->hImeWnd = (HWND)dwValue; 1508 break; 1509 1510 default: 1511 return FALSE; 1512 } 1513 1514 return TRUE; 1515 } 1516 1517 BOOL 1518 NTAPI 1519 NtUserUpdateInputContext( 1520 HIMC hIMC, 1521 DWORD dwType, 1522 DWORD_PTR dwValue) 1523 { 1524 PIMC pIMC; 1525 BOOL ret = FALSE; 1526 1527 UserEnterExclusive(); 1528 1529 if (!IS_IMM_MODE()) 1530 { 1531 ERR("!IS_IMM_MODE()\n"); 1532 goto Quit; 1533 } 1534 1535 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1536 if (!pIMC) 1537 goto Quit; 1538 1539 ret = UserUpdateInputContext(pIMC, dwType, dwValue); 1540 1541 Quit: 1542 UserLeave(); 1543 return ret; 1544 } 1545 1546 DWORD_PTR 1547 NTAPI 1548 NtUserQueryInputContext(HIMC hIMC, DWORD dwType) 1549 { 1550 PIMC pIMC; 1551 PTHREADINFO ptiIMC; 1552 DWORD_PTR ret = 0; 1553 1554 UserEnterExclusive(); 1555 1556 if (!IS_IMM_MODE()) 1557 { 1558 ERR("!IS_IMM_MODE()\n"); 1559 goto Quit; 1560 } 1561 1562 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1563 if (!pIMC) 1564 goto Quit; 1565 1566 ptiIMC = pIMC->head.pti; 1567 1568 switch (dwType) 1569 { 1570 case QIC_INPUTPROCESSID: 1571 ret = (DWORD_PTR)PsGetThreadProcessId(ptiIMC->pEThread); 1572 break; 1573 1574 case QIC_INPUTTHREADID: 1575 ret = (DWORD_PTR)PsGetThreadId(ptiIMC->pEThread); 1576 break; 1577 1578 case QIC_DEFAULTWINDOWIME: 1579 if (ptiIMC->spwndDefaultIme) 1580 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spwndDefaultIme); 1581 break; 1582 1583 case QIC_DEFAULTIMC: 1584 if (ptiIMC->spDefaultImc) 1585 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spDefaultImc); 1586 break; 1587 } 1588 1589 Quit: 1590 UserLeave(); 1591 return ret; 1592 } 1593 1594 /* EOF */ 1595