1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing IME manipulation of IMM32 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 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua> 10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 11 */ 12 13 #include "precomp.h" 14 15 WINE_DEFAULT_DEBUG_CHANNEL(imm); 16 17 RTL_CRITICAL_SECTION g_csImeDpi; 18 PIMEDPI g_pImeDpiList = NULL; 19 20 PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL) 21 { 22 PIMEDPI pImeDpi; 23 24 RtlEnterCriticalSection(&g_csImeDpi); 25 for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext) 26 { 27 if (pImeDpi->hKL == hKL) 28 break; 29 } 30 RtlLeaveCriticalSection(&g_csImeDpi); 31 32 return pImeDpi; 33 } 34 35 VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy) 36 { 37 if (pImeDpi->hInst == NULL) 38 return; 39 if (bDestroy) 40 pImeDpi->ImeDestroy(0); 41 FreeLibrary(pImeDpi->hInst); 42 pImeDpi->hInst = NULL; 43 } 44 45 BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi) 46 { 47 WCHAR szUIClass[64]; 48 WNDCLASSW wcW; 49 DWORD dwSysInfoFlags = 0; // TODO: ??? 50 LPIMEINFO pImeInfo = &pImeDpi->ImeInfo; 51 52 // TODO: NtUserGetThreadState(16); 53 54 if (!IS_IME_HKL(pImeDpi->hKL)) 55 { 56 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) && 57 pImeDpi->CtfImeInquireExW) 58 { 59 // TODO: 60 return FALSE; 61 } 62 } 63 64 if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags)) 65 return FALSE; 66 67 szUIClass[_countof(szUIClass) - 1] = 0; 68 69 if (pImeInfo->dwPrivateDataSize == 0) 70 pImeInfo->dwPrivateDataSize = 4; 71 72 #define VALID_IME_PROP (IME_PROP_AT_CARET | \ 73 IME_PROP_SPECIAL_UI | \ 74 IME_PROP_CANDLIST_START_FROM_1 | \ 75 IME_PROP_UNICODE | \ 76 IME_PROP_COMPLETE_ON_UNSELECT | \ 77 IME_PROP_END_UNLOAD | \ 78 IME_PROP_KBD_CHAR_FIRST | \ 79 IME_PROP_IGNORE_UPKEYS | \ 80 IME_PROP_NEED_ALTKEY | \ 81 IME_PROP_NO_KEYS_ON_CLOSE | \ 82 IME_PROP_ACCEPT_WIDE_VKEY) 83 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \ 84 IME_CMODE_NATIVE | \ 85 IME_CMODE_KATAKANA | \ 86 IME_CMODE_LANGUAGE | \ 87 IME_CMODE_FULLSHAPE | \ 88 IME_CMODE_ROMAN | \ 89 IME_CMODE_CHARCODE | \ 90 IME_CMODE_HANJACONVERT | \ 91 IME_CMODE_SOFTKBD | \ 92 IME_CMODE_NOCONVERSION | \ 93 IME_CMODE_EUDC | \ 94 IME_CMODE_SYMBOL | \ 95 IME_CMODE_FIXED) 96 #define VALID_SMODE_CAPS (IME_SMODE_NONE | \ 97 IME_SMODE_PLAURALCLAUSE | \ 98 IME_SMODE_SINGLECONVERT | \ 99 IME_SMODE_AUTOMATIC | \ 100 IME_SMODE_PHRASEPREDICT | \ 101 IME_SMODE_CONVERSATION) 102 #define VALID_UI_CAPS (UI_CAP_2700 | \ 103 UI_CAP_ROT90 | \ 104 UI_CAP_ROTANY | \ 105 UI_CAP_SOFTKBD) 106 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR | \ 107 SCS_CAP_MAKEREAD | \ 108 SCS_CAP_SETRECONVERTSTRING) 109 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE) 110 111 if (pImeInfo->fdwProperty & ~VALID_IME_PROP) 112 return FALSE; 113 if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS) 114 return FALSE; 115 if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS) 116 return FALSE; 117 if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS) 118 return FALSE; 119 if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS) 120 return FALSE; 121 if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS) 122 return FALSE; 123 124 #undef VALID_IME_PROP 125 #undef VALID_CMODE_CAPS 126 #undef VALID_SMODE_CAPS 127 #undef VALID_UI_CAPS 128 #undef VALID_SCS_CAPS 129 #undef VALID_SELECT_CAPS 130 131 if (pImeInfo->fdwProperty & IME_PROP_UNICODE) 132 { 133 StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass); 134 } 135 else 136 { 137 if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage) 138 return FALSE; 139 140 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1, 141 pImeDpi->szUIClass, _countof(pImeDpi->szUIClass)); 142 } 143 144 return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW); 145 } 146 147 BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) 148 { 149 WCHAR szPath[MAX_PATH]; 150 HINSTANCE hIME; 151 FARPROC fn; 152 153 if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile)) 154 return FALSE; 155 156 hIME = GetModuleHandleW(szPath); 157 if (hIME == NULL) 158 { 159 hIME = LoadLibraryW(szPath); 160 if (hIME == NULL) 161 { 162 ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath); 163 return FALSE; 164 } 165 } 166 pImeDpi->hInst = hIME; 167 168 #define DEFINE_IME_ENTRY(type, name, params, extended) \ 169 do { \ 170 fn = GetProcAddress(hIME, #name); \ 171 if (fn) pImeDpi->name = (FN_##name)fn; \ 172 else if (!extended) goto Failed; \ 173 } while (0); 174 #include "../../../win32ss/include/imetable.h" 175 #undef DEFINE_IME_ENTRY 176 177 if (!Imm32InquireIme(pImeDpi)) 178 { 179 ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n"); 180 goto Failed; 181 } 182 183 if (pImeInfoEx->fLoadFlag) 184 return TRUE; 185 186 NtUserSetImeOwnerWindow(pImeInfoEx, TRUE); 187 return TRUE; 188 189 Failed: 190 FreeLibrary(pImeDpi->hInst); 191 pImeDpi->hInst = NULL; 192 return FALSE; 193 } 194 195 PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock) 196 { 197 IMEINFOEX ImeInfoEx; 198 CHARSETINFO ci; 199 PIMEDPI pImeDpiNew, pImeDpiFound; 200 UINT uCodePage; 201 LCID lcid; 202 203 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) || 204 ImeInfoEx.fLoadFlag == 1) 205 { 206 return NULL; 207 } 208 209 pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI)); 210 if (pImeDpiNew == NULL) 211 return NULL; 212 213 pImeDpiNew->hKL = hKL; 214 215 lcid = LOWORD(hKL); 216 if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE)) 217 uCodePage = ci.ciACP; 218 else 219 uCodePage = CP_ACP; 220 pImeDpiNew->uCodePage = uCodePage; 221 222 if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew)) 223 { 224 HeapFree(g_hImm32Heap, 0, pImeDpiNew); 225 return FALSE; 226 } 227 228 RtlEnterCriticalSection(&g_csImeDpi); 229 230 pImeDpiFound = Imm32FindImeDpi(hKL); 231 if (pImeDpiFound) 232 { 233 if (!bLock) 234 pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED; 235 236 RtlLeaveCriticalSection(&g_csImeDpi); 237 238 Imm32FreeImeDpi(pImeDpiNew, FALSE); 239 HeapFree(g_hImm32Heap, 0, pImeDpiNew); 240 return pImeDpiFound; 241 } 242 else 243 { 244 if (bLock) 245 { 246 pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED; 247 pImeDpiNew->cLockObj = 1; 248 } 249 250 pImeDpiNew->pNext = g_pImeDpiList; 251 g_pImeDpiList = pImeDpiNew; 252 253 RtlLeaveCriticalSection(&g_csImeDpi); 254 return pImeDpiNew; 255 } 256 } 257 258 PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL) 259 { 260 PW32CLIENTINFO pInfo; 261 PIMEDPI pImeDpi; 262 263 if (!IS_IME_HKL(hKL)) 264 { 265 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 266 return NULL; 267 268 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); 269 if ((pInfo->W32ClientInfo[0] & 2)) 270 return NULL; 271 } 272 273 pImeDpi = ImmLockImeDpi(hKL); 274 if (pImeDpi == NULL) 275 pImeDpi = Ime32LoadImeDpi(hKL, TRUE); 276 return pImeDpi; 277 } 278 279 /*********************************************************************** 280 * ImmIsIME (IMM32.@) 281 */ 282 BOOL WINAPI ImmIsIME(HKL hKL) 283 { 284 IMEINFOEX info; 285 TRACE("(%p)\n", hKL); 286 return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL); 287 } 288 289 /*********************************************************************** 290 * ImmGetDefaultIMEWnd (IMM32.@) 291 */ 292 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) 293 { 294 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 295 return NULL; 296 297 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 298 if (hWnd == NULL) 299 return (HWND)NtUserGetThreadState(3); 300 301 return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME); 302 } 303 304 /*********************************************************************** 305 * ImmNotifyIME (IMM32.@) 306 */ 307 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) 308 { 309 HKL hKL; 310 PIMEDPI pImeDpi; 311 BOOL ret; 312 313 TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue); 314 315 if (hIMC && Imm32IsCrossThreadAccess(hIMC)) 316 return FALSE; 317 318 hKL = GetKeyboardLayout(0); 319 pImeDpi = ImmLockImeDpi(hKL); 320 if (pImeDpi == NULL) 321 return FALSE; 322 323 ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); 324 ImmUnlockImeDpi(pImeDpi); 325 return ret; 326 } 327 328 /*********************************************************************** 329 * ImmDisableLegacyIME(IMM32.@) 330 */ 331 BOOL WINAPI ImmDisableLegacyIME(void) 332 { 333 FIXME("stub\n"); 334 return TRUE; 335 } 336 337 /*********************************************************************** 338 * CtfImmIsTextFrameServiceDisabled(IMM32.@) 339 */ 340 BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID) 341 { 342 PTEB pTeb = NtCurrentTeb(); 343 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED) 344 return TRUE; 345 return FALSE; 346 } 347 348 /*********************************************************************** 349 * ImmGetImeInfoEx (IMM32.@) 350 */ 351 BOOL WINAPI 352 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey) 353 { 354 BOOL bDisabled = FALSE; 355 HKL hKL; 356 PTEB pTeb; 357 358 switch (SearchType) 359 { 360 case ImeInfoExKeyboardLayout: 361 break; 362 363 case ImeInfoExImeWindow: 364 bDisabled = CtfImmIsTextFrameServiceDisabled(); 365 SearchType = ImeInfoExKeyboardLayout; 366 break; 367 368 case ImeInfoExImeFileName: 369 StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile), 370 pvSearchKey); 371 goto Quit; 372 } 373 374 hKL = *(HKL*)pvSearchKey; 375 pImeInfoEx->hkl = hKL; 376 377 if (!IS_IME_HKL(hKL)) 378 { 379 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 380 { 381 pTeb = NtCurrentTeb(); 382 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2) 383 return FALSE; 384 if (!bDisabled) 385 goto Quit; 386 } 387 return FALSE; 388 } 389 390 Quit: 391 return NtUserGetImeInfoEx(pImeInfoEx, SearchType); 392 } 393 394 /*********************************************************************** 395 * ImmLockImeDpi (IMM32.@) 396 */ 397 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL) 398 { 399 PIMEDPI pImeDpi = NULL; 400 401 TRACE("(%p)\n", hKL); 402 403 RtlEnterCriticalSection(&g_csImeDpi); 404 405 /* Find by hKL */ 406 for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext) 407 { 408 if (pImeDpi->hKL == hKL) /* found */ 409 { 410 /* lock if possible */ 411 if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) 412 pImeDpi = NULL; 413 else 414 ++(pImeDpi->cLockObj); 415 break; 416 } 417 } 418 419 RtlLeaveCriticalSection(&g_csImeDpi); 420 return pImeDpi; 421 } 422 423 /*********************************************************************** 424 * ImmUnlockImeDpi (IMM32.@) 425 */ 426 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi) 427 { 428 PIMEDPI *ppEntry; 429 430 TRACE("(%p)\n", pImeDpi); 431 432 if (pImeDpi == NULL) 433 return; 434 435 RtlEnterCriticalSection(&g_csImeDpi); 436 437 /* unlock */ 438 --(pImeDpi->cLockObj); 439 if (pImeDpi->cLockObj != 0) 440 { 441 RtlLeaveCriticalSection(&g_csImeDpi); 442 return; 443 } 444 445 if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0) 446 { 447 if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 || 448 (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0) 449 { 450 RtlLeaveCriticalSection(&g_csImeDpi); 451 return; 452 } 453 } 454 455 /* Remove from list */ 456 for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext)) 457 { 458 if (*ppEntry == pImeDpi) /* found */ 459 { 460 *ppEntry = pImeDpi->pNext; 461 break; 462 } 463 } 464 465 Imm32FreeImeDpi(pImeDpi, TRUE); 466 HeapFree(g_hImm32Heap, 0, pImeDpi); 467 468 RtlLeaveCriticalSection(&g_csImeDpi); 469 } 470 471 /*********************************************************************** 472 * ImmLoadIME (IMM32.@) 473 */ 474 BOOL WINAPI ImmLoadIME(HKL hKL) 475 { 476 PW32CLIENTINFO pInfo; 477 PIMEDPI pImeDpi; 478 479 if (!IS_IME_HKL(hKL)) 480 { 481 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 482 return FALSE; 483 484 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); 485 if ((pInfo->W32ClientInfo[0] & 2)) 486 return FALSE; 487 } 488 489 pImeDpi = Imm32FindImeDpi(hKL); 490 if (pImeDpi == NULL) 491 pImeDpi = Ime32LoadImeDpi(hKL, FALSE); 492 return (pImeDpi != NULL); 493 } 494 495 /*********************************************************************** 496 * ImmDisableIME (IMM32.@) 497 */ 498 BOOL WINAPI ImmDisableIME(DWORD dwThreadId) 499 { 500 return NtUserDisableThreadIme(dwThreadId); 501 } 502 503 /*********************************************************************** 504 * ImmGetDescriptionA (IMM32.@) 505 */ 506 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen) 507 { 508 IMEINFOEX info; 509 size_t cch; 510 511 TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen); 512 513 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 514 return 0; 515 516 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); 517 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch, 518 lpszDescription, uBufLen, NULL, NULL); 519 if (uBufLen) 520 lpszDescription[cch] = 0; 521 return (UINT)cch; 522 } 523 524 /*********************************************************************** 525 * ImmGetDescriptionW (IMM32.@) 526 */ 527 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) 528 { 529 IMEINFOEX info; 530 size_t cch; 531 532 TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen); 533 534 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 535 return 0; 536 537 if (uBufLen != 0) 538 StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription); 539 540 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); 541 return (UINT)cch; 542 } 543 544 /*********************************************************************** 545 * ImmGetIMEFileNameA (IMM32.@) 546 */ 547 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) 548 { 549 BOOL bDefUsed; 550 IMEINFOEX info; 551 size_t cch; 552 553 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); 554 555 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 556 { 557 if (uBufLen > 0) 558 lpszFileName[0] = 0; 559 return 0; 560 } 561 562 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); 563 564 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch, 565 lpszFileName, uBufLen, NULL, &bDefUsed); 566 if (uBufLen == 0) 567 return (UINT)cch; 568 569 if (cch > uBufLen - 1) 570 cch = uBufLen - 1; 571 572 lpszFileName[cch] = 0; 573 return (UINT)cch; 574 } 575 576 /*********************************************************************** 577 * ImmGetIMEFileNameW (IMM32.@) 578 */ 579 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) 580 { 581 IMEINFOEX info; 582 size_t cch; 583 584 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); 585 586 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 587 { 588 if (uBufLen > 0) 589 lpszFileName[0] = 0; 590 return 0; 591 } 592 593 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); 594 if (uBufLen == 0) 595 return (UINT)cch; 596 597 StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch); 598 599 if (cch > uBufLen - 1) 600 cch = uBufLen - 1; 601 602 lpszFileName[cch] = 0; 603 return (UINT)cch; 604 } 605 606 /*********************************************************************** 607 * ImmGetProperty (IMM32.@) 608 */ 609 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) 610 { 611 IMEINFOEX ImeInfoEx; 612 LPIMEINFO pImeInfo; 613 DWORD dwValue; 614 PIMEDPI pImeDpi = NULL; 615 616 TRACE("(%p, %lu)\n", hKL, fdwIndex); 617 618 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL)) 619 return FALSE; 620 621 if (fdwIndex == IGP_GETIMEVERSION) 622 return ImeInfoEx.dwImeWinVersion; 623 624 if (ImeInfoEx.fLoadFlag != 2) 625 { 626 pImeDpi = ImmLockOrLoadImeDpi(hKL); 627 if (pImeDpi == NULL) 628 return FALSE; 629 630 pImeInfo = &pImeDpi->ImeInfo; 631 } 632 else 633 { 634 pImeInfo = &ImeInfoEx.ImeInfo; 635 } 636 637 switch (fdwIndex) 638 { 639 case IGP_PROPERTY: dwValue = pImeInfo->fdwProperty; break; 640 case IGP_CONVERSION: dwValue = pImeInfo->fdwConversionCaps; break; 641 case IGP_SENTENCE: dwValue = pImeInfo->fdwSentenceCaps; break; 642 case IGP_UI: dwValue = pImeInfo->fdwUICaps; break; 643 case IGP_SETCOMPSTR: dwValue = pImeInfo->fdwSCSCaps; break; 644 case IGP_SELECT: dwValue = pImeInfo->fdwSelectCaps; break; 645 default: dwValue = 0; break; 646 } 647 648 if (pImeDpi) 649 ImmUnlockImeDpi(pImeDpi); 650 return dwValue; 651 } 652 653 /*********************************************************************** 654 * ImmGetOpenStatus (IMM32.@) 655 */ 656 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) 657 { 658 BOOL ret; 659 LPINPUTCONTEXT pIC; 660 661 TRACE("(%p)\n", hIMC); 662 663 if (!hIMC) 664 return FALSE; 665 666 pIC = ImmLockIMC(hIMC); 667 if (!pIC) 668 return FALSE; 669 670 ret = pIC->fOpen; 671 672 ImmUnlockIMC(hIMC); 673 return ret; 674 } 675 676 /*********************************************************************** 677 * ImmSetOpenStatus (IMM32.@) 678 */ 679 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) 680 { 681 DWORD dwConversion; 682 LPINPUTCONTEXT pIC; 683 HWND hWnd; 684 BOOL bHasChange = FALSE; 685 686 TRACE("(%p, %d)\n", hIMC, fOpen); 687 688 if (Imm32IsCrossThreadAccess(hIMC)) 689 return FALSE; 690 691 pIC = ImmLockIMC(hIMC); 692 if (pIC == NULL) 693 return FALSE; 694 695 if (pIC->fOpen != fOpen) 696 { 697 pIC->fOpen = fOpen; 698 hWnd = pIC->hWnd; 699 dwConversion = pIC->fdwConversion; 700 bHasChange = TRUE; 701 } 702 703 ImmUnlockIMC(hIMC); 704 705 if (bHasChange) 706 { 707 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 708 IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0); 709 NtUserNotifyIMEStatus(hWnd, hIMC, dwConversion); 710 } 711 712 return TRUE; 713 } 714 715 /*********************************************************************** 716 * ImmGetStatusWindowPos (IMM32.@) 717 */ 718 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) 719 { 720 LPINPUTCONTEXT pIC; 721 BOOL ret; 722 723 TRACE("(%p, %p)\n", hIMC, lpptPos); 724 725 pIC = ImmLockIMC(hIMC); 726 if (pIC == NULL) 727 return FALSE; 728 729 ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS); 730 if (ret) 731 *lpptPos = pIC->ptStatusWndPos; 732 733 ImmUnlockIMC(hIMC); 734 return ret; 735 } 736 737 /*********************************************************************** 738 * ImmSetStatusWindowPos (IMM32.@) 739 */ 740 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) 741 { 742 LPINPUTCONTEXT pIC; 743 HWND hWnd; 744 745 TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y); 746 747 if (Imm32IsCrossThreadAccess(hIMC)) 748 return FALSE; 749 750 pIC = ImmLockIMC(hIMC); 751 if (!pIC) 752 return FALSE; 753 754 hWnd = pIC->hWnd; 755 pIC->ptStatusWndPos = *lpptPos; 756 pIC->fdwInit |= INIT_STATUSWNDPOS; 757 758 ImmUnlockIMC(hIMC); 759 760 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 761 IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0); 762 return TRUE; 763 } 764 765 /*********************************************************************** 766 * ImmGetCompositionWindow (IMM32.@) 767 */ 768 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) 769 { 770 LPINPUTCONTEXT pIC; 771 BOOL ret = FALSE; 772 773 TRACE("(%p, %p)\n", hIMC, lpCompForm); 774 775 pIC = ImmLockIMC(hIMC); 776 if (!pIC) 777 return FALSE; 778 779 if (pIC->fdwInit & INIT_COMPFORM) 780 { 781 *lpCompForm = pIC->cfCompForm; 782 ret = TRUE; 783 } 784 785 ImmUnlockIMC(hIMC); 786 return ret; 787 } 788 789 /*********************************************************************** 790 * ImmSetCompositionWindow (IMM32.@) 791 */ 792 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) 793 { 794 LPINPUTCONTEXT pIC; 795 HWND hWnd; 796 797 if (Imm32IsCrossThreadAccess(hIMC)) 798 return FALSE; 799 800 pIC = ImmLockIMC(hIMC); 801 if (pIC == NULL) 802 return FALSE; 803 804 pIC->cfCompForm = *lpCompForm; 805 pIC->fdwInit |= INIT_COMPFORM; 806 807 hWnd = pIC->hWnd; 808 809 ImmUnlockIMC(hIMC); 810 811 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 812 IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0); 813 return TRUE; 814 } 815 816 /*********************************************************************** 817 * ImmGetCompositionFontA (IMM32.@) 818 */ 819 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) 820 { 821 PCLIENTIMC pClientImc; 822 BOOL ret = FALSE, bWide; 823 LPINPUTCONTEXT pIC; 824 825 TRACE("(%p, %p)\n", hIMC, lplf); 826 827 pClientImc = ImmLockClientImc(hIMC); 828 if (pClientImc == NULL) 829 return FALSE; 830 831 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 832 ImmUnlockClientImc(pClientImc); 833 834 pIC = ImmLockIMC(hIMC); 835 if (pIC == NULL) 836 return FALSE; 837 838 if (pIC->fdwInit & INIT_LOGFONT) 839 { 840 if (bWide) 841 LogFontWideToAnsi(&pIC->lfFont.W, lplf); 842 else 843 *lplf = pIC->lfFont.A; 844 845 ret = TRUE; 846 } 847 848 ImmUnlockIMC(hIMC); 849 return ret; 850 } 851 852 /*********************************************************************** 853 * ImmGetCompositionFontW (IMM32.@) 854 */ 855 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) 856 { 857 PCLIENTIMC pClientImc; 858 BOOL bWide; 859 LPINPUTCONTEXT pIC; 860 BOOL ret = FALSE; 861 862 TRACE("(%p, %p)\n", hIMC, lplf); 863 864 pClientImc = ImmLockClientImc(hIMC); 865 if (pClientImc == NULL) 866 return FALSE; 867 868 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 869 ImmUnlockClientImc(pClientImc); 870 871 pIC = ImmLockIMC(hIMC); 872 if (pIC == NULL) 873 return FALSE; 874 875 if (pIC->fdwInit & INIT_LOGFONT) 876 { 877 if (bWide) 878 *lplf = pIC->lfFont.W; 879 else 880 LogFontAnsiToWide(&pIC->lfFont.A, lplf); 881 882 ret = TRUE; 883 } 884 885 ImmUnlockIMC(hIMC); 886 return ret; 887 } 888 889 /*********************************************************************** 890 * ImmSetCompositionFontA (IMM32.@) 891 */ 892 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) 893 { 894 LOGFONTW lfW; 895 PCLIENTIMC pClientImc; 896 BOOL bWide; 897 LPINPUTCONTEXTDX pIC; 898 LCID lcid; 899 HWND hWnd; 900 PTEB pTeb; 901 902 TRACE("(%p, %p)\n", hIMC, lplf); 903 904 if (Imm32IsCrossThreadAccess(hIMC)) 905 return FALSE; 906 907 pClientImc = ImmLockClientImc(hIMC); 908 if (pClientImc == NULL) 909 return FALSE; 910 911 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 912 ImmUnlockClientImc(pClientImc); 913 914 if (bWide) 915 { 916 LogFontAnsiToWide(lplf, &lfW); 917 return ImmSetCompositionFontW(hIMC, &lfW); 918 } 919 920 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 921 if (pIC == NULL) 922 return FALSE; 923 924 pTeb = NtCurrentTeb(); 925 if (pTeb->Win32ClientInfo[2] < 0x400) 926 { 927 lcid = GetSystemDefaultLCID(); 928 if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) && 929 pIC->cfCompForm.dwStyle != CFS_DEFAULT) 930 { 931 PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 932 } 933 } 934 935 pIC->lfFont.A = *lplf; 936 pIC->fdwInit |= INIT_LOGFONT; 937 hWnd = pIC->hWnd; 938 939 ImmUnlockIMC(hIMC); 940 941 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, 942 IMN_SETCOMPOSITIONFONT, 0); 943 return TRUE; 944 } 945 946 /*********************************************************************** 947 * ImmSetCompositionFontW (IMM32.@) 948 */ 949 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) 950 { 951 LOGFONTA lfA; 952 PCLIENTIMC pClientImc; 953 BOOL bWide; 954 HWND hWnd; 955 LPINPUTCONTEXTDX pIC; 956 PTEB pTeb; 957 LCID lcid; 958 959 TRACE("(%p, %p)\n", hIMC, lplf); 960 961 if (Imm32IsCrossThreadAccess(hIMC)) 962 return FALSE; 963 964 pClientImc = ImmLockClientImc(hIMC); 965 if (pClientImc == NULL) 966 return FALSE; 967 968 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 969 ImmUnlockClientImc(pClientImc); 970 971 if (!bWide) 972 { 973 LogFontWideToAnsi(lplf, &lfA); 974 return ImmSetCompositionFontA(hIMC, &lfA); 975 } 976 977 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 978 if (pIC == NULL) 979 return FALSE; 980 981 pTeb = NtCurrentTeb(); 982 if (pTeb->Win32ClientInfo[2] < 0x400) 983 { 984 lcid = GetSystemDefaultLCID(); 985 if (PRIMARYLANGID(lcid) == LANG_JAPANESE && 986 !(pIC->dwUIFlags & 2) && 987 pIC->cfCompForm.dwStyle != CFS_DEFAULT) 988 { 989 PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 990 } 991 } 992 993 pIC->lfFont.W = *lplf; 994 pIC->fdwInit |= INIT_LOGFONT; 995 hWnd = pIC->hWnd; 996 997 ImmUnlockIMC(hIMC); 998 999 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, 1000 IMN_SETCOMPOSITIONFONT, 0); 1001 return TRUE; 1002 } 1003 1004 /*********************************************************************** 1005 * ImmGetConversionListA (IMM32.@) 1006 */ 1007 DWORD WINAPI 1008 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst, 1009 DWORD dwBufLen, UINT uFlag) 1010 { 1011 DWORD ret = 0; 1012 UINT cb; 1013 LPWSTR pszSrcW = NULL; 1014 LPCANDIDATELIST pCL = NULL; 1015 PIMEDPI pImeDpi; 1016 1017 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc), 1018 lpDst, dwBufLen, uFlag); 1019 1020 pImeDpi = ImmLockOrLoadImeDpi(hKL); 1021 if (pImeDpi == NULL) 1022 return 0; 1023 1024 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 1025 { 1026 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); 1027 ImmUnlockImeDpi(pImeDpi); 1028 return ret; 1029 } 1030 1031 if (pSrc) 1032 { 1033 pszSrcW = Imm32WideFromAnsi(pSrc); 1034 if (pszSrcW == NULL) 1035 goto Quit; 1036 } 1037 1038 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag); 1039 if (cb == 0) 1040 goto Quit; 1041 1042 pCL = Imm32HeapAlloc(0, cb); 1043 if (pCL == NULL) 1044 goto Quit; 1045 1046 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag); 1047 if (cb == 0) 1048 goto Quit; 1049 1050 ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP); 1051 1052 Quit: 1053 if (pszSrcW) 1054 HeapFree(g_hImm32Heap, 0, pszSrcW); 1055 if (pCL) 1056 HeapFree(g_hImm32Heap, 0, pCL); 1057 ImmUnlockImeDpi(pImeDpi); 1058 return ret; 1059 } 1060 1061 /*********************************************************************** 1062 * ImmGetConversionListW (IMM32.@) 1063 */ 1064 DWORD WINAPI 1065 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst, 1066 DWORD dwBufLen, UINT uFlag) 1067 { 1068 DWORD ret = 0; 1069 INT cb; 1070 PIMEDPI pImeDpi; 1071 LPCANDIDATELIST pCL = NULL; 1072 LPSTR pszSrcA = NULL; 1073 1074 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc), 1075 lpDst, dwBufLen, uFlag); 1076 1077 pImeDpi = ImmLockOrLoadImeDpi(hKL); 1078 if (!pImeDpi) 1079 return 0; 1080 1081 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 1082 { 1083 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); 1084 ImmUnlockImeDpi(pImeDpi); 1085 return ret; 1086 } 1087 1088 if (pSrc) 1089 { 1090 pszSrcA = Imm32AnsiFromWide(pSrc); 1091 if (pszSrcA == NULL) 1092 goto Quit; 1093 } 1094 1095 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag); 1096 if (cb == 0) 1097 goto Quit; 1098 1099 pCL = Imm32HeapAlloc(0, cb); 1100 if (!pCL) 1101 goto Quit; 1102 1103 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag); 1104 if (!cb) 1105 goto Quit; 1106 1107 ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP); 1108 1109 Quit: 1110 if (pszSrcA) 1111 HeapFree(g_hImm32Heap, 0, pszSrcA); 1112 if (pCL) 1113 HeapFree(g_hImm32Heap, 0, pCL); 1114 ImmUnlockImeDpi(pImeDpi); 1115 return ret; 1116 } 1117 1118 /*********************************************************************** 1119 * ImmGetConversionStatus (IMM32.@) 1120 */ 1121 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) 1122 { 1123 LPINPUTCONTEXT pIC; 1124 1125 TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence); 1126 1127 pIC = ImmLockIMC(hIMC); 1128 if (!pIC) 1129 return FALSE; 1130 1131 if (lpfdwConversion) 1132 *lpfdwConversion = pIC->fdwConversion; 1133 if (lpfdwSentence) 1134 *lpfdwSentence = pIC->fdwSentence; 1135 1136 ImmUnlockIMC(hIMC); 1137 return TRUE; 1138 } 1139 1140 /*********************************************************************** 1141 * ImmSetConversionStatus (IMM32.@) 1142 */ 1143 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) 1144 { 1145 HKL hKL; 1146 LPINPUTCONTEXT pIC; 1147 DWORD dwOldConversion, dwOldSentence; 1148 BOOL fConversionChange = FALSE, fSentenceChange = FALSE; 1149 HWND hWnd; 1150 1151 TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence); 1152 1153 hKL = GetKeyboardLayout(0); 1154 if (!IS_IME_HKL(hKL)) 1155 { 1156 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 1157 { 1158 FIXME("Cicero\n"); 1159 return FALSE; 1160 } 1161 } 1162 1163 if (Imm32IsCrossThreadAccess(hIMC)) 1164 return FALSE; 1165 1166 pIC = ImmLockIMC(hIMC); 1167 if (pIC == NULL) 1168 return FALSE; 1169 1170 if (pIC->fdwConversion != fdwConversion) 1171 { 1172 dwOldConversion = pIC->fdwConversion; 1173 pIC->fdwConversion = fdwConversion; 1174 fConversionChange = TRUE; 1175 } 1176 1177 if (pIC->fdwSentence != fdwSentence) 1178 { 1179 dwOldSentence = pIC->fdwSentence; 1180 pIC->fdwSentence = fdwSentence; 1181 fSentenceChange = TRUE; 1182 } 1183 1184 hWnd = pIC->hWnd; 1185 ImmUnlockIMC(hIMC); 1186 1187 if (fConversionChange) 1188 { 1189 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion, 1190 IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0); 1191 NtUserNotifyIMEStatus(hWnd, hIMC, fdwConversion); 1192 } 1193 1194 if (fSentenceChange) 1195 { 1196 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence, 1197 IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0); 1198 } 1199 1200 return TRUE; 1201 } 1202