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