mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-01 06:06:13 +00:00
3322 lines
95 KiB
C
3322 lines
95 KiB
C
/*
|
|
* IMM32 library
|
|
*
|
|
* Copyright 1998 Patrik Stridvall
|
|
* Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define COBJMACROS
|
|
#include "initguid.h"
|
|
#include "imm_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
|
|
|
#define IMM_INIT_MAGIC 0x19650412
|
|
BOOL WINAPI User32InitializeImmEntryTable(DWORD);
|
|
|
|
HMODULE imm32_module;
|
|
|
|
/* MSIME messages */
|
|
UINT WM_MSIME_SERVICE;
|
|
UINT WM_MSIME_RECONVERTOPTIONS;
|
|
UINT WM_MSIME_MOUSE;
|
|
UINT WM_MSIME_RECONVERTREQUEST;
|
|
UINT WM_MSIME_RECONVERT;
|
|
UINT WM_MSIME_QUERYPOSITION;
|
|
UINT WM_MSIME_DOCUMENTFEED;
|
|
|
|
struct imc_entry
|
|
{
|
|
HIMC himc;
|
|
INPUTCONTEXT context;
|
|
struct list entry;
|
|
};
|
|
|
|
struct ime
|
|
{
|
|
LONG refcount; /* guarded by ime_cs */
|
|
|
|
HKL hkl;
|
|
HMODULE module;
|
|
struct list entry;
|
|
|
|
IMEINFO info;
|
|
WCHAR ui_class[17];
|
|
struct list input_contexts;
|
|
|
|
BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD);
|
|
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 *, TRANSMSGLIST *, UINT, HIMC);
|
|
BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
|
|
BOOL (WINAPI *pImeRegisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*);
|
|
BOOL (WINAPI *pImeUnregisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*);
|
|
UINT (WINAPI *pImeEnumRegisterWord)(void */*REGISTERWORDENUMPROCW*/, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, void *);
|
|
BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, DWORD);
|
|
DWORD (WINAPI *pImeConversionList)(HIMC, const void/*TCHAR*/*, CANDIDATELIST*, DWORD, UINT);
|
|
UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, void/*STYLEBUFW*/*);
|
|
BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE*);
|
|
DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, void/*IMEMENUITEMINFOW*/*, void/*IMEMENUITEMINFOW*/*, DWORD);
|
|
};
|
|
|
|
static HRESULT (WINAPI *pCoRevokeInitializeSpy)(ULARGE_INTEGER cookie);
|
|
static void (WINAPI *pCoUninitialize)(void);
|
|
|
|
struct imc
|
|
{
|
|
HIMC handle;
|
|
DWORD dwLock;
|
|
INPUTCONTEXT IMC;
|
|
|
|
struct ime *ime;
|
|
UINT vkey;
|
|
|
|
HWND ui_hwnd; /* IME UI window, on the default input context */
|
|
};
|
|
|
|
#define WINE_IMC_VALID_MAGIC 0x56434D49
|
|
|
|
struct coinit_spy
|
|
{
|
|
IInitializeSpy IInitializeSpy_iface;
|
|
LONG ref;
|
|
ULARGE_INTEGER cookie;
|
|
enum
|
|
{
|
|
IMM_APT_INIT = 0x1,
|
|
IMM_APT_CREATED = 0x2,
|
|
IMM_APT_CAN_FREE = 0x4,
|
|
IMM_APT_BROKEN = 0x8
|
|
} apt_flags;
|
|
};
|
|
|
|
static CRITICAL_SECTION ime_cs;
|
|
static CRITICAL_SECTION_DEBUG ime_cs_debug =
|
|
{
|
|
0, 0, &ime_cs,
|
|
{ &ime_cs_debug.ProcessLocksList, &ime_cs_debug.ProcessLocksList },
|
|
0, 0, { (DWORD_PTR)(__FILE__ ": ime_cs") }
|
|
};
|
|
static CRITICAL_SECTION ime_cs = { &ime_cs_debug, -1, 0, 0, 0, 0 };
|
|
static struct list ime_list = LIST_INIT( ime_list );
|
|
|
|
static const WCHAR layouts_formatW[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
|
|
|
|
static const char *debugstr_composition( const COMPOSITIONFORM *composition )
|
|
{
|
|
if (!composition) return "(null)";
|
|
return wine_dbg_sprintf( "style %#lx, pos %s, area %s", composition->dwStyle,
|
|
wine_dbgstr_point( &composition->ptCurrentPos ),
|
|
wine_dbgstr_rect( &composition->rcArea ) );
|
|
}
|
|
|
|
static const char *debugstr_candidate( const CANDIDATEFORM *candidate )
|
|
{
|
|
if (!candidate) return "(null)";
|
|
return wine_dbg_sprintf( "idx %#lx, style %#lx, pos %s, area %s", candidate->dwIndex,
|
|
candidate->dwStyle, wine_dbgstr_point( &candidate->ptCurrentPos ),
|
|
wine_dbgstr_rect( &candidate->rcArea ) );
|
|
}
|
|
|
|
static BOOL ime_is_unicode( const struct ime *ime )
|
|
{
|
|
return !!(ime->info.fdwProperty & IME_PROP_UNICODE);
|
|
}
|
|
|
|
static BOOL input_context_is_unicode( INPUTCONTEXT *ctx )
|
|
{
|
|
struct imc *imc = CONTAINING_RECORD( ctx, struct imc, IMC );
|
|
return !imc->ime || ime_is_unicode( imc->ime );
|
|
}
|
|
|
|
static BOOL IMM_DestroyContext(HIMC hIMC);
|
|
static struct imc *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 = malloc( 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 = malloc( len ))) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static DWORD convert_candidatelist_WtoA(
|
|
LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
|
|
{
|
|
DWORD ret, i, len;
|
|
|
|
ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
|
|
if ( lpDst && dwBufLen > 0 )
|
|
{
|
|
*lpDst = *lpSrc;
|
|
lpDst->dwOffset[0] = ret;
|
|
}
|
|
|
|
for ( i = 0; i < lpSrc->dwCount; i++)
|
|
{
|
|
LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
|
|
|
|
if ( lpDst && dwBufLen > 0 )
|
|
{
|
|
LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
|
|
|
|
len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
|
|
(LPSTR)dest, dwBufLen, NULL, NULL);
|
|
|
|
if ( i + 1 < lpSrc->dwCount )
|
|
lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
|
|
dwBufLen -= len * sizeof(char);
|
|
}
|
|
else
|
|
len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
|
|
|
|
ret += len * sizeof(char);
|
|
}
|
|
|
|
if ( lpDst )
|
|
lpDst->dwSize = ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static DWORD convert_candidatelist_AtoW(
|
|
LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
|
|
{
|
|
DWORD ret, i, len;
|
|
|
|
ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
|
|
if ( lpDst && dwBufLen > 0 )
|
|
{
|
|
*lpDst = *lpSrc;
|
|
lpDst->dwOffset[0] = ret;
|
|
}
|
|
|
|
for ( i = 0; i < lpSrc->dwCount; i++)
|
|
{
|
|
LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
|
|
|
|
if ( lpDst && dwBufLen > 0 )
|
|
{
|
|
LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
|
|
|
|
len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
|
|
(LPWSTR)dest, dwBufLen);
|
|
|
|
if ( i + 1 < lpSrc->dwCount )
|
|
lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
|
|
dwBufLen -= len * sizeof(WCHAR);
|
|
}
|
|
else
|
|
len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
|
|
|
|
ret += len * sizeof(WCHAR);
|
|
}
|
|
|
|
if ( lpDst )
|
|
lpDst->dwSize = ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct coinit_spy *get_thread_coinit_spy(void)
|
|
{
|
|
return (struct coinit_spy *)(UINT_PTR)NtUserGetThreadInfo()->client_imm;
|
|
}
|
|
|
|
static void imm_couninit_thread(BOOL cleanup)
|
|
{
|
|
struct coinit_spy *spy;
|
|
|
|
TRACE("implicit COM deinitialization\n");
|
|
|
|
if (!(spy = get_thread_coinit_spy()) || (spy->apt_flags & IMM_APT_BROKEN))
|
|
return;
|
|
|
|
if (cleanup && spy->cookie.QuadPart)
|
|
{
|
|
pCoRevokeInitializeSpy(spy->cookie);
|
|
spy->cookie.QuadPart = 0;
|
|
}
|
|
|
|
if (!(spy->apt_flags & IMM_APT_INIT))
|
|
return;
|
|
spy->apt_flags &= ~IMM_APT_INIT;
|
|
|
|
if (spy->apt_flags & IMM_APT_CREATED)
|
|
{
|
|
spy->apt_flags &= ~IMM_APT_CREATED;
|
|
if (spy->apt_flags & IMM_APT_CAN_FREE)
|
|
pCoUninitialize();
|
|
}
|
|
if (cleanup)
|
|
spy->apt_flags = 0;
|
|
}
|
|
|
|
static inline struct coinit_spy *impl_from_IInitializeSpy(IInitializeSpy *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct coinit_spy, IInitializeSpy_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj)
|
|
{
|
|
if (IsEqualIID(&IID_IInitializeSpy, riid) ||
|
|
IsEqualIID(&IID_IUnknown, riid))
|
|
{
|
|
*obj = iface;
|
|
IInitializeSpy_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI InitializeSpy_AddRef(IInitializeSpy *iface)
|
|
{
|
|
struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
|
|
return InterlockedIncrement(&spy->ref);
|
|
}
|
|
|
|
static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
|
|
{
|
|
struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
|
|
LONG ref = InterlockedDecrement(&spy->ref);
|
|
if (!ref)
|
|
{
|
|
free( spy );
|
|
NtUserGetThreadInfo()->client_imm = 0;
|
|
}
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
|
|
DWORD coinit, DWORD refs)
|
|
{
|
|
struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
|
|
|
|
if ((spy->apt_flags & IMM_APT_CREATED) &&
|
|
!(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
|
|
{
|
|
imm_couninit_thread(TRUE);
|
|
spy->apt_flags |= IMM_APT_BROKEN;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
|
|
HRESULT hr, DWORD coinit, DWORD refs)
|
|
{
|
|
struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
|
|
|
|
if ((spy->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
|
|
hr = S_OK;
|
|
if (SUCCEEDED(hr))
|
|
spy->apt_flags |= IMM_APT_CAN_FREE;
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD refs)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
|
|
{
|
|
struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
|
|
|
|
TRACE("%lu %p\n", refs, ImmGetDefaultIMEWnd(0));
|
|
|
|
if (refs == 1 && !ImmGetDefaultIMEWnd(0))
|
|
imm_couninit_thread(FALSE);
|
|
else if (!refs)
|
|
spy->apt_flags &= ~IMM_APT_CAN_FREE;
|
|
return S_OK;
|
|
}
|
|
|
|
static const IInitializeSpyVtbl InitializeSpyVtbl =
|
|
{
|
|
InitializeSpy_QueryInterface,
|
|
InitializeSpy_AddRef,
|
|
InitializeSpy_Release,
|
|
InitializeSpy_PreInitialize,
|
|
InitializeSpy_PostInitialize,
|
|
InitializeSpy_PreUninitialize,
|
|
InitializeSpy_PostUninitialize,
|
|
};
|
|
|
|
static BOOL WINAPI init_ole32_funcs( INIT_ONCE *once, void *param, void **context )
|
|
{
|
|
HMODULE module_ole32 = GetModuleHandleA("ole32");
|
|
pCoRevokeInitializeSpy = (void*)GetProcAddress(module_ole32, "CoRevokeInitializeSpy");
|
|
pCoUninitialize = (void*)GetProcAddress(module_ole32, "CoUninitialize");
|
|
return TRUE;
|
|
}
|
|
|
|
static void imm_coinit_thread(void)
|
|
{
|
|
struct coinit_spy *spy;
|
|
HRESULT hr;
|
|
static INIT_ONCE init_ole32_once = INIT_ONCE_STATIC_INIT;
|
|
|
|
TRACE("implicit COM initialization\n");
|
|
|
|
if (!(spy = get_thread_coinit_spy()))
|
|
{
|
|
if (!(spy = malloc( sizeof(*spy) ))) return;
|
|
spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
|
|
spy->ref = 1;
|
|
spy->cookie.QuadPart = 0;
|
|
spy->apt_flags = 0;
|
|
NtUserGetThreadInfo()->client_imm = (UINT_PTR)spy;
|
|
|
|
}
|
|
|
|
if (spy->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
|
|
return;
|
|
spy->apt_flags |= IMM_APT_INIT;
|
|
|
|
if(!spy->cookie.QuadPart)
|
|
{
|
|
hr = CoRegisterInitializeSpy(&spy->IInitializeSpy_iface, &spy->cookie);
|
|
if (FAILED(hr))
|
|
return;
|
|
}
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
if (SUCCEEDED(hr))
|
|
spy->apt_flags |= IMM_APT_CREATED;
|
|
|
|
InitOnceExecuteOnce(&init_ole32_once, init_ole32_funcs, NULL, NULL);
|
|
}
|
|
|
|
static struct imc *query_imc_data( HIMC handle )
|
|
{
|
|
struct imc *ret;
|
|
|
|
if (!handle) return NULL;
|
|
ret = (void *)NtUserQueryInputContext(handle, NtUserInputContextClientPtr);
|
|
return ret && ret->handle == handle ? ret : NULL;
|
|
}
|
|
|
|
/* lookup an IME from a HKL, must hold ime_cs */
|
|
static struct ime *find_ime_from_hkl( HKL hkl )
|
|
{
|
|
struct ime *ime = NULL;
|
|
LIST_FOR_EACH_ENTRY( ime, &ime_list, struct ime, entry )
|
|
if (ime->hkl == hkl) return ime;
|
|
return NULL;
|
|
}
|
|
|
|
BOOL WINAPI ImmFreeLayout( HKL hkl )
|
|
{
|
|
struct imc_entry *imc_entry, *imc_next;
|
|
struct ime *ime;
|
|
|
|
TRACE( "hkl %p\n", hkl );
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
if ((ime = find_ime_from_hkl( hkl )))
|
|
{
|
|
list_remove( &ime->entry );
|
|
if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" );
|
|
LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry )
|
|
{
|
|
ImmDestroyIMCC( imc_entry->context.hPrivate );
|
|
free( imc_entry );
|
|
}
|
|
}
|
|
LeaveCriticalSection( &ime_cs );
|
|
if (!ime) return TRUE;
|
|
|
|
FreeLibrary( ime->module );
|
|
free( ime );
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI ImmLoadIME( HKL hkl )
|
|
{
|
|
WCHAR buffer[MAX_PATH] = {0};
|
|
BOOL use_default_ime;
|
|
struct ime *ime;
|
|
|
|
TRACE( "hkl %p\n", hkl );
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
if ((ime = find_ime_from_hkl( hkl )) || !(ime = calloc( 1, sizeof(*ime) )))
|
|
{
|
|
LeaveCriticalSection( &ime_cs );
|
|
return !!ime;
|
|
}
|
|
|
|
if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE;
|
|
else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE;
|
|
else use_default_ime = FALSE;
|
|
|
|
if (use_default_ime)
|
|
{
|
|
if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) );
|
|
ime->module = LoadLibraryW( L"imm32" );
|
|
ime->pImeInquire = (void *)ImeInquire;
|
|
ime->pImeDestroy = ImeDestroy;
|
|
ime->pImeSelect = ImeSelect;
|
|
ime->pImeConfigure = ImeConfigure;
|
|
ime->pImeEscape = ImeEscape;
|
|
ime->pImeSetActiveContext = ImeSetActiveContext;
|
|
ime->pImeToAsciiEx = (void *)ImeToAsciiEx;
|
|
ime->pNotifyIME = NotifyIME;
|
|
ime->pImeRegisterWord = (void *)ImeRegisterWord;
|
|
ime->pImeUnregisterWord = (void *)ImeUnregisterWord;
|
|
ime->pImeEnumRegisterWord = (void *)ImeEnumRegisterWord;
|
|
ime->pImeSetCompositionString = ImeSetCompositionString;
|
|
ime->pImeConversionList = (void *)ImeConversionList;
|
|
ime->pImeProcessKey = (void *)ImeProcessKey;
|
|
ime->pImeGetRegisterWordStyle = (void *)ImeGetRegisterWordStyle;
|
|
ime->pImeGetImeMenuItems = (void *)ImeGetImeMenuItems;
|
|
}
|
|
else
|
|
{
|
|
#define LOAD_FUNCPTR( f ) \
|
|
if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f ))) \
|
|
{ \
|
|
WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \
|
|
goto failed; \
|
|
}
|
|
|
|
LOAD_FUNCPTR( ImeInquire );
|
|
LOAD_FUNCPTR( ImeDestroy );
|
|
LOAD_FUNCPTR( ImeSelect );
|
|
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 );
|
|
#undef LOAD_FUNCPTR
|
|
}
|
|
|
|
ime->hkl = hkl;
|
|
if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed;
|
|
|
|
if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) );
|
|
else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) );
|
|
list_init( &ime->input_contexts );
|
|
|
|
list_add_tail( &ime_list, &ime->entry );
|
|
LeaveCriticalSection( &ime_cs );
|
|
|
|
TRACE( "Created IME %p for HKL %p\n", ime, hkl );
|
|
return TRUE;
|
|
|
|
failed:
|
|
LeaveCriticalSection( &ime_cs );
|
|
|
|
if (ime->module) FreeLibrary( ime->module );
|
|
free( ime );
|
|
return FALSE;
|
|
}
|
|
|
|
static struct ime *ime_acquire( HKL hkl )
|
|
{
|
|
struct ime *ime;
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
|
|
if (!ImmLoadIME( hkl )) ime = NULL;
|
|
else ime = find_ime_from_hkl( hkl );
|
|
|
|
if (ime)
|
|
{
|
|
ULONG ref = ++ime->refcount;
|
|
TRACE( "ime %p increasing refcount to %lu.\n", ime, ref );
|
|
}
|
|
|
|
LeaveCriticalSection( &ime_cs );
|
|
|
|
return ime;
|
|
}
|
|
|
|
static void ime_release( struct ime *ime )
|
|
{
|
|
ULONG ref;
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
|
|
ref = --ime->refcount;
|
|
TRACE( "ime %p decreasing refcount to %lu.\n", ime, ref );
|
|
|
|
if (!ref && (ime->info.fdwProperty & IME_PROP_END_UNLOAD))
|
|
ImmFreeLayout( ime->hkl );
|
|
|
|
LeaveCriticalSection( &ime_cs );
|
|
}
|
|
|
|
static void ime_save_input_context( struct ime *ime, HIMC himc, INPUTCONTEXT *ctx )
|
|
{
|
|
static INPUTCONTEXT default_input_context =
|
|
{
|
|
.cfCandForm = {{.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}}
|
|
};
|
|
const INPUTCONTEXT old = *ctx;
|
|
struct imc_entry *entry;
|
|
|
|
*ctx = default_input_context;
|
|
ctx->hWnd = old.hWnd;
|
|
ctx->hMsgBuf = old.hMsgBuf;
|
|
ctx->hCompStr = old.hCompStr;
|
|
ctx->hCandInfo = old.hCandInfo;
|
|
ctx->hGuideLine = old.hGuideLine;
|
|
if (!(ctx->hPrivate = ImmCreateIMCC( ime->info.dwPrivateDataSize )))
|
|
WARN( "Failed to allocate IME private data\n" );
|
|
|
|
if (!(entry = malloc( sizeof(*entry) ))) return;
|
|
entry->himc = himc;
|
|
entry->context = *ctx;
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
|
|
/* reference the IME the first time the input context cache is used
|
|
* in the same way Windows does it, so it doesn't get destroyed and
|
|
* INPUTCONTEXT cache lost when keyboard layout is changed
|
|
*/
|
|
if (list_empty( &ime->input_contexts )) ime->refcount++;
|
|
|
|
list_add_tail( &ime->input_contexts, &entry->entry );
|
|
LeaveCriticalSection( &ime_cs );
|
|
}
|
|
|
|
static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc )
|
|
{
|
|
struct imc_entry *entry;
|
|
|
|
EnterCriticalSection( &ime_cs );
|
|
LIST_FOR_EACH_ENTRY( entry, &ime->input_contexts, struct imc_entry, entry )
|
|
if (entry->himc == himc) break;
|
|
LeaveCriticalSection( &ime_cs );
|
|
|
|
if (&entry->entry == &ime->input_contexts) return NULL;
|
|
return &entry->context;
|
|
}
|
|
|
|
static void imc_release_ime( struct imc *imc, struct ime *ime )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd );
|
|
imc->ui_hwnd = NULL;
|
|
ime->pImeSelect( imc->handle, FALSE );
|
|
|
|
if ((ctx = ime_find_input_context( ime, imc->handle ))) *ctx = imc->IMC;
|
|
ime_release( ime );
|
|
}
|
|
|
|
static struct ime *imc_select_ime( struct imc *imc )
|
|
{
|
|
HKL hkl = GetKeyboardLayout( 0 );
|
|
struct ime *ime;
|
|
|
|
if ((ime = imc->ime))
|
|
{
|
|
if (ime->hkl == hkl) return ime;
|
|
imc->ime = NULL;
|
|
imc_release_ime( imc, ime );
|
|
}
|
|
|
|
if (!(imc->ime = ime_acquire( hkl )))
|
|
WARN( "Failed to acquire IME for HKL %p\n", hkl );
|
|
else
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
if ((ctx = ime_find_input_context( imc->ime, imc->handle ))) imc->IMC = *ctx;
|
|
else ime_save_input_context( imc->ime, imc->handle, &imc->IMC );
|
|
|
|
imc->ime->pImeSelect( imc->handle, TRUE );
|
|
}
|
|
|
|
return imc->ime;
|
|
}
|
|
|
|
static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam )
|
|
{
|
|
if (ImmLockIMC( himc )) ImmUnlockIMC( himc );
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL WINAPI ImmActivateLayout( HKL hkl )
|
|
{
|
|
TRACE( "hkl %p\n", hkl );
|
|
|
|
if (hkl == GetKeyboardLayout( 0 )) return TRUE;
|
|
if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE;
|
|
|
|
ImmEnumInputContext( 0, enum_activate_layout, 0 );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL free_input_context_data( HIMC hIMC )
|
|
{
|
|
struct imc *data = query_imc_data( hIMC );
|
|
struct ime *ime;
|
|
|
|
if (!data) return FALSE;
|
|
|
|
TRACE( "Destroying %p\n", hIMC );
|
|
|
|
if ((ime = imc_select_ime( data ))) imc_release_ime( data, ime );
|
|
|
|
ImmDestroyIMCC( data->IMC.hCompStr );
|
|
ImmDestroyIMCC( data->IMC.hCandInfo );
|
|
ImmDestroyIMCC( data->IMC.hGuideLine );
|
|
ImmDestroyIMCC( data->IMC.hMsgBuf );
|
|
|
|
free( data );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void input_context_init( INPUTCONTEXT *ctx )
|
|
{
|
|
COMPOSITIONSTRING *str;
|
|
CANDIDATEINFO *info;
|
|
GUIDELINE *line;
|
|
UINT i;
|
|
|
|
if (!(ctx->hMsgBuf = ImmCreateIMCC( 0 )))
|
|
WARN( "Failed to allocate %p message buffer\n", ctx );
|
|
|
|
if (!(ctx->hCompStr = ImmCreateIMCC( sizeof(COMPOSITIONSTRING) )))
|
|
WARN( "Failed to allocate %p COMPOSITIONSTRING\n", ctx );
|
|
else if (!(str = ImmLockIMCC( ctx->hCompStr )))
|
|
WARN( "Failed to lock IMCC for COMPOSITIONSTRING\n" );
|
|
else
|
|
{
|
|
str->dwSize = sizeof(COMPOSITIONSTRING);
|
|
ImmUnlockIMCC( ctx->hCompStr );
|
|
}
|
|
|
|
if (!(ctx->hCandInfo = ImmCreateIMCC( sizeof(CANDIDATEINFO) )))
|
|
WARN( "Failed to allocate %p CANDIDATEINFO\n", ctx );
|
|
else if (!(info = ImmLockIMCC( ctx->hCandInfo )))
|
|
WARN( "Failed to lock IMCC for CANDIDATEINFO\n" );
|
|
else
|
|
{
|
|
info->dwSize = sizeof(CANDIDATEINFO);
|
|
ImmUnlockIMCC( ctx->hCandInfo );
|
|
}
|
|
|
|
if (!(ctx->hGuideLine = ImmCreateIMCC( sizeof(GUIDELINE) )))
|
|
WARN( "Failed to allocate %p GUIDELINE\n", ctx );
|
|
else if (!(line = ImmLockIMCC( ctx->hGuideLine )))
|
|
WARN( "Failed to lock IMCC for GUIDELINE\n" );
|
|
else
|
|
{
|
|
line->dwSize = sizeof(GUIDELINE);
|
|
ImmUnlockIMCC( ctx->hGuideLine );
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ctx->cfCandForm); i++)
|
|
ctx->cfCandForm[i].dwIndex = ~0u;
|
|
}
|
|
|
|
static void IMM_FreeThreadData(void)
|
|
{
|
|
struct coinit_spy *spy;
|
|
|
|
free_input_context_data( UlongToHandle( NtUserGetThreadInfo()->default_imc ) );
|
|
if ((spy = get_thread_coinit_spy())) IInitializeSpy_Release( &spy->IInitializeSpy_iface );
|
|
}
|
|
|
|
static void IMM_FreeAllImmHkl(void)
|
|
{
|
|
struct ime *ime, *ime_next;
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE( ime, ime_next, &ime_list, struct ime, entry )
|
|
{
|
|
struct imc_entry *imc_entry, *imc_next;
|
|
list_remove( &ime->entry );
|
|
|
|
ime->pImeDestroy( 1 );
|
|
FreeLibrary( ime->module );
|
|
LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry )
|
|
{
|
|
ImmDestroyIMCC( imc_entry->context.hPrivate );
|
|
free( imc_entry );
|
|
}
|
|
|
|
free( ime );
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
|
|
{
|
|
TRACE( "instance %p, reason %lx, reserved %p\n", instance, reason, reserved );
|
|
|
|
switch (reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE;
|
|
imm32_module = instance;
|
|
break;
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
case DLL_THREAD_DETACH:
|
|
IMM_FreeThreadData();
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
if (reserved) break;
|
|
IMM_FreeThreadData();
|
|
IMM_FreeAllImmHkl();
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetActiveContext (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
|
|
{
|
|
struct imc *data = get_imc_data( himc );
|
|
struct ime *ime;
|
|
|
|
TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
|
|
|
|
if (himc && !data && activate)
|
|
return FALSE;
|
|
|
|
imm_coinit_thread();
|
|
|
|
if (data)
|
|
{
|
|
if (activate) data->IMC.hWnd = hwnd;
|
|
if ((ime = imc_select_ime( data ))) ime->pImeSetActiveContext( himc, activate );
|
|
}
|
|
|
|
if (IsWindow(hwnd))
|
|
{
|
|
SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL);
|
|
/* TODO: send WM_IME_NOTIFY */
|
|
}
|
|
SetLastError(0);
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmConfigureIMEA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data );
|
|
|
|
if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE;
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (mode != IME_CONFIG_REGISTERWORD || !ime_is_unicode( ime ))
|
|
ret = ime->pImeConfigure( hkl, hwnd, mode, data );
|
|
else
|
|
{
|
|
REGISTERWORDA *wordA = data;
|
|
REGISTERWORDW wordW;
|
|
wordW.lpWord = strdupAtoW( wordA->lpWord );
|
|
wordW.lpReading = strdupAtoW( wordA->lpReading );
|
|
ret = ime->pImeConfigure( hkl, hwnd, mode, &wordW );
|
|
free( wordW.lpReading );
|
|
free( wordW.lpWord );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmConfigureIMEW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data );
|
|
|
|
if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE;
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (mode != IME_CONFIG_REGISTERWORD || ime_is_unicode( ime ))
|
|
ret = ime->pImeConfigure( hkl, hwnd, mode, data );
|
|
else
|
|
{
|
|
REGISTERWORDW *wordW = data;
|
|
REGISTERWORDA wordA;
|
|
wordA.lpWord = strdupWtoA( wordW->lpWord );
|
|
wordA.lpReading = strdupWtoA( wordW->lpReading );
|
|
ret = ime->pImeConfigure( hkl, hwnd, mode, &wordA );
|
|
free( wordA.lpReading );
|
|
free( wordA.lpWord );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
static struct imc *create_input_context( HIMC default_imc )
|
|
{
|
|
struct imc *new_context;
|
|
|
|
if (!(new_context = calloc( 1, sizeof(*new_context) ))) return NULL;
|
|
input_context_init( &new_context->IMC );
|
|
|
|
if (!default_imc)
|
|
new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context);
|
|
else if (NtUserUpdateInputContext(default_imc, NtUserInputContextClientPtr, (UINT_PTR)new_context))
|
|
new_context->handle = default_imc;
|
|
if (!new_context->handle)
|
|
{
|
|
free_input_context_data(new_context);
|
|
return 0;
|
|
}
|
|
|
|
TRACE("Created context %p\n", new_context);
|
|
return new_context;
|
|
}
|
|
|
|
static struct imc *get_imc_data( HIMC handle )
|
|
{
|
|
struct imc *ret;
|
|
|
|
if ((ret = query_imc_data(handle)) || !handle) return ret;
|
|
return create_input_context(handle);
|
|
}
|
|
|
|
static struct imc *default_input_context(void)
|
|
{
|
|
UINT *himc = &NtUserGetThreadInfo()->default_imc;
|
|
if (!*himc) *himc = (UINT_PTR)NtUserCreateInputContext( 0 );
|
|
return get_imc_data( (HIMC)(UINT_PTR)*himc );
|
|
}
|
|
|
|
static HWND get_ime_ui_window(void)
|
|
{
|
|
struct imc *imc = default_input_context();
|
|
struct ime *ime;
|
|
|
|
if (!(ime = imc_select_ime( imc ))) return 0;
|
|
|
|
if (!imc->ui_hwnd)
|
|
{
|
|
imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1,
|
|
ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 );
|
|
SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)NtUserGetWindowInputContext( GetFocus() ) );
|
|
}
|
|
return imc->ui_hwnd;
|
|
}
|
|
|
|
static void set_ime_ui_window_himc( HIMC himc )
|
|
{
|
|
HWND hwnd;
|
|
if (!(hwnd = get_ime_ui_window())) return;
|
|
SetWindowLongPtrW( hwnd, IMMGWL_IMC, (LONG_PTR)himc );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmCreateContext (IMM32.@)
|
|
*/
|
|
HIMC WINAPI ImmCreateContext(void)
|
|
{
|
|
struct imc *new_context;
|
|
|
|
if (!(new_context = create_input_context(0))) return 0;
|
|
return new_context->handle;
|
|
}
|
|
|
|
static BOOL IMM_DestroyContext(HIMC hIMC)
|
|
{
|
|
if (!free_input_context_data(hIMC)) return FALSE;
|
|
NtUserDestroyInputContext(hIMC);
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmDestroyContext (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
|
|
{
|
|
if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE;
|
|
if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
return IMM_DestroyContext(hIMC);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmAssociateContext (IMM32.@)
|
|
*/
|
|
HIMC WINAPI ImmAssociateContext( HWND hwnd, HIMC new_himc )
|
|
{
|
|
HIMC old_himc;
|
|
UINT ret;
|
|
|
|
TRACE( "hwnd %p, new_himc %p\n", hwnd, new_himc );
|
|
|
|
old_himc = NtUserGetWindowInputContext( hwnd );
|
|
ret = NtUserAssociateInputContext( hwnd, new_himc, 0 );
|
|
if (ret == AICR_FOCUS_CHANGED)
|
|
{
|
|
ImmSetActiveContext( hwnd, old_himc, FALSE );
|
|
ImmSetActiveContext( hwnd, new_himc, TRUE );
|
|
if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc );
|
|
}
|
|
|
|
return ret == AICR_FAILED ? 0 : old_himc;
|
|
}
|
|
|
|
static BOOL CALLBACK enum_associate_context( HWND hwnd, LPARAM lparam )
|
|
{
|
|
ImmAssociateContext( hwnd, (HIMC)lparam );
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmAssociateContextEx (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmAssociateContextEx( HWND hwnd, HIMC new_himc, DWORD flags )
|
|
{
|
|
HIMC old_himc;
|
|
UINT ret;
|
|
|
|
TRACE( "hwnd %p, new_himc %p, flags %#lx\n", hwnd, new_himc, flags );
|
|
|
|
if (!hwnd) return FALSE;
|
|
|
|
if (flags == IACE_CHILDREN)
|
|
{
|
|
EnumChildWindows( hwnd, enum_associate_context, (LPARAM)new_himc );
|
|
return TRUE;
|
|
}
|
|
|
|
old_himc = NtUserGetWindowInputContext( hwnd );
|
|
ret = NtUserAssociateInputContext( hwnd, new_himc, flags );
|
|
if (ret == AICR_FOCUS_CHANGED)
|
|
{
|
|
ImmSetActiveContext( hwnd, old_himc, FALSE );
|
|
ImmSetActiveContext( hwnd, new_himc, TRUE );
|
|
if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc );
|
|
}
|
|
|
|
return ret != AICR_FAILED;
|
|
}
|
|
|
|
struct enum_register_word_params_WtoA
|
|
{
|
|
REGISTERWORDENUMPROCA proc;
|
|
void *user;
|
|
};
|
|
|
|
static int CALLBACK enum_register_word_WtoA( const WCHAR *readingW, DWORD style,
|
|
const WCHAR *stringW, void *user )
|
|
{
|
|
char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
|
|
struct enum_register_word_params_WtoA *params = user;
|
|
int ret = params->proc( readingA, style, stringA, params->user );
|
|
free( readingA );
|
|
free( stringA );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmEnumRegisterWordA (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const char *readingA,
|
|
DWORD style, const char *stringA, void *user )
|
|
{
|
|
struct ime *ime;
|
|
UINT ret;
|
|
|
|
TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA,
|
|
debugstr_a(readingA), style, debugstr_a(stringA), user );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (!ime_is_unicode( ime ))
|
|
ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user );
|
|
else
|
|
{
|
|
struct enum_register_word_params_WtoA params = {.proc = procA, .user = user};
|
|
WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
|
|
ret = ime->pImeEnumRegisterWord( enum_register_word_WtoA, readingW, style, stringW, ¶ms );
|
|
free( readingW );
|
|
free( stringW );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
struct enum_register_word_params_AtoW
|
|
{
|
|
REGISTERWORDENUMPROCW proc;
|
|
void *user;
|
|
};
|
|
|
|
static int CALLBACK enum_register_word_AtoW( const char *readingA, DWORD style,
|
|
const char *stringA, void *user )
|
|
{
|
|
WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
|
|
struct enum_register_word_params_AtoW *params = user;
|
|
int ret = params->proc( readingW, style, stringW, params->user );
|
|
free( readingW );
|
|
free( stringW );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmEnumRegisterWordW (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WCHAR *readingW,
|
|
DWORD style, const WCHAR *stringW, void *user )
|
|
{
|
|
struct ime *ime;
|
|
UINT ret;
|
|
|
|
TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW,
|
|
debugstr_w(readingW), style, debugstr_w(stringW), user );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (ime_is_unicode( ime ))
|
|
ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user );
|
|
else
|
|
{
|
|
struct enum_register_word_params_AtoW params = {.proc = procW, .user = user};
|
|
char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
|
|
ret = ime->pImeEnumRegisterWord( enum_register_word_AtoW, readingA, style, stringA, ¶ms );
|
|
free( readingA );
|
|
free( stringA );
|
|
}
|
|
|
|
ime_release( ime );
|
|
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 code, void *data )
|
|
{
|
|
struct ime *ime;
|
|
LRESULT ret;
|
|
|
|
TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (!EscapeRequiresWA( code ) || !ime_is_unicode( ime ) || !data)
|
|
ret = ime->pImeEscape( himc, code, data );
|
|
else
|
|
{
|
|
WCHAR buffer[81]; /* largest required buffer should be 80 */
|
|
if (code == IME_ESC_SET_EUDC_DICTIONARY)
|
|
{
|
|
MultiByteToWideChar( CP_ACP, 0, data, -1, buffer, 81 );
|
|
ret = ime->pImeEscape( himc, code, buffer );
|
|
}
|
|
else
|
|
{
|
|
ret = ime->pImeEscape( himc, code, buffer );
|
|
WideCharToMultiByte( CP_ACP, 0, buffer, -1, data, 80, NULL, NULL );
|
|
}
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmEscapeW (IMM32.@)
|
|
*/
|
|
LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data )
|
|
{
|
|
struct ime *ime;
|
|
LRESULT ret;
|
|
|
|
TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (!EscapeRequiresWA( code ) || ime_is_unicode( ime ) || !data)
|
|
ret = ime->pImeEscape( himc, code, data );
|
|
else
|
|
{
|
|
char buffer[81]; /* largest required buffer should be 80 */
|
|
if (code == IME_ESC_SET_EUDC_DICTIONARY)
|
|
{
|
|
WideCharToMultiByte( CP_ACP, 0, data, -1, buffer, 81, NULL, NULL );
|
|
ret = ime->pImeEscape( himc, code, buffer );
|
|
}
|
|
else
|
|
{
|
|
ret = ime->pImeEscape( himc, code, buffer );
|
|
MultiByteToWideChar( CP_ACP, 0, buffer, -1, data, 80 );
|
|
}
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCandidateListA (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetCandidateListA(
|
|
HIMC hIMC, DWORD dwIndex,
|
|
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
LPCANDIDATEINFO candinfo;
|
|
LPCANDIDATELIST candlist;
|
|
struct ime *ime;
|
|
DWORD ret = 0;
|
|
|
|
TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
|
|
|
|
if (!data || !data->IMC.hCandInfo)
|
|
return 0;
|
|
|
|
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
|
|
if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
|
|
goto done;
|
|
|
|
candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
|
|
if ( !candlist->dwSize || !candlist->dwCount )
|
|
goto done;
|
|
|
|
if (!(ime = imc_select_ime( data )))
|
|
ret = 0;
|
|
else if (!ime_is_unicode( ime ))
|
|
{
|
|
ret = candlist->dwSize;
|
|
if ( lpCandList && dwBufLen >= ret )
|
|
memcpy(lpCandList, candlist, ret);
|
|
}
|
|
else
|
|
ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
|
|
|
|
done:
|
|
ImmUnlockIMCC(data->IMC.hCandInfo);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCandidateListCountA (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetCandidateListCountA(
|
|
HIMC hIMC, LPDWORD lpdwListCount)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
LPCANDIDATEINFO candinfo;
|
|
DWORD ret, count;
|
|
struct ime *ime;
|
|
|
|
TRACE("%p, %p\n", hIMC, lpdwListCount);
|
|
|
|
if (!data || !lpdwListCount || !data->IMC.hCandInfo)
|
|
return 0;
|
|
|
|
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
|
|
|
|
*lpdwListCount = count = candinfo->dwCount;
|
|
|
|
if (!(ime = imc_select_ime( data )))
|
|
ret = 0;
|
|
else if (!ime_is_unicode( ime ))
|
|
ret = candinfo->dwSize;
|
|
else
|
|
{
|
|
ret = sizeof(CANDIDATEINFO);
|
|
while ( count-- )
|
|
ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
|
|
}
|
|
|
|
ImmUnlockIMCC(data->IMC.hCandInfo);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCandidateListCountW (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetCandidateListCountW(
|
|
HIMC hIMC, LPDWORD lpdwListCount)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
LPCANDIDATEINFO candinfo;
|
|
DWORD ret, count;
|
|
struct ime *ime;
|
|
|
|
TRACE("%p, %p\n", hIMC, lpdwListCount);
|
|
|
|
if (!data || !lpdwListCount || !data->IMC.hCandInfo)
|
|
return 0;
|
|
|
|
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
|
|
|
|
*lpdwListCount = count = candinfo->dwCount;
|
|
|
|
if (!(ime = imc_select_ime( data )))
|
|
ret = 0;
|
|
else if (ime_is_unicode( ime ))
|
|
ret = candinfo->dwSize;
|
|
else
|
|
{
|
|
ret = sizeof(CANDIDATEINFO);
|
|
while ( count-- )
|
|
ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
|
|
}
|
|
|
|
ImmUnlockIMCC(data->IMC.hCandInfo);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCandidateListW (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetCandidateListW(
|
|
HIMC hIMC, DWORD dwIndex,
|
|
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
LPCANDIDATEINFO candinfo;
|
|
LPCANDIDATELIST candlist;
|
|
struct ime *ime;
|
|
DWORD ret = 0;
|
|
|
|
TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
|
|
|
|
if (!data || !data->IMC.hCandInfo)
|
|
return 0;
|
|
|
|
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
|
|
if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
|
|
goto done;
|
|
|
|
candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
|
|
if ( !candlist->dwSize || !candlist->dwCount )
|
|
goto done;
|
|
|
|
if (!(ime = imc_select_ime( data )))
|
|
ret = 0;
|
|
else if (ime_is_unicode( ime ))
|
|
{
|
|
ret = candlist->dwSize;
|
|
if ( lpCandList && dwBufLen >= ret )
|
|
memcpy(lpCandList, candlist, ret);
|
|
}
|
|
else
|
|
ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
|
|
|
|
done:
|
|
ImmUnlockIMCC(data->IMC.hCandInfo);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCandidateWindow (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetCandidateWindow( HIMC himc, DWORD index, CANDIDATEFORM *candidate )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL ret = TRUE;
|
|
|
|
TRACE( "himc %p, index %lu, candidate %p\n", himc, index, candidate );
|
|
|
|
if (!candidate) return FALSE;
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if (ctx->cfCandForm[index].dwIndex == -1) ret = FALSE;
|
|
else *candidate = ctx->cfCandForm[index];
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCompositionFontA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetCompositionFontA( HIMC himc, LOGFONTA *fontA )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
LOGFONTW fontW;
|
|
BOOL ret = TRUE;
|
|
|
|
TRACE( "himc %p, fontA %p\n", himc, fontA );
|
|
|
|
if (!fontA) return FALSE;
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE;
|
|
else if (!input_context_is_unicode( ctx )) *fontA = ctx->lfFont.A;
|
|
else if ((ret = ImmGetCompositionFontW( himc, &fontW )))
|
|
{
|
|
memcpy( fontA, &fontW, offsetof(LOGFONTA, lfFaceName) );
|
|
WideCharToMultiByte( CP_ACP, 0, fontW.lfFaceName, -1, fontA->lfFaceName, LF_FACESIZE, NULL, NULL );
|
|
}
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetCompositionFontW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetCompositionFontW( HIMC himc, LOGFONTW *fontW )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
LOGFONTA fontA;
|
|
BOOL ret = TRUE;
|
|
|
|
TRACE( "himc %p, fontW %p\n", himc, fontW );
|
|
|
|
if (!fontW) return FALSE;
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE;
|
|
else if (input_context_is_unicode( ctx )) *fontW = ctx->lfFont.W;
|
|
else if ((ret = ImmGetCompositionFontA( himc, &fontA )))
|
|
{
|
|
memcpy( fontW, &fontA, offsetof(LOGFONTW, lfFaceName) );
|
|
MultiByteToWideChar( CP_ACP, 0, fontA.lfFaceName, -1, fontW->lfFaceName, LF_FACESIZE );
|
|
}
|
|
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( BOOL src_unicode, const void *src, INT src_len,
|
|
void *dst, INT dst_len, BOOL dst_unicode )
|
|
{
|
|
int char_size = dst_unicode ? sizeof(WCHAR) : sizeof(char);
|
|
INT ret;
|
|
|
|
if (src_unicode ^ dst_unicode)
|
|
{
|
|
if (dst_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( BOOL src_unicode, 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 (src_unicode && !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 (!src_unicode && 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( BOOL src_unicode, LPBYTE source, INT slen, LPBYTE ssource,
|
|
LPBYTE target, INT tlen, BOOL unicode )
|
|
{
|
|
INT rc;
|
|
|
|
if (src_unicode && !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 (!src_unicode && 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( BOOL src_unicode, DWORD offset, LPBYTE ssource, BOOL unicode )
|
|
{
|
|
int rc;
|
|
|
|
if (src_unicode && !unicode)
|
|
{
|
|
rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
|
|
}
|
|
else if (!src_unicode && 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;
|
|
struct imc *data = get_imc_data( hIMC );
|
|
LPCOMPOSITIONSTRING compstr;
|
|
BOOL src_unicode;
|
|
struct ime *ime;
|
|
LPBYTE compdata;
|
|
|
|
TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen);
|
|
|
|
if (!data)
|
|
return FALSE;
|
|
|
|
if (!data->IMC.hCompStr)
|
|
return FALSE;
|
|
|
|
if (!(ime = imc_select_ime( data )))
|
|
return FALSE;
|
|
src_unicode = ime_is_unicode( ime );
|
|
|
|
compdata = ImmLockIMCC(data->IMC.hCompStr);
|
|
compstr = (LPCOMPOSITIONSTRING)compdata;
|
|
|
|
switch (dwIndex)
|
|
{
|
|
case GCS_RESULTSTR:
|
|
TRACE("GCS_RESULTSTR\n");
|
|
rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPSTR:
|
|
TRACE("GCS_COMPSTR\n");
|
|
rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPATTR:
|
|
TRACE("GCS_COMPATTR\n");
|
|
rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
|
|
compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPCLAUSE:
|
|
TRACE("GCS_COMPCLAUSE\n");
|
|
rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
|
|
compdata + compstr->dwCompStrOffset,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_RESULTCLAUSE:
|
|
TRACE("GCS_RESULTCLAUSE\n");
|
|
rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
|
|
compdata + compstr->dwResultStrOffset,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_RESULTREADSTR:
|
|
TRACE("GCS_RESULTREADSTR\n");
|
|
rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_RESULTREADCLAUSE:
|
|
TRACE("GCS_RESULTREADCLAUSE\n");
|
|
rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
|
|
compdata + compstr->dwResultStrOffset,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPREADSTR:
|
|
TRACE("GCS_COMPREADSTR\n");
|
|
rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPREADATTR:
|
|
TRACE("GCS_COMPREADATTR\n");
|
|
rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
|
|
compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_COMPREADCLAUSE:
|
|
TRACE("GCS_COMPREADCLAUSE\n");
|
|
rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
|
|
compdata + compstr->dwCompStrOffset,
|
|
lpBuf, dwBufLen, unicode);
|
|
break;
|
|
case GCS_CURSORPOS:
|
|
TRACE("GCS_CURSORPOS\n");
|
|
rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
|
|
break;
|
|
case GCS_DELTASTART:
|
|
TRACE("GCS_DELTASTART\n");
|
|
rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
|
|
break;
|
|
default:
|
|
FIXME("Unhandled index 0x%lx\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, COMPOSITIONFORM *composition )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL ret;
|
|
|
|
TRACE( "himc %p, composition %p\n", himc, composition );
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if ((ret = !!(ctx->fdwInit & INIT_COMPFORM))) *composition = ctx->cfCompForm;
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetContext (IMM32.@)
|
|
*
|
|
*/
|
|
HIMC WINAPI ImmGetContext( HWND hwnd )
|
|
{
|
|
TRACE( "hwnd %p\n", hwnd );
|
|
return NtUserGetWindowInputContext( hwnd );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetConversionListA (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDIDATELIST *listA,
|
|
DWORD lengthA, UINT flags )
|
|
{
|
|
struct ime *ime;
|
|
DWORD ret;
|
|
|
|
TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc,
|
|
debugstr_a(srcA), listA, lengthA, flags );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (!ime_is_unicode( ime ))
|
|
ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags );
|
|
else
|
|
{
|
|
CANDIDATELIST *listW;
|
|
WCHAR *srcW = strdupAtoW( srcA );
|
|
DWORD lengthW = ime->pImeConversionList( himc, srcW, NULL, 0, flags );
|
|
|
|
if (!(listW = malloc( lengthW ))) ret = 0;
|
|
else
|
|
{
|
|
ime->pImeConversionList( himc, srcW, listW, lengthW, flags );
|
|
ret = convert_candidatelist_WtoA( listW, listA, lengthA );
|
|
free( listW );
|
|
}
|
|
free( srcW );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetConversionListW (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDIDATELIST *listW,
|
|
DWORD lengthW, UINT flags )
|
|
{
|
|
struct ime *ime;
|
|
DWORD ret;
|
|
|
|
TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc,
|
|
debugstr_w(srcW), listW, lengthW, flags );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (ime_is_unicode( ime ))
|
|
ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags );
|
|
else
|
|
{
|
|
CANDIDATELIST *listA;
|
|
char *srcA = strdupWtoA( srcW );
|
|
DWORD lengthA = ime->pImeConversionList( himc, srcA, NULL, 0, flags );
|
|
|
|
if (!(listA = malloc( lengthA ))) ret = 0;
|
|
else
|
|
{
|
|
ime->pImeConversionList( himc, srcA, listA, lengthA, flags );
|
|
ret = convert_candidatelist_AtoW( listA, listW, lengthW );
|
|
free( listA );
|
|
}
|
|
free( srcA );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetConversionStatus (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetConversionStatus( HIMC himc, DWORD *conversion, DWORD *sentence )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p, conversion %p, sentence %p\n", himc, conversion, sentence );
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if (conversion) *conversion = ctx->fdwConversion;
|
|
if (sentence) *sentence = ctx->fdwSentence;
|
|
ImmUnlockIMC( himc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetDefaultIMEWnd (IMM32.@)
|
|
*/
|
|
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
|
|
{
|
|
return NtUserGetDefaultImeWindow(hWnd);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetDescriptionA (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetDescriptionA( HKL hkl, LPSTR bufferA, UINT lengthA )
|
|
{
|
|
WCHAR *bufferW;
|
|
DWORD lengthW;
|
|
|
|
TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA );
|
|
|
|
if (!(lengthW = ImmGetDescriptionW( hkl, NULL, 0 ))) return 0;
|
|
if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0;
|
|
lengthW = ImmGetDescriptionW( hkl, bufferW, lengthW + 1 );
|
|
lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA,
|
|
bufferA ? lengthA : 0, NULL, NULL );
|
|
if (bufferA) bufferA[lengthA] = 0;
|
|
free( bufferW );
|
|
|
|
return lengthA;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetDescriptionW (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetDescriptionW( HKL hkl, WCHAR *buffer, UINT length )
|
|
{
|
|
WCHAR path[MAX_PATH];
|
|
HKEY hkey = 0;
|
|
DWORD size;
|
|
|
|
TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length );
|
|
|
|
swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl );
|
|
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0;
|
|
|
|
size = ARRAY_SIZE(path) * sizeof(WCHAR);
|
|
if (RegGetValueW( hkey, NULL, L"Layout Text", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0;
|
|
RegCloseKey( hkey );
|
|
|
|
size = wcslen( path );
|
|
if (!buffer) return size;
|
|
|
|
lstrcpynW( buffer, path, length );
|
|
return wcslen( buffer );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetGuideLineA (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetGuideLineA(
|
|
HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
|
|
{
|
|
FIXME("(%p, %ld, %s, %ld): stub\n",
|
|
hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
|
|
);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetGuideLineW (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
|
|
{
|
|
FIXME("(%p, %ld, %s, %ld): stub\n",
|
|
hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
|
|
);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetIMEFileNameA (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetIMEFileNameA( HKL hkl, char *bufferA, UINT lengthA )
|
|
{
|
|
WCHAR *bufferW;
|
|
DWORD lengthW;
|
|
|
|
TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA );
|
|
|
|
if (!(lengthW = ImmGetIMEFileNameW( hkl, NULL, 0 ))) return 0;
|
|
if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0;
|
|
lengthW = ImmGetIMEFileNameW( hkl, bufferW, lengthW + 1 );
|
|
lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA,
|
|
bufferA ? lengthA : 0, NULL, NULL );
|
|
if (bufferA) bufferA[lengthA] = 0;
|
|
free( bufferW );
|
|
|
|
return lengthA;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetIMEFileNameW (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length )
|
|
{
|
|
WCHAR path[MAX_PATH];
|
|
HKEY hkey = 0;
|
|
DWORD size;
|
|
|
|
TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length );
|
|
|
|
swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl );
|
|
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0;
|
|
|
|
size = ARRAY_SIZE(path) * sizeof(WCHAR);
|
|
if (RegGetValueW( hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0;
|
|
RegCloseKey( hkey );
|
|
|
|
size = wcslen( path );
|
|
if (!buffer) return size;
|
|
|
|
lstrcpynW( buffer, path, length );
|
|
return wcslen( buffer );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetOpenStatus (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetOpenStatus( HIMC himc )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL status;
|
|
|
|
TRACE( "himc %p\n", himc );
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
status = ctx->fOpen;
|
|
ImmUnlockIMC( himc );
|
|
|
|
return status;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetProperty (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index )
|
|
{
|
|
struct ime *ime;
|
|
DWORD ret;
|
|
|
|
TRACE( "hkl %p, index %lu.\n", hkl, index );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
switch (index)
|
|
{
|
|
case IGP_PROPERTY: ret = ime->info.fdwProperty; break;
|
|
case IGP_CONVERSION: ret = ime->info.fdwConversionCaps; break;
|
|
case IGP_SENTENCE: ret = ime->info.fdwSentenceCaps; break;
|
|
case IGP_SETCOMPSTR: ret = ime->info.fdwSCSCaps; break;
|
|
case IGP_SELECT: ret = ime->info.fdwSelectCaps; break;
|
|
case IGP_GETIMEVERSION: ret = IMEVER_0400; break;
|
|
case IGP_UI: ret = 0; break;
|
|
default: ret = 0; break;
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetRegisterWordStyleA (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA )
|
|
{
|
|
struct ime *ime;
|
|
UINT ret;
|
|
|
|
TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (!ime_is_unicode( ime ))
|
|
ret = ime->pImeGetRegisterWordStyle( count, styleA );
|
|
else
|
|
{
|
|
STYLEBUFW styleW;
|
|
ret = ime->pImeGetRegisterWordStyle( count, &styleW );
|
|
WideCharToMultiByte( CP_ACP, 0, styleW.szDescription, -1, styleA->szDescription, 32, NULL, NULL );
|
|
styleA->dwStyle = styleW.dwStyle;
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetRegisterWordStyleW (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW )
|
|
{
|
|
struct ime *ime;
|
|
UINT ret;
|
|
|
|
TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return 0;
|
|
|
|
if (ime_is_unicode( ime ))
|
|
ret = ime->pImeGetRegisterWordStyle( count, styleW );
|
|
else
|
|
{
|
|
STYLEBUFA styleA;
|
|
ret = ime->pImeGetRegisterWordStyle( count, &styleA );
|
|
MultiByteToWideChar( CP_ACP, 0, styleA.szDescription, -1, styleW->szDescription, 32 );
|
|
styleW->dwStyle = styleA.dwStyle;
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetStatusWindowPos (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGetStatusWindowPos( HIMC himc, POINT *pos )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL ret;
|
|
|
|
TRACE( "himc %p, pos %p\n", himc, pos );
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
if ((ret = !!(ctx->fdwInit & INIT_STATUSWNDPOS))) *pos = ctx->ptStatusWndPos;
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetVirtualKey (IMM32.@)
|
|
*/
|
|
UINT WINAPI ImmGetVirtualKey( HWND hwnd )
|
|
{
|
|
HIMC himc = ImmGetContext( hwnd );
|
|
struct imc *imc;
|
|
|
|
TRACE( "%p\n", hwnd );
|
|
|
|
if ((imc = get_imc_data( himc ))) return imc->vkey;
|
|
return VK_PROCESSKEY;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmInstallIMEA (IMM32.@)
|
|
*/
|
|
HKL WINAPI ImmInstallIMEA( const char *filenameA, const char *descriptionA )
|
|
{
|
|
WCHAR *filenameW = strdupAtoW( filenameA ), *descriptionW = strdupAtoW( descriptionA );
|
|
HKL hkl;
|
|
|
|
TRACE( "filenameA %s, descriptionA %s\n", debugstr_a(filenameA), debugstr_a(descriptionA) );
|
|
|
|
hkl = ImmInstallIMEW( filenameW, descriptionW );
|
|
free( descriptionW );
|
|
free( filenameW );
|
|
|
|
return hkl;
|
|
}
|
|
|
|
static LCID get_ime_file_lang( const WCHAR *filename )
|
|
{
|
|
DWORD *languages;
|
|
LCID lcid = 0;
|
|
void *info;
|
|
UINT len;
|
|
|
|
if (!(len = GetFileVersionInfoSizeW( filename, NULL ))) return 0;
|
|
if (!(info = malloc( len ))) goto done;
|
|
if (!GetFileVersionInfoW( filename, 0, len, info )) goto done;
|
|
if (!VerQueryValueW( info, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done;
|
|
lcid = languages[0];
|
|
|
|
done:
|
|
free( info );
|
|
return lcid;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmInstallIMEW (IMM32.@)
|
|
*/
|
|
HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description )
|
|
{
|
|
WCHAR path[ARRAY_SIZE(layouts_formatW)+8], buffer[MAX_PATH];
|
|
LCID lcid;
|
|
WORD count = 0x20;
|
|
const WCHAR *tmp;
|
|
DWORD length;
|
|
HKEY hkey;
|
|
HKL hkl;
|
|
|
|
TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) );
|
|
|
|
if (!filename || !description || !(lcid = get_ime_file_lang( filename )))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
|
|
while (count < 0xfff)
|
|
{
|
|
DWORD disposition = 0;
|
|
|
|
hkl = (HKL)(UINT_PTR)MAKELONG( lcid, 0xe000 | count );
|
|
swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl);
|
|
if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, path, 0, NULL, 0,
|
|
KEY_WRITE, NULL, &hkey, &disposition ))
|
|
{
|
|
if (disposition == REG_CREATED_NEW_KEY) break;
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
if (count == 0xfff)
|
|
{
|
|
WARN("Unable to find slot to install IME\n");
|
|
return 0;
|
|
}
|
|
|
|
if ((tmp = wcsrchr( filename, '\\' ))) tmp++;
|
|
else tmp = filename;
|
|
|
|
length = LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, tmp, -1, buffer, ARRAY_SIZE(buffer) );
|
|
|
|
if (RegSetValueExW( hkey, L"Ime File", 0, REG_SZ, (const BYTE *)buffer, length * sizeof(WCHAR) ) ||
|
|
RegSetValueExW( hkey, L"Layout Text", 0, REG_SZ, (const BYTE *)description,
|
|
(wcslen(description) + 1) * sizeof(WCHAR) ))
|
|
{
|
|
WARN( "Unable to write registry to install IME\n");
|
|
hkl = 0;
|
|
}
|
|
RegCloseKey( hkey );
|
|
|
|
if (!hkl) RegDeleteKeyW( HKEY_LOCAL_MACHINE, path );
|
|
return hkl;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmIsIME (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmIsIME( HKL hkl )
|
|
{
|
|
TRACE( "hkl %p\n", hkl );
|
|
if (!hkl) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmIsUIMessageA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmIsUIMessageA(
|
|
HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
|
|
if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
|
|
(msg == WM_IME_SETCONTEXT) ||
|
|
(msg == WM_IME_NOTIFY) ||
|
|
(msg == WM_IME_COMPOSITIONFULL) ||
|
|
(msg == WM_IME_SELECT) ||
|
|
(msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
|
|
{
|
|
if (hWndIME)
|
|
SendMessageA(hWndIME, msg, wParam, lParam);
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmIsUIMessageW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmIsUIMessageW(
|
|
HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
|
|
if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
|
|
(msg == WM_IME_SETCONTEXT) ||
|
|
(msg == WM_IME_NOTIFY) ||
|
|
(msg == WM_IME_COMPOSITIONFULL) ||
|
|
(msg == WM_IME_SELECT) ||
|
|
(msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
|
|
{
|
|
if (hWndIME)
|
|
SendMessageW(hWndIME, msg, wParam, lParam);
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmNotifyIME (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmNotifyIME(
|
|
HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
struct ime *ime;
|
|
|
|
TRACE("(%p, %ld, %ld, %ld)\n",
|
|
hIMC, dwAction, dwIndex, dwValue);
|
|
|
|
if (hIMC == NULL)
|
|
{
|
|
SetLastError(ERROR_SUCCESS);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!data)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ime = imc_select_ime( data ))) return FALSE;
|
|
return ime->pNotifyIME( hIMC, dwAction, dwIndex, dwValue );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmRegisterWordA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (!ime_is_unicode( ime ))
|
|
ret = ime->pImeRegisterWord( readingA, style, stringA );
|
|
else
|
|
{
|
|
WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
|
|
ret = ime->pImeRegisterWord( readingW, style, stringW );
|
|
free( readingW );
|
|
free( stringW );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmRegisterWordW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (ime_is_unicode( ime ))
|
|
ret = ime->pImeRegisterWord( readingW, style, stringW );
|
|
else
|
|
{
|
|
char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
|
|
ret = ime->pImeRegisterWord( readingA, style, stringA );
|
|
free( readingA );
|
|
free( stringA );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmReleaseContext (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
|
|
{
|
|
static BOOL shown = FALSE;
|
|
|
|
if (!shown) {
|
|
FIXME("(%p, %p): stub\n", hWnd, hIMC);
|
|
shown = TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmRequestMessageA(IMM32.@)
|
|
*/
|
|
LRESULT WINAPI ImmRequestMessageA( HIMC himc, WPARAM wparam, LPARAM lparam )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
LRESULT res;
|
|
|
|
TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
|
|
switch (wparam)
|
|
{
|
|
case IMR_CANDIDATEWINDOW:
|
|
case IMR_COMPOSITIONFONT:
|
|
case IMR_COMPOSITIONWINDOW:
|
|
case IMR_CONFIRMRECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
case IMR_QUERYCHARPOSITION:
|
|
case IMR_RECONVERTSTRING:
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
res = SendMessageA( ctx->hWnd, WM_IME_REQUEST, wparam, lparam );
|
|
ImmUnlockIMC( himc );
|
|
|
|
return res;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmRequestMessageW(IMM32.@)
|
|
*/
|
|
LRESULT WINAPI ImmRequestMessageW( HIMC himc, WPARAM wparam, LPARAM lparam )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
LRESULT res;
|
|
|
|
TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
|
|
switch (wparam)
|
|
{
|
|
case IMR_CANDIDATEWINDOW:
|
|
case IMR_COMPOSITIONFONT:
|
|
case IMR_COMPOSITIONWINDOW:
|
|
case IMR_CONFIRMRECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
case IMR_QUERYCHARPOSITION:
|
|
case IMR_RECONVERTSTRING:
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
res = SendMessageW( ctx->hWnd, WM_IME_REQUEST, wparam, lparam );
|
|
ImmUnlockIMC( himc );
|
|
|
|
return res;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetCandidateWindow (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetCandidateWindow( HIMC himc, CANDIDATEFORM *candidate )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "hwnd %p, candidate %s\n", himc, debugstr_candidate( candidate ) );
|
|
|
|
if (!candidate) return FALSE;
|
|
if (candidate->dwIndex >= ARRAY_SIZE(ctx->cfCandForm)) return FALSE;
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
ctx->cfCandForm[candidate->dwIndex] = *candidate;
|
|
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCANDIDATEPOS, 1 << candidate->dwIndex );
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetCompositionFontA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetCompositionFontA( HIMC himc, LOGFONTA *fontA )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL ret = TRUE;
|
|
|
|
TRACE( "hwnd %p, fontA %p\n", himc, fontA );
|
|
|
|
if (!fontA) return FALSE;
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
if (input_context_is_unicode( ctx ))
|
|
{
|
|
LOGFONTW fontW;
|
|
memcpy( &fontW, fontA, offsetof(LOGFONTW, lfFaceName) );
|
|
MultiByteToWideChar( CP_ACP, 0, fontA->lfFaceName, -1, fontW.lfFaceName, LF_FACESIZE );
|
|
ret = ImmSetCompositionFontW( himc, &fontW );
|
|
}
|
|
else
|
|
{
|
|
ctx->lfFont.A = *fontA;
|
|
ctx->fdwInit |= INIT_LOGFONT;
|
|
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 );
|
|
}
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetCompositionFontW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetCompositionFontW( HIMC himc, LOGFONTW *fontW )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
BOOL ret = TRUE;
|
|
|
|
TRACE( "hwnd %p, fontW %p\n", himc, fontW );
|
|
|
|
if (!fontW) return FALSE;
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
if (!input_context_is_unicode( ctx ))
|
|
{
|
|
LOGFONTA fontA;
|
|
memcpy( &fontA, fontW, offsetof(LOGFONTA, lfFaceName) );
|
|
WideCharToMultiByte( CP_ACP, 0, fontW->lfFaceName, -1, fontA.lfFaceName, LF_FACESIZE, NULL, NULL );
|
|
ret = ImmSetCompositionFontA( himc, &fontA );
|
|
}
|
|
else
|
|
{
|
|
ctx->lfFont.W = *fontW;
|
|
ctx->fdwInit |= INIT_LOGFONT;
|
|
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 );
|
|
}
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* 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;
|
|
struct imc *data = get_imc_data( hIMC );
|
|
struct ime *ime;
|
|
|
|
TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
|
|
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
|
|
|
|
if (!data)
|
|
return FALSE;
|
|
|
|
if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
|
|
if (!(dwIndex == SCS_SETSTR ||
|
|
dwIndex == SCS_CHANGEATTR ||
|
|
dwIndex == SCS_CHANGECLAUSE ||
|
|
dwIndex == SCS_SETRECONVERTSTRING ||
|
|
dwIndex == SCS_QUERYRECONVERTSTRING))
|
|
return FALSE;
|
|
|
|
if (!(ime = imc_select_ime( data ))) return FALSE;
|
|
if (!ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen );
|
|
|
|
comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
|
|
if (comp_len)
|
|
{
|
|
CompBuffer = malloc( 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 = malloc( read_len * sizeof(WCHAR) );
|
|
MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
|
|
}
|
|
|
|
rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
|
|
ReadBuffer, read_len);
|
|
|
|
free( CompBuffer );
|
|
free( 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;
|
|
struct imc *data = get_imc_data( hIMC );
|
|
struct ime *ime;
|
|
|
|
TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
|
|
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
|
|
|
|
if (!data)
|
|
return FALSE;
|
|
|
|
if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
|
|
if (!(dwIndex == SCS_SETSTR ||
|
|
dwIndex == SCS_CHANGEATTR ||
|
|
dwIndex == SCS_CHANGECLAUSE ||
|
|
dwIndex == SCS_SETRECONVERTSTRING ||
|
|
dwIndex == SCS_QUERYRECONVERTSTRING))
|
|
return FALSE;
|
|
|
|
if (!(ime = imc_select_ime( data ))) return FALSE;
|
|
if (ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen );
|
|
|
|
comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
|
|
NULL);
|
|
if (comp_len)
|
|
{
|
|
CompBuffer = malloc( 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 = malloc( read_len );
|
|
WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
|
|
NULL, NULL);
|
|
}
|
|
|
|
rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
|
|
ReadBuffer, read_len);
|
|
|
|
free( CompBuffer );
|
|
free( ReadBuffer );
|
|
|
|
return rc;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetCompositionWindow (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p, composition %s\n", himc, debugstr_composition( composition ) );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
ctx->cfCompForm = *composition;
|
|
ctx->fdwInit |= INIT_COMPFORM;
|
|
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0 );
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetConversionStatus (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetConversionStatus( HIMC himc, DWORD conversion, DWORD sentence )
|
|
{
|
|
DWORD old_conversion, old_sentence;
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p, conversion %#lx, sentence %#lx\n", himc, conversion, sentence );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
if (conversion != ctx->fdwConversion)
|
|
{
|
|
old_conversion = ctx->fdwConversion;
|
|
ctx->fdwConversion = conversion;
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_conversion, IMC_SETCONVERSIONMODE );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0 );
|
|
}
|
|
|
|
if (sentence != ctx->fdwSentence)
|
|
{
|
|
old_sentence = ctx->fdwSentence;
|
|
ctx->fdwSentence = sentence;
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_sentence, IMC_SETSENTENCEMODE );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0 );
|
|
}
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetOpenStatus (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p, status %u\n", himc, status );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
if (status != ctx->fOpen)
|
|
{
|
|
ctx->fOpen = status;
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0 );
|
|
}
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSetStatusWindowPos (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSetStatusWindowPos( HIMC himc, POINT *pos )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p, pos %s\n", himc, wine_dbgstr_point( pos ) );
|
|
|
|
if (!pos)
|
|
{
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return FALSE;
|
|
}
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
ctx->ptStatusWndPos = *pos;
|
|
ctx->fdwInit |= INIT_STATUSWNDPOS;
|
|
|
|
ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS );
|
|
SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSTATUSWINDOWPOS, 0 );
|
|
|
|
ImmUnlockIMC( himc );
|
|
|
|
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)
|
|
{
|
|
FIXME("(%p): stub\n", hSoftWnd);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmShowSoftKeyboard(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
|
|
{
|
|
FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmSimulateHotKey (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
|
|
{
|
|
FIXME("(%p, %ld): stub\n", hWnd, dwHotKeyID);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmUnregisterWordA (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (!ime_is_unicode( ime ))
|
|
ret = ime->pImeUnregisterWord( readingA, style, stringA );
|
|
else
|
|
{
|
|
WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA );
|
|
ret = ime->pImeUnregisterWord( readingW, style, stringW );
|
|
free( readingW );
|
|
free( stringW );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmUnregisterWordW (IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW )
|
|
{
|
|
struct ime *ime;
|
|
BOOL ret;
|
|
|
|
TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) );
|
|
|
|
if (!(ime = ime_acquire( hkl ))) return FALSE;
|
|
|
|
if (ime_is_unicode( ime ))
|
|
ret = ime->pImeUnregisterWord( readingW, style, stringW );
|
|
else
|
|
{
|
|
char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW );
|
|
ret = ime->pImeUnregisterWord( readingA, style, stringA );
|
|
free( readingA );
|
|
free( stringA );
|
|
}
|
|
|
|
ime_release( ime );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetImeMenuItemsA (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOA *parentA,
|
|
IMEMENUITEMINFOA *menuA, DWORD size )
|
|
{
|
|
struct imc *data = get_imc_data( himc );
|
|
struct ime *ime;
|
|
DWORD ret;
|
|
|
|
TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n",
|
|
himc, flags, type, parentA, menuA, size );
|
|
|
|
if (!data)
|
|
{
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return 0;
|
|
}
|
|
|
|
if (!(ime = imc_select_ime( data ))) return 0;
|
|
if (!ime_is_unicode( ime ) || (!parentA && !menuA))
|
|
ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size );
|
|
else
|
|
{
|
|
IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL;
|
|
|
|
if (!menuA) menuW = NULL;
|
|
else
|
|
{
|
|
int count = size / sizeof(LPIMEMENUITEMINFOA);
|
|
size = count * sizeof(IMEMENUITEMINFOW);
|
|
menuW = malloc( size );
|
|
}
|
|
|
|
ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size );
|
|
|
|
if (parentA)
|
|
{
|
|
memcpy( parentA, parentW, sizeof(IMEMENUITEMINFOA) );
|
|
parentA->hbmpItem = parentW->hbmpItem;
|
|
WideCharToMultiByte( CP_ACP, 0, parentW->szString, -1, parentA->szString,
|
|
IMEMENUITEM_STRING_SIZE, NULL, NULL );
|
|
}
|
|
if (menuA && ret)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < ret; i++)
|
|
{
|
|
memcpy( &menuA[i], &menuW[1], sizeof(IMEMENUITEMINFOA) );
|
|
menuA[i].hbmpItem = menuW[i].hbmpItem;
|
|
WideCharToMultiByte( CP_ACP, 0, menuW[i].szString, -1, menuA[i].szString,
|
|
IMEMENUITEM_STRING_SIZE, NULL, NULL );
|
|
}
|
|
}
|
|
free( menuW );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetImeMenuItemsW (IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parentW,
|
|
IMEMENUITEMINFOW *menuW, DWORD size )
|
|
{
|
|
struct imc *data = get_imc_data( himc );
|
|
struct ime *ime;
|
|
DWORD ret;
|
|
|
|
TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n",
|
|
himc, flags, type, parentW, menuW, size );
|
|
|
|
if (!data)
|
|
{
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return 0;
|
|
}
|
|
|
|
if (!(ime = imc_select_ime( data ))) return 0;
|
|
if (ime_is_unicode( ime ) || (!parentW && !menuW))
|
|
ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size );
|
|
else
|
|
{
|
|
IMEMENUITEMINFOA tmpA, *menuA, *parentA = parentW ? &tmpA : NULL;
|
|
|
|
if (!menuW) menuA = NULL;
|
|
else
|
|
{
|
|
int count = size / sizeof(LPIMEMENUITEMINFOW);
|
|
size = count * sizeof(IMEMENUITEMINFOA);
|
|
menuA = malloc( size );
|
|
}
|
|
|
|
ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size );
|
|
|
|
if (parentW)
|
|
{
|
|
memcpy( parentW, parentA, sizeof(IMEMENUITEMINFOA) );
|
|
parentW->hbmpItem = parentA->hbmpItem;
|
|
MultiByteToWideChar( CP_ACP, 0, parentA->szString, -1, parentW->szString, IMEMENUITEM_STRING_SIZE );
|
|
}
|
|
if (menuW && ret)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < ret; i++)
|
|
{
|
|
memcpy( &menuW[i], &menuA[1], sizeof(IMEMENUITEMINFOA) );
|
|
menuW[i].hbmpItem = menuA[i].hbmpItem;
|
|
MultiByteToWideChar( CP_ACP, 0, menuA[i].szString, -1, menuW[i].szString, IMEMENUITEM_STRING_SIZE );
|
|
}
|
|
}
|
|
free( menuA );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmLockIMC(IMM32.@)
|
|
*/
|
|
INPUTCONTEXT *WINAPI ImmLockIMC( HIMC himc )
|
|
{
|
|
struct imc *imc = get_imc_data( himc );
|
|
|
|
TRACE( "himc %p\n", himc );
|
|
|
|
if (!imc) return NULL;
|
|
imc->dwLock++;
|
|
|
|
imc_select_ime( imc );
|
|
return &imc->IMC;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmUnlockIMC(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
|
|
if (!data)
|
|
return FALSE;
|
|
if (data->dwLock)
|
|
data->dwLock--;
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetIMCLockCount(IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
|
|
{
|
|
struct imc *data = get_imc_data( hIMC );
|
|
if (!data)
|
|
return 0;
|
|
return data->dwLock;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmCreateIMCC(IMM32.@)
|
|
*/
|
|
HIMCC WINAPI ImmCreateIMCC(DWORD size)
|
|
{
|
|
return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmDestroyIMCC(IMM32.@)
|
|
*/
|
|
HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
|
|
{
|
|
return GlobalFree(block);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmLockIMCC(IMM32.@)
|
|
*/
|
|
LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
|
|
{
|
|
return GlobalLock(imcc);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmUnlockIMCC(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
|
|
{
|
|
return GlobalUnlock(imcc);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetIMCCLockCount(IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
|
|
{
|
|
return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmReSizeIMCC(IMM32.@)
|
|
*/
|
|
HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
|
|
{
|
|
return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetIMCCSize(IMM32.@)
|
|
*/
|
|
DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
|
|
{
|
|
return GlobalSize(imcc);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGenerateMessage(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmGenerateMessage( HIMC himc )
|
|
{
|
|
INPUTCONTEXT *ctx;
|
|
|
|
TRACE( "himc %p\n", himc );
|
|
|
|
if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE;
|
|
if (!(ctx = ImmLockIMC( himc ))) return FALSE;
|
|
|
|
while (ctx->dwNumMsgBuf--)
|
|
{
|
|
TRANSMSG *msgs, msg;
|
|
if (!(msgs = ImmLockIMCC( ctx->hMsgBuf ))) return FALSE;
|
|
msg = msgs[0];
|
|
memmove( msgs, msgs + 1, ctx->dwNumMsgBuf * sizeof(*msgs) );
|
|
ImmUnlockIMCC( ctx->hMsgBuf );
|
|
SendMessageW( ctx->hWnd, msg.message, msg.wParam, msg.lParam );
|
|
}
|
|
ctx->dwNumMsgBuf++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmTranslateMessage(IMM32.@)
|
|
* ( Undocumented, call internally and from user32.dll )
|
|
*/
|
|
BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
UINT uMsgCount;
|
|
TRANSMSG TransMsg[10];
|
|
};
|
|
TRANSMSGLIST list;
|
|
} buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)};
|
|
TRANSMSG *msgs = buffer.TransMsg;
|
|
UINT scan, vkey, count, i;
|
|
struct imc *data;
|
|
struct ime *ime;
|
|
BYTE state[256];
|
|
WCHAR chr;
|
|
|
|
TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
|
|
|
|
if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE;
|
|
if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE;
|
|
if (!(ime = imc_select_ime( data ))) return FALSE;
|
|
|
|
if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE;
|
|
data->vkey = VK_PROCESSKEY;
|
|
GetKeyboardState( state );
|
|
scan = lparam >> 0x10;
|
|
|
|
if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
|
|
{
|
|
if (!ime_is_unicode( ime )) ToAscii( vkey, scan, state, &chr, 0 );
|
|
else ToUnicodeEx( vkey, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) );
|
|
vkey = MAKELONG( vkey, chr );
|
|
}
|
|
|
|
count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle );
|
|
if (count >= ARRAY_SIZE(buffer.TransMsg)) return 0;
|
|
|
|
for (i = 0; i < count; i++) PostMessageW( hwnd, msgs[i].message, msgs[i].wParam, msgs[i].lParam );
|
|
TRACE( "%u messages generated\n", count );
|
|
|
|
return count > 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmProcessKey(IMM32.@)
|
|
* ( Undocumented, called from user32.dll )
|
|
*/
|
|
BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD unknown )
|
|
{
|
|
struct imc *imc;
|
|
struct ime *ime;
|
|
BYTE state[256];
|
|
BOOL ret;
|
|
|
|
TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown );
|
|
|
|
if (hkl != GetKeyboardLayout( 0 )) return FALSE;
|
|
if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE;
|
|
if (!(ime = imc_select_ime( imc ))) return FALSE;
|
|
|
|
GetKeyboardState( state );
|
|
|
|
ret = ime->pImeProcessKey( imc->handle, vkey, lparam, state );
|
|
imc->vkey = ret ? vkey : VK_PROCESSKEY;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmDisableTextFrameService(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
|
|
{
|
|
FIXME("Stub\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmEnumInputContext(IMM32.@)
|
|
*/
|
|
|
|
BOOL WINAPI ImmEnumInputContext( DWORD thread, IMCENUMPROC callback, LPARAM lparam )
|
|
{
|
|
HIMC buffer[256];
|
|
NTSTATUS status;
|
|
UINT i, size;
|
|
|
|
TRACE( "thread %lu, callback %p, lparam %#Ix\n", thread, callback, lparam );
|
|
|
|
if ((status = NtUserBuildHimcList( thread, ARRAY_SIZE(buffer), buffer, &size )))
|
|
{
|
|
RtlSetLastWin32Error( RtlNtStatusToDosError( status ) );
|
|
WARN( "NtUserBuildHimcList returned %#lx\n", status );
|
|
return FALSE;
|
|
}
|
|
|
|
if (size == ARRAY_SIZE(buffer)) FIXME( "NtUserBuildHimcList returned %u handles\n", size );
|
|
for (i = 0; i < size; i++) if (!callback( buffer[i], lparam )) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmGetHotKey(IMM32.@)
|
|
*/
|
|
|
|
BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL *hkl)
|
|
{
|
|
FIXME("%lx, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
|
|
return FALSE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* ImmDisableLegacyIME(IMM32.@)
|
|
*/
|
|
BOOL WINAPI ImmDisableLegacyIME(void)
|
|
{
|
|
FIXME("stub\n");
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL is_ime_ui_msg(UINT msg)
|
|
{
|
|
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_CONTROL:
|
|
case WM_IME_COMPOSITIONFULL:
|
|
case WM_IME_SELECT:
|
|
case WM_IME_CHAR:
|
|
case WM_IME_REQUEST:
|
|
case WM_IME_KEYDOWN:
|
|
case WM_IME_KEYUP:
|
|
return TRUE;
|
|
default:
|
|
return msg == WM_MSIME_RECONVERTOPTIONS ||
|
|
msg == WM_MSIME_SERVICE ||
|
|
msg == WM_MSIME_MOUSE ||
|
|
msg == WM_MSIME_RECONVERTREQUEST ||
|
|
msg == WM_MSIME_RECONVERT ||
|
|
msg == WM_MSIME_QUERYPOSITION ||
|
|
msg == WM_MSIME_DOCUMENTFEED;
|
|
}
|
|
}
|
|
|
|
static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam)
|
|
{
|
|
HWND hwnd;
|
|
HIMC himc;
|
|
|
|
switch (wparam)
|
|
{
|
|
case IME_INTERNAL_ACTIVATE:
|
|
hwnd = (HWND)lparam;
|
|
himc = NtUserGetWindowInputContext( hwnd );
|
|
ImmSetActiveContext( hwnd, himc, TRUE );
|
|
set_ime_ui_window_himc( himc );
|
|
break;
|
|
case IME_INTERNAL_DEACTIVATE:
|
|
hwnd = (HWND)lparam;
|
|
himc = NtUserGetWindowInputContext( hwnd );
|
|
ImmSetActiveContext( hwnd, himc, FALSE );
|
|
break;
|
|
case IME_INTERNAL_HKL_ACTIVATE:
|
|
ImmEnumInputContext( 0, enum_activate_layout, 0 );
|
|
if (!(hwnd = get_ime_ui_window())) break;
|
|
SendMessageW( hwnd, WM_IME_SELECT, TRUE, lparam );
|
|
break;
|
|
case IME_INTERNAL_HKL_DEACTIVATE:
|
|
if (!(hwnd = get_ime_ui_window())) break;
|
|
SendMessageW( hwnd, WM_IME_SELECT, FALSE, lparam );
|
|
break;
|
|
default:
|
|
FIXME("wparam = %Ix\n", wparam);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void init_messages(void)
|
|
{
|
|
static BOOL initialized;
|
|
|
|
if (initialized) return;
|
|
|
|
WM_MSIME_SERVICE = RegisterWindowMessageW(L"MSIMEService");
|
|
WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageW(L"MSIMEReconvertOptions");
|
|
WM_MSIME_MOUSE = RegisterWindowMessageW(L"MSIMEMouseOperation");
|
|
WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageW(L"MSIMEReconvertRequest");
|
|
WM_MSIME_RECONVERT = RegisterWindowMessageW(L"MSIMEReconvert");
|
|
WM_MSIME_QUERYPOSITION = RegisterWindowMessageW(L"MSIMEQueryPosition");
|
|
WM_MSIME_DOCUMENTFEED = RegisterWindowMessageW(L"MSIMEDocumentFeed");
|
|
initialized = TRUE;
|
|
}
|
|
|
|
LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi)
|
|
{
|
|
HWND ui_hwnd;
|
|
|
|
TRACE( "hwnd %p, msg %s, wparam %#Ix, lparam %#Ix, ansi %u\n",
|
|
hwnd, debugstr_wm_ime(msg), wparam, lparam, ansi );
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_CREATE:
|
|
init_messages();
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
HWND default_hwnd = ImmGetDefaultIMEWnd(0);
|
|
if (!default_hwnd || hwnd == default_hwnd)
|
|
imm_couninit_thread(TRUE);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_IME_INTERNAL:
|
|
return ime_internal_msg(wparam, lparam);
|
|
}
|
|
|
|
if (is_ime_ui_msg(msg))
|
|
{
|
|
if ((ui_hwnd = get_ime_ui_window()))
|
|
{
|
|
if (ansi)
|
|
return SendMessageA(ui_hwnd, msg, wparam, lparam);
|
|
else
|
|
return SendMessageW(ui_hwnd, msg, wparam, lparam);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (ansi)
|
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
|
else
|
|
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
|
}
|