reactos/dll/win32/imm32/imm.c

5212 lines
141 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS IMM32
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: Implementing Far-Eastern languages input
* COPYRIGHT: Copyright 1998 Patrik Stridvall
* Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
* Copyright 2017 James Tabor <james.tabor@reactos.org>
* Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
* Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
* Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include <stdarg.h>
#include <stdio.h>
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
#include <winerror.h>
#include <wine/debug.h>
#include <imm.h>
#include <ddk/imm.h>
#include <winnls.h>
#include <winreg.h>
#include <wine/list.h>
#include <stdlib.h>
#include <ndk/umtypes.h>
#include <ndk/pstypes.h>
#include <ndk/rtlfuncs.h>
#include "../../../win32ss/include/ntuser.h"
#include "../../../win32ss/include/ntwin32.h"
#include <undocuser.h>
#include <imm32_undoc.h>
#include <strsafe.h>
WINE_DEFAULT_DEBUG_CHANNEL(imm);
#define IMM_INIT_MAGIC 0x19650412
#define IMM_INVALID_CANDFORM ULONG_MAX
#define INVALID_HOTKEY_ID 0xFFFFFFFF
#define MAX_CANDIDATEFORM 4
#define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
#define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)
#define REGKEY_KEYBOARD_LAYOUTS \
L"System\\CurrentControlSet\\Control\\Keyboard Layouts"
#define REGKEY_IMM \
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM"
#define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */
HMODULE g_hImm32Inst = NULL;
RTL_CRITICAL_SECTION g_csImeDpi;
PIMEDPI g_pImeDpiList = NULL;
PSERVERINFO g_psi = NULL;
SHAREDINFO g_SharedInfo = { NULL };
BYTE g_bClientRegd = FALSE;
HANDLE g_hImm32Heap = NULL;
static PWND FASTCALL ValidateHwndNoErr(HWND hwnd)
{
PCLIENTINFO ClientInfo = GetWin32ClientInfo();
INT index;
PUSER_HANDLE_TABLE ht;
PUSER_HANDLE_ENTRY he;
WORD generation;
/* See if the window is cached */
if (hwnd == ClientInfo->CallbackWnd.hWnd)
return ClientInfo->CallbackWnd.pWnd;
if (!NtUserValidateHandleSecure(hwnd))
return NULL;
ht = g_SharedInfo.aheList; /* handle table */
ASSERT(ht);
/* ReactOS-Specific! */
ASSERT(g_SharedInfo.ulSharedDelta != 0);
he = (PUSER_HANDLE_ENTRY)((ULONG_PTR)ht->handles - g_SharedInfo.ulSharedDelta);
index = (LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1;
if (index < 0 || index >= ht->nb_handles || he[index].type != TYPE_WINDOW)
return NULL;
generation = HIWORD(hwnd);
if (generation != he[index].generation && generation && generation != 0xFFFF)
return NULL;
return (PWND)&he[index];
}
static BOOL APIENTRY Imm32InitInstance(HMODULE hMod)
{
NTSTATUS status;
if (hMod)
g_hImm32Inst = hMod;
if (g_bClientRegd)
return TRUE;
status = RtlInitializeCriticalSection(&g_csImeDpi);
if (NT_ERROR(status))
return FALSE;
g_bClientRegd = TRUE;
return TRUE;
}
LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes)
{
if (!g_hImm32Heap)
{
g_hImm32Heap = RtlGetProcessHeap();
if (g_hImm32Heap == NULL)
return NULL;
}
return HeapAlloc(g_hImm32Heap, dwFlags, dwBytes);
}
static LPWSTR APIENTRY Imm32WideFromAnsi(LPCSTR pszA)
{
INT cch = lstrlenA(pszA);
LPWSTR pszW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
if (pszW == NULL)
return NULL;
cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1);
pszW[cch] = 0;
return pszW;
}
static LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW)
{
INT cchW = lstrlenW(pszW);
INT cchA = (cchW + 1) * sizeof(WCHAR);
LPSTR pszA = Imm32HeapAlloc(0, cchA);
if (!pszA)
return NULL;
cchA = WideCharToMultiByte(CP_ACP, 0, pszW, cchW, pszA, cchA, NULL, NULL);
pszA[cchA] = 0;
return pszA;
}
static inline BOOL Imm32IsCrossThreadAccess(HIMC hIMC)
{
DWORD dwImeThreadId = NtUserQueryInputContext(hIMC, 1);
DWORD dwThreadId = GetCurrentThreadId();
return (dwImeThreadId != dwThreadId);
}
static BOOL Imm32IsCrossProcessAccess(HWND hWnd)
{
return (NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) !=
(DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess);
}
static VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy)
{
if (pImeDpi->hInst == NULL)
return;
if (bDestroy)
pImeDpi->ImeDestroy(0);
FreeLibrary(pImeDpi->hInst);
pImeDpi->hInst = NULL;
}
static BOOL APIENTRY
Imm32NotifyAction(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue,
DWORD_PTR dwCommand, DWORD_PTR dwData)
{
DWORD dwLayout;
HKL hKL;
PIMEDPI pImeDpi;
if (dwAction)
{
dwLayout = NtUserQueryInputContext(hIMC, 1);
if (dwLayout)
{
/* find keyboard layout and lock it */
hKL = GetKeyboardLayout(dwLayout);
pImeDpi = ImmLockImeDpi(hKL);
if (pImeDpi)
{
/* do notify */
pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
ImmUnlockImeDpi(pImeDpi); /* unlock */
}
}
}
if (hwnd && dwCommand)
SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData);
return TRUE;
}
static 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;
}
static BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName)
{
if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath))
return FALSE;
StringCchCatW(pszPath, cchPath, L"\\");
StringCchCatW(pszPath, cchPath, pszFileName);
return TRUE;
}
static 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);
}
static 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;
}
#ifdef IMP_SUPPORT /* 3.x support */
static DWORD APIENTRY
ImpJTransCompA(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS,
const TRANSMSG *pSrc, LPTRANSMSG pDest)
{
// FIXME
*pDest = *pSrc;
return 1;
}
static DWORD APIENTRY
ImpJTransCompW(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS,
const TRANSMSG *pSrc, LPTRANSMSG pDest)
{
// FIXME
*pDest = *pSrc;
return 1;
}
typedef LRESULT (WINAPI *FN_SendMessage)(HWND, UINT, WPARAM, LPARAM);
static DWORD APIENTRY
ImpJTrans(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC,
LPCOMPOSITIONSTRING pCS, BOOL bAnsi)
{
DWORD ret = 0;
HWND hWnd, hwndDefIME;
LPTRANSMSG pTempList, pEntry, pNext;
DWORD dwIndex, iCandForm, dwNumber, cbTempList;
HGLOBAL hGlobal;
CANDIDATEFORM CandForm;
FN_SendMessage pSendMessage;
hWnd = pIC->hWnd;
hwndDefIME = ImmGetDefaultIMEWnd(hWnd);
pSendMessage = (IsWindowUnicode(hWnd) ? SendMessageW : SendMessageA);
// clone the message list
cbTempList = (dwCount + 1) * sizeof(TRANSMSG);
pTempList = Imm32HeapAlloc(HEAP_ZERO_MEMORY, cbTempList);
if (pTempList == NULL)
return 0;
RtlCopyMemory(pTempList, pTrans, dwCount * sizeof(TRANSMSG));
if (pIC->dwUIFlags & 0x2)
{
// find WM_IME_ENDCOMPOSITION
pEntry = pTempList;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pEntry)
{
if (pEntry->message == WM_IME_ENDCOMPOSITION)
break;
}
if (pEntry->message == WM_IME_ENDCOMPOSITION) // if found
{
// move WM_IME_ENDCOMPOSITION to the end of the list
for (pNext = pEntry + 1; pNext->message != 0; ++pEntry, ++pNext)
*pEntry = *pNext;
pEntry->message = WM_IME_ENDCOMPOSITION;
pEntry->wParam = 0;
pEntry->lParam = 0;
}
}
for (pEntry = pTempList; pEntry->message != 0; ++pEntry)
{
switch (pEntry->message)
{
case WM_IME_STARTCOMPOSITION:
if (!(pIC->dwUIFlags & 0x2))
{
// send IR_OPENCONVERT
if (pIC->cfCompForm.dwStyle != CFS_DEFAULT)
pSendMessage(hWnd, WM_IME_REPORT, IR_OPENCONVERT, 0);
goto DoDefault;
}
break;
case WM_IME_ENDCOMPOSITION:
if (pIC->dwUIFlags & 0x2)
{
// send IR_UNDETERMINE
hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(UNDETERMINESTRUCT));
if (hGlobal)
{
pSendMessage(hWnd, WM_IME_REPORT, IR_UNDETERMINE, (LPARAM)hGlobal);
GlobalFree(hGlobal);
}
}
else
{
// send IR_CLOSECONVERT
if (pIC->cfCompForm.dwStyle != CFS_DEFAULT)
pSendMessage(hWnd, WM_IME_REPORT, IR_CLOSECONVERT, 0);
goto DoDefault;
}
break;
case WM_IME_COMPOSITION:
if (bAnsi)
dwNumber = ImpJTransCompA(pIC, pCS, pEntry, pTrans);
else
dwNumber = ImpJTransCompW(pIC, pCS, pEntry, pTrans);
ret += dwNumber;
pTrans += dwNumber;
// send IR_CHANGECONVERT
if (!(pIC->dwUIFlags & 0x2))
{
if (pIC->cfCompForm.dwStyle != CFS_DEFAULT)
pSendMessage(hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
}
break;
case WM_IME_NOTIFY:
if (pEntry->wParam == IMN_OPENCANDIDATE)
{
if (IsWindow(hWnd) && (pIC->dwUIFlags & 0x2))
{
// send IMC_SETCANDIDATEPOS
for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm)
{
if (!(pEntry->lParam & (1 << iCandForm)))
continue;
CandForm.dwIndex = iCandForm;
CandForm.dwStyle = CFS_EXCLUDE;
CandForm.ptCurrentPos = pIC->cfCompForm.ptCurrentPos;
CandForm.rcArea = pIC->cfCompForm.rcArea;
pSendMessage(hwndDefIME, WM_IME_CONTROL, IMC_SETCANDIDATEPOS,
(LPARAM)&CandForm);
}
}
}
if (!(pIC->dwUIFlags & 0x2))
goto DoDefault;
// send a WM_IME_NOTIFY notification to the default ime window
pSendMessage(hwndDefIME, pEntry->message, pEntry->wParam, pEntry->lParam);
break;
DoDefault:
default:
// default processing
*pTrans++ = *pEntry;
++ret;
break;
}
}
HeapFree(g_hImm32Heap, 0, pTempList);
return ret;
}
static DWORD APIENTRY
ImpKTrans(DWORD dwCount, LPTRANSMSG pEntries, LPINPUTCONTEXTDX pIC,
LPCOMPOSITIONSTRING pCS, BOOL bAnsi)
{
return dwCount; // FIXME
}
static DWORD APIENTRY
ImpTrans(DWORD dwCount, LPTRANSMSG pEntries, HIMC hIMC, BOOL bAnsi, WORD wLang)
{
BOOL ret = FALSE;
LPINPUTCONTEXTDX pIC;
LPCOMPOSITIONSTRING pCS;
pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
if (pIC == NULL)
return 0;
pCS = ImmLockIMCC(pIC->hCompStr);
if (pCS)
{
if (wLang == LANG_JAPANESE)
ret = ImpJTrans(dwCount, pEntries, pIC, pCS, bAnsi);
else if (wLang == LANG_KOREAN)
ret = ImpKTrans(dwCount, pEntries, pIC, pCS, bAnsi);
ImmUnlockIMCC(pIC->hCompStr);
}
ImmUnlockIMC(hIMC);
return ret;
}
#endif /* def IMP_SUPPORT */
static 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;
}
}
/***********************************************************************
* 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);
}
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;
}
/***********************************************************************
* ImmLoadLayout (IMM32.@)
*/
HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
{
DWORD cbData;
UNICODE_STRING UnicodeString;
HKEY hLayoutKey = NULL, hLayoutsKey = NULL;
LONG error;
NTSTATUS Status;
WCHAR szLayout[MAX_PATH];
TRACE("(%p, %p)\n", hKL, pImeInfoEx);
if (IS_IME_HKL(hKL) ||
!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) ||
((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->W32ClientInfo[0] & 2)
{
UnicodeString.Buffer = szLayout;
UnicodeString.MaximumLength = sizeof(szLayout);
Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString);
if (!NT_SUCCESS(Status))
return NULL;
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey);
if (error)
return NULL;
error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
}
else
{
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey);
}
if (error)
{
ERR("RegOpenKeyW error: 0x%08lX\n", error);
hKL = NULL;
}
else
{
cbData = sizeof(pImeInfoEx->wszImeFile);
error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
(LPBYTE)pImeInfoEx->wszImeFile, &cbData);
if (error)
hKL = NULL;
}
RegCloseKey(hLayoutKey);
if (hLayoutsKey)
RegCloseKey(hLayoutsKey);
return hKL;
}
typedef struct _tagImmHkl{
struct list entry;
HKL hkl;
HMODULE hIME;
IMEINFO imeInfo;
WCHAR imeClassName[17]; /* 16 character max */
ULONG uSelected;
HWND UIWnd;
/* Function Pointers */
BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
BOOL (WINAPI *pImeDestroy)(UINT);
LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
} ImmHkl;
typedef struct tagInputContextData
{
DWORD dwLock;
INPUTCONTEXT IMC;
DWORD threadID;
ImmHkl *immKbd;
UINT lastVK;
BOOL threadDefault;
DWORD magic;
} InputContextData;
#define WINE_IMC_VALID_MAGIC 0x56434D49
typedef struct _tagIMMThreadData {
struct list entry;
DWORD threadID;
HIMC defaultContext;
HWND hwndDefault;
BOOL disableIME;
DWORD windowRefs;
} IMMThreadData;
static struct list ImmHklList = LIST_INIT(ImmHklList);
static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
static const WCHAR szwIME[] = {'I','M','E',0};
static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
static CRITICAL_SECTION threaddata_cs;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &threaddata_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
};
static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static inline BOOL is_himc_ime_unicode(const InputContextData *data)
{
return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
}
static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
{
return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
}
static InputContextData* get_imc_data(HIMC hIMC);
static inline WCHAR *strdupAtoW( const char *str )
{
WCHAR *ret = NULL;
if (str)
{
DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
}
return ret;
}
static inline CHAR *strdupWtoA( const WCHAR *str )
{
CHAR *ret = NULL;
if (str)
{
DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
}
return ret;
}
static HMODULE load_graphics_driver(void)
{
static const WCHAR display_device_guid_propW[] = {
'_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
'd','e','v','i','c','e','_','g','u','i','d',0 };
static const WCHAR key_pathW[] = {
'S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\',
'V','i','d','e','o','\\','{',0};
static const WCHAR displayW[] = {'}','\\','0','0','0','0',0};
static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0};
HMODULE ret = 0;
HKEY hkey;
DWORD size;
WCHAR path[MAX_PATH];
WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW ));
if (!guid_atom) return 0;
memcpy( key, key_pathW, sizeof(key_pathW) );
if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
lstrcatW( key, displayW );
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
size = sizeof(path);
if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path );
RegCloseKey( hkey );
TRACE( "%s %p\n", debugstr_w(path), ret );
return ret;
}
/* ImmHkl loading and freeing */
#define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
static ImmHkl *IMM_GetImmHkl(HKL hkl)
{
ImmHkl *ptr;
WCHAR filename[MAX_PATH];
TRACE("Seeking ime for keyboard %p\n",hkl);
LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
{
if (ptr->hkl == hkl)
return ptr;
}
/* not found... create it */
ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
ptr->hkl = hkl;
if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
if (!ptr->hIME) ptr->hIME = load_graphics_driver();
if (ptr->hIME)
{
LOAD_FUNCPTR(ImeInquire);
if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
{
FreeLibrary(ptr->hIME);
ptr->hIME = NULL;
}
else
{
LOAD_FUNCPTR(ImeDestroy);
LOAD_FUNCPTR(ImeSelect);
if (!ptr->pImeSelect || !ptr->pImeDestroy)
{
FreeLibrary(ptr->hIME);
ptr->hIME = NULL;
}
else
{
LOAD_FUNCPTR(ImeConfigure);
LOAD_FUNCPTR(ImeEscape);
LOAD_FUNCPTR(ImeSetActiveContext);
LOAD_FUNCPTR(ImeToAsciiEx);
LOAD_FUNCPTR(NotifyIME);
LOAD_FUNCPTR(ImeRegisterWord);
LOAD_FUNCPTR(ImeUnregisterWord);
LOAD_FUNCPTR(ImeEnumRegisterWord);
LOAD_FUNCPTR(ImeSetCompositionString);
LOAD_FUNCPTR(ImeConversionList);
LOAD_FUNCPTR(ImeProcessKey);
LOAD_FUNCPTR(ImeGetRegisterWordStyle);
LOAD_FUNCPTR(ImeGetImeMenuItems);
/* make sure our classname is WCHAR */
if (!is_kbd_ime_unicode(ptr))
{
WCHAR bufW[17];
MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
-1, bufW, 17);
lstrcpyW(ptr->imeClassName, bufW);
}
}
}
}
list_add_head(&ImmHklList,&ptr->entry);
return ptr;
}
#undef LOAD_FUNCPTR
static InputContextData* get_imc_data(HIMC hIMC)
{
InputContextData *data = (InputContextData *)hIMC;
if (hIMC == NULL)
return NULL;
if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
return data;
}
static HIMC get_default_context( HWND hwnd )
{
FIXME("Don't use this function\n");
return FALSE;
}
static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
{
InputContextData *data;
if (hWnd)
{
DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
if (thread != GetCurrentThreadId()) return TRUE;
}
data = get_imc_data(hIMC);
if (data && data->threadID != GetCurrentThreadId())
return TRUE;
return FALSE;
}
/***********************************************************************
* ImmAssociateContext (IMM32.@)
*/
HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
{
HIMC old = NULL;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p):\n", hWnd, hIMC);
if(hIMC && !data)
return NULL;
/*
* If already associated just return
*/
if (hIMC && data->IMC.hWnd == hWnd)
return hIMC;
if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
return NULL;
if (hWnd)
{
HIMC defaultContext = get_default_context( hWnd );
old = RemovePropW(hWnd,szwWineIMCProperty);
if (old == NULL)
old = defaultContext;
else if (old == (HIMC)-1)
old = NULL;
if (hIMC != defaultContext)
{
if (hIMC == NULL) /* Meaning disable imm for that window*/
SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
else
SetPropW(hWnd,szwWineIMCProperty,hIMC);
}
if (old)
{
InputContextData *old_data = (InputContextData *)old;
if (old_data->IMC.hWnd == hWnd)
old_data->IMC.hWnd = NULL;
}
}
if (!hIMC)
return old;
if(GetActiveWindow() == data->IMC.hWnd)
{
SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
data->IMC.hWnd = hWnd;
SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
}
return old;
}
/*
* Helper function for ImmAssociateContextEx
*/
static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
{
HIMC hImc = (HIMC)lParam;
ImmAssociateContext(hwnd,hImc);
return TRUE;
}
/***********************************************************************
* ImmAssociateContextEx (IMM32.@)
*/
BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
{
TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
if (!hWnd)
return FALSE;
switch (dwFlags)
{
case 0:
ImmAssociateContext(hWnd,hIMC);
return TRUE;
case IACE_DEFAULT:
{
HIMC defaultContext = get_default_context( hWnd );
if (!defaultContext) return FALSE;
ImmAssociateContext(hWnd,defaultContext);
return TRUE;
}
case IACE_IGNORENOCONTEXT:
if (GetPropW(hWnd,szwWineIMCProperty))
ImmAssociateContext(hWnd,hIMC);
return TRUE;
case IACE_CHILDREN:
EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
return TRUE;
default:
FIXME("Unknown dwFlags 0x%x\n",dwFlags);
return FALSE;
}
}
/***********************************************************************
* ImmConfigureIMEA (IMM32.@)
*/
BOOL WINAPI ImmConfigureIMEA(
HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
return FALSE;
if (immHkl->hIME && immHkl->pImeConfigure)
{
if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
else
{
REGISTERWORDW rww;
REGISTERWORDA *rwa = lpData;
BOOL rc;
rww.lpReading = strdupAtoW(rwa->lpReading);
rww.lpWord = strdupAtoW(rwa->lpWord);
rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
HeapFree(GetProcessHeap(),0,rww.lpReading);
HeapFree(GetProcessHeap(),0,rww.lpWord);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmConfigureIMEW (IMM32.@)
*/
BOOL WINAPI ImmConfigureIMEW(
HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
return FALSE;
if (immHkl->hIME && immHkl->pImeConfigure)
{
if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
else
{
REGISTERWORDW *rww = lpData;
REGISTERWORDA rwa;
BOOL rc;
rwa.lpReading = strdupWtoA(rww->lpReading);
rwa.lpWord = strdupWtoA(rww->lpWord);
rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
HeapFree(GetProcessHeap(),0,rwa.lpReading);
HeapFree(GetProcessHeap(),0,rwa.lpWord);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmCreateContext (IMM32.@)
*/
HIMC WINAPI ImmCreateContext(void)
{
PCLIENTIMC pClientImc;
HIMC hIMC;
TRACE("()\n");
if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
return NULL;
pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
if (pClientImc == NULL)
return NULL;
hIMC = NtUserCreateInputContext(pClientImc);
if (hIMC == NULL)
{
HeapFree(g_hImm32Heap, 0, pClientImc);
return NULL;
}
RtlInitializeCriticalSection(&pClientImc->cs);
// FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
pClientImc->unknown = NtUserGetThreadState(13);
return hIMC;
}
static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC)
{
FIXME("We have to do something do here");
}
static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC)
{
// FIXME
return NULL;
}
BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
{
PIMEDPI pImeDpi;
LPINPUTCONTEXT pIC;
PCLIENTIMC pClientImc;
if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL)
return FALSE;
FIXME("We have do something to do here\n");
pClientImc = Imm32FindClientImc(hIMC);
if (!pClientImc)
return FALSE;
if (pClientImc->hImc == NULL)
{
pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
ImmUnlockClientImc(pClientImc);
if (!bKeep)
return NtUserDestroyInputContext(hIMC);
return TRUE;
}
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmUnlockClientImc(pClientImc);
return FALSE;
}
FIXME("We have do something to do here\n");
if (pClientImc->hKL == hKL)
{
pImeDpi = ImmLockImeDpi(hKL);
if (pImeDpi != NULL)
{
if (IS_IME_HKL(hKL))
{
pImeDpi->ImeSelect(hIMC, FALSE);
}
else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
{
FIXME("We have do something to do here\n");
}
ImmUnlockImeDpi(pImeDpi);
}
pClientImc->hKL = NULL;
}
ImmDestroyIMCC(pIC->hPrivate);
ImmDestroyIMCC(pIC->hMsgBuf);
ImmDestroyIMCC(pIC->hGuideLine);
ImmDestroyIMCC(pIC->hCandInfo);
ImmDestroyIMCC(pIC->hCompStr);
Imm32CleanupContextExtra(pIC);
ImmUnlockIMC(hIMC);
pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
ImmUnlockClientImc(pClientImc);
if (!bKeep)
return NtUserDestroyInputContext(hIMC);
return TRUE;
}
/***********************************************************************
* ImmDestroyContext (IMM32.@)
*/
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{
HKL hKL;
TRACE("(%p)\n", hIMC);
if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
return FALSE;
if (Imm32IsCrossThreadAccess(hIMC))
return FALSE;
hKL = GetKeyboardLayout(0);
return Imm32CleanupContext(hIMC, hKL, FALSE);
}
/***********************************************************************
* ImmDisableIME (IMM32.@)
*/
BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
{
return NtUserDisableThreadIme(dwThreadId);
}
/*
* These functions absorb the difference between Ansi and Wide.
*/
typedef struct ENUM_WORD_A2W
{
REGISTERWORDENUMPROCW lpfnEnumProc;
LPVOID lpData;
UINT ret;
} ENUM_WORD_A2W, *LPENUM_WORD_A2W;
typedef struct ENUM_WORD_W2A
{
REGISTERWORDENUMPROCA lpfnEnumProc;
LPVOID lpData;
UINT ret;
} ENUM_WORD_W2A, *LPENUM_WORD_W2A;
static INT CALLBACK
Imm32EnumWordProcA2W(LPCSTR pszReadingA, DWORD dwStyle, LPCSTR pszRegisterA, LPVOID lpData)
{
INT ret = 0;
LPENUM_WORD_A2W lpEnumData = lpData;
LPWSTR pszReadingW = NULL, pszRegisterW = NULL;
if (pszReadingA)
{
pszReadingW = Imm32WideFromAnsi(pszReadingA);
if (pszReadingW == NULL)
goto Quit;
}
if (pszRegisterA)
{
pszRegisterW = Imm32WideFromAnsi(pszRegisterA);
if (pszRegisterW == NULL)
goto Quit;
}
ret = lpEnumData->lpfnEnumProc(pszReadingW, dwStyle, pszRegisterW, lpEnumData->lpData);
lpEnumData->ret = ret;
Quit:
if (pszReadingW)
HeapFree(g_hImm32Heap, 0, pszReadingW);
if (pszRegisterW)
HeapFree(g_hImm32Heap, 0, pszRegisterW);
return ret;
}
static INT CALLBACK
Imm32EnumWordProcW2A(LPCWSTR pszReadingW, DWORD dwStyle, LPCWSTR pszRegisterW, LPVOID lpData)
{
INT ret = 0;
LPENUM_WORD_W2A lpEnumData = lpData;
LPSTR pszReadingA = NULL, pszRegisterA = NULL;
if (pszReadingW)
{
pszReadingA = Imm32AnsiFromWide(pszReadingW);
if (pszReadingW == NULL)
goto Quit;
}
if (pszRegisterW)
{
pszRegisterA = Imm32AnsiFromWide(pszRegisterW);
if (pszRegisterA == NULL)
goto Quit;
}
ret = lpEnumData->lpfnEnumProc(pszReadingA, dwStyle, pszRegisterA, lpEnumData->lpData);
lpEnumData->ret = ret;
Quit:
if (pszReadingA)
HeapFree(g_hImm32Heap, 0, pszReadingA);
if (pszRegisterA)
HeapFree(g_hImm32Heap, 0, pszRegisterA);
return ret;
}
/***********************************************************************
* ImmEnumRegisterWordA (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordA(
HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
LPCSTR lpszReading, DWORD dwStyle,
LPCSTR lpszRegister, LPVOID lpData)
{
UINT ret = 0;
LPWSTR pszReadingW = NULL, pszRegisterW = NULL;
ENUM_WORD_W2A EnumDataW2A;
PIMEDPI pImeDpi;
TRACE("(%p, %p, %s, 0x%lX, %s, %p)", hKL, lpfnEnumProc, debugstr_a(lpszReading),
dwStyle, debugstr_a(lpszRegister), lpData);
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return 0;
if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
{
ret = pImeDpi->ImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
lpszRegister, lpData);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingW = Imm32WideFromAnsi(lpszReading);
if (pszReadingW == NULL)
goto Quit;
}
if (lpszRegister)
{
pszRegisterW = Imm32WideFromAnsi(lpszRegister);
if (pszRegisterW == NULL)
goto Quit;
}
EnumDataW2A.lpfnEnumProc = lpfnEnumProc;
EnumDataW2A.lpData = lpData;
EnumDataW2A.ret = 0;
pImeDpi->ImeEnumRegisterWord(Imm32EnumWordProcW2A, pszReadingW, dwStyle,
pszRegisterW, &EnumDataW2A);
ret = EnumDataW2A.ret;
Quit:
if (pszReadingW)
HeapFree(g_hImm32Heap, 0, pszReadingW);
if (pszRegisterW)
HeapFree(g_hImm32Heap, 0, pszRegisterW);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmEnumRegisterWordW (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordW(
HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
LPCWSTR lpszReading, DWORD dwStyle,
LPCWSTR lpszRegister, LPVOID lpData)
{
UINT ret = 0;
LPSTR pszReadingA = NULL, pszRegisterA = NULL;
ENUM_WORD_A2W EnumDataA2W;
PIMEDPI pImeDpi;
TRACE("(%p, %p, %s, 0x%lX, %s, %p)", hKL, lpfnEnumProc, debugstr_w(lpszReading),
dwStyle, debugstr_w(lpszRegister), lpData);
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return 0;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
ret = pImeDpi->ImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
lpszRegister, lpData);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingA = Imm32AnsiFromWide(lpszReading);
if (pszReadingA == NULL)
goto Quit;
}
if (lpszRegister)
{
pszRegisterA = Imm32AnsiFromWide(lpszRegister);
if (pszRegisterA == NULL)
goto Quit;
}
EnumDataA2W.lpfnEnumProc = lpfnEnumProc;
EnumDataA2W.lpData = lpData;
EnumDataA2W.ret = 0;
pImeDpi->ImeEnumRegisterWord(Imm32EnumWordProcA2W, pszReadingA, dwStyle,
pszRegisterA, &EnumDataA2W);
ret = EnumDataA2W.ret;
Quit:
if (pszReadingA)
HeapFree(g_hImm32Heap, 0, pszReadingA);
if (pszRegisterA)
HeapFree(g_hImm32Heap, 0, pszRegisterA);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
static inline BOOL EscapeRequiresWA(UINT uEscape)
{
if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
uEscape == IME_ESC_IME_NAME ||
uEscape == IME_ESC_GETHELPFILENAME)
return TRUE;
return FALSE;
}
/***********************************************************************
* ImmEscapeA (IMM32.@)
*/
LRESULT WINAPI ImmEscapeA(
HKL hKL, HIMC hIMC,
UINT uEscape, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
if (immHkl->hIME && immHkl->pImeEscape)
{
if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
return immHkl->pImeEscape(hIMC,uEscape,lpData);
else
{
WCHAR buffer[81]; /* largest required buffer should be 80 */
LRESULT rc;
if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
{
MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
}
else
{
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
}
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmEscapeW (IMM32.@)
*/
LRESULT WINAPI ImmEscapeW(
HKL hKL, HIMC hIMC,
UINT uEscape, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
if (immHkl->hIME && immHkl->pImeEscape)
{
if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
return immHkl->pImeEscape(hIMC,uEscape,lpData);
else
{
CHAR buffer[81]; /* largest required buffer should be 80 */
LRESULT rc;
if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
{
WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
}
else
{
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
}
return rc;
}
}
else
return 0;
}
static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void)
{
// FIXME: Do something properly here
return NULL;
}
static DWORD APIENTRY Imm32AllocAndBuildHimcList(DWORD dwThreadId, HIMC **pphList)
{
#define INITIAL_COUNT 0x40
#define MAX_RETRY 10
NTSTATUS Status;
DWORD dwCount = INITIAL_COUNT, cRetry = 0;
HIMC *phNewList;
phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
if (phNewList == NULL)
return 0;
Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
while (Status == STATUS_BUFFER_TOO_SMALL)
{
HeapFree(g_hImm32Heap, 0, phNewList);
if (cRetry++ >= MAX_RETRY)
return 0;
phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
if (phNewList == NULL)
return 0;
Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
}
if (NT_ERROR(Status) || !dwCount)
{
HeapFree(g_hImm32Heap, 0, phNewList);
return 0;
}
*pphList = phNewList;
return dwCount;
#undef INITIAL_COUNT
#undef MAX_RETRY
}
static BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID)
{
LPINPUTCONTEXT pIC;
BOOL fOpen;
if (hWnd != NULL)
return FALSE;
if (!IS_IME_HKL(hKL) || LOWORD(hKL) != LangID)
{
FIXME("We have to do something here\n");
return TRUE;
}
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return TRUE;
fOpen = pIC->fOpen;
ImmUnlockIMC(hIMC);
if (!fOpen)
{
ImmSetOpenStatus(hIMC, TRUE);
return TRUE;
}
FIXME("We have to do something here\n");
return TRUE;
}
static BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd)
{
LPINPUTCONTEXT pIC;
BOOL fOpen;
DWORD dwConversion, dwSentence;
if (hWnd == NULL || !IS_IME_HKL(hKL))
return FALSE;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return TRUE;
fOpen = pIC->fOpen;
if (fOpen)
{
dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
dwSentence = pIC->fdwSentence;
}
ImmUnlockIMC(hIMC);
if (fOpen)
ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
else
ImmSetOpenStatus(hIMC, TRUE);
return TRUE;
}
static BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd)
{
LPINPUTCONTEXT pIC;
BOOL fOpen;
DWORD dwConversion, dwSentence;
if (hWnd == NULL || !IS_IME_HKL(hKL))
return FALSE;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return TRUE;
fOpen = pIC->fOpen;
if (fOpen)
{
dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL);
dwSentence = pIC->fdwSentence;
}
ImmUnlockIMC(hIMC);
if (fOpen)
ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
else
ImmSetOpenStatus(hIMC, TRUE);
return TRUE;
}
static BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd)
{
BOOL fOpen;
if (ImmIsIME(hKL) && LOWORD(hKL) == LANGID_JAPANESE)
{
fOpen = ImmGetOpenStatus(hIMC);
ImmSetOpenStatus(hIMC, !fOpen);
return TRUE;
}
FIXME("We have to do something here\n");
return TRUE;
}
static BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC)
{
LPINPUTCONTEXT pIC;
DWORD dwConversion, dwSentence;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
dwSentence = pIC->fdwSentence;
ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE))
ImmSetOpenStatus(hIMC, TRUE);
else
ImmSetOpenStatus(hIMC, FALSE);
ImmUnlockIMC(hIMC);
return TRUE;
}
static BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC)
{
LPINPUTCONTEXT pIC;
DWORD dwConversion, dwSentence;
pIC = ImmLockIMC(hIMC);
if (!pIC)
return FALSE;
dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT);
dwSentence = pIC->fdwSentence;
ImmUnlockIMC(hIMC);
ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
return TRUE;
}
static BOOL APIENTRY Imm32KEnglish(HIMC hIMC)
{
LPINPUTCONTEXT pIC;
DWORD dwConversion, dwSentence;
BOOL fOpen;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE);
dwSentence = pIC->fdwSentence;
ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0);
ImmSetOpenStatus(hIMC, fOpen);
ImmUnlockIMC(hIMC);
return TRUE;
}
static BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID)
{
PIMEDPI pImeDpi;
BOOL ret;
if (hIMC && Imm32IsCrossThreadAccess(hIMC))
return FALSE;
switch (dwHotKeyID)
{
case IME_CHOTKEY_IME_NONIME_TOGGLE:
return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED);
case IME_CHOTKEY_SHAPE_TOGGLE:
return Imm32CShapeToggle(hIMC, hKL, hWnd);
case IME_CHOTKEY_SYMBOL_TOGGLE:
return Imm32CSymbolToggle(hIMC, hKL, hWnd);
case IME_JHOTKEY_CLOSE_OPEN:
return Imm32JCloseOpen(hIMC, hKL, hWnd);
case IME_KHOTKEY_SHAPE_TOGGLE:
return Imm32KShapeToggle(hIMC);
case IME_KHOTKEY_HANJACONVERT:
return Imm32KHanjaConvert(hIMC);
case IME_KHOTKEY_ENGLISH:
return Imm32KEnglish(hIMC);
case IME_THOTKEY_IME_NONIME_TOGGLE:
return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL);
case IME_THOTKEY_SHAPE_TOGGLE:
return Imm32CShapeToggle(hIMC, hKL, hWnd);
case IME_THOTKEY_SYMBOL_TOGGLE:
return Imm32CSymbolToggle(hIMC, hKL, hWnd);
default:
break;
}
if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID)
return FALSE;
pImeDpi = ImmLockImeDpi(hKL);
if (pImeDpi == NULL)
return FALSE;
ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmLockClientImc (IMM32.@)
*/
PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
{
PCLIENTIMC pClientImc;
TRACE("(%p)\n", hImc);
if (hImc == NULL)
return NULL;
pClientImc = Imm32GetClientImcCache();
if (!pClientImc)
{
pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
if (!pClientImc)
return NULL;
RtlInitializeCriticalSection(&pClientImc->cs);
// FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
pClientImc->unknown = NtUserGetThreadState(13);
if (!NtUserUpdateInputContext(hImc, 0, pClientImc))
{
HeapFree(g_hImm32Heap, 0, pClientImc);
return NULL;
}
pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
return NULL;
}
InterlockedIncrement(&pClientImc->cLockObj);
return pClientImc;
}
/***********************************************************************
* ImmUnlockClientImc (IMM32.@)
*/
VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
{
LONG cLocks;
HIMC hImc;
TRACE("(%p)\n", pClientImc);
cLocks = InterlockedDecrement(&pClientImc->cLockObj);
if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
return;
hImc = pClientImc->hImc;
if (hImc)
LocalFree(hImc);
RtlDeleteCriticalSection(&pClientImc->cs);
HeapFree(g_hImm32Heap, 0, pClientImc);
}
static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags)
{
HIMC hIMC;
PCLIENTIMC pClientImc;
PWND pWnd;
if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
return NULL;
if (!hWnd)
{
// FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
hIMC = (HIMC)NtUserGetThreadState(4);
goto Quit;
}
pWnd = ValidateHwndNoErr(hWnd);
if (!pWnd || Imm32IsCrossProcessAccess(hWnd))
return NULL;
hIMC = pWnd->hImc;
if (!hIMC && (dwContextFlags & 1))
hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
Quit:
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return NULL;
if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3))
hIMC = NULL;
ImmUnlockClientImc(pClientImc);
return hIMC;
}
static DWORD APIENTRY
CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen,
UINT uCodePage)
{
BOOL bUsedDefault;
DWORD dwSize, dwIndex, cbGot, cbLeft;
const BYTE *pbWide;
LPBYTE pbAnsi;
LPDWORD pibOffsets;
/* calculate total ansi size */
if (pWideCL->dwCount > 0)
{
dwSize = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex)
{
pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex];
cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1, NULL, 0,
NULL, &bUsedDefault);
dwSize += cbGot;
}
}
else
{
dwSize = sizeof(CANDIDATELIST);
}
dwSize = ROUNDUP4(dwSize);
if (dwBufLen == 0)
return dwSize;
if (dwBufLen < dwSize)
return 0;
/* store to ansi */
pAnsiCL->dwSize = dwBufLen;
pAnsiCL->dwStyle = pWideCL->dwStyle;
pAnsiCL->dwCount = pWideCL->dwCount;
pAnsiCL->dwSelection = pWideCL->dwSelection;
pAnsiCL->dwPageStart = pWideCL->dwPageStart;
pAnsiCL->dwPageSize = pWideCL->dwPageSize;
pibOffsets = pAnsiCL->dwOffset;
if (pWideCL->dwCount > 0)
{
pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
cbLeft = dwBufLen - pibOffsets[0];
for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex)
{
pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex];
pbAnsi = (LPBYTE)pAnsiCL + pibOffsets[dwIndex];
/* convert to ansi */
cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1,
(LPSTR)pbAnsi, cbLeft, NULL, &bUsedDefault);
cbLeft -= cbGot;
if (dwIndex < pWideCL->dwCount - 1)
pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot;
}
}
else
{
pibOffsets[0] = sizeof(CANDIDATELIST);
}
return dwBufLen;
}
static DWORD APIENTRY
CandidateListAnsiToWide(const CANDIDATELIST *pAnsiCL, LPCANDIDATELIST pWideCL, DWORD dwBufLen,
UINT uCodePage)
{
DWORD dwSize, dwIndex, cchGot, cbGot, cbLeft;
const BYTE *pbAnsi;
LPBYTE pbWide;
LPDWORD pibOffsets;
/* calculate total wide size */
if (pAnsiCL->dwCount > 0)
{
dwSize = sizeof(CANDIDATELIST) + ((pAnsiCL->dwCount - 1) * sizeof(DWORD));
for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex)
{
pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex];
cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1, NULL, 0);
dwSize += cchGot * sizeof(WCHAR);
}
}
else
{
dwSize = sizeof(CANDIDATELIST);
}
dwSize = ROUNDUP4(dwSize);
if (dwBufLen == 0)
return dwSize;
if (dwBufLen < dwSize)
return 0;
/* store to wide */
pWideCL->dwSize = dwBufLen;
pWideCL->dwStyle = pAnsiCL->dwStyle;
pWideCL->dwCount = pAnsiCL->dwCount;
pWideCL->dwSelection = pAnsiCL->dwSelection;
pWideCL->dwPageStart = pAnsiCL->dwPageStart;
pWideCL->dwPageSize = pAnsiCL->dwPageSize;
pibOffsets = pWideCL->dwOffset;
if (pAnsiCL->dwCount > 0)
{
pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
cbLeft = dwBufLen - pibOffsets[0];
for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex)
{
pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex];
pbWide = (LPBYTE)pWideCL + pibOffsets[dwIndex];
/* convert to wide */
cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1,
(LPWSTR)pbWide, cbLeft / sizeof(WCHAR));
cbGot = cchGot * sizeof(WCHAR);
cbLeft -= cbGot;
if (dwIndex + 1 < pAnsiCL->dwCount)
pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot;
}
}
else
{
pibOffsets[0] = sizeof(CANDIDATELIST);
}
return dwBufLen;
}
static DWORD APIENTRY
ImmGetCandidateListAW(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen,
BOOL bAnsi)
{
DWORD ret = 0;
LPINPUTCONTEXT pIC;
PCLIENTIMC pClientImc;
LPCANDIDATEINFO pCI;
LPCANDIDATELIST pCL;
DWORD dwSize;
pClientImc = ImmLockClientImc(hIMC);
if (!pClientImc)
return 0;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmUnlockClientImc(pClientImc);
return 0;
}
pCI = ImmLockIMCC(pIC->hCandInfo);
if (pCI == NULL)
{
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return 0;
}
if (pCI->dwSize < sizeof(CANDIDATEINFO) || pCI->dwCount <= dwIndex)
goto Quit;
/* get required size */
pCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]);
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
dwSize = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP);
else
dwSize = pCL->dwSize;
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
dwSize = pCL->dwSize;
else
dwSize = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP);
}
if (dwBufLen != 0 && dwSize != 0)
{
if (lpCandList == NULL || dwBufLen < dwSize)
goto Quit;
/* store */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
CandidateListAnsiToWide(pCL, lpCandList, dwSize, CP_ACP);
else
RtlCopyMemory(lpCandList, pCL, dwSize);
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
RtlCopyMemory(lpCandList, pCL, dwSize);
else
CandidateListWideToAnsi(pCL, lpCandList, dwSize, CP_ACP);
}
}
ret = dwSize;
Quit:
ImmUnlockIMCC(pIC->hCandInfo);
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return ret;
}
DWORD APIENTRY ImmGetCandidateListCountAW(HIMC hIMC, LPDWORD lpdwListCount, BOOL bAnsi)
{
DWORD ret = 0, cbGot, dwIndex;
PCLIENTIMC pClientImc;
LPINPUTCONTEXT pIC;
const CANDIDATEINFO *pCI;
const BYTE *pb;
const CANDIDATELIST *pCL;
const DWORD *pdwOffsets;
if (lpdwListCount == NULL)
return 0;
*lpdwListCount = 0;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return 0;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmUnlockClientImc(pClientImc);
return 0;
}
pCI = ImmLockIMCC(pIC->hCandInfo);
if (pCI == NULL)
{
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return 0;
}
if (pCI->dwSize < sizeof(CANDIDATEINFO))
goto Quit;
*lpdwListCount = pCI->dwCount; /* the number of candidate lists */
/* calculate total size of candidate lists */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = ROUNDUP4(pCI->dwPrivateSize);
pdwOffsets = pCI->dwOffset;
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
{
pb = (const BYTE *)pCI + pdwOffsets[dwIndex];
pCL = (const CANDIDATELIST *)pb;
cbGot = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP);
ret += cbGot;
}
}
else
{
ret = pCI->dwSize;
}
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = pCI->dwSize;
}
else
{
ret = ROUNDUP4(pCI->dwPrivateSize);
pdwOffsets = pCI->dwOffset;
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
{
pb = (const BYTE *)pCI + pdwOffsets[dwIndex];
pCL = (const CANDIDATELIST *)pb;
cbGot = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP);
ret += cbGot;
}
}
}
Quit:
ImmUnlockIMCC(pIC->hCandInfo);
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return ret;
}
/***********************************************************************
* ImmGetCandidateListA (IMM32.@)
*/
DWORD WINAPI ImmGetCandidateListA(
HIMC hIMC, DWORD dwIndex,
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, TRUE);
}
/***********************************************************************
* ImmGetCandidateListCountA (IMM32.@)
*/
DWORD WINAPI ImmGetCandidateListCountA(
HIMC hIMC, LPDWORD lpdwListCount)
{
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, TRUE);
}
/***********************************************************************
* ImmGetCandidateListCountW (IMM32.@)
*/
DWORD WINAPI ImmGetCandidateListCountW(
HIMC hIMC, LPDWORD lpdwListCount)
{
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, FALSE);
}
/***********************************************************************
* ImmGetCandidateListW (IMM32.@)
*/
DWORD WINAPI ImmGetCandidateListW(
HIMC hIMC, DWORD dwIndex,
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, FALSE);
}
/***********************************************************************
* ImmGetCandidateWindow (IMM32.@)
*/
BOOL WINAPI ImmGetCandidateWindow(
HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
{
BOOL ret = FALSE;
LPINPUTCONTEXT pIC;
LPCANDIDATEFORM pCF;
TRACE("(%p, %lu, %p)\n", hIMC, dwIndex, lpCandidate);
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
pCF = &pIC->cfCandForm[dwIndex];
if (pCF->dwIndex != IMM_INVALID_CANDFORM)
{
*lpCandidate = *pCF;
ret = TRUE;
}
ImmUnlockIMC(hIMC);
return ret;
}
static VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW)
{
size_t cch;
RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName));
StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch);
cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch,
plfW->lfFaceName, _countof(plfW->lfFaceName));
if (cch > _countof(plfW->lfFaceName) - 1)
cch = _countof(plfW->lfFaceName) - 1;
plfW->lfFaceName[cch] = 0;
}
static VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA)
{
size_t cch;
RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName));
StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch);
cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch,
plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL);
if (cch > _countof(plfA->lfFaceName) - 1)
cch = _countof(plfA->lfFaceName) - 1;
plfA->lfFaceName[cch] = 0;
}
/***********************************************************************
* 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;
}
/* Helpers for the GetCompositionString functions */
/* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
length is always in bytes. */
static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
INT dst_len, BOOL unicode)
{
int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
INT ret;
if (is_himc_ime_unicode(data) ^ unicode)
{
if (unicode)
ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
else
ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
ret *= char_size;
}
else
{
if (dst_len)
{
ret = min(src_len * char_size, dst_len);
memcpy(dst, src, ret);
}
else
ret = src_len * char_size;
}
return ret;
}
/* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
passed mode. String length is in characters, attributes are in byte arrays. */
static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
{
union
{
const void *str;
const WCHAR *strW;
const char *strA;
} string;
INT rc;
string.str = comp_string;
if (is_himc_ime_unicode(data) && !unicode)
{
rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
if (dst_len)
{
int i, j = 0, k = 0;
if (rc < dst_len)
dst_len = rc;
for (i = 0; i < str_len; ++i)
{
int len;
len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
for (; len > 0; --len)
{
dst[j++] = src[k];
if (j >= dst_len)
goto end;
}
++k;
}
end:
rc = j;
}
}
else if (!is_himc_ime_unicode(data) && unicode)
{
rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
if (dst_len)
{
int i, j = 0;
if (rc < dst_len)
dst_len = rc;
for (i = 0; i < str_len; ++i)
{
if (IsDBCSLeadByte(string.strA[i]))
continue;
dst[j++] = src[i];
if (j >= dst_len)
break;
}
rc = j;
}
}
else
{
memcpy(dst, src, min(src_len, dst_len));
rc = src_len;
}
return rc;
}
static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
LPBYTE target, INT tlen, BOOL unicode )
{
INT rc;
if (is_himc_ime_unicode(data) && !unicode)
{
if (tlen)
{
int i;
if (slen < tlen)
tlen = slen;
tlen /= sizeof (DWORD);
for (i = 0; i < tlen; ++i)
{
((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
((DWORD *)source)[i],
NULL, 0,
NULL, NULL);
}
rc = sizeof (DWORD) * i;
}
else
rc = slen;
}
else if (!is_himc_ime_unicode(data) && unicode)
{
if (tlen)
{
int i;
if (slen < tlen)
tlen = slen;
tlen /= sizeof (DWORD);
for (i = 0; i < tlen; ++i)
{
((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
((DWORD *)source)[i],
NULL, 0);
}
rc = sizeof (DWORD) * i;
}
else
rc = slen;
}
else
{
memcpy( target, source, min(slen,tlen));
rc = slen;
}
return rc;
}
static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
{
int rc;
if (is_himc_ime_unicode(data) && !unicode)
{
rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
}
else if (!is_himc_ime_unicode(data) && unicode)
{
rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
}
else
rc = offset;
return rc;
}
static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
DWORD dwBufLen, BOOL unicode)
{
LONG rc = 0;
InputContextData *data = get_imc_data(hIMC);
LPCOMPOSITIONSTRING compstr;
LPBYTE compdata;
TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
if (!data)
return FALSE;
if (!data->IMC.hCompStr)
return FALSE;
compdata = ImmLockIMCC(data->IMC.hCompStr);
compstr = (LPCOMPOSITIONSTRING)compdata;
switch (dwIndex)
{
case GCS_RESULTSTR:
TRACE("GCS_RESULTSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPSTR:
TRACE("GCS_COMPSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPATTR:
TRACE("GCS_COMPATTR\n");
rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPCLAUSE:
TRACE("GCS_COMPCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
compdata + compstr->dwCompStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTCLAUSE:
TRACE("GCS_RESULTCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
compdata + compstr->dwResultStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTREADSTR:
TRACE("GCS_RESULTREADSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTREADCLAUSE:
TRACE("GCS_RESULTREADCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
compdata + compstr->dwResultStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADSTR:
TRACE("GCS_COMPREADSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADATTR:
TRACE("GCS_COMPREADATTR\n");
rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADCLAUSE:
TRACE("GCS_COMPREADCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
compdata + compstr->dwCompStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_CURSORPOS:
TRACE("GCS_CURSORPOS\n");
rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
break;
case GCS_DELTASTART:
TRACE("GCS_DELTASTART\n");
rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
break;
default:
FIXME("Unhandled index 0x%x\n",dwIndex);
break;
}
ImmUnlockIMCC(data->IMC.hCompStr);
return rc;
}
/***********************************************************************
* ImmGetCompositionStringA (IMM32.@)
*/
LONG WINAPI ImmGetCompositionStringA(
HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
{
return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
}
/***********************************************************************
* ImmGetCompositionStringW (IMM32.@)
*/
LONG WINAPI ImmGetCompositionStringW(
HIMC hIMC, DWORD dwIndex,
LPVOID lpBuf, DWORD dwBufLen)
{
return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, 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;
}
/***********************************************************************
* ImmGetContext (IMM32.@)
*/
HIMC WINAPI ImmGetContext(HWND hWnd)
{
TRACE("(%p)\n", hWnd);
if (hWnd == NULL)
return NULL;
return Imm32GetContextEx(hWnd, 2);
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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);
}
/***********************************************************************
* CtfImmIsCiceroEnabled (IMM32.@)
*/
BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
{
return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED));
}
/***********************************************************************
* 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;
}
static DWORD APIENTRY
ImmGetGuideLineAW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsi)
{
PCLIENTIMC pClientImc;
LPINPUTCONTEXT pIC;
LPGUIDELINE pGuideLine;
DWORD cb, ret = 0;
LPVOID pvStr, pvPrivate;
BOOL bUsedDefault;
pClientImc = ImmLockClientImc(hIMC);
if (!pClientImc)
return 0;
pIC = ImmLockIMC(hIMC);
if (!pIC)
{
ImmUnlockClientImc(pClientImc);
return 0;
}
pGuideLine = ImmLockIMCC(pIC->hGuideLine);
if (!pGuideLine)
{
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return 0;
}
if (dwIndex == GGL_LEVEL)
{
ret = pGuideLine->dwLevel;
goto Quit;
}
if (dwIndex == GGL_INDEX)
{
ret = pGuideLine->dwIndex;
goto Quit;
}
if (dwIndex == GGL_STRING)
{
pvStr = (LPBYTE)pGuideLine + pGuideLine->dwStrOffset;
/* get size */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
cb = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen,
NULL, 0, NULL, &bUsedDefault);
}
else
{
cb = pGuideLine->dwStrLen * sizeof(CHAR);
}
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
cb = pGuideLine->dwStrLen * sizeof(WCHAR);
}
else
{
cb = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen,
NULL, 0) * sizeof(WCHAR);
}
}
if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb)
{
ret = cb;
goto Quit;
}
/* store to buffer */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen,
lpBuf, dwBufLen, NULL, &bUsedDefault);
goto Quit;
}
}
else
{
if (!(pClientImc->dwFlags & CLIENTIMC_WIDE))
{
ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen,
lpBuf, dwBufLen) * sizeof(WCHAR);
goto Quit;
}
}
RtlCopyMemory(lpBuf, pvStr, cb);
ret = cb;
goto Quit;
}
if (dwIndex == GGL_PRIVATE)
{
pvPrivate = (LPBYTE)pGuideLine + pGuideLine->dwPrivateOffset;
/* get size */
if (bAnsi)
{
if ((pClientImc->dwFlags & CLIENTIMC_WIDE) &&
pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
{
cb = CandidateListWideToAnsi(pvPrivate, NULL, 0, CP_ACP);
}
else
{
cb = pGuideLine->dwPrivateSize;
}
}
else
{
if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) &&
pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
{
cb = CandidateListAnsiToWide(pvPrivate, NULL, 0, CP_ACP);
}
else
{
cb = pGuideLine->dwPrivateSize;
}
}
if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb)
{
ret = cb;
goto Quit;
}
/* store to buffer */
if (bAnsi)
{
if ((pClientImc->dwFlags & CLIENTIMC_WIDE) &&
pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
{
ret = CandidateListWideToAnsi(pvPrivate, lpBuf, cb, CP_ACP);
goto Quit;
}
}
else
{
if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) &&
pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
{
ret = CandidateListAnsiToWide(pvPrivate, lpBuf, cb, CP_ACP);
goto Quit;
}
}
RtlCopyMemory(lpBuf, pvPrivate, cb);
ret = cb;
goto Quit;
}
Quit:
ImmUnlockIMCC(pIC->hGuideLine);
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return ret;
}
/***********************************************************************
* ImmGetGuideLineA (IMM32.@)
*/
DWORD WINAPI ImmGetGuideLineA(
HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
{
TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
}
/***********************************************************************
* ImmGetGuideLineW (IMM32.@)
*/
DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
{
TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* ImmGetRegisterWordStyleA (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleA(
HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
{
UINT iItem, ret = 0;
PIMEDPI pImeDpi;
LPSTYLEBUFA pDestA;
LPSTYLEBUFW pSrcW, pNewStylesW = NULL;
size_t cchW;
INT cchA;
TRACE("(%p, %u, %p)\n", hKL, nItem, lpStyleBuf);
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return 0;
if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
{
ret = pImeDpi->ImeGetRegisterWordStyle(nItem, lpStyleBuf);
goto Quit;
}
if (nItem > 0)
{
pNewStylesW = Imm32HeapAlloc(0, nItem * sizeof(STYLEBUFW));
if (!pNewStylesW)
goto Quit;
}
ret = pImeDpi->ImeGetRegisterWordStyle(nItem, pNewStylesW);
if (nItem > 0)
{
/* lpStyleBuf <-- pNewStylesW */
for (iItem = 0; iItem < ret; ++iItem)
{
pSrcW = &pNewStylesW[iItem];
pDestA = &lpStyleBuf[iItem];
pDestA->dwStyle = pSrcW->dwStyle;
StringCchLengthW(pSrcW->szDescription, _countof(pSrcW->szDescription), &cchW);
cchA = WideCharToMultiByte(CP_ACP, MB_PRECOMPOSED,
pSrcW->szDescription, (INT)cchW,
pDestA->szDescription, _countof(pDestA->szDescription),
NULL, NULL);
if (cchA > _countof(pDestA->szDescription) - 1)
cchA = _countof(pDestA->szDescription) - 1;
pDestA->szDescription[cchA] = 0;
}
}
Quit:
if (pNewStylesW)
HeapFree(g_hImm32Heap, 0, pNewStylesW);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmGetRegisterWordStyleW (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleW(
HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
{
UINT iItem, ret = 0;
PIMEDPI pImeDpi;
LPSTYLEBUFA pSrcA, pNewStylesA = NULL;
LPSTYLEBUFW pDestW;
size_t cchA;
INT cchW;
TRACE("(%p, %u, %p)\n", hKL, nItem, lpStyleBuf);
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return 0;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
ret = pImeDpi->ImeGetRegisterWordStyle(nItem, lpStyleBuf);
goto Quit;
}
if (nItem > 0)
{
pNewStylesA = Imm32HeapAlloc(0, nItem * sizeof(STYLEBUFA));
if (!pNewStylesA)
goto Quit;
}
ret = pImeDpi->ImeGetRegisterWordStyle(nItem, pNewStylesA);
if (nItem > 0)
{
/* lpStyleBuf <-- pNewStylesA */
for (iItem = 0; iItem < ret; ++iItem)
{
pSrcA = &pNewStylesA[iItem];
pDestW = &lpStyleBuf[iItem];
pDestW->dwStyle = pSrcA->dwStyle;
StringCchLengthA(pSrcA->szDescription, _countof(pSrcA->szDescription), &cchA);
cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
pSrcA->szDescription, (INT)cchA,
pDestW->szDescription, _countof(pDestW->szDescription));
if (cchW > _countof(pDestW->szDescription) - 1)
cchW = _countof(pDestW->szDescription) - 1;
pDestW->szDescription[cchW] = 0;
}
}
Quit:
if (pNewStylesA)
HeapFree(g_hImm32Heap, 0, pNewStylesA);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* ImmGetVirtualKey (IMM32.@)
*/
UINT WINAPI ImmGetVirtualKey(HWND hWnd)
{
HIMC hIMC;
LPINPUTCONTEXTDX pIC;
UINT ret = VK_PROCESSKEY;
TRACE("(%p)\n", hWnd);
hIMC = ImmGetContext(hWnd);
pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
if (!pIC)
return ret;
if (pIC->bNeedsTrans)
ret = pIC->nVKey;
ImmUnlockIMC(hIMC);
return ret;
}
/***********************************************************************
* ImmInstallIMEA (IMM32.@)
*/
HKL WINAPI ImmInstallIMEA(
LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
{
HKL hKL = NULL;
LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
if (pszFileNameW == NULL)
goto Quit;
pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
if (pszLayoutTextW == NULL)
goto Quit;
hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
Quit:
if (pszFileNameW)
HeapFree(g_hImm32Heap, 0, pszFileNameW);
if (pszLayoutTextW)
HeapFree(g_hImm32Heap, 0, pszLayoutTextW);
return hKL;
}
/***********************************************************************
* ImmInstallIMEW (IMM32.@)
*/
HKL WINAPI ImmInstallIMEW(
LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
{
INT lcid = GetUserDefaultLCID();
INT count;
HKL hkl;
DWORD rc;
HKEY hkey;
WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
debugstr_w(lpszLayoutText));
/* Start with 2. e001 will be blank and so default to the wine internal IME */
count = 2;
while (count < 0xfff)
{
DWORD disposition = 0;
hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
break;
else if (rc == ERROR_SUCCESS)
RegCloseKey(hkey);
count++;
}
if (count == 0xfff)
{
WARN("Unable to find slot to install IME\n");
return 0;
}
if (rc == ERROR_SUCCESS)
{
rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
(lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
(lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
RegCloseKey(hkey);
return hkl;
}
else
{
WARN("Unable to set IME registry values\n");
return 0;
}
}
/***********************************************************************
* ImmIsIME (IMM32.@)
*/
BOOL WINAPI ImmIsIME(HKL hKL)
{
IMEINFOEX info;
TRACE("(%p)\n", hKL);
return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL);
}
static BOOL APIENTRY
ImmIsUIMessageAW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAnsi)
{
switch (msg)
{
case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION:
case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY:
case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_SYSTEM:
break;
default:
return FALSE;
}
if (!hWndIME)
return TRUE;
if (bAnsi)
SendMessageA(hWndIME, msg, wParam, lParam);
else
SendMessageW(hWndIME, msg, wParam, lParam);
return TRUE;
}
/***********************************************************************
* ImmIsUIMessageA (IMM32.@)
*/
BOOL WINAPI ImmIsUIMessageA(
HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
{
TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam);
return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE);
}
/***********************************************************************
* ImmIsUIMessageW (IMM32.@)
*/
BOOL WINAPI ImmIsUIMessageW(
HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
{
TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam);
return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE);
}
/***********************************************************************
* 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;
}
/***********************************************************************
* ImmRegisterWordA (IMM32.@)
*/
BOOL WINAPI ImmRegisterWordA(
HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
{
BOOL ret = FALSE;
PIMEDPI pImeDpi;
LPWSTR pszReadingW = NULL, pszRegisterW = NULL;
TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle,
debugstr_a(lpszRegister));
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return FALSE;
if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
{
ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingW = Imm32WideFromAnsi(lpszReading);
if (pszReadingW == NULL)
goto Quit;
}
if (lpszRegister)
{
pszRegisterW = Imm32WideFromAnsi(lpszRegister);
if (pszRegisterW == NULL)
goto Quit;
}
ret = pImeDpi->ImeRegisterWord(pszReadingW, dwStyle, pszRegisterW);
Quit:
if (pszReadingW)
HeapFree(g_hImm32Heap, 0, pszReadingW);
if (pszRegisterW)
HeapFree(g_hImm32Heap, 0, pszRegisterW);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmRegisterWordW (IMM32.@)
*/
BOOL WINAPI ImmRegisterWordW(
HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
{
BOOL ret = FALSE;
PIMEDPI pImeDpi;
LPSTR pszReadingA = NULL, pszRegisterA = NULL;
TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_w(lpszReading), dwStyle,
debugstr_w(lpszRegister));
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return FALSE;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingA = Imm32AnsiFromWide(lpszReading);
if (!pszReadingA)
goto Quit;
}
if (lpszRegister)
{
pszRegisterA = Imm32AnsiFromWide(lpszRegister);
if (!pszRegisterA)
goto Quit;
}
ret = pImeDpi->ImeRegisterWord(pszReadingA, dwStyle, pszRegisterA);
Quit:
if (pszReadingA)
HeapFree(g_hImm32Heap, 0, pszReadingA);
if (pszRegisterA)
HeapFree(g_hImm32Heap, 0, pszRegisterA);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmReleaseContext (IMM32.@)
*/
BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
{
TRACE("(%p, %p)\n", hWnd, hIMC);
UNREFERENCED_PARAMETER(hWnd);
UNREFERENCED_PARAMETER(hIMC);
return TRUE; // Do nothing. This is correct.
}
/***********************************************************************
* ImmRequestMessageA(IMM32.@)
*/
LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/***********************************************************************
* ImmRequestMessageW(IMM32.@)
*/
LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/***********************************************************************
* ImmSetCandidateWindow (IMM32.@)
*/
BOOL WINAPI ImmSetCandidateWindow(
HIMC hIMC, LPCANDIDATEFORM lpCandidate)
{
HWND hWnd;
LPINPUTCONTEXT pIC;
TRACE("(%p, %p)\n", hIMC, lpCandidate);
if (lpCandidate->dwIndex >= MAX_CANDIDATEFORM)
return FALSE;
if (Imm32IsCrossThreadAccess(hIMC))
return FALSE;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
hWnd = pIC->hWnd;
pIC->cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
ImmUnlockIMC(hIMC);
Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS,
IMN_SETCANDIDATEPOS, (1 << (BYTE)lpCandidate->dwIndex));
return TRUE;
}
static VOID APIENTRY WideToAnsiLogFont(const LOGFONTW *plfW, LPLOGFONTA plfA)
{
BOOL bUsedDef;
size_t cchW, cchA = _countof(plfA->lfFaceName);
RtlCopyMemory(plfA, plfW, offsetof(LOGFONTA, lfFaceName));
StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cchW);
cchA = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cchW,
plfA->lfFaceName, (INT)cchA, NULL, &bUsedDef);
if (cchA > _countof(plfA->lfFaceName) - 1)
cchA = _countof(plfA->lfFaceName) - 1;
plfA->lfFaceName[cchA] = 0;
}
static VOID APIENTRY AnsiToWideLogFont(const LOGFONTA *plfA, LPLOGFONTW plfW)
{
size_t cchA, cchW = _countof(plfW->lfFaceName);
RtlCopyMemory(plfW, plfA, offsetof(LOGFONTW, lfFaceName));
StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cchA);
cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cchA,
plfW->lfFaceName, (INT)cchW);
if (cchW > _countof(plfW->lfFaceName) - 1)
cchW = _countof(plfW->lfFaceName) - 1;
plfW->lfFaceName[cchW] = 0;
}
/***********************************************************************
* 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)
{
AnsiToWideLogFont(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)
{
WideToAnsiLogFont(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;
}
/***********************************************************************
* ImmSetCompositionStringA (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionStringA(
HIMC hIMC, DWORD dwIndex,
LPCVOID lpComp, DWORD dwCompLen,
LPCVOID lpRead, DWORD dwReadLen)
{
DWORD comp_len;
DWORD read_len;
WCHAR *CompBuffer = NULL;
WCHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
if (!data)
return FALSE;
if (!(dwIndex == SCS_SETSTR ||
dwIndex == SCS_CHANGEATTR ||
dwIndex == SCS_CHANGECLAUSE ||
dwIndex == SCS_SETRECONVERTSTRING ||
dwIndex == SCS_QUERYRECONVERTSTRING))
return FALSE;
if (!is_himc_ime_unicode(data))
return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
dwCompLen, lpRead, dwReadLen);
comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
if (comp_len)
{
CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
}
read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
if (read_len)
{
ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
}
rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
ReadBuffer, read_len);
HeapFree(GetProcessHeap(), 0, CompBuffer);
HeapFree(GetProcessHeap(), 0, ReadBuffer);
return rc;
}
/***********************************************************************
* ImmSetCompositionStringW (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionStringW(
HIMC hIMC, DWORD dwIndex,
LPCVOID lpComp, DWORD dwCompLen,
LPCVOID lpRead, DWORD dwReadLen)
{
DWORD comp_len;
DWORD read_len;
CHAR *CompBuffer = NULL;
CHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
if (!data)
return FALSE;
if (!(dwIndex == SCS_SETSTR ||
dwIndex == SCS_CHANGEATTR ||
dwIndex == SCS_CHANGECLAUSE ||
dwIndex == SCS_SETRECONVERTSTRING ||
dwIndex == SCS_QUERYRECONVERTSTRING))
return FALSE;
if (is_himc_ime_unicode(data))
return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
dwCompLen, lpRead, dwReadLen);
comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
NULL);
if (comp_len)
{
CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
NULL, NULL);
}
read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
NULL);
if (read_len)
{
ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
NULL, NULL);
}
rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
ReadBuffer, read_len);
HeapFree(GetProcessHeap(), 0, CompBuffer);
HeapFree(GetProcessHeap(), 0, ReadBuffer);
return rc;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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);
}
/***********************************************************************
* 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;
}
/***********************************************************************
* 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;
}
/***********************************************************************
* ImmCreateSoftKeyboard(IMM32.@)
*/
HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
{
FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/***********************************************************************
* ImmDestroySoftKeyboard(IMM32.@)
*/
BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
{
TRACE("(%p)\n", hSoftWnd);
return DestroyWindow(hSoftWnd);
}
/***********************************************************************
* ImmShowSoftKeyboard(IMM32.@)
*/
BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
{
TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
if (hSoftWnd)
return ShowWindow(hSoftWnd, nCmdShow);
return FALSE;
}
/***********************************************************************
* ImmSimulateHotKey (IMM32.@)
*/
BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
{
HIMC hIMC;
DWORD dwThreadId;
HKL hKL;
BOOL ret;
TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID);
hIMC = ImmGetContext(hWnd);
dwThreadId = GetWindowThreadProcessId(hWnd, NULL);
hKL = GetKeyboardLayout(dwThreadId);
ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID);
ImmReleaseContext(hWnd, hIMC);
return ret;
}
/***********************************************************************
* ImmUnregisterWordA (IMM32.@)
*/
BOOL WINAPI ImmUnregisterWordA(
HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
{
BOOL ret = FALSE;
PIMEDPI pImeDpi;
LPWSTR pszReadingW = NULL, pszUnregisterW = NULL;
TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle,
debugstr_a(lpszUnregister));
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (pImeDpi == NULL)
return FALSE;
if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
{
ret = pImeDpi->ImeUnregisterWord(lpszReading, dwStyle, lpszUnregister);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingW = Imm32WideFromAnsi(lpszReading);
if (pszReadingW == NULL)
goto Quit;
}
if (lpszUnregister)
{
pszUnregisterW = Imm32WideFromAnsi(lpszUnregister);
if (pszUnregisterW == NULL)
goto Quit;
}
ret = pImeDpi->ImeUnregisterWord(pszReadingW, dwStyle, pszUnregisterW);
Quit:
if (pszReadingW)
HeapFree(g_hImm32Heap, 0, pszReadingW);
if (pszUnregisterW)
HeapFree(g_hImm32Heap, 0, pszUnregisterW);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmUnregisterWordW (IMM32.@)
*/
BOOL WINAPI ImmUnregisterWordW(
HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
{
BOOL ret = FALSE;
PIMEDPI pImeDpi;
LPSTR pszReadingA = NULL, pszUnregisterA = NULL;
TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_w(lpszReading), dwStyle,
debugstr_w(lpszUnregister));
pImeDpi = ImmLockOrLoadImeDpi(hKL);
if (!pImeDpi)
return FALSE;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
ret = pImeDpi->ImeUnregisterWord(lpszReading, dwStyle, lpszUnregister);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
if (lpszReading)
{
pszReadingA = Imm32AnsiFromWide(lpszReading);
if (!pszReadingA)
goto Quit;
}
if (lpszUnregister)
{
pszUnregisterA = Imm32AnsiFromWide(lpszUnregister);
if (!pszUnregisterA)
goto Quit;
}
ret = pImeDpi->ImeUnregisterWord(pszReadingA, dwStyle, pszUnregisterA);
Quit:
if (pszReadingA)
HeapFree(g_hImm32Heap, 0, pszReadingA);
if (pszUnregisterA)
HeapFree(g_hImm32Heap, 0, pszUnregisterA);
ImmUnlockImeDpi(pImeDpi);
return ret;
}
/***********************************************************************
* ImmGetImeMenuItemsA (IMM32.@)
*/
DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
DWORD dwSize)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
{
if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
(IMEMENUITEMINFOW*)lpImeParentMenu,
(IMEMENUITEMINFOW*)lpImeMenu, dwSize);
else
{
IMEMENUITEMINFOW lpImeParentMenuW;
IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
DWORD rc;
if (lpImeParentMenu)
parent = &lpImeParentMenuW;
if (lpImeMenu)
{
int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
dwSize = count * sizeof(IMEMENUITEMINFOW);
lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
}
else
lpImeMenuW = NULL;
rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
parent, lpImeMenuW, dwSize);
if (lpImeParentMenu)
{
memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
-1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
NULL, NULL);
}
if (lpImeMenu && rc)
{
unsigned int i;
for (i = 0; i < rc; i++)
{
memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
-1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
NULL, NULL);
}
}
HeapFree(GetProcessHeap(),0,lpImeMenuW);
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetImeMenuItemsW (IMM32.@)
*/
DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
DWORD dwSize)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
{
if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
else
{
IMEMENUITEMINFOA lpImeParentMenuA;
IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
DWORD rc;
if (lpImeParentMenu)
parent = &lpImeParentMenuA;
if (lpImeMenu)
{
int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
dwSize = count * sizeof(IMEMENUITEMINFOA);
lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
}
else
lpImeMenuA = NULL;
rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
(IMEMENUITEMINFOW*)parent,
(IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
if (lpImeParentMenu)
{
memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
-1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
}
if (lpImeMenu && rc)
{
unsigned int i;
for (i = 0; i < rc; i++)
{
memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
-1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
}
}
HeapFree(GetProcessHeap(),0,lpImeMenuA);
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmLockIMC(IMM32.@)
*/
LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
if (!data)
return NULL;
data->dwLock++;
return &data->IMC;
}
/***********************************************************************
* ImmUnlockIMC(IMM32.@)
*/
BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
{
PCLIENTIMC pClientImc;
HIMC hClientImc;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return FALSE;
hClientImc = pClientImc->hImc;
if (hClientImc)
LocalUnlock(hClientImc);
InterlockedDecrement(&pClientImc->cLockObj);
ImmUnlockClientImc(pClientImc);
return TRUE;
}
/***********************************************************************
* ImmGetIMCLockCount(IMM32.@)
*/
DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
{
DWORD ret;
HIMC hClientImc;
PCLIENTIMC pClientImc;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return 0;
ret = 0;
hClientImc = pClientImc->hImc;
if (hClientImc)
ret = (LocalFlags(hClientImc) & LMEM_LOCKCOUNT);
ImmUnlockClientImc(pClientImc);
return ret;
}
/***********************************************************************
* ImmCreateIMCC(IMM32.@)
*/
HIMCC WINAPI ImmCreateIMCC(DWORD size)
{
if (size < 4)
size = 4;
return LocalAlloc(LHND, size);
}
/***********************************************************************
* ImmDestroyIMCC(IMM32.@)
*/
HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
{
if (block)
return LocalFree(block);
return NULL;
}
/***********************************************************************
* ImmLockIMCC(IMM32.@)
*/
LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
{
if (imcc)
return LocalLock(imcc);
return NULL;
}
/***********************************************************************
* ImmUnlockIMCC(IMM32.@)
*/
BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
{
if (imcc)
return LocalUnlock(imcc);
return FALSE;
}
/***********************************************************************
* ImmGetIMCCLockCount(IMM32.@)
*/
DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
{
return LocalFlags(imcc) & LMEM_LOCKCOUNT;
}
/***********************************************************************
* ImmReSizeIMCC(IMM32.@)
*/
HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
{
if (!imcc)
return NULL;
return LocalReAlloc(imcc, size, LHND);
}
/***********************************************************************
* ImmGetIMCCSize(IMM32.@)
*/
DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
{
if (imcc)
return LocalSize(imcc);
return 0;
}
/***********************************************************************
* ImmGenerateMessage(IMM32.@)
*/
BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
{
PCLIENTIMC pClientImc;
LPINPUTCONTEXT pIC;
LPTRANSMSG pMsgs, pTrans = NULL, pItem;
HWND hWnd;
DWORD dwIndex, dwCount, cbTrans;
HIMCC hMsgBuf = NULL;
BOOL bAnsi;
TRACE("(%p)\n", hIMC);
if (Imm32IsCrossThreadAccess(hIMC))
return FALSE;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return FALSE;
bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
ImmUnlockClientImc(pClientImc);
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
dwCount = pIC->dwNumMsgBuf;
if (dwCount == 0)
goto Quit;
hMsgBuf = pIC->hMsgBuf;
pMsgs = ImmLockIMCC(hMsgBuf);
if (pMsgs == NULL)
goto Quit;
cbTrans = dwCount * sizeof(TRANSMSG);
pTrans = Imm32HeapAlloc(0, cbTrans);
if (pTrans == NULL)
goto Quit;
RtlCopyMemory(pTrans, pMsgs, cbTrans);
#ifdef IMP_SUPPORT
if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
{
LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
WORD wLang = PRIMARYLANGID(LangID);
/* translate the messages if Japanese or Korean */
if (wLang == LANG_JAPANESE ||
(wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3))
{
dwCount = ImpTrans(dwCount, pTrans, hIMC, bAnsi, wLang);
}
}
#endif
/* send them */
hWnd = pIC->hWnd;
pItem = pTrans;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem)
{
if (bAnsi)
SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam);
else
SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam);
}
Quit:
if (pTrans)
HeapFree(g_hImm32Heap, 0, pTrans);
if (hMsgBuf)
ImmUnlockIMCC(hMsgBuf);
pIC->dwNumMsgBuf = 0; /* done */
ImmUnlockIMC(hIMC);
return TRUE;
}
static VOID APIENTRY
Imm32PostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg)
{
DWORD dwIndex;
PCLIENTIMC pClientImc;
LPTRANSMSG pNewTransMsg = lpTransMsg, pItem;
BOOL bAnsi;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return;
bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
ImmUnlockClientImc(pClientImc);
#ifdef IMP_SUPPORT
if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
{
LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
WORD Lang = PRIMARYLANGID(LangID);
/* translate the messages if Japanese or Korean */
if (Lang == LANG_JAPANESE ||
(Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3))
{
DWORD cbTransMsg = dwCount * sizeof(TRANSMSG);
pNewTransMsg = Imm32HeapAlloc(0, cbTransMsg);
if (pNewTransMsg)
{
RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg);
dwCount = ImpTrans(dwCount, pNewTransMsg, hIMC, bAnsi, Lang);
}
else
{
pNewTransMsg = lpTransMsg;
}
}
}
#endif
/* post them */
pItem = pNewTransMsg;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem)
{
if (bAnsi)
PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam);
else
PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam);
}
#ifdef IMP_SUPPORT
if (pNewTransMsg && pNewTransMsg != lpTransMsg)
HeapFree(g_hImm32Heap, 0, pNewTransMsg);
#endif
}
/***********************************************************************
* ImmTranslateMessage(IMM32.@)
* ( Undocumented, call internally and from user32.dll )
*/
BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
{
#define MSG_COUNT 0x100
BOOL ret = FALSE;
INT kret;
LPINPUTCONTEXTDX pIC;
PIMEDPI pImeDpi = NULL;
LPTRANSMSGLIST pList = NULL;
LPTRANSMSG pTransMsg;
BYTE abKeyState[256];
HIMC hIMC;
HKL hKL;
UINT vk;
DWORD dwThreadId, dwCount, cbList;
WCHAR wch;
WORD wChar;
TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData);
/* filter the message */
switch (msg)
{
case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP:
break;
default:
return FALSE;
}
hIMC = ImmGetContext(hwnd);
pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmReleaseContext(hwnd, hIMC);
return FALSE;
}
if (!pIC->bNeedsTrans) /* is translation needed? */
{
/* directly post them */
dwCount = pIC->dwNumMsgBuf;
if (dwCount == 0)
goto Quit;
pTransMsg = ImmLockIMCC(pIC->hMsgBuf);
if (pTransMsg)
{
Imm32PostMessages(hwnd, hIMC, dwCount, pTransMsg);
ImmUnlockIMCC(pIC->hMsgBuf);
ret = TRUE;
}
pIC->dwNumMsgBuf = 0; /* done */
goto Quit;
}
pIC->bNeedsTrans = FALSE; /* clear the flag */
dwThreadId = GetWindowThreadProcessId(hwnd, NULL);
hKL = GetKeyboardLayout(dwThreadId);
pImeDpi = ImmLockImeDpi(hKL);
if (pImeDpi == NULL)
goto Quit;
if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */
goto Quit;
/* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */
vk = pIC->nVKey;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
{
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
wch = 0;
kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0);
if (kret == 1)
vk = MAKELONG(LOBYTE(vk), wch);
}
else
{
wChar = 0;
kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL);
if (kret > 0)
vk = MAKEWORD(vk, wChar);
}
}
/* allocate a list */
cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG);
pList = Imm32HeapAlloc(0, cbList);
if (!pList)
goto Quit;
/* use IME conversion engine and convert the list */
pList->uMsgCount = MSG_COUNT;
kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC);
if (kret <= 0)
goto Quit;
/* post them */
if (kret <= MSG_COUNT)
{
Imm32PostMessages(hwnd, hIMC, kret, pList->TransMsg);
ret = TRUE;
}
else
{
pTransMsg = ImmLockIMCC(pIC->hMsgBuf);
if (pTransMsg == NULL)
goto Quit;
Imm32PostMessages(hwnd, hIMC, kret, pTransMsg);
ImmUnlockIMCC(pIC->hMsgBuf);
}
Quit:
if (pList)
HeapFree(g_hImm32Heap, 0, pList);
ImmUnlockImeDpi(pImeDpi);
ImmUnlockIMC(hIMC);
ImmReleaseContext(hwnd, hIMC);
return ret;
#undef MSG_COUNT
}
/***********************************************************************
* ImmProcessKey(IMM32.@)
* ( Undocumented, called from user32.dll )
*/
DWORD WINAPI ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID)
{
DWORD ret = 0;
HIMC hIMC;
PIMEDPI pImeDpi;
LPINPUTCONTEXTDX pIC;
BYTE KeyState[256];
UINT vk;
BOOL bUseIme = TRUE, bSkipThisKey = FALSE, bLowWordOnly = FALSE;
TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID);
hIMC = ImmGetContext(hWnd);
pImeDpi = ImmLockImeDpi(hKL);
if (pImeDpi)
{
pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
if (pIC)
{
if (LOBYTE(vKey) == VK_PACKET &&
!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY))
{
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
{
bLowWordOnly = TRUE;
}
else
{
bUseIme = FALSE;
if (pIC->fOpen)
bSkipThisKey = TRUE;
}
}
if (bUseIme)
{
if (GetKeyboardState(KeyState))
{
vk = (bLowWordOnly ? LOWORD(vKey) : vKey);
if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState))
{
pIC->bNeedsTrans = TRUE;
pIC->nVKey = vKey;
ret |= IPHK_PROCESSBYIME;
}
}
}
else if (bSkipThisKey)
{
ret |= IPHK_SKIPTHISKEY;
}
ImmUnlockIMC(hIMC);
}
ImmUnlockImeDpi(pImeDpi);
}
if (dwHotKeyID != INVALID_HOTKEY_ID)
{
if (Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID))
{
if (vKey != VK_KANJI || dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)
ret |= IPHK_HOTKEY;
}
}
if (ret & IPHK_PROCESSBYIME)
{
FIXME("TODO: We have to do something here.\n");
}
ImmReleaseContext(hWnd, hIMC);
return ret;
}
/***********************************************************************
* ImmDisableTextFrameService(IMM32.@)
*/
BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
{
FIXME("Stub\n");
return FALSE;
}
/***********************************************************************
* ImmEnumInputContext(IMM32.@)
*/
BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam)
{
HIMC *phList;
DWORD dwIndex, dwCount;
BOOL ret = TRUE;
HIMC hIMC;
TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
if (!dwCount)
return FALSE;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
{
hIMC = phList[dwIndex];
ret = (*lpfn)(hIMC, lParam);
if (!ret)
break;
}
HeapFree(g_hImm32Heap, 0, phList);
return ret;
}
/***********************************************************************
* ImmGetHotKey(IMM32.@)
*/
BOOL WINAPI
ImmGetHotKey(IN DWORD dwHotKey,
OUT LPUINT lpuModifiers,
OUT LPUINT lpuVKey,
OUT LPHKL lphKL)
{
TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL);
if (lpuModifiers && lpuVKey)
return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL);
return FALSE;
}
/***********************************************************************
* ImmDisableLegacyIME(IMM32.@)
*/
BOOL WINAPI ImmDisableLegacyIME(void)
{
FIXME("stub\n");
return TRUE;
}
/***********************************************************************
* ImmSetActiveContext(IMM32.@)
*/
BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag)
{
FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag);
return FALSE;
}
/***********************************************************************
* ImmSetActiveContextConsoleIME(IMM32.@)
*/
BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
{
HIMC hIMC;
TRACE("(%p, %d)\n", hwnd, fFlag);
hIMC = ImmGetContext(hwnd);
if (hIMC)
return ImmSetActiveContext(hwnd, hIMC, fFlag);
return FALSE;
}
/***********************************************************************
* ImmRegisterClient(IMM32.@)
* ( Undocumented, called from user32.dll )
*/
BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
{
g_SharedInfo = *ptr;
g_psi = g_SharedInfo.psi;
return Imm32InitInstance(hMod);
}
/***********************************************************************
* 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);
}
/***********************************************************************
* ImmWINNLSGetIMEHotkey (IMM32.@)
*/
UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme)
{
TRACE("(%p)\n", hwndIme);
UNREFERENCED_PARAMETER(hwndIme);
return 0; /* This is correct. This function of Windows just returns zero. */
}
BOOL WINAPI User32InitializeImmEntryTable(DWORD);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
HKL hKL;
HIMC hIMC;
PTEB pTeb;
TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
//Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense
if (!Imm32InitInstance(hinstDLL))
{
ERR("Imm32InitInstance failed\n");
return FALSE;
}
if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
{
ERR("User32InitializeImmEntryTable failed\n");
return FALSE;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
return TRUE;
pTeb = NtCurrentTeb();
if (pTeb->Win32ThreadInfo == NULL)
return TRUE;
hKL = GetKeyboardLayout(0);
// FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
hIMC = (HIMC)NtUserGetThreadState(4);
Imm32CleanupContext(hIMC, hKL, TRUE);
break;
case DLL_PROCESS_DETACH:
RtlDeleteCriticalSection(&g_csImeDpi);
TRACE("imm32.dll is unloaded\n");
break;
}
return TRUE;
}