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 static VOID FASTCALL IntAddImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 138 { 139 PIMEHOTKEY pNode; 140 141 if (!*ppList) 142 { 143 *ppList = pHotKey; 144 return; 145 } 146 147 for (pNode = *ppList; pNode; pNode = pNode->pNext) 148 { 149 if (!pNode->pNext) 150 { 151 pNode->pNext = pHotKey; 152 return; 153 } 154 } 155 } 156 157 static PIMEHOTKEY FASTCALL IntGetImeHotKeyById(PIMEHOTKEY pList, DWORD dwHotKeyId) 158 { 159 PIMEHOTKEY pNode; 160 for (pNode = pList; pNode; pNode = pNode->pNext) 161 { 162 if (pNode->dwHotKeyId == dwHotKeyId) 163 return pNode; 164 } 165 return NULL; 166 } 167 168 static PIMEHOTKEY APIENTRY 169 IntGetImeHotKeyByKeyAndLang(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, 170 UINT uVirtualKey, LANGID TargetLangId) 171 { 172 PIMEHOTKEY pNode; 173 LANGID LangID; 174 UINT uModifiers; 175 176 for (pNode = pList; pNode; pNode = pNode->pNext) 177 { 178 if (pNode->uVirtualKey != uVirtualKey) 179 continue; 180 181 LangID = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 182 if (LangID != TargetLangId) 183 continue; 184 185 uModifiers = pNode->uModifiers; 186 if (uModifiers & MOD_IGNORE_ALL_MODIFIER) 187 return pNode; 188 189 if ((uModifiers & MOD_KEYS) != uModKeys) 190 continue; 191 192 if ((uModifiers & uLeftRight) || (uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 193 return pNode; 194 } 195 196 return NULL; 197 } 198 199 static VOID FASTCALL IntDeleteImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey) 200 { 201 PIMEHOTKEY pNode; 202 203 if (*ppList == pHotKey) 204 { 205 *ppList = pHotKey->pNext; 206 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 207 return; 208 } 209 210 for (pNode = *ppList; pNode; pNode = pNode->pNext) 211 { 212 if (pNode->pNext == pHotKey) 213 { 214 pNode->pNext = pHotKey->pNext; 215 ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY); 216 return; 217 } 218 } 219 } 220 221 PIMEHOTKEY 222 IntGetImeHotKeyByKey(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight, UINT uVirtualKey) 223 { 224 PIMEHOTKEY pNode, ret = NULL; 225 PTHREADINFO pti = GetW32ThreadInfo(); 226 LANGID LangId; 227 HKL hKL = IntGetActiveKeyboardLayout(); 228 BOOL fKorean = (PRIMARYLANGID(LOWORD(hKL)) == LANG_KOREAN); 229 UINT nScore, nMaxScore = 0; 230 231 for (pNode = pList; pNode; pNode = pNode->pNext) 232 { 233 if (pNode->uVirtualKey != uVirtualKey) 234 continue; 235 236 if ((pNode->uModifiers & MOD_IGNORE_ALL_MODIFIER)) 237 { 238 ; 239 } 240 else if ((pNode->uModifiers & MOD_KEYS) != uModKeys) 241 { 242 continue; 243 } 244 else if ((pNode->uModifiers & uLeftRight) || 245 (pNode->uModifiers & MOD_LEFT_RIGHT) == uLeftRight) 246 { 247 ; 248 } 249 else 250 { 251 continue; 252 } 253 254 LangId = IntGetImeHotKeyLangId(pNode->dwHotKeyId); 255 nScore = IntGetImeHotKeyLanguageScore(hKL, LangId); 256 if (nScore >= 3) 257 return pNode; 258 259 if (fKorean) 260 continue; 261 262 if (nScore == 0) 263 { 264 if (pNode->dwHotKeyId == IME_CHOTKEY_IME_NONIME_TOGGLE || 265 pNode->dwHotKeyId == IME_THOTKEY_IME_NONIME_TOGGLE) 266 { 267 if (LOWORD(pti->hklPrev) == LangId) 268 return pNode; 269 } 270 } 271 272 if (nMaxScore < nScore) 273 { 274 nMaxScore = nScore; 275 ret = pNode; 276 } 277 } 278 279 return ret; 280 } 281 282 PIMEHOTKEY IntCheckImeHotKey(PUSER_MESSAGE_QUEUE MessageQueue, UINT uVirtualKey, LPARAM lParam) 283 { 284 PIMEHOTKEY pHotKey; 285 UINT uModifiers; 286 BOOL bKeyUp = (lParam & 0x80000000); 287 const BYTE *KeyState = MessageQueue->afKeyState; 288 static UINT s_uKeyUpVKey = 0; 289 290 if (bKeyUp) 291 { 292 if (s_uKeyUpVKey != uVirtualKey) 293 { 294 s_uKeyUpVKey = 0; 295 return NULL; 296 } 297 298 s_uKeyUpVKey = 0; 299 } 300 301 uModifiers = 0; 302 if (IS_KEY_DOWN(KeyState, VK_LSHIFT)) uModifiers |= (MOD_SHIFT | MOD_LEFT); 303 if (IS_KEY_DOWN(KeyState, VK_RSHIFT)) uModifiers |= (MOD_SHIFT | MOD_RIGHT); 304 if (IS_KEY_DOWN(KeyState, VK_LCONTROL)) uModifiers |= (MOD_CONTROL | MOD_LEFT); 305 if (IS_KEY_DOWN(KeyState, VK_RCONTROL)) uModifiers |= (MOD_CONTROL | MOD_RIGHT); 306 if (IS_KEY_DOWN(KeyState, VK_LMENU)) uModifiers |= (MOD_ALT | MOD_LEFT); 307 if (IS_KEY_DOWN(KeyState, VK_RMENU)) uModifiers |= (MOD_ALT | MOD_RIGHT); 308 309 pHotKey = IntGetImeHotKeyByKey(gpImeHotKeyList, 310 (uModifiers & MOD_KEYS), 311 (uModifiers & MOD_LEFT_RIGHT), 312 uVirtualKey); 313 if (pHotKey) 314 { 315 if (bKeyUp) 316 { 317 if (pHotKey->uModifiers & MOD_ON_KEYUP) 318 return pHotKey; 319 } 320 else 321 { 322 if (pHotKey->uModifiers & MOD_ON_KEYUP) 323 s_uKeyUpVKey = uVirtualKey; 324 else 325 return pHotKey; 326 } 327 } 328 329 return NULL; 330 } 331 332 VOID FASTCALL IntFreeImeHotKeys(VOID) 333 { 334 PIMEHOTKEY pNode, pNext; 335 for (pNode = gpImeHotKeyList; pNode; pNode = pNext) 336 { 337 pNext = pNode->pNext; 338 ExFreePoolWithTag(pNode, USERTAG_IMEHOTKEY); 339 } 340 gpImeHotKeyList = NULL; 341 } 342 343 static BOOL APIENTRY 344 IntSetImeHotKey(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL hKL, DWORD dwAction) 345 { 346 PIMEHOTKEY pNode; 347 LANGID LangId; 348 349 switch (dwAction) 350 { 351 case SETIMEHOTKEY_DELETE: 352 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 353 if (!pNode) 354 { 355 ERR("dwHotKeyId: 0x%lX\n", dwHotKeyId); 356 return FALSE; 357 } 358 359 IntDeleteImeHotKey(&gpImeHotKeyList, pNode); 360 return TRUE; 361 362 case SETIMEHOTKEY_ADD: 363 if (uVirtualKey == VK_PACKET) 364 return FALSE; 365 366 LangId = IntGetImeHotKeyLangId(dwHotKeyId); 367 if (LangId == LANGID_KOREAN) 368 return FALSE; 369 370 pNode = IntGetImeHotKeyByKeyAndLang(gpImeHotKeyList, 371 (uModifiers & MOD_KEYS), 372 (uModifiers & MOD_LEFT_RIGHT), 373 uVirtualKey, LangId); 374 if (!pNode) 375 pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId); 376 377 if (pNode) 378 { 379 pNode->uModifiers = uModifiers; 380 pNode->uVirtualKey = uVirtualKey; 381 pNode->hKL = hKL; 382 return TRUE; 383 } 384 385 pNode = ExAllocatePoolWithTag(PagedPool, sizeof(IMEHOTKEY), USERTAG_IMEHOTKEY); 386 if (!pNode) 387 return FALSE; 388 389 pNode->pNext = NULL; 390 pNode->dwHotKeyId = dwHotKeyId; 391 pNode->uModifiers = uModifiers; 392 pNode->uVirtualKey = uVirtualKey; 393 pNode->hKL = hKL; 394 IntAddImeHotKey(&gpImeHotKeyList, pNode); 395 return TRUE; 396 397 case SETIMEHOTKEY_DELETEALL: 398 IntFreeImeHotKeys(); 399 return TRUE; 400 401 default: 402 return FALSE; 403 } 404 } 405 406 BOOL NTAPI 407 NtUserGetImeHotKey(DWORD dwHotKeyId, LPUINT lpuModifiers, LPUINT lpuVirtualKey, LPHKL lphKL) 408 { 409 PIMEHOTKEY pNode = NULL; 410 411 UserEnterExclusive(); 412 413 _SEH2_TRY 414 { 415 ProbeForWrite(lpuModifiers, sizeof(UINT), 1); 416 ProbeForWrite(lpuVirtualKey, sizeof(UINT), 1); 417 if (lphKL) 418 ProbeForWrite(lphKL, sizeof(HKL), 1); 419 } 420 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 421 { 422 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 pNode = NULL; 440 } 441 _SEH2_END; 442 443 Quit: 444 UserLeave(); 445 return !!pNode; 446 } 447 448 BOOL 449 NTAPI 450 NtUserSetImeHotKey( 451 DWORD dwHotKeyId, 452 UINT uModifiers, 453 UINT uVirtualKey, 454 HKL hKL, 455 DWORD dwAction) 456 { 457 BOOL ret; 458 UserEnterExclusive(); 459 ret = IntSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, dwAction); 460 UserLeave(); 461 return ret; 462 } 463 464 DWORD 465 NTAPI 466 NtUserCheckImeHotKey(UINT uVirtualKey, LPARAM lParam) 467 { 468 PIMEHOTKEY pNode; 469 DWORD ret = INVALID_HOTKEY; 470 471 UserEnterExclusive(); 472 473 if (!gpqForeground || !IS_IMM_MODE()) 474 goto Quit; 475 476 pNode = IntCheckImeHotKey(gpqForeground, uVirtualKey, lParam); 477 if (pNode) 478 ret = pNode->dwHotKeyId; 479 480 Quit: 481 UserLeave(); 482 return ret; 483 } 484 485 PWND FASTCALL IntGetTopLevelWindow(PWND pwnd) 486 { 487 if (!pwnd) 488 return NULL; 489 490 while (pwnd->style & WS_CHILD) 491 pwnd = pwnd->spwndParent; 492 493 return pwnd; 494 } 495 496 HIMC FASTCALL IntAssociateInputContext(PWND pWnd, PIMC pImc) 497 { 498 HIMC hOldImc = pWnd->hImc; 499 pWnd->hImc = (pImc ? UserHMGetHandle(pImc) : NULL); 500 return hOldImc; 501 } 502 503 DWORD 504 NTAPI 505 NtUserSetThreadLayoutHandles(HKL hNewKL, HKL hOldKL) 506 { 507 PTHREADINFO pti; 508 PKL pOldKL, pNewKL; 509 510 UserEnterExclusive(); 511 512 pti = GetW32ThreadInfo(); 513 pOldKL = pti->KeyboardLayout; 514 if (pOldKL && pOldKL->hkl != hOldKL) 515 goto Quit; 516 517 pNewKL = UserHklToKbl(hNewKL); 518 if (!pNewKL) 519 goto Quit; 520 521 if (IS_IME_HKL(hNewKL) != IS_IME_HKL(hOldKL)) 522 pti->hklPrev = hOldKL; 523 524 pti->KeyboardLayout = pNewKL; 525 526 Quit: 527 UserLeave(); 528 return 0; 529 } 530 531 DWORD FASTCALL UserBuildHimcList(PTHREADINFO pti, DWORD dwCount, HIMC *phList) 532 { 533 PIMC pIMC; 534 DWORD dwRealCount = 0; 535 536 if (pti) 537 { 538 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 539 { 540 if (dwRealCount < dwCount) 541 phList[dwRealCount] = UserHMGetHandle(pIMC); 542 543 ++dwRealCount; 544 } 545 } 546 else 547 { 548 for (pti = GetW32ThreadInfo()->ppi->ptiList; pti; pti = pti->ptiSibling) 549 { 550 for (pIMC = pti->spDefaultImc; pIMC; pIMC = pIMC->pImcNext) 551 { 552 if (dwRealCount < dwCount) 553 phList[dwRealCount] = UserHMGetHandle(pIMC); 554 555 ++dwRealCount; 556 } 557 } 558 } 559 560 return dwRealCount; 561 } 562 563 UINT FASTCALL 564 IntImmProcessKey(PUSER_MESSAGE_QUEUE MessageQueue, PWND pWnd, UINT uMsg, 565 WPARAM wParam, LPARAM lParam) 566 { 567 UINT uVirtualKey, ret = 0; 568 DWORD dwHotKeyId; 569 PKL pKL; 570 PIMC pIMC = NULL; 571 PIMEHOTKEY pImeHotKey; 572 HKL hKL; 573 HWND hWnd; 574 575 ASSERT_REFS_CO(pWnd); 576 577 switch (uMsg) 578 { 579 case WM_KEYDOWN: 580 case WM_KEYUP: 581 case WM_SYSKEYDOWN: 582 case WM_SYSKEYUP: 583 break; 584 585 default: 586 return 0; 587 } 588 589 hWnd = UserHMGetHandle(pWnd); 590 pKL = pWnd->head.pti->KeyboardLayout; 591 if (!pKL) 592 return 0; 593 594 uVirtualKey = LOBYTE(wParam); 595 pImeHotKey = IntCheckImeHotKey(MessageQueue, uVirtualKey, lParam); 596 if (pImeHotKey) 597 { 598 dwHotKeyId = pImeHotKey->dwHotKeyId; 599 hKL = pImeHotKey->hKL; 600 } 601 else 602 { 603 dwHotKeyId = INVALID_HOTKEY; 604 hKL = NULL; 605 } 606 607 if (IME_HOTKEY_DSWITCH_FIRST <= dwHotKeyId && dwHotKeyId <= IME_HOTKEY_DSWITCH_LAST) 608 { 609 if (pKL->hkl != hKL) 610 { 611 UserPostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, 612 ((pKL->dwFontSigs & gSystemFS) ? INPUTLANGCHANGE_SYSCHARSET : 0), 613 (LPARAM)hKL); 614 } 615 616 if (IntGetImeCompatFlags(pWnd->head.pti) & 0x800000) 617 return 0; 618 619 return IPHK_HOTKEY; 620 } 621 622 if (!IS_IMM_MODE()) 623 return 0; 624 625 if (dwHotKeyId == INVALID_HOTKEY) 626 { 627 if (!pKL->piiex) 628 return 0; 629 630 if (pWnd->hImc) 631 pIMC = UserGetObject(gHandleTable, pWnd->hImc, TYPE_INPUTCONTEXT); 632 if (!pIMC) 633 return 0; 634 635 if ((lParam & 0x80000000) && 636 (pKL->piiex->ImeInfo.fdwProperty & IME_PROP_IGNORE_UPKEYS)) 637 { 638 return 0; 639 } 640 641 switch (uVirtualKey) 642 { 643 case VK_DBE_CODEINPUT: 644 case VK_DBE_ENTERCONFIGMODE: 645 case VK_DBE_ENTERWORDREGISTERMODE: 646 case VK_DBE_HIRAGANA: 647 case VK_DBE_KATAKANA: 648 case VK_DBE_NOCODEINPUT: 649 case VK_DBE_NOROMAN: 650 case VK_DBE_ROMAN: 651 break; 652 653 default: 654 { 655 if (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP) 656 { 657 if (uVirtualKey != VK_MENU && uVirtualKey != VK_F10) 658 return 0; 659 } 660 661 if (!(pKL->piiex->ImeInfo.fdwProperty & IME_PROP_NEED_ALTKEY)) 662 { 663 if (uVirtualKey == VK_MENU || (lParam & 0x20000000)) 664 return 0; 665 } 666 break; 667 } 668 } 669 } 670 671 if (LOBYTE(uVirtualKey) == VK_PACKET) 672 uVirtualKey = MAKELONG(wParam, GetW32ThreadInfo()->wchInjected); 673 674 ret = co_IntImmProcessKey(hWnd, pKL->hkl, uVirtualKey, lParam, dwHotKeyId); 675 676 if (IntGetImeCompatFlags(pWnd->head.pti) & 0x800000) 677 ret &= ~IPHK_HOTKEY; 678 679 return ret; 680 } 681 682 NTSTATUS 683 NTAPI 684 NtUserBuildHimcList(DWORD dwThreadId, DWORD dwCount, HIMC *phList, LPDWORD pdwCount) 685 { 686 NTSTATUS ret = STATUS_UNSUCCESSFUL; 687 DWORD dwRealCount; 688 PTHREADINFO pti; 689 690 UserEnterExclusive(); 691 692 if (!IS_IMM_MODE()) 693 { 694 ERR("!IS_IMM_MODE()\n"); 695 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 696 goto Quit; 697 } 698 699 if (dwThreadId == 0) 700 { 701 pti = GetW32ThreadInfo(); 702 } 703 else if (dwThreadId == INVALID_THREAD_ID) 704 { 705 pti = NULL; 706 } 707 else 708 { 709 pti = IntTID2PTI(UlongToHandle(dwThreadId)); 710 if (!pti || !pti->rpdesk) 711 goto Quit; 712 } 713 714 _SEH2_TRY 715 { 716 ProbeForWrite(phList, dwCount * sizeof(HIMC), 1); 717 ProbeForWrite(pdwCount, sizeof(DWORD), 1); 718 *pdwCount = dwRealCount = UserBuildHimcList(pti, dwCount, phList); 719 } 720 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 721 { 722 goto Quit; 723 } 724 _SEH2_END; 725 726 if (dwCount < dwRealCount) 727 ret = STATUS_BUFFER_TOO_SMALL; 728 else 729 ret = STATUS_SUCCESS; 730 731 Quit: 732 UserLeave(); 733 return ret; 734 } 735 736 static VOID FASTCALL UserSetImeConversionKeyState(PTHREADINFO pti, DWORD dwConversion) 737 { 738 HKL hKL; 739 LANGID LangID; 740 LPBYTE KeyState; 741 BOOL bAlphaNumeric, bKatakana, bHiragana, bFullShape, bRoman, bCharCode; 742 743 if (!pti->KeyboardLayout) 744 return; 745 746 hKL = pti->KeyboardLayout->hkl; 747 LangID = LOWORD(hKL); 748 KeyState = pti->MessageQueue->afKeyState; 749 750 switch (PRIMARYLANGID(LangID)) 751 { 752 case LANG_JAPANESE: 753 bAlphaNumeric = !(dwConversion & IME_CMODE_NATIVE); 754 bKatakana = !bAlphaNumeric && (dwConversion & IME_CMODE_KATAKANA); 755 bHiragana = !bAlphaNumeric && !(dwConversion & IME_CMODE_KATAKANA); 756 SET_KEY_DOWN(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 757 SET_KEY_LOCKED(KeyState, VK_DBE_ALPHANUMERIC, bAlphaNumeric); 758 SET_KEY_DOWN(KeyState, VK_DBE_HIRAGANA, bHiragana); 759 SET_KEY_LOCKED(KeyState, VK_DBE_HIRAGANA, bHiragana); 760 SET_KEY_DOWN(KeyState, VK_DBE_KATAKANA, bKatakana); 761 SET_KEY_LOCKED(KeyState, VK_DBE_KATAKANA, bKatakana); 762 763 bFullShape = (dwConversion & IME_CMODE_FULLSHAPE); 764 SET_KEY_DOWN(KeyState, VK_DBE_DBCSCHAR, bFullShape); 765 SET_KEY_LOCKED(KeyState, VK_DBE_DBCSCHAR, bFullShape); 766 SET_KEY_DOWN(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 767 SET_KEY_LOCKED(KeyState, VK_DBE_SBCSCHAR, !bFullShape); 768 769 bRoman = (dwConversion & IME_CMODE_ROMAN); 770 SET_KEY_DOWN(KeyState, VK_DBE_ROMAN, bRoman); 771 SET_KEY_LOCKED(KeyState, VK_DBE_ROMAN, bRoman); 772 SET_KEY_DOWN(KeyState, VK_DBE_NOROMAN, !bRoman); 773 SET_KEY_LOCKED(KeyState, VK_DBE_NOROMAN, !bRoman); 774 775 bCharCode = (dwConversion & IME_CMODE_CHARCODE); 776 SET_KEY_DOWN(KeyState, VK_DBE_CODEINPUT, bCharCode); 777 SET_KEY_LOCKED(KeyState, VK_DBE_CODEINPUT, bCharCode); 778 SET_KEY_DOWN(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 779 SET_KEY_LOCKED(KeyState, VK_DBE_NOCODEINPUT, !bCharCode); 780 break; 781 782 case LANG_KOREAN: 783 SET_KEY_LOCKED(KeyState, VK_HANGUL, (dwConversion & IME_CMODE_NATIVE)); 784 SET_KEY_LOCKED(KeyState, VK_JUNJA, (dwConversion & IME_CMODE_FULLSHAPE)); 785 SET_KEY_LOCKED(KeyState, VK_HANJA, (dwConversion & IME_CMODE_HANJACONVERT)); 786 break; 787 788 default: 789 break; 790 } 791 } 792 793 DWORD 794 NTAPI 795 NtUserNotifyIMEStatus(HWND hwnd, BOOL fOpen, DWORD dwConversion) 796 { 797 PWND pwnd; 798 PTHREADINFO pti; 799 HKL hKL; 800 801 UserEnterExclusive(); 802 803 if (!IS_IMM_MODE()) 804 { 805 ERR("!IS_IMM_MODE()\n"); 806 goto Quit; 807 } 808 809 pwnd = ValidateHwndNoErr(hwnd); 810 if (!pwnd) 811 goto Quit; 812 813 pti = pwnd->head.pti; 814 if (!pti || !gptiForeground) 815 goto Quit; 816 if (pti != gptiForeground && pti->MessageQueue != gptiForeground->MessageQueue) 817 goto Quit; 818 if (ghIMC == pwnd->hImc && gfImeOpen == !!fOpen && gdwImeConversion == dwConversion) 819 goto Quit; 820 821 ghIMC = pwnd->hImc; 822 if (ghIMC) 823 { 824 gfImeOpen = !!fOpen; 825 gdwImeConversion = dwConversion; 826 UserSetImeConversionKeyState(pti, (fOpen ? dwConversion : IME_CMODE_ALPHANUMERIC)); 827 } 828 829 if (ISITHOOKED(WH_SHELL)) 830 { 831 hKL = (pti->KeyboardLayout ? pti->KeyboardLayout->hkl : NULL); 832 co_HOOK_CallHooks(WH_SHELL, HSHELL_LANGUAGE, (WPARAM)hwnd, (LPARAM)hKL); 833 } 834 835 // TODO: 836 837 Quit: 838 UserLeave(); 839 return 0; 840 } 841 842 BOOL 843 NTAPI 844 NtUserDisableThreadIme( 845 DWORD dwThreadID) 846 { 847 PTHREADINFO pti, ptiCurrent; 848 PPROCESSINFO ppi; 849 BOOL ret = FALSE; 850 851 UserEnterExclusive(); 852 853 if (!IS_IMM_MODE()) 854 { 855 ERR("!IS_IMM_MODE()\n"); 856 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 857 goto Quit; 858 } 859 860 ptiCurrent = GetW32ThreadInfo(); 861 862 if (dwThreadID == INVALID_THREAD_ID) 863 { 864 ppi = ptiCurrent->ppi; 865 ppi->W32PF_flags |= W32PF_DISABLEIME; 866 867 Retry: 868 for (pti = ppi->ptiList; pti; pti = pti->ptiSibling) 869 { 870 pti->TIF_flags |= TIF_DISABLEIME; 871 872 if (pti->spwndDefaultIme) 873 { 874 co_UserDestroyWindow(pti->spwndDefaultIme); 875 pti->spwndDefaultIme = NULL; 876 goto Retry; /* The contents of ppi->ptiList may be changed. */ 877 } 878 } 879 } 880 else 881 { 882 if (dwThreadID == 0) 883 { 884 pti = ptiCurrent; 885 } 886 else 887 { 888 pti = IntTID2PTI(UlongToHandle(dwThreadID)); 889 890 /* The thread needs to reside in the current process. */ 891 if (!pti || pti->ppi != ptiCurrent->ppi) 892 goto Quit; 893 } 894 895 pti->TIF_flags |= TIF_DISABLEIME; 896 897 if (pti->spwndDefaultIme) 898 { 899 co_UserDestroyWindow(pti->spwndDefaultIme); 900 pti->spwndDefaultIme = NULL; 901 } 902 } 903 904 ret = TRUE; 905 906 Quit: 907 UserLeave(); 908 return ret; 909 } 910 911 DWORD 912 NTAPI 913 NtUserGetAppImeLevel(HWND hWnd) 914 { 915 DWORD ret = 0; 916 PWND pWnd; 917 PTHREADINFO pti; 918 919 UserEnterShared(); 920 921 pWnd = ValidateHwndNoErr(hWnd); 922 if (!pWnd) 923 goto Quit; 924 925 if (!IS_IMM_MODE()) 926 { 927 ERR("!IS_IMM_MODE()\n"); 928 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 929 goto Quit; 930 } 931 932 pti = PsGetCurrentThreadWin32Thread(); 933 if (pWnd->head.pti->ppi == pti->ppi) 934 ret = (DWORD)(ULONG_PTR)UserGetProp(pWnd, AtomImeLevel, TRUE); 935 936 Quit: 937 UserLeave(); 938 return ret; 939 } 940 941 BOOL FASTCALL UserGetImeInfoEx(LPVOID pUnknown, PIMEINFOEX pInfoEx, IMEINFOEXCLASS SearchType) 942 { 943 PKL pkl, pklHead; 944 945 if (!gspklBaseLayout) 946 return FALSE; 947 948 pkl = pklHead = gspklBaseLayout; 949 950 /* Find the matching entry from the list and get info */ 951 if (SearchType == ImeInfoExKeyboardLayout) 952 { 953 do 954 { 955 if (pInfoEx->hkl == pkl->hkl) 956 { 957 if (!pkl->piiex) 958 break; 959 960 *pInfoEx = *pkl->piiex; 961 return TRUE; 962 } 963 964 pkl = pkl->pklNext; 965 } while (pkl != pklHead); 966 } 967 else if (SearchType == ImeInfoExImeFileName) 968 { 969 do 970 { 971 if (pkl->piiex && 972 _wcsnicmp(pkl->piiex->wszImeFile, pInfoEx->wszImeFile, 973 RTL_NUMBER_OF(pkl->piiex->wszImeFile)) == 0) 974 { 975 *pInfoEx = *pkl->piiex; 976 return TRUE; 977 } 978 979 pkl = pkl->pklNext; 980 } while (pkl != pklHead); 981 } 982 else 983 { 984 /* Do nothing */ 985 } 986 987 return FALSE; 988 } 989 990 BOOL 991 NTAPI 992 NtUserGetImeInfoEx( 993 PIMEINFOEX pImeInfoEx, 994 IMEINFOEXCLASS SearchType) 995 { 996 IMEINFOEX ImeInfoEx; 997 BOOL ret = FALSE; 998 999 UserEnterShared(); 1000 1001 if (!IS_IMM_MODE()) 1002 { 1003 ERR("!IS_IMM_MODE()\n"); 1004 goto Quit; 1005 } 1006 1007 _SEH2_TRY 1008 { 1009 ProbeForWrite(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1010 ImeInfoEx = *pImeInfoEx; 1011 } 1012 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1013 { 1014 goto Quit; 1015 } 1016 _SEH2_END; 1017 1018 ret = UserGetImeInfoEx(NULL, &ImeInfoEx, SearchType); 1019 if (!ret) 1020 goto Quit; 1021 1022 _SEH2_TRY 1023 { 1024 *pImeInfoEx = ImeInfoEx; 1025 } 1026 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1027 { 1028 ret = FALSE; 1029 } 1030 _SEH2_END; 1031 1032 Quit: 1033 UserLeave(); 1034 return ret; 1035 } 1036 1037 BOOL 1038 NTAPI 1039 NtUserSetAppImeLevel(HWND hWnd, DWORD dwLevel) 1040 { 1041 BOOL ret = FALSE; 1042 PWND pWnd; 1043 PTHREADINFO pti; 1044 1045 UserEnterExclusive(); 1046 1047 if (!IS_IMM_MODE()) 1048 { 1049 ERR("!IS_IMM_MODE()\n"); 1050 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1051 goto Quit; 1052 } 1053 1054 pWnd = ValidateHwndNoErr(hWnd); 1055 if (!pWnd) 1056 goto Quit; 1057 1058 pti = PsGetCurrentThreadWin32Thread(); 1059 if (pWnd->head.pti->ppi == pti->ppi) 1060 ret = UserSetProp(pWnd, AtomImeLevel, (HANDLE)(ULONG_PTR)dwLevel, TRUE); 1061 1062 Quit: 1063 UserLeave(); 1064 return ret; 1065 } 1066 1067 BOOL FASTCALL UserSetImeInfoEx(LPVOID pUnknown, PIMEINFOEX pImeInfoEx) 1068 { 1069 PKL pklHead, pkl; 1070 1071 pkl = pklHead = gspklBaseLayout; 1072 1073 do 1074 { 1075 if (pkl->hkl != pImeInfoEx->hkl) 1076 { 1077 pkl = pkl->pklNext; 1078 continue; 1079 } 1080 1081 if (!pkl->piiex) 1082 return FALSE; 1083 1084 if (!pkl->piiex->fLoadFlag) 1085 *pkl->piiex = *pImeInfoEx; 1086 1087 return TRUE; 1088 } while (pkl != pklHead); 1089 1090 return FALSE; 1091 } 1092 1093 BOOL 1094 NTAPI 1095 NtUserSetImeInfoEx(PIMEINFOEX pImeInfoEx) 1096 { 1097 BOOL ret = FALSE; 1098 IMEINFOEX ImeInfoEx; 1099 1100 UserEnterExclusive(); 1101 1102 if (!IS_IMM_MODE()) 1103 { 1104 ERR("!IS_IMM_MODE()\n"); 1105 goto Quit; 1106 } 1107 1108 _SEH2_TRY 1109 { 1110 ProbeForRead(pImeInfoEx, sizeof(*pImeInfoEx), 1); 1111 ImeInfoEx = *pImeInfoEx; 1112 } 1113 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1114 { 1115 goto Quit; 1116 } 1117 _SEH2_END; 1118 1119 ret = UserSetImeInfoEx(NULL, &ImeInfoEx); 1120 1121 Quit: 1122 UserLeave(); 1123 return ret; 1124 } 1125 1126 BOOL NTAPI 1127 NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus) 1128 { 1129 BOOL ret = FALSE; 1130 PWND pImeWnd, pwndFocus, pwndTopLevel, pwnd, pwndActive; 1131 PTHREADINFO ptiIme; 1132 1133 UserEnterExclusive(); 1134 1135 if (!IS_IMM_MODE()) 1136 { 1137 ERR("!IS_IMM_MODE()\n"); 1138 goto Quit; 1139 } 1140 1141 pImeWnd = ValidateHwndNoErr(hImeWnd); 1142 if (!pImeWnd || pImeWnd->fnid != FNID_IME) 1143 goto Quit; 1144 1145 pwndFocus = ValidateHwndNoErr(hwndFocus); 1146 if (pwndFocus) 1147 { 1148 if (IS_WND_IMELIKE(pwndFocus)) 1149 goto Quit; 1150 1151 pwndTopLevel = IntGetTopLevelWindow(pwndFocus); 1152 1153 for (pwnd = pwndTopLevel; pwnd; pwnd = pwnd->spwndOwner) 1154 { 1155 if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]) 1156 { 1157 pwndTopLevel = NULL; 1158 break; 1159 } 1160 } 1161 1162 pImeWnd->spwndOwner = pwndTopLevel; 1163 // TODO: 1164 } 1165 else 1166 { 1167 ptiIme = pImeWnd->head.pti; 1168 pwndActive = ptiIme->MessageQueue->spwndActive; 1169 1170 if (!pwndActive || pwndActive != pImeWnd->spwndOwner) 1171 { 1172 if (pwndActive && ptiIme == pwndActive->head.pti && !IS_WND_IMELIKE(pwndActive)) 1173 { 1174 pImeWnd->spwndOwner = pwndActive; 1175 } 1176 else 1177 { 1178 // TODO: 1179 } 1180 1181 // TODO: 1182 } 1183 } 1184 1185 ret = TRUE; 1186 1187 Quit: 1188 UserLeave(); 1189 return ret; 1190 } 1191 1192 PVOID 1193 AllocInputContextObject(PDESKTOP pDesk, 1194 PTHREADINFO pti, 1195 SIZE_T Size, 1196 PVOID* HandleOwner) 1197 { 1198 PTHRDESKHEAD ObjHead; 1199 1200 ASSERT(Size > sizeof(*ObjHead)); 1201 ASSERT(pti != NULL); 1202 1203 if (!pDesk) 1204 pDesk = pti->rpdesk; 1205 1206 ObjHead = DesktopHeapAlloc(pDesk, Size); 1207 if (!ObjHead) 1208 return NULL; 1209 1210 RtlZeroMemory(ObjHead, Size); 1211 1212 ObjHead->pSelf = ObjHead; 1213 ObjHead->rpdesk = pDesk; 1214 ObjHead->pti = pti; 1215 IntReferenceThreadInfo(pti); 1216 *HandleOwner = pti; 1217 pti->ppi->UserHandleCount++; 1218 1219 return ObjHead; 1220 } 1221 1222 VOID UserFreeInputContext(PVOID Object) 1223 { 1224 PTHRDESKHEAD ObjHead = Object; 1225 PDESKTOP pDesk = ObjHead->rpdesk; 1226 PIMC pIMC = Object, *ppIMC; 1227 PTHREADINFO pti; 1228 1229 if (!pIMC) 1230 return; 1231 1232 /* Find the IMC in the list and remove it */ 1233 pti = pIMC->head.pti; 1234 for (ppIMC = &pti->spDefaultImc; *ppIMC; ppIMC = &(*ppIMC)->pImcNext) 1235 { 1236 if (*ppIMC == pIMC) 1237 { 1238 *ppIMC = pIMC->pImcNext; 1239 break; 1240 } 1241 } 1242 1243 DesktopHeapFree(pDesk, Object); 1244 1245 pti->ppi->UserHandleCount--; 1246 IntDereferenceThreadInfo(pti); 1247 } 1248 1249 BOOLEAN UserDestroyInputContext(PVOID Object) 1250 { 1251 PIMC pIMC = Object; 1252 1253 if (!pIMC) 1254 return TRUE; 1255 1256 UserMarkObjectDestroy(pIMC); 1257 1258 return UserDeleteObject(UserHMGetHandle(pIMC), TYPE_INPUTCONTEXT); 1259 } 1260 1261 BOOL NTAPI NtUserDestroyInputContext(HIMC hIMC) 1262 { 1263 PIMC pIMC; 1264 BOOL ret = FALSE; 1265 HWND *phwnd; 1266 PWND pWnd; 1267 PWINDOWLIST pwl; 1268 PTHREADINFO pti; 1269 1270 UserEnterExclusive(); 1271 1272 if (!IS_IMM_MODE()) 1273 { 1274 ERR("!IS_IMM_MODE()\n"); 1275 EngSetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1276 goto Quit; 1277 } 1278 1279 pIMC = UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1280 if (!pIMC) 1281 goto Quit; 1282 1283 pti = pIMC->head.pti; 1284 if (pti != GetW32ThreadInfo() || pIMC == pti->spDefaultImc) 1285 goto Quit; 1286 1287 UserMarkObjectDestroy(pIMC); 1288 1289 pwl = IntBuildHwndList(pti->rpdesk->pDeskInfo->spwnd->spwndChild, 1290 IACE_CHILDREN | IACE_LIST, pti); 1291 if (pwl) 1292 { 1293 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1294 { 1295 pWnd = ValidateHwndNoErr(*phwnd); 1296 if (!pWnd) 1297 continue; 1298 1299 if (pWnd->hImc == hIMC) 1300 IntAssociateInputContext(pWnd, pti->spDefaultImc); 1301 } 1302 1303 IntFreeHwndList(pwl); 1304 } 1305 1306 ret = UserDeleteObject(hIMC, TYPE_INPUTCONTEXT); 1307 1308 Quit: 1309 UserLeave(); 1310 return ret; 1311 } 1312 1313 PIMC FASTCALL UserCreateInputContext(ULONG_PTR dwClientImcData) 1314 { 1315 PIMC pIMC; 1316 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1317 PDESKTOP pdesk = pti->rpdesk; 1318 1319 if (!IS_IMM_MODE() || (pti->TIF_flags & TIF_DISABLEIME)) // Disabled? 1320 { 1321 ERR("IME is disabled\n"); 1322 return NULL; 1323 } 1324 1325 if (!pdesk) // No desktop? 1326 return NULL; 1327 1328 // pti->spDefaultImc should be already set if non-first time. 1329 if (dwClientImcData && !pti->spDefaultImc) 1330 return NULL; 1331 1332 // Create an input context user object. 1333 pIMC = UserCreateObject(gHandleTable, pdesk, pti, NULL, TYPE_INPUTCONTEXT, sizeof(IMC)); 1334 if (!pIMC) 1335 return NULL; 1336 1337 // Release the extra reference (UserCreateObject added 2 references). 1338 UserDereferenceObject(pIMC); 1339 1340 if (dwClientImcData) // Non-first time. 1341 { 1342 // Insert pIMC to the second position (non-default) of the list. 1343 pIMC->pImcNext = pti->spDefaultImc->pImcNext; 1344 pti->spDefaultImc->pImcNext = pIMC; 1345 } 1346 else // First time. It's the default IMC. 1347 { 1348 // Add the first one (default) to the list. 1349 pti->spDefaultImc = pIMC; 1350 pIMC->pImcNext = NULL; 1351 } 1352 1353 pIMC->dwClientImcData = dwClientImcData; // Set it. 1354 return pIMC; 1355 } 1356 1357 HIMC 1358 NTAPI 1359 NtUserCreateInputContext(ULONG_PTR dwClientImcData) 1360 { 1361 PIMC pIMC; 1362 HIMC ret = NULL; 1363 1364 if (!dwClientImcData) 1365 return NULL; 1366 1367 UserEnterExclusive(); 1368 1369 if (!IS_IMM_MODE()) 1370 { 1371 ERR("!IS_IMM_MODE()\n"); 1372 goto Quit; 1373 } 1374 1375 pIMC = UserCreateInputContext(dwClientImcData); 1376 if (pIMC) 1377 ret = UserHMGetHandle(pIMC); 1378 1379 Quit: 1380 UserLeave(); 1381 return ret; 1382 } 1383 1384 DWORD FASTCALL IntAssociateInputContextEx(PWND pWnd, PIMC pIMC, DWORD dwFlags) 1385 { 1386 DWORD ret = 0; 1387 PWINDOWLIST pwl; 1388 BOOL bIgnoreNullImc = (dwFlags & IACE_IGNORENOCONTEXT); 1389 PTHREADINFO pti = pWnd->head.pti; 1390 PWND pwndTarget, pwndFocus = pti->MessageQueue->spwndFocus; 1391 HWND *phwnd; 1392 HIMC hIMC; 1393 1394 if (dwFlags & IACE_DEFAULT) 1395 { 1396 pIMC = pti->spDefaultImc; 1397 } 1398 else 1399 { 1400 if (pIMC && pti != pIMC->head.pti) 1401 return 2; 1402 } 1403 1404 if (pWnd->head.pti->ppi != GetW32ThreadInfo()->ppi || 1405 (pIMC && pIMC->head.rpdesk != pWnd->head.rpdesk)) 1406 { 1407 return 2; 1408 } 1409 1410 if ((dwFlags & IACE_CHILDREN) && pWnd->spwndChild) 1411 { 1412 pwl = IntBuildHwndList(pWnd->spwndChild, IACE_CHILDREN | IACE_LIST, pti); 1413 if (pwl) 1414 { 1415 for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1416 { 1417 pwndTarget = ValidateHwndNoErr(*phwnd); 1418 if (!pwndTarget) 1419 continue; 1420 1421 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1422 if (pwndTarget->hImc == hIMC || (bIgnoreNullImc && !pwndTarget->hImc)) 1423 continue; 1424 1425 IntAssociateInputContext(pwndTarget, pIMC); 1426 if (pwndTarget == pwndFocus) 1427 ret = 1; 1428 } 1429 1430 IntFreeHwndList(pwl); 1431 } 1432 } 1433 1434 if (!bIgnoreNullImc || pWnd->hImc) 1435 { 1436 hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); 1437 if (pWnd->hImc != hIMC) 1438 { 1439 IntAssociateInputContext(pWnd, pIMC); 1440 if (pWnd == pwndFocus) 1441 ret = 1; 1442 } 1443 } 1444 1445 return ret; 1446 } 1447 1448 DWORD 1449 NTAPI 1450 NtUserAssociateInputContext(HWND hWnd, HIMC hIMC, DWORD dwFlags) 1451 { 1452 DWORD ret = 2; 1453 PWND pWnd; 1454 PIMC pIMC; 1455 1456 UserEnterExclusive(); 1457 1458 if (!IS_IMM_MODE()) 1459 { 1460 ERR("!IS_IMM_MODE()\n"); 1461 goto Quit; 1462 } 1463 1464 pWnd = ValidateHwndNoErr(hWnd); 1465 if (!pWnd) 1466 goto Quit; 1467 1468 pIMC = (hIMC ? UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT) : NULL); 1469 ret = IntAssociateInputContextEx(pWnd, pIMC, dwFlags); 1470 1471 Quit: 1472 UserLeave(); 1473 return ret; 1474 } 1475 1476 BOOL FASTCALL UserUpdateInputContext(PIMC pIMC, DWORD dwType, DWORD_PTR dwValue) 1477 { 1478 PTHREADINFO pti = GetW32ThreadInfo(); 1479 PTHREADINFO ptiIMC = pIMC->head.pti; 1480 1481 if (pti->ppi != ptiIMC->ppi) // Different process? 1482 return FALSE; 1483 1484 switch (dwType) 1485 { 1486 case UIC_CLIENTIMCDATA: 1487 if (pIMC->dwClientImcData) 1488 return FALSE; // Already set 1489 1490 pIMC->dwClientImcData = dwValue; 1491 break; 1492 1493 case UIC_IMEWINDOW: 1494 if (!ValidateHwndNoErr((HWND)dwValue)) 1495 return FALSE; // Invalid HWND 1496 1497 pIMC->hImeWnd = (HWND)dwValue; 1498 break; 1499 1500 default: 1501 return FALSE; 1502 } 1503 1504 return TRUE; 1505 } 1506 1507 BOOL 1508 NTAPI 1509 NtUserUpdateInputContext( 1510 HIMC hIMC, 1511 DWORD dwType, 1512 DWORD_PTR dwValue) 1513 { 1514 PIMC pIMC; 1515 BOOL ret = FALSE; 1516 1517 UserEnterExclusive(); 1518 1519 if (!IS_IMM_MODE()) 1520 { 1521 ERR("!IS_IMM_MODE()\n"); 1522 goto Quit; 1523 } 1524 1525 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1526 if (!pIMC) 1527 goto Quit; 1528 1529 ret = UserUpdateInputContext(pIMC, dwType, dwValue); 1530 1531 Quit: 1532 UserLeave(); 1533 return ret; 1534 } 1535 1536 DWORD_PTR 1537 NTAPI 1538 NtUserQueryInputContext(HIMC hIMC, DWORD dwType) 1539 { 1540 PIMC pIMC; 1541 PTHREADINFO ptiIMC; 1542 DWORD_PTR ret = 0; 1543 1544 UserEnterExclusive(); 1545 1546 if (!IS_IMM_MODE()) 1547 { 1548 ERR("!IS_IMM_MODE()\n"); 1549 goto Quit; 1550 } 1551 1552 pIMC = UserGetObject(gHandleTable, hIMC, TYPE_INPUTCONTEXT); 1553 if (!pIMC) 1554 goto Quit; 1555 1556 ptiIMC = pIMC->head.pti; 1557 1558 switch (dwType) 1559 { 1560 case QIC_INPUTPROCESSID: 1561 ret = (DWORD_PTR)PsGetThreadProcessId(ptiIMC->pEThread); 1562 break; 1563 1564 case QIC_INPUTTHREADID: 1565 ret = (DWORD_PTR)PsGetThreadId(ptiIMC->pEThread); 1566 break; 1567 1568 case QIC_DEFAULTWINDOWIME: 1569 if (ptiIMC->spwndDefaultIme) 1570 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spwndDefaultIme); 1571 break; 1572 1573 case QIC_DEFAULTIMC: 1574 if (ptiIMC->spDefaultImc) 1575 ret = (DWORD_PTR)UserHMGetHandle(ptiIMC->spDefaultImc); 1576 break; 1577 } 1578 1579 Quit: 1580 UserLeave(); 1581 return ret; 1582 } 1583 1584 /* EOF */ 1585