1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing Far-Eastern languages input 5 * COPYRIGHT: Copyright 1998 Patrik Stridvall 6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart 7 * Copyright 2017 James Tabor <james.tabor@reactos.org> 8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org> 9 * Copyright 2020-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 10 */ 11 12 #include "precomp.h" 13 14 WINE_DEFAULT_DEBUG_CHANNEL(imm); 15 16 HMODULE ghImm32Inst = NULL; // Win: ghInst 17 PSERVERINFO gpsi = NULL; // Win: gpsi 18 SHAREDINFO gSharedInfo = { NULL }; // Win: gSharedInfo 19 BYTE gfImmInitialized = FALSE; // Win: gfInitialized 20 21 // Win: ImmInitializeGlobals 22 static BOOL APIENTRY ImmInitializeGlobals(HMODULE hMod) 23 { 24 NTSTATUS status; 25 26 if (hMod) 27 ghImm32Inst = hMod; 28 29 if (gfImmInitialized) 30 return TRUE; 31 32 status = RtlInitializeCriticalSection(&gcsImeDpi); 33 if (NT_ERROR(status)) 34 return FALSE; 35 36 gfImmInitialized = TRUE; 37 return TRUE; 38 } 39 40 /*********************************************************************** 41 * ImmRegisterClient(IMM32.@) 42 * ( Undocumented, called from user32.dll ) 43 */ 44 BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod) 45 { 46 gSharedInfo = *ptr; 47 gpsi = gSharedInfo.psi; 48 return ImmInitializeGlobals(hMod); 49 } 50 51 /*********************************************************************** 52 * ImmLoadLayout (IMM32.@) 53 */ 54 BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) 55 { 56 DWORD cbData, dwType; 57 HKEY hLayoutKey; 58 LONG error; 59 WCHAR szLayout[MAX_PATH]; 60 61 TRACE("(%p, %p)\n", hKL, pImeInfoEx); 62 63 ZeroMemory(pImeInfoEx, sizeof(IMEINFOEX)); 64 65 if (IS_IME_HKL(hKL) || !IS_CICERO_MODE() || IS_16BIT_MODE()) 66 { 67 StringCchPrintfW(szLayout, _countof(szLayout), L"%s\\%08lX", 68 REGKEY_KEYBOARD_LAYOUTS, HandleToUlong(hKL)); 69 70 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szLayout, 0, KEY_READ, &hLayoutKey); 71 if (error) 72 { 73 ERR("RegOpenKeyExW: 0x%08lX\n", error); 74 return FALSE; 75 } 76 } 77 else 78 { 79 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGKEY_IMM, 0, KEY_READ, &hLayoutKey); 80 if (error) 81 { 82 ERR("RegOpenKeyExW: 0x%08lX\n", error); 83 return FALSE; 84 } 85 } 86 87 cbData = sizeof(pImeInfoEx->wszImeFile); 88 error = RegQueryValueExW(hLayoutKey, L"Ime File", NULL, &dwType, 89 (LPBYTE)pImeInfoEx->wszImeFile, &cbData); 90 pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = UNICODE_NULL; 91 92 RegCloseKey(hLayoutKey); 93 94 pImeInfoEx->fLoadFlag = 0; 95 96 if (error != ERROR_SUCCESS || dwType != REG_SZ) 97 { 98 ERR("RegQueryValueExW: 0x%lX, 0x%lX\n", error, dwType); 99 return FALSE; 100 } 101 102 pImeInfoEx->hkl = hKL; 103 return Imm32LoadImeVerInfo(pImeInfoEx); 104 } 105 106 /*********************************************************************** 107 * ImmFreeLayout (IMM32.@) 108 */ 109 BOOL WINAPI ImmFreeLayout(DWORD dwUnknown) 110 { 111 WCHAR szKBD[KL_NAMELENGTH]; 112 UINT iKL, cKLs; 113 HKL hOldKL, hNewKL, *pList; 114 PIMEDPI pImeDpi; 115 LANGID LangID; 116 117 TRACE("(0x%lX)\n", dwUnknown); 118 119 hOldKL = GetKeyboardLayout(0); 120 121 if (dwUnknown == 1) 122 { 123 if (!IS_IME_HKL(hOldKL)) 124 return TRUE; 125 126 LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 127 128 cKLs = GetKeyboardLayoutList(0, NULL); 129 if (cKLs) 130 { 131 pList = ImmLocalAlloc(0, cKLs * sizeof(HKL)); 132 if (pList == NULL) 133 return FALSE; 134 135 cKLs = GetKeyboardLayoutList(cKLs, pList); 136 for (iKL = 0; iKL < cKLs; ++iKL) 137 { 138 if (!IS_IME_HKL(pList[iKL])) 139 { 140 LangID = LOWORD(pList[iKL]); 141 break; 142 } 143 } 144 145 ImmLocalFree(pList); 146 } 147 148 StringCchPrintfW(szKBD, _countof(szKBD), L"%08X", LangID); 149 if (!LoadKeyboardLayoutW(szKBD, KLF_ACTIVATE)) 150 LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | 0x200); 151 } 152 else if (dwUnknown == 2) 153 { 154 RtlEnterCriticalSection(&gcsImeDpi); 155 Retry: 156 for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext) 157 { 158 if (Imm32ReleaseIME(pImeDpi->hKL)) 159 goto Retry; 160 } 161 RtlLeaveCriticalSection(&gcsImeDpi); 162 } 163 else 164 { 165 hNewKL = (HKL)(DWORD_PTR)dwUnknown; 166 if (IS_IME_HKL(hNewKL) && hNewKL != hOldKL) 167 Imm32ReleaseIME(hNewKL); 168 } 169 170 return TRUE; 171 } 172 173 // Win: SelectInputContext 174 VOID APIENTRY Imm32SelectInputContext(HKL hNewKL, HKL hOldKL, HIMC hIMC) 175 { 176 PCLIENTIMC pClientImc; 177 LPINPUTCONTEXTDX pIC; 178 LPGUIDELINE pGL; 179 LPCANDIDATEINFO pCI; 180 LPCOMPOSITIONSTRING pCS; 181 LOGFONTA LogFontA; 182 LOGFONTW LogFontW; 183 BOOL fOpen, bIsNewHKLIme = TRUE, bIsOldHKLIme = TRUE, bClientWide, bNewDpiWide; 184 DWORD cbNewPrivate = 0, cbOldPrivate = 0, dwConversion, dwSentence, dwSize, dwNewSize; 185 PIMEDPI pNewImeDpi = NULL, pOldImeDpi = NULL; 186 HANDLE hPrivate; 187 PIME_STATE pNewState = NULL, pOldState = NULL; 188 189 pClientImc = ImmLockClientImc(hIMC); 190 if (!pClientImc) 191 return; 192 193 pNewImeDpi = ImmLockImeDpi(hNewKL); 194 195 if (hNewKL != hOldKL) 196 pOldImeDpi = ImmLockImeDpi(hOldKL); 197 198 if (pNewImeDpi) 199 { 200 cbNewPrivate = pNewImeDpi->ImeInfo.dwPrivateDataSize; 201 pClientImc->uCodePage = pNewImeDpi->uCodePage; 202 } 203 else 204 { 205 pClientImc->uCodePage = CP_ACP; 206 } 207 208 if (cbNewPrivate < sizeof(DWORD)) 209 cbNewPrivate = sizeof(DWORD); 210 211 if (pOldImeDpi) 212 cbOldPrivate = pOldImeDpi->ImeInfo.dwPrivateDataSize; 213 214 if (cbOldPrivate < sizeof(DWORD)) 215 cbOldPrivate = sizeof(DWORD); 216 217 if (pClientImc->hKL == hOldKL) 218 { 219 if (pOldImeDpi) 220 { 221 if (IS_IME_HKL(hOldKL)) 222 pOldImeDpi->ImeSelect(hIMC, FALSE); 223 else if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 224 pOldImeDpi->CtfImeSelectEx(hIMC, FALSE, hOldKL); 225 } 226 pClientImc->hKL = NULL; 227 } 228 229 if (CtfImmIsTextFrameServiceDisabled()) 230 { 231 if (IS_IMM_MODE() && !IS_CICERO_MODE()) 232 { 233 bIsNewHKLIme = IS_IME_HKL(hNewKL); 234 bIsOldHKLIme = IS_IME_HKL(hOldKL); 235 } 236 } 237 238 pIC = (LPINPUTCONTEXTDX)Imm32InternalLockIMC(hIMC, FALSE); 239 if (!pIC) 240 { 241 if (pNewImeDpi) 242 { 243 if (IS_IME_HKL(hNewKL)) 244 pNewImeDpi->ImeSelect(hIMC, TRUE); 245 else if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 246 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL); 247 248 pClientImc->hKL = hNewKL; 249 } 250 } 251 else 252 { 253 dwConversion = pIC->fdwConversion; 254 dwSentence = pIC->fdwSentence; 255 fOpen = pIC->fOpen; 256 257 if (pNewImeDpi) 258 { 259 bClientWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 260 bNewDpiWide = ImeDpi_IsUnicode(pNewImeDpi); 261 if (bClientWide && !bNewDpiWide) 262 { 263 if (pIC->fdwInit & INIT_LOGFONT) 264 { 265 LogFontWideToAnsi(&pIC->lfFont.W, &LogFontA); 266 pIC->lfFont.A = LogFontA; 267 } 268 pClientImc->dwFlags &= ~CLIENTIMC_WIDE; 269 } 270 else if (!bClientWide && bNewDpiWide) 271 { 272 if (pIC->fdwInit & INIT_LOGFONT) 273 { 274 LogFontAnsiToWide(&pIC->lfFont.A, &LogFontW); 275 pIC->lfFont.W = LogFontW; 276 } 277 pClientImc->dwFlags |= CLIENTIMC_WIDE; 278 } 279 } 280 281 if (cbOldPrivate != cbNewPrivate) 282 { 283 hPrivate = ImmReSizeIMCC(pIC->hPrivate, cbNewPrivate); 284 if (!hPrivate) 285 { 286 ImmDestroyIMCC(pIC->hPrivate); 287 hPrivate = ImmCreateIMCC(cbNewPrivate); 288 } 289 pIC->hPrivate = hPrivate; 290 } 291 292 #define MAX_IMCC_SIZE 0x1000 293 dwSize = ImmGetIMCCSize(pIC->hMsgBuf); 294 if (ImmGetIMCCLockCount(pIC->hMsgBuf) || dwSize > MAX_IMCC_SIZE) 295 { 296 ImmDestroyIMCC(pIC->hMsgBuf); 297 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT)); 298 pIC->dwNumMsgBuf = 0; 299 } 300 301 dwSize = ImmGetIMCCSize(pIC->hGuideLine); 302 dwNewSize = sizeof(GUIDELINE); 303 if (ImmGetIMCCLockCount(pIC->hGuideLine) || 304 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE) 305 { 306 ImmDestroyIMCC(pIC->hGuideLine); 307 pIC->hGuideLine = ImmCreateIMCC(dwNewSize); 308 pGL = ImmLockIMCC(pIC->hGuideLine); 309 if (pGL) 310 { 311 pGL->dwSize = dwNewSize; 312 ImmUnlockIMCC(pIC->hGuideLine); 313 } 314 } 315 316 dwSize = ImmGetIMCCSize(pIC->hCandInfo); 317 dwNewSize = sizeof(CANDIDATEINFO); 318 if (ImmGetIMCCLockCount(pIC->hCandInfo) || 319 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE) 320 { 321 ImmDestroyIMCC(pIC->hCandInfo); 322 pIC->hCandInfo = ImmCreateIMCC(dwNewSize); 323 pCI = ImmLockIMCC(pIC->hCandInfo); 324 if (pCI) 325 { 326 pCI->dwSize = dwNewSize; 327 ImmUnlockIMCC(pIC->hCandInfo); 328 } 329 } 330 331 dwSize = ImmGetIMCCSize(pIC->hCompStr); 332 dwNewSize = sizeof(COMPOSITIONSTRING); 333 if (ImmGetIMCCLockCount(pIC->hCompStr) || 334 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE) 335 { 336 ImmDestroyIMCC(pIC->hCompStr); 337 pIC->hCompStr = ImmCreateIMCC(dwNewSize); 338 pCS = ImmLockIMCC(pIC->hCompStr); 339 if (pCS) 340 { 341 pCS->dwSize = dwNewSize; 342 ImmUnlockIMCC(pIC->hCompStr); 343 } 344 } 345 #undef MAX_IMCC_SIZE 346 347 if (pOldImeDpi && bIsOldHKLIme) 348 { 349 pOldState = Imm32FetchImeState(pIC, hOldKL); 350 if (pOldState) 351 Imm32SaveImeStateSentence(pIC, pOldState, hOldKL); 352 } 353 354 if (pNewImeDpi && bIsNewHKLIme) 355 pNewState = Imm32FetchImeState(pIC, hNewKL); 356 357 if (pOldState != pNewState) 358 { 359 if (pOldState) 360 { 361 pOldState->fOpen = !!pIC->fOpen; 362 pOldState->dwConversion = (pIC->fdwConversion & ~IME_CMODE_EUDC); 363 pOldState->dwSentence = pIC->fdwSentence; 364 pOldState->dwInit = pIC->fdwInit; 365 } 366 367 if (pNewState) 368 { 369 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_FORCE_OPEN) 370 { 371 pIC->dwChange &= ~INPUTCONTEXTDX_CHANGE_FORCE_OPEN; 372 pIC->fOpen = TRUE; 373 } 374 else 375 { 376 pIC->fOpen = pNewState->fOpen; 377 } 378 379 pIC->fdwConversion = (pNewState->dwConversion & ~IME_CMODE_EUDC); 380 pIC->fdwSentence = pNewState->dwSentence; 381 pIC->fdwInit = pNewState->dwInit; 382 } 383 } 384 385 if (pNewState) 386 Imm32LoadImeStateSentence(pIC, pNewState, hNewKL); 387 388 if (pNewImeDpi) 389 { 390 if (IS_IME_HKL(hNewKL)) 391 pNewImeDpi->ImeSelect(hIMC, TRUE); 392 else if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 393 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL); 394 395 pClientImc->hKL = hNewKL; 396 } 397 398 pIC->dwChange = 0; 399 if (pIC->fOpen != fOpen) 400 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_OPEN; 401 if (pIC->fdwConversion != dwConversion) 402 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_CONVERSION; 403 if (pIC->fdwSentence != dwSentence) 404 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_SENTENCE; 405 406 ImmUnlockIMC(hIMC); 407 } 408 409 ImmUnlockImeDpi(pOldImeDpi); 410 ImmUnlockImeDpi(pNewImeDpi); 411 ImmUnlockClientImc(pClientImc); 412 } 413 414 typedef struct SELECT_LAYOUT 415 { 416 HKL hNewKL; 417 HKL hOldKL; 418 } SELECT_LAYOUT, *LPSELECT_LAYOUT; 419 420 // Win: SelectContextProc 421 static BOOL CALLBACK Imm32SelectContextProc(HIMC hIMC, LPARAM lParam) 422 { 423 LPSELECT_LAYOUT pSelect = (LPSELECT_LAYOUT)lParam; 424 Imm32SelectInputContext(pSelect->hNewKL, pSelect->hOldKL, hIMC); 425 return TRUE; 426 } 427 428 // Win: NotifyIMEProc 429 static BOOL CALLBACK Imm32NotifyIMEProc(HIMC hIMC, LPARAM lParam) 430 { 431 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, (DWORD)lParam, 0); 432 return TRUE; 433 } 434 435 /*********************************************************************** 436 * ImmActivateLayout (IMM32.@) 437 */ 438 BOOL WINAPI ImmActivateLayout(HKL hKL) 439 { 440 PIMEDPI pImeDpi; 441 HKL hOldKL; 442 LPARAM lParam; 443 HWND hwndDefIME = NULL; 444 SELECT_LAYOUT SelectLayout; 445 446 hOldKL = GetKeyboardLayout(0); 447 448 if (hOldKL == hKL && !(GetWin32ClientInfo()->CI_flags & CI_IMMACTIVATE)) 449 return TRUE; 450 451 ImmLoadIME(hKL); 452 453 if (hOldKL != hKL) 454 { 455 pImeDpi = ImmLockImeDpi(hOldKL); 456 if (pImeDpi) 457 { 458 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT) 459 lParam = CPS_COMPLETE; 460 else 461 lParam = CPS_CANCEL; 462 ImmUnlockImeDpi(pImeDpi); 463 464 ImmEnumInputContext(0, Imm32NotifyIMEProc, lParam); 465 } 466 467 hwndDefIME = ImmGetDefaultIMEWnd(NULL); 468 if (IsWindow(hwndDefIME)) 469 SendMessageW(hwndDefIME, WM_IME_SELECT, FALSE, (LPARAM)hOldKL); 470 471 NtUserSetThreadLayoutHandles(hKL, hOldKL); 472 } 473 474 SelectLayout.hNewKL = hKL; 475 SelectLayout.hOldKL = hOldKL; 476 ImmEnumInputContext(0, Imm32SelectContextProc, (LPARAM)&SelectLayout); 477 478 if (IsWindow(hwndDefIME)) 479 SendMessageW(hwndDefIME, WM_IME_SELECT, TRUE, (LPARAM)hKL); 480 481 return TRUE; 482 } 483 484 static VOID APIENTRY Imm32CiceroSetActiveContext(HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL) 485 { 486 TRACE("We have to do something\n"); 487 } 488 489 /*********************************************************************** 490 * ImmAssociateContext (IMM32.@) 491 */ 492 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) 493 { 494 PWND pWnd; 495 HWND hwndFocus; 496 DWORD dwValue; 497 HIMC hOldIMC; 498 499 TRACE("(%p, %p)\n", hWnd, hIMC); 500 501 if (!IS_IMM_MODE()) 502 return NULL; 503 504 pWnd = ValidateHwnd(hWnd); 505 if (!pWnd) 506 return NULL; 507 508 if (hIMC && Imm32IsCrossThreadAccess(hIMC)) 509 return NULL; 510 511 hOldIMC = pWnd->hImc; 512 if (hOldIMC == hIMC) 513 return hIMC; 514 515 dwValue = NtUserAssociateInputContext(hWnd, hIMC, 0); 516 if (dwValue == 0) 517 return hOldIMC; 518 if (dwValue != 1) 519 return NULL; 520 521 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS); 522 if (hwndFocus == hWnd) 523 { 524 ImmSetActiveContext(hWnd, hOldIMC, FALSE); 525 ImmSetActiveContext(hWnd, hIMC, TRUE); 526 } 527 528 return hOldIMC; 529 } 530 531 /*********************************************************************** 532 * ImmAssociateContextEx (IMM32.@) 533 */ 534 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) 535 { 536 HWND hwndFocus; 537 PWND pFocusWnd; 538 HIMC hOldIMC = NULL; 539 DWORD dwValue; 540 541 TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags); 542 543 if (!IS_IMM_MODE()) 544 return FALSE; 545 546 if (hIMC && !(dwFlags & IACE_DEFAULT) && Imm32IsCrossThreadAccess(hIMC)) 547 return FALSE; 548 549 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS); 550 pFocusWnd = ValidateHwnd(hwndFocus); 551 if (pFocusWnd) 552 hOldIMC = pFocusWnd->hImc; 553 554 dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags); 555 switch (dwValue) 556 { 557 case 0: 558 return TRUE; 559 560 case 1: 561 pFocusWnd = ValidateHwnd(hwndFocus); 562 if (pFocusWnd) 563 { 564 hIMC = pFocusWnd->hImc; 565 if (hIMC != hOldIMC) 566 { 567 ImmSetActiveContext(hwndFocus, hOldIMC, FALSE); 568 ImmSetActiveContext(hwndFocus, hIMC, TRUE); 569 } 570 } 571 return TRUE; 572 573 default: 574 return FALSE; 575 } 576 } 577 578 /*********************************************************************** 579 * ImmCreateContext (IMM32.@) 580 */ 581 HIMC WINAPI ImmCreateContext(void) 582 { 583 PCLIENTIMC pClientImc; 584 HIMC hIMC; 585 586 TRACE("()\n"); 587 588 if (!IS_IMM_MODE()) 589 return NULL; 590 591 pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 592 if (pClientImc == NULL) 593 return NULL; 594 595 hIMC = NtUserCreateInputContext((ULONG_PTR)pClientImc); 596 if (hIMC == NULL) 597 { 598 ImmLocalFree(pClientImc); 599 return NULL; 600 } 601 602 RtlInitializeCriticalSection(&pClientImc->cs); 603 604 pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS); 605 606 return hIMC; 607 } 608 609 // Win: DestroyImeModeSaver 610 static VOID APIENTRY Imm32DestroyImeModeSaver(LPINPUTCONTEXTDX pIC) 611 { 612 PIME_STATE pState, pNext; 613 PIME_SUBSTATE pSubState, pSubNext; 614 615 for (pState = pIC->pState; pState; pState = pNext) 616 { 617 pNext = pState->pNext; 618 619 for (pSubState = pState->pSubState; pSubState; pSubState = pSubNext) 620 { 621 pSubNext = pSubState->pNext; 622 ImmLocalFree(pSubState); 623 } 624 625 ImmLocalFree(pState); 626 } 627 628 pIC->pState = NULL; 629 } 630 631 // Win: DestroyInputContext 632 BOOL APIENTRY Imm32DestroyInputContext(HIMC hIMC, HKL hKL, BOOL bKeep) 633 { 634 PIMEDPI pImeDpi; 635 LPINPUTCONTEXTDX pIC; 636 PCLIENTIMC pClientImc; 637 PIMC pIMC; 638 639 if (!hIMC || !IS_IMM_MODE()) 640 return FALSE; 641 642 pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT); 643 if (!pIMC || pIMC->head.pti != Imm32CurrentPti()) 644 { 645 ERR("invalid pIMC: %p\n", pIMC); 646 return FALSE; 647 } 648 649 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData; 650 if (!pClientImc) 651 goto Finish; 652 653 if ((pClientImc->dwFlags & CLIENTIMC_UNKNOWN2) && !bKeep) 654 { 655 ERR("CLIENTIMC_UNKNOWN2\n"); 656 return FALSE; 657 } 658 659 if (pClientImc->dwFlags & CLIENTIMC_DESTROY) 660 return TRUE; 661 662 InterlockedIncrement(&pClientImc->cLockObj); 663 664 if (!pClientImc->hInputContext) 665 goto Quit; 666 667 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 668 if (!pIC) 669 { 670 ImmUnlockClientImc(pClientImc); 671 ERR("!pIC\n"); 672 return FALSE; 673 } 674 675 CtfImmTIMDestroyInputContext(hIMC); 676 677 if (pClientImc->hKL == hKL) 678 { 679 pImeDpi = ImmLockImeDpi(hKL); 680 if (pImeDpi) 681 { 682 if (IS_IME_HKL(hKL)) 683 pImeDpi->ImeSelect(hIMC, FALSE); 684 else if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 685 pImeDpi->CtfImeSelectEx(hIMC, FALSE, hKL); 686 687 ImmUnlockImeDpi(pImeDpi); 688 } 689 690 pClientImc->hKL = NULL; 691 } 692 693 ImmDestroyIMCC(pIC->hPrivate); 694 ImmDestroyIMCC(pIC->hMsgBuf); 695 ImmDestroyIMCC(pIC->hGuideLine); 696 ImmDestroyIMCC(pIC->hCandInfo); 697 ImmDestroyIMCC(pIC->hCompStr); 698 Imm32DestroyImeModeSaver(pIC); 699 ImmUnlockIMC(hIMC); 700 701 Quit: 702 pClientImc->dwFlags |= CLIENTIMC_DESTROY; 703 ImmUnlockClientImc(pClientImc); 704 705 Finish: 706 if (bKeep) 707 return TRUE; 708 return NtUserDestroyInputContext(hIMC); 709 } 710 711 // NOTE: Windows does recursive call ImmLockIMC here but we don't do so. 712 // Win: BOOL CreateInputContext(HIMC hIMC, HKL hKL, BOOL fSelect) 713 BOOL APIENTRY 714 Imm32CreateInputContext(HIMC hIMC, LPINPUTCONTEXT pIC, PCLIENTIMC pClientImc, HKL hKL, BOOL fSelect) 715 { 716 DWORD dwIndex, cbPrivate; 717 PIMEDPI pImeDpi = NULL; 718 LPCOMPOSITIONSTRING pCS; 719 LPCANDIDATEINFO pCI; 720 LPGUIDELINE pGL; 721 722 /* Create IC components */ 723 pIC->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); 724 pIC->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO)); 725 pIC->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE)); 726 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT)); 727 if (!pIC->hCompStr || !pIC->hCandInfo || !pIC->hGuideLine || !pIC->hMsgBuf) 728 goto Fail; 729 730 /* Initialize IC components */ 731 pCS = ImmLockIMCC(pIC->hCompStr); 732 if (!pCS) 733 goto Fail; 734 pCS->dwSize = sizeof(COMPOSITIONSTRING); 735 ImmUnlockIMCC(pIC->hCompStr); 736 737 pCI = ImmLockIMCC(pIC->hCandInfo); 738 if (!pCI) 739 goto Fail; 740 pCI->dwSize = sizeof(CANDIDATEINFO); 741 ImmUnlockIMCC(pIC->hCandInfo); 742 743 pGL = ImmLockIMCC(pIC->hGuideLine); 744 if (!pGL) 745 goto Fail; 746 pGL->dwSize = sizeof(GUIDELINE); 747 ImmUnlockIMCC(pIC->hGuideLine); 748 749 pIC->dwNumMsgBuf = 0; 750 pIC->fOpen = FALSE; 751 pIC->fdwConversion = pIC->fdwSentence = 0; 752 753 for (dwIndex = 0; dwIndex < MAX_CANDIDATEFORM; ++dwIndex) 754 pIC->cfCandForm[dwIndex].dwIndex = IMM_INVALID_CANDFORM; 755 756 /* Get private data size */ 757 pImeDpi = ImmLockImeDpi(hKL); 758 if (!pImeDpi) 759 { 760 cbPrivate = sizeof(DWORD); 761 } 762 else 763 { 764 /* Update CLIENTIMC */ 765 pClientImc->uCodePage = pImeDpi->uCodePage; 766 if (ImeDpi_IsUnicode(pImeDpi)) 767 pClientImc->dwFlags |= CLIENTIMC_WIDE; 768 769 cbPrivate = pImeDpi->ImeInfo.dwPrivateDataSize; 770 } 771 772 /* Create private data */ 773 pIC->hPrivate = ImmCreateIMCC(cbPrivate); 774 if (!pIC->hPrivate) 775 goto Fail; 776 777 if (pImeDpi) 778 { 779 /* Select the IME */ 780 if (fSelect) 781 { 782 if (IS_IME_HKL(hKL)) 783 pImeDpi->ImeSelect(hIMC, TRUE); 784 else if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 785 pImeDpi->CtfImeSelectEx(hIMC, TRUE, hKL); 786 } 787 788 /* Set HKL */ 789 pClientImc->hKL = hKL; 790 791 ImmUnlockImeDpi(pImeDpi); 792 } 793 794 return TRUE; 795 796 Fail: 797 if (pImeDpi) 798 ImmUnlockImeDpi(pImeDpi); 799 800 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf); 801 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine); 802 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo); 803 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr); 804 return FALSE; 805 } 806 807 // Win: InternalImmLockIMC 808 LPINPUTCONTEXT APIENTRY Imm32InternalLockIMC(HIMC hIMC, BOOL fSelect) 809 { 810 HANDLE hIC; 811 LPINPUTCONTEXT pIC = NULL; 812 PCLIENTIMC pClientImc; 813 WORD LangID; 814 DWORD dwThreadId; 815 HKL hOldKL, hNewKL; 816 PIMEDPI pImeDpi = NULL; 817 818 pClientImc = ImmLockClientImc(hIMC); 819 if (!pClientImc) 820 return NULL; 821 822 RtlEnterCriticalSection(&pClientImc->cs); 823 824 if (pClientImc->hInputContext) 825 { 826 pIC = LocalLock(pClientImc->hInputContext); 827 if (pIC) 828 goto Success; 829 else 830 goto Failure; 831 } 832 833 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 834 if (dwThreadId == GetCurrentThreadId() && IS_CICERO_MODE() && !IS_16BIT_MODE()) 835 { 836 hOldKL = GetKeyboardLayout(0); 837 LangID = LOWORD(hOldKL); 838 hNewKL = (HKL)(DWORD_PTR)MAKELONG(LangID, LangID); 839 840 pImeDpi = Imm32FindOrLoadImeDpi(hNewKL); 841 if (pImeDpi) 842 { 843 CtfImmTIMActivate(hNewKL); 844 } 845 } 846 847 if (!NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME)) 848 goto Failure; 849 850 hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX)); 851 pIC = LocalLock(hIC); 852 if (!pIC) 853 { 854 LocalFree(hIC); 855 goto Failure; 856 } 857 pClientImc->hInputContext = hIC; 858 859 hNewKL = GetKeyboardLayout(dwThreadId); 860 if (!Imm32CreateInputContext(hIMC, pIC, pClientImc, hNewKL, fSelect)) 861 { 862 pClientImc->hInputContext = LocalFree(pClientImc->hInputContext); 863 goto Failure; 864 } 865 866 Success: 867 CtfImmTIMCreateInputContext(hIMC); 868 RtlLeaveCriticalSection(&pClientImc->cs); 869 InterlockedIncrement(&pClientImc->cLockObj); 870 ImmUnlockClientImc(pClientImc); 871 return pIC; 872 873 Failure: 874 RtlLeaveCriticalSection(&pClientImc->cs); 875 ImmUnlockClientImc(pClientImc); 876 return NULL; 877 } 878 879 /*********************************************************************** 880 * ImmDestroyContext (IMM32.@) 881 */ 882 BOOL WINAPI ImmDestroyContext(HIMC hIMC) 883 { 884 HKL hKL; 885 886 TRACE("(%p)\n", hIMC); 887 888 if (!IS_IMM_MODE()) 889 return FALSE; 890 891 if (Imm32IsCrossThreadAccess(hIMC)) 892 return FALSE; 893 894 hKL = GetKeyboardLayout(0); 895 return Imm32DestroyInputContext(hIMC, hKL, FALSE); 896 } 897 898 /*********************************************************************** 899 * ImmLockClientImc (IMM32.@) 900 */ 901 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc) 902 { 903 PIMC pIMC; 904 PCLIENTIMC pClientImc; 905 906 TRACE("(%p)\n", hImc); 907 908 if (!hImc) 909 return NULL; 910 911 pIMC = ValidateHandle(hImc, TYPE_INPUTCONTEXT); 912 if (!pIMC || !Imm32CheckImcProcess(pIMC)) 913 return NULL; 914 915 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData; 916 if (pClientImc) 917 { 918 if (pClientImc->dwFlags & CLIENTIMC_DESTROY) 919 return NULL; 920 goto Finish; 921 } 922 923 pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 924 if (!pClientImc) 925 return NULL; 926 927 RtlInitializeCriticalSection(&pClientImc->cs); 928 pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS); 929 930 if (!NtUserUpdateInputContext(hImc, UIC_CLIENTIMCDATA, (DWORD_PTR)pClientImc)) 931 { 932 ImmLocalFree(pClientImc); 933 return NULL; 934 } 935 936 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2; 937 938 Finish: 939 InterlockedIncrement(&pClientImc->cLockObj); 940 return pClientImc; 941 } 942 943 /*********************************************************************** 944 * ImmUnlockClientImc (IMM32.@) 945 */ 946 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc) 947 { 948 LONG cLocks; 949 HANDLE hInputContext; 950 951 TRACE("(%p)\n", pClientImc); 952 953 cLocks = InterlockedDecrement(&pClientImc->cLockObj); 954 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_DESTROY)) 955 return; 956 957 hInputContext = pClientImc->hInputContext; 958 if (hInputContext) 959 LocalFree(hInputContext); 960 961 RtlDeleteCriticalSection(&pClientImc->cs); 962 ImmLocalFree(pClientImc); 963 } 964 965 // Win: ImmGetSaveContext 966 static HIMC APIENTRY ImmGetSaveContext(HWND hWnd, DWORD dwContextFlags) 967 { 968 HIMC hIMC; 969 PCLIENTIMC pClientImc; 970 PWND pWnd; 971 972 if (!IS_IMM_MODE()) 973 return NULL; 974 975 if (!hWnd) 976 { 977 hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT); 978 goto Quit; 979 } 980 981 pWnd = ValidateHwnd(hWnd); 982 if (!pWnd || Imm32IsCrossProcessAccess(hWnd)) 983 return NULL; 984 985 hIMC = pWnd->hImc; 986 if (!hIMC && (dwContextFlags & 1)) 987 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT); 988 989 Quit: 990 pClientImc = ImmLockClientImc(hIMC); 991 if (pClientImc == NULL) 992 return NULL; 993 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_DISABLEIME)) 994 hIMC = NULL; 995 ImmUnlockClientImc(pClientImc); 996 return hIMC; 997 } 998 999 /*********************************************************************** 1000 * ImmGetContext (IMM32.@) 1001 */ 1002 HIMC WINAPI ImmGetContext(HWND hWnd) 1003 { 1004 TRACE("(%p)\n", hWnd); 1005 if (hWnd == NULL) 1006 return NULL; 1007 return ImmGetSaveContext(hWnd, 2); 1008 } 1009 1010 /*********************************************************************** 1011 * ImmLockIMC(IMM32.@) 1012 * 1013 * NOTE: This is not ImmLockIMCC. Don't confuse. 1014 */ 1015 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) 1016 { 1017 TRACE("(%p)\n", hIMC); 1018 return Imm32InternalLockIMC(hIMC, TRUE); 1019 } 1020 1021 /*********************************************************************** 1022 * ImmUnlockIMC(IMM32.@) 1023 */ 1024 BOOL WINAPI ImmUnlockIMC(HIMC hIMC) 1025 { 1026 PCLIENTIMC pClientImc; 1027 1028 pClientImc = ImmLockClientImc(hIMC); 1029 if (pClientImc == NULL) 1030 return FALSE; 1031 1032 if (pClientImc->hInputContext) 1033 LocalUnlock(pClientImc->hInputContext); 1034 1035 InterlockedDecrement(&pClientImc->cLockObj); 1036 ImmUnlockClientImc(pClientImc); 1037 return TRUE; 1038 } 1039 1040 /*********************************************************************** 1041 * ImmReleaseContext (IMM32.@) 1042 */ 1043 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) 1044 { 1045 TRACE("(%p, %p)\n", hWnd, hIMC); 1046 UNREFERENCED_PARAMETER(hWnd); 1047 UNREFERENCED_PARAMETER(hIMC); 1048 return TRUE; // Do nothing. This is correct. 1049 } 1050 1051 /*********************************************************************** 1052 * ImmCreateSoftKeyboard(IMM32.@) 1053 */ 1054 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y) 1055 { 1056 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y); 1057 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1058 return 0; 1059 } 1060 1061 /*********************************************************************** 1062 * ImmDestroySoftKeyboard(IMM32.@) 1063 */ 1064 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd) 1065 { 1066 TRACE("(%p)\n", hSoftWnd); 1067 return DestroyWindow(hSoftWnd); 1068 } 1069 1070 /*********************************************************************** 1071 * ImmShowSoftKeyboard(IMM32.@) 1072 */ 1073 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow) 1074 { 1075 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow); 1076 if (hSoftWnd) 1077 return ShowWindow(hSoftWnd, nCmdShow); 1078 return FALSE; 1079 } 1080 1081 /*********************************************************************** 1082 * ImmDisableTextFrameService(IMM32.@) 1083 */ 1084 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId) 1085 { 1086 FIXME("Stub\n"); 1087 return FALSE; 1088 } 1089 1090 /*********************************************************************** 1091 * ImmEnumInputContext(IMM32.@) 1092 */ 1093 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam) 1094 { 1095 HIMC *phList; 1096 DWORD dwIndex, dwCount; 1097 BOOL ret = TRUE; 1098 HIMC hIMC; 1099 1100 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam); 1101 1102 dwCount = Imm32BuildHimcList(dwThreadId, &phList); 1103 if (!dwCount) 1104 return FALSE; 1105 1106 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex) 1107 { 1108 hIMC = phList[dwIndex]; 1109 ret = (*lpfn)(hIMC, lParam); 1110 if (!ret) 1111 break; 1112 } 1113 1114 ImmLocalFree(phList); 1115 return ret; 1116 } 1117 1118 /*********************************************************************** 1119 * ImmSetActiveContext(IMM32.@) 1120 */ 1121 BOOL WINAPI ImmSetActiveContext(HWND hWnd, HIMC hIMC, BOOL fActive) 1122 { 1123 PCLIENTIMC pClientImc; 1124 LPINPUTCONTEXTDX pIC; 1125 PIMEDPI pImeDpi; 1126 HKL hKL; 1127 BOOL fOpen = FALSE; 1128 DWORD dwConversion = 0, iShow = ISC_SHOWUIALL; 1129 HWND hwndDefIME; 1130 1131 TRACE("(%p, %p, %d)\n", hWnd, hIMC, fActive); 1132 1133 if (!IS_IMM_MODE()) 1134 return FALSE; 1135 1136 pClientImc = ImmLockClientImc(hIMC); 1137 1138 if (!fActive) 1139 { 1140 if (pClientImc) 1141 pClientImc->dwFlags &= ~CLIENTIMC_UNKNOWN4; 1142 } 1143 else if (hIMC) 1144 { 1145 if (!pClientImc) 1146 return FALSE; 1147 1148 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 1149 if (!pIC) 1150 { 1151 ImmUnlockClientImc(pClientImc); 1152 return FALSE; 1153 } 1154 1155 pIC->hWnd = hWnd; 1156 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN5; 1157 1158 if (pIC->dwUIFlags & 2) 1159 iShow = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW); 1160 1161 fOpen = pIC->fOpen; 1162 dwConversion = pIC->fdwConversion; 1163 1164 ImmUnlockIMC(hIMC); 1165 } 1166 else 1167 { 1168 hIMC = ImmGetSaveContext(hWnd, 1); 1169 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 1170 if (pIC) 1171 { 1172 pIC->hWnd = hWnd; 1173 ImmUnlockIMC(hIMC); 1174 } 1175 hIMC = NULL; 1176 } 1177 1178 hKL = GetKeyboardLayout(0); 1179 1180 if (IS_CICERO_MODE() && !IS_16BIT_MODE()) 1181 { 1182 Imm32CiceroSetActiveContext(hIMC, fActive, hWnd, hKL); 1183 hKL = GetKeyboardLayout(0); 1184 } 1185 1186 pImeDpi = ImmLockImeDpi(hKL); 1187 if (pImeDpi) 1188 { 1189 if (IS_IME_HKL(hKL)) 1190 pImeDpi->ImeSetActiveContext(hIMC, fActive); 1191 ImmUnlockImeDpi(pImeDpi); 1192 } 1193 1194 if (IsWindow(hWnd)) 1195 { 1196 SendMessageW(hWnd, WM_IME_SETCONTEXT, fActive, iShow); 1197 if (fActive) 1198 NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion); 1199 } 1200 else if (!fActive) 1201 { 1202 hwndDefIME = ImmGetDefaultIMEWnd(NULL); 1203 if (hwndDefIME) 1204 SendMessageW(hwndDefIME, WM_IME_SETCONTEXT, 0, iShow); 1205 } 1206 1207 if (pClientImc) 1208 ImmUnlockClientImc(pClientImc); 1209 1210 return TRUE; 1211 } 1212 1213 /*********************************************************************** 1214 * ImmWINNLSGetEnableStatus (IMM32.@) 1215 */ 1216 1217 BOOL WINAPI ImmWINNLSGetEnableStatus(HWND hWnd) 1218 { 1219 if (!Imm32IsSystemJapaneseOrKorean()) 1220 { 1221 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1222 return FALSE; 1223 } 1224 1225 return !!ImmGetSaveContext(hWnd, 2); 1226 } 1227 1228 /*********************************************************************** 1229 * ImmSetActiveContextConsoleIME(IMM32.@) 1230 */ 1231 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag) 1232 { 1233 HIMC hIMC; 1234 TRACE("(%p, %d)\n", hwnd, fFlag); 1235 1236 hIMC = ImmGetContext(hwnd); 1237 if (hIMC) 1238 return ImmSetActiveContext(hwnd, hIMC, fFlag); 1239 return FALSE; 1240 } 1241 1242 BOOL WINAPI User32InitializeImmEntryTable(DWORD); 1243 1244 BOOL 1245 WINAPI 1246 ImmDllInitialize( 1247 _In_ HANDLE hDll, 1248 _In_ ULONG dwReason, 1249 _In_opt_ PVOID pReserved) 1250 { 1251 HKL hKL; 1252 HIMC hIMC; 1253 1254 TRACE("(%p, 0x%X, %p)\n", hDll, dwReason, pReserved); 1255 1256 switch (dwReason) 1257 { 1258 case DLL_PROCESS_ATTACH: 1259 if (!ImmInitializeGlobals(hDll)) 1260 { 1261 ERR("ImmInitializeGlobals failed\n"); 1262 return FALSE; 1263 } 1264 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) 1265 { 1266 ERR("User32InitializeImmEntryTable failed\n"); 1267 return FALSE; 1268 } 1269 break; 1270 1271 case DLL_THREAD_ATTACH: 1272 break; 1273 1274 case DLL_THREAD_DETACH: 1275 if (!IS_IMM_MODE() || NtCurrentTeb()->Win32ThreadInfo == NULL) 1276 return TRUE; 1277 1278 hKL = GetKeyboardLayout(0); 1279 hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT); 1280 Imm32DestroyInputContext(hIMC, hKL, TRUE); 1281 break; 1282 1283 case DLL_PROCESS_DETACH: 1284 RtlDeleteCriticalSection(&gcsImeDpi); 1285 TRACE("imm32.dll is unloaded\n"); 1286 break; 1287 } 1288 1289 return TRUE; 1290 } 1291