/* * PROJECT: ReactOS IMM32 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Implementing IME manipulation of IMM32 * COPYRIGHT: Copyright 1998 Patrik Stridvall * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart * Copyright 2017 James Tabor * Copyright 2018 Amine Khaldi * Copyright 2020 Oleg Dubinskiy * Copyright 2020-2021 Katayama Hirofumi MZ */ #include "precomp.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); RTL_CRITICAL_SECTION g_csImeDpi; PIMEDPI g_pImeDpiList = NULL; PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL) { PIMEDPI pImeDpi; RtlEnterCriticalSection(&g_csImeDpi); for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext) { if (pImeDpi->hKL == hKL) break; } RtlLeaveCriticalSection(&g_csImeDpi); return pImeDpi; } VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy) { if (pImeDpi->hInst == NULL) return; if (bDestroy) pImeDpi->ImeDestroy(0); FreeLibrary(pImeDpi->hInst); pImeDpi->hInst = NULL; } BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi) { WCHAR szUIClass[64]; WNDCLASSW wcW; DWORD dwSysInfoFlags = 0; // TODO: ??? LPIMEINFO pImeInfo = &pImeDpi->ImeInfo; // TODO: NtUserGetThreadState(16); if (!IS_IME_HKL(pImeDpi->hKL)) { if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) && pImeDpi->CtfImeInquireExW) { // TODO: return FALSE; } } if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags)) return FALSE; szUIClass[_countof(szUIClass) - 1] = 0; if (pImeInfo->dwPrivateDataSize == 0) pImeInfo->dwPrivateDataSize = 4; #define VALID_IME_PROP (IME_PROP_AT_CARET | \ IME_PROP_SPECIAL_UI | \ IME_PROP_CANDLIST_START_FROM_1 | \ IME_PROP_UNICODE | \ IME_PROP_COMPLETE_ON_UNSELECT | \ IME_PROP_END_UNLOAD | \ IME_PROP_KBD_CHAR_FIRST | \ IME_PROP_IGNORE_UPKEYS | \ IME_PROP_NEED_ALTKEY | \ IME_PROP_NO_KEYS_ON_CLOSE | \ IME_PROP_ACCEPT_WIDE_VKEY) #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \ IME_CMODE_NATIVE | \ IME_CMODE_KATAKANA | \ IME_CMODE_LANGUAGE | \ IME_CMODE_FULLSHAPE | \ IME_CMODE_ROMAN | \ IME_CMODE_CHARCODE | \ IME_CMODE_HANJACONVERT | \ IME_CMODE_SOFTKBD | \ IME_CMODE_NOCONVERSION | \ IME_CMODE_EUDC | \ IME_CMODE_SYMBOL | \ IME_CMODE_FIXED) #define VALID_SMODE_CAPS (IME_SMODE_NONE | \ IME_SMODE_PLAURALCLAUSE | \ IME_SMODE_SINGLECONVERT | \ IME_SMODE_AUTOMATIC | \ IME_SMODE_PHRASEPREDICT | \ IME_SMODE_CONVERSATION) #define VALID_UI_CAPS (UI_CAP_2700 | \ UI_CAP_ROT90 | \ UI_CAP_ROTANY | \ UI_CAP_SOFTKBD) #define VALID_SCS_CAPS (SCS_CAP_COMPSTR | \ SCS_CAP_MAKEREAD | \ SCS_CAP_SETRECONVERTSTRING) #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE) if (pImeInfo->fdwProperty & ~VALID_IME_PROP) return FALSE; if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS) return FALSE; if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS) return FALSE; if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS) return FALSE; if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS) return FALSE; if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS) return FALSE; #undef VALID_IME_PROP #undef VALID_CMODE_CAPS #undef VALID_SMODE_CAPS #undef VALID_UI_CAPS #undef VALID_SCS_CAPS #undef VALID_SELECT_CAPS if (pImeInfo->fdwProperty & IME_PROP_UNICODE) { StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass); } else { if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage) return FALSE; MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1, pImeDpi->szUIClass, _countof(pImeDpi->szUIClass)); } return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW); } BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) { WCHAR szPath[MAX_PATH]; HINSTANCE hIME; FARPROC fn; if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile)) return FALSE; hIME = GetModuleHandleW(szPath); if (hIME == NULL) { hIME = LoadLibraryW(szPath); if (hIME == NULL) { ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath); return FALSE; } } pImeDpi->hInst = hIME; #define DEFINE_IME_ENTRY(type, name, params, extended) \ do { \ fn = GetProcAddress(hIME, #name); \ if (fn) pImeDpi->name = (FN_##name)fn; \ else if (!extended) goto Failed; \ } while (0); #include "../../../win32ss/include/imetable.h" #undef DEFINE_IME_ENTRY if (!Imm32InquireIme(pImeDpi)) { ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n"); goto Failed; } if (pImeInfoEx->fLoadFlag) return TRUE; NtUserSetImeOwnerWindow(pImeInfoEx, TRUE); return TRUE; Failed: FreeLibrary(pImeDpi->hInst); pImeDpi->hInst = NULL; return FALSE; } PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock) { IMEINFOEX ImeInfoEx; CHARSETINFO ci; PIMEDPI pImeDpiNew, pImeDpiFound; UINT uCodePage; LCID lcid; if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) || ImeInfoEx.fLoadFlag == 1) { return NULL; } pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI)); if (pImeDpiNew == NULL) return NULL; pImeDpiNew->hKL = hKL; lcid = LOWORD(hKL); if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE)) uCodePage = ci.ciACP; else uCodePage = CP_ACP; pImeDpiNew->uCodePage = uCodePage; if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew)) { HeapFree(g_hImm32Heap, 0, pImeDpiNew); return FALSE; } RtlEnterCriticalSection(&g_csImeDpi); pImeDpiFound = Imm32FindImeDpi(hKL); if (pImeDpiFound) { if (!bLock) pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED; RtlLeaveCriticalSection(&g_csImeDpi); Imm32FreeImeDpi(pImeDpiNew, FALSE); HeapFree(g_hImm32Heap, 0, pImeDpiNew); return pImeDpiFound; } else { if (bLock) { pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED; pImeDpiNew->cLockObj = 1; } pImeDpiNew->pNext = g_pImeDpiList; g_pImeDpiList = pImeDpiNew; RtlLeaveCriticalSection(&g_csImeDpi); return pImeDpiNew; } } PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL) { PW32CLIENTINFO pInfo; PIMEDPI pImeDpi; if (!IS_IME_HKL(hKL)) { if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) return NULL; pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); if ((pInfo->W32ClientInfo[0] & 2)) return NULL; } pImeDpi = ImmLockImeDpi(hKL); if (pImeDpi == NULL) pImeDpi = Ime32LoadImeDpi(hKL, TRUE); return pImeDpi; } /*********************************************************************** * ImmIsIME (IMM32.@) */ BOOL WINAPI ImmIsIME(HKL hKL) { IMEINFOEX info; TRACE("(%p)\n", hKL); return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL); } /*********************************************************************** * ImmGetDefaultIMEWnd (IMM32.@) */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) return NULL; // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. if (hWnd == NULL) return (HWND)NtUserGetThreadState(3); return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME); } /*********************************************************************** * ImmNotifyIME (IMM32.@) */ BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { HKL hKL; PIMEDPI pImeDpi; BOOL ret; TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue); if (hIMC && Imm32IsCrossThreadAccess(hIMC)) return FALSE; hKL = GetKeyboardLayout(0); pImeDpi = ImmLockImeDpi(hKL); if (pImeDpi == NULL) return FALSE; ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); ImmUnlockImeDpi(pImeDpi); return ret; } /*********************************************************************** * ImmDisableLegacyIME(IMM32.@) */ BOOL WINAPI ImmDisableLegacyIME(void) { FIXME("stub\n"); return TRUE; } /*********************************************************************** * CtfImmIsTextFrameServiceDisabled(IMM32.@) */ BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID) { PTEB pTeb = NtCurrentTeb(); if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED) return TRUE; return FALSE; } /*********************************************************************** * ImmGetImeInfoEx (IMM32.@) */ BOOL WINAPI ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey) { BOOL bDisabled = FALSE; HKL hKL; PTEB pTeb; switch (SearchType) { case ImeInfoExKeyboardLayout: break; case ImeInfoExImeWindow: bDisabled = CtfImmIsTextFrameServiceDisabled(); SearchType = ImeInfoExKeyboardLayout; break; case ImeInfoExImeFileName: StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile), pvSearchKey); goto Quit; } hKL = *(HKL*)pvSearchKey; pImeInfoEx->hkl = hKL; if (!IS_IME_HKL(hKL)) { if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) { pTeb = NtCurrentTeb(); if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2) return FALSE; if (!bDisabled) goto Quit; } return FALSE; } Quit: return NtUserGetImeInfoEx(pImeInfoEx, SearchType); } /*********************************************************************** * ImmLockImeDpi (IMM32.@) */ PIMEDPI WINAPI ImmLockImeDpi(HKL hKL) { PIMEDPI pImeDpi = NULL; TRACE("(%p)\n", hKL); RtlEnterCriticalSection(&g_csImeDpi); /* Find by hKL */ for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext) { if (pImeDpi->hKL == hKL) /* found */ { /* lock if possible */ if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) pImeDpi = NULL; else ++(pImeDpi->cLockObj); break; } } RtlLeaveCriticalSection(&g_csImeDpi); return pImeDpi; } /*********************************************************************** * ImmUnlockImeDpi (IMM32.@) */ VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi) { PIMEDPI *ppEntry; TRACE("(%p)\n", pImeDpi); if (pImeDpi == NULL) return; RtlEnterCriticalSection(&g_csImeDpi); /* unlock */ --(pImeDpi->cLockObj); if (pImeDpi->cLockObj != 0) { RtlLeaveCriticalSection(&g_csImeDpi); return; } if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0) { if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 || (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0) { RtlLeaveCriticalSection(&g_csImeDpi); return; } } /* Remove from list */ for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext)) { if (*ppEntry == pImeDpi) /* found */ { *ppEntry = pImeDpi->pNext; break; } } Imm32FreeImeDpi(pImeDpi, TRUE); HeapFree(g_hImm32Heap, 0, pImeDpi); RtlLeaveCriticalSection(&g_csImeDpi); } /*********************************************************************** * ImmLoadIME (IMM32.@) */ BOOL WINAPI ImmLoadIME(HKL hKL) { PW32CLIENTINFO pInfo; PIMEDPI pImeDpi; if (!IS_IME_HKL(hKL)) { if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) return FALSE; pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); if ((pInfo->W32ClientInfo[0] & 2)) return FALSE; } pImeDpi = Imm32FindImeDpi(hKL); if (pImeDpi == NULL) pImeDpi = Ime32LoadImeDpi(hKL, FALSE); return (pImeDpi != NULL); } /*********************************************************************** * ImmDisableIME (IMM32.@) */ BOOL WINAPI ImmDisableIME(DWORD dwThreadId) { return NtUserDisableThreadIme(dwThreadId); } /*********************************************************************** * ImmGetDescriptionA (IMM32.@) */ UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen) { IMEINFOEX info; size_t cch; TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen); if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) return 0; StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch, lpszDescription, uBufLen, NULL, NULL); if (uBufLen) lpszDescription[cch] = 0; return (UINT)cch; } /*********************************************************************** * ImmGetDescriptionW (IMM32.@) */ UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) { IMEINFOEX info; size_t cch; TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen); if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) return 0; if (uBufLen != 0) StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription); StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); return (UINT)cch; } /*********************************************************************** * ImmGetIMEFileNameA (IMM32.@) */ UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) { BOOL bDefUsed; IMEINFOEX info; size_t cch; TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) { if (uBufLen > 0) lpszFileName[0] = 0; return 0; } StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch, lpszFileName, uBufLen, NULL, &bDefUsed); if (uBufLen == 0) return (UINT)cch; if (cch > uBufLen - 1) cch = uBufLen - 1; lpszFileName[cch] = 0; return (UINT)cch; } /*********************************************************************** * ImmGetIMEFileNameW (IMM32.@) */ UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) { IMEINFOEX info; size_t cch; TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) { if (uBufLen > 0) lpszFileName[0] = 0; return 0; } StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); if (uBufLen == 0) return (UINT)cch; StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch); if (cch > uBufLen - 1) cch = uBufLen - 1; lpszFileName[cch] = 0; return (UINT)cch; } /*********************************************************************** * ImmGetProperty (IMM32.@) */ DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) { IMEINFOEX ImeInfoEx; LPIMEINFO pImeInfo; DWORD dwValue; PIMEDPI pImeDpi = NULL; TRACE("(%p, %lu)\n", hKL, fdwIndex); if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL)) return FALSE; if (fdwIndex == IGP_GETIMEVERSION) return ImeInfoEx.dwImeWinVersion; if (ImeInfoEx.fLoadFlag != 2) { pImeDpi = ImmLockOrLoadImeDpi(hKL); if (pImeDpi == NULL) return FALSE; pImeInfo = &pImeDpi->ImeInfo; } else { pImeInfo = &ImeInfoEx.ImeInfo; } switch (fdwIndex) { case IGP_PROPERTY: dwValue = pImeInfo->fdwProperty; break; case IGP_CONVERSION: dwValue = pImeInfo->fdwConversionCaps; break; case IGP_SENTENCE: dwValue = pImeInfo->fdwSentenceCaps; break; case IGP_UI: dwValue = pImeInfo->fdwUICaps; break; case IGP_SETCOMPSTR: dwValue = pImeInfo->fdwSCSCaps; break; case IGP_SELECT: dwValue = pImeInfo->fdwSelectCaps; break; default: dwValue = 0; break; } if (pImeDpi) ImmUnlockImeDpi(pImeDpi); return dwValue; } /*********************************************************************** * ImmGetOpenStatus (IMM32.@) */ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) { BOOL ret; LPINPUTCONTEXT pIC; TRACE("(%p)\n", hIMC); if (!hIMC) return FALSE; pIC = ImmLockIMC(hIMC); if (!pIC) return FALSE; ret = pIC->fOpen; ImmUnlockIMC(hIMC); return ret; } /*********************************************************************** * ImmSetOpenStatus (IMM32.@) */ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { DWORD dwConversion; LPINPUTCONTEXT pIC; HWND hWnd; BOOL bHasChange = FALSE; TRACE("(%p, %d)\n", hIMC, fOpen); if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; if (pIC->fOpen != fOpen) { pIC->fOpen = fOpen; hWnd = pIC->hWnd; dwConversion = pIC->fdwConversion; bHasChange = TRUE; } ImmUnlockIMC(hIMC); if (bHasChange) { Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0); NtUserNotifyIMEStatus(hWnd, hIMC, dwConversion); } return TRUE; } /*********************************************************************** * ImmGetStatusWindowPos (IMM32.@) */ BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { LPINPUTCONTEXT pIC; BOOL ret; TRACE("(%p, %p)\n", hIMC, lpptPos); pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS); if (ret) *lpptPos = pIC->ptStatusWndPos; ImmUnlockIMC(hIMC); return ret; } /*********************************************************************** * ImmSetStatusWindowPos (IMM32.@) */ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { LPINPUTCONTEXT pIC; HWND hWnd; TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y); if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pIC = ImmLockIMC(hIMC); if (!pIC) return FALSE; hWnd = pIC->hWnd; pIC->ptStatusWndPos = *lpptPos; pIC->fdwInit |= INIT_STATUSWNDPOS; ImmUnlockIMC(hIMC); Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0); return TRUE; } /*********************************************************************** * ImmGetCompositionWindow (IMM32.@) */ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { LPINPUTCONTEXT pIC; BOOL ret = FALSE; TRACE("(%p, %p)\n", hIMC, lpCompForm); pIC = ImmLockIMC(hIMC); if (!pIC) return FALSE; if (pIC->fdwInit & INIT_COMPFORM) { *lpCompForm = pIC->cfCompForm; ret = TRUE; } ImmUnlockIMC(hIMC); return ret; } /*********************************************************************** * ImmSetCompositionWindow (IMM32.@) */ BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { LPINPUTCONTEXT pIC; HWND hWnd; if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; pIC->cfCompForm = *lpCompForm; pIC->fdwInit |= INIT_COMPFORM; hWnd = pIC->hWnd; ImmUnlockIMC(hIMC); Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; } /*********************************************************************** * ImmGetCompositionFontA (IMM32.@) */ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { PCLIENTIMC pClientImc; BOOL ret = FALSE, bWide; LPINPUTCONTEXT pIC; TRACE("(%p, %p)\n", hIMC, lplf); pClientImc = ImmLockClientImc(hIMC); if (pClientImc == NULL) return FALSE; bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); ImmUnlockClientImc(pClientImc); pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; if (pIC->fdwInit & INIT_LOGFONT) { if (bWide) LogFontWideToAnsi(&pIC->lfFont.W, lplf); else *lplf = pIC->lfFont.A; ret = TRUE; } ImmUnlockIMC(hIMC); return ret; } /*********************************************************************** * ImmGetCompositionFontW (IMM32.@) */ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { PCLIENTIMC pClientImc; BOOL bWide; LPINPUTCONTEXT pIC; BOOL ret = FALSE; TRACE("(%p, %p)\n", hIMC, lplf); pClientImc = ImmLockClientImc(hIMC); if (pClientImc == NULL) return FALSE; bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); ImmUnlockClientImc(pClientImc); pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; if (pIC->fdwInit & INIT_LOGFONT) { if (bWide) *lplf = pIC->lfFont.W; else LogFontAnsiToWide(&pIC->lfFont.A, lplf); ret = TRUE; } ImmUnlockIMC(hIMC); return ret; } /*********************************************************************** * ImmSetCompositionFontA (IMM32.@) */ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { LOGFONTW lfW; PCLIENTIMC pClientImc; BOOL bWide; LPINPUTCONTEXTDX pIC; LCID lcid; HWND hWnd; PTEB pTeb; TRACE("(%p, %p)\n", hIMC, lplf); if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pClientImc = ImmLockClientImc(hIMC); if (pClientImc == NULL) return FALSE; bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); ImmUnlockClientImc(pClientImc); if (bWide) { LogFontAnsiToWide(lplf, &lfW); return ImmSetCompositionFontW(hIMC, &lfW); } pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; pTeb = NtCurrentTeb(); if (pTeb->Win32ClientInfo[2] < 0x400) { lcid = GetSystemDefaultLCID(); if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) && pIC->cfCompForm.dwStyle != CFS_DEFAULT) { PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); } } pIC->lfFont.A = *lplf; pIC->fdwInit |= INIT_LOGFONT; hWnd = pIC->hWnd; ImmUnlockIMC(hIMC); Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, IMN_SETCOMPOSITIONFONT, 0); return TRUE; } /*********************************************************************** * ImmSetCompositionFontW (IMM32.@) */ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { LOGFONTA lfA; PCLIENTIMC pClientImc; BOOL bWide; HWND hWnd; LPINPUTCONTEXTDX pIC; PTEB pTeb; LCID lcid; TRACE("(%p, %p)\n", hIMC, lplf); if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pClientImc = ImmLockClientImc(hIMC); if (pClientImc == NULL) return FALSE; bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); ImmUnlockClientImc(pClientImc); if (!bWide) { LogFontWideToAnsi(lplf, &lfA); return ImmSetCompositionFontA(hIMC, &lfA); } pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; pTeb = NtCurrentTeb(); if (pTeb->Win32ClientInfo[2] < 0x400) { lcid = GetSystemDefaultLCID(); if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) && pIC->cfCompForm.dwStyle != CFS_DEFAULT) { PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); } } pIC->lfFont.W = *lplf; pIC->fdwInit |= INIT_LOGFONT; hWnd = pIC->hWnd; ImmUnlockIMC(hIMC); Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, IMN_SETCOMPOSITIONFONT, 0); return TRUE; } /*********************************************************************** * ImmGetConversionListA (IMM32.@) */ DWORD WINAPI ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { DWORD ret = 0; UINT cb; LPWSTR pszSrcW = NULL; LPCANDIDATELIST pCL = NULL; PIMEDPI pImeDpi; TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag); pImeDpi = ImmLockOrLoadImeDpi(hKL); if (pImeDpi == NULL) return 0; if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) { ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); ImmUnlockImeDpi(pImeDpi); return ret; } if (pSrc) { pszSrcW = Imm32WideFromAnsi(pSrc); if (pszSrcW == NULL) goto Quit; } cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag); if (cb == 0) goto Quit; pCL = Imm32HeapAlloc(0, cb); if (pCL == NULL) goto Quit; cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag); if (cb == 0) goto Quit; ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP); Quit: if (pszSrcW) HeapFree(g_hImm32Heap, 0, pszSrcW); if (pCL) HeapFree(g_hImm32Heap, 0, pCL); ImmUnlockImeDpi(pImeDpi); return ret; } /*********************************************************************** * ImmGetConversionListW (IMM32.@) */ DWORD WINAPI ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { DWORD ret = 0; INT cb; PIMEDPI pImeDpi; LPCANDIDATELIST pCL = NULL; LPSTR pszSrcA = NULL; TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag); pImeDpi = ImmLockOrLoadImeDpi(hKL); if (!pImeDpi) return 0; if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) { ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); ImmUnlockImeDpi(pImeDpi); return ret; } if (pSrc) { pszSrcA = Imm32AnsiFromWide(pSrc); if (pszSrcA == NULL) goto Quit; } cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag); if (cb == 0) goto Quit; pCL = Imm32HeapAlloc(0, cb); if (!pCL) goto Quit; cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag); if (!cb) goto Quit; ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP); Quit: if (pszSrcA) HeapFree(g_hImm32Heap, 0, pszSrcA); if (pCL) HeapFree(g_hImm32Heap, 0, pCL); ImmUnlockImeDpi(pImeDpi); return ret; } /*********************************************************************** * ImmGetConversionStatus (IMM32.@) */ BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) { LPINPUTCONTEXT pIC; TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence); pIC = ImmLockIMC(hIMC); if (!pIC) return FALSE; if (lpfdwConversion) *lpfdwConversion = pIC->fdwConversion; if (lpfdwSentence) *lpfdwSentence = pIC->fdwSentence; ImmUnlockIMC(hIMC); return TRUE; } /*********************************************************************** * ImmSetConversionStatus (IMM32.@) */ BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) { HKL hKL; LPINPUTCONTEXT pIC; DWORD dwOldConversion, dwOldSentence; BOOL fConversionChange = FALSE, fSentenceChange = FALSE; HWND hWnd; TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence); hKL = GetKeyboardLayout(0); if (!IS_IME_HKL(hKL)) { if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) { FIXME("Cicero\n"); return FALSE; } } if (Imm32IsCrossThreadAccess(hIMC)) return FALSE; pIC = ImmLockIMC(hIMC); if (pIC == NULL) return FALSE; if (pIC->fdwConversion != fdwConversion) { dwOldConversion = pIC->fdwConversion; pIC->fdwConversion = fdwConversion; fConversionChange = TRUE; } if (pIC->fdwSentence != fdwSentence) { dwOldSentence = pIC->fdwSentence; pIC->fdwSentence = fdwSentence; fSentenceChange = TRUE; } hWnd = pIC->hWnd; ImmUnlockIMC(hIMC); if (fConversionChange) { Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion, IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0); NtUserNotifyIMEStatus(hWnd, hIMC, fdwConversion); } if (fSentenceChange) { Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence, IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0); } return TRUE; }