Sweden-Number/dlls/imm32/imm.c

3367 lines
96 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 <stdarg.h>
#include <stdio.h>
#include "initguid.h"
#include "objbase.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "imm.h"
#include "ddk/imm.h"
#include "winnls.h"
#include "winreg.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm);
#define IMM_INIT_MAGIC 0x19650412
BOOL WINAPI User32InitializeImmEntryTable(DWORD);
typedef struct _tagImmHkl{
struct list entry;
HKL hkl;
HMODULE hIME;
IMEINFO imeInfo;
WCHAR imeClassName[17]; /* 16 character max */
ULONG uSelected;
HWND UIWnd;
/* Function Pointers */
BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
BOOL (WINAPI *pImeDestroy)(UINT);
LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
} ImmHkl;
typedef struct tagInputContextData
{
DWORD dwLock;
INPUTCONTEXT IMC;
DWORD threadID;
ImmHkl *immKbd;
UINT lastVK;
BOOL threadDefault;
DWORD magic;
} InputContextData;
#define WINE_IMC_VALID_MAGIC 0x56434D49
typedef struct _tagTRANSMSG {
UINT message;
WPARAM wParam;
LPARAM lParam;
} TRANSMSG, *LPTRANSMSG;
typedef struct _tagIMMThreadData {
struct list entry;
DWORD threadID;
HIMC defaultContext;
HWND hwndDefault;
BOOL disableIME;
DWORD windowRefs;
IInitializeSpy IInitializeSpy_iface;
ULARGE_INTEGER spy_cookie;
enum
{
IMM_APT_INIT = 0x1,
IMM_APT_CREATED = 0x2,
IMM_APT_CAN_FREE = 0x4,
IMM_APT_BROKEN = 0x8
} apt_flags;
} IMMThreadData;
static struct list ImmHklList = LIST_INIT(ImmHklList);
static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
static const WCHAR szwWineIMCProperty[] = L"WineImmHIMCProperty";
static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
static CRITICAL_SECTION threaddata_cs;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &threaddata_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
};
static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static BOOL disable_ime;
static inline BOOL is_himc_ime_unicode(const InputContextData *data)
{
return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
}
static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
{
return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
}
static BOOL IMM_DestroyContext(HIMC hIMC);
static InputContextData* get_imc_data(HIMC hIMC);
static inline WCHAR *strdupAtoW( const char *str )
{
WCHAR *ret = NULL;
if (str)
{
DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
}
return ret;
}
static inline CHAR *strdupWtoA( const WCHAR *str )
{
CHAR *ret = NULL;
if (str)
{
DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
}
return ret;
}
static 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 void imm_coinit_thread(IMMThreadData *thread_data)
{
HRESULT hr;
TRACE("implicit COM initialization\n");
if (thread_data->threadID != GetCurrentThreadId())
return;
if (thread_data->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
return;
thread_data->apt_flags |= IMM_APT_INIT;
if(!thread_data->spy_cookie.QuadPart)
{
hr = CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface,
&thread_data->spy_cookie);
if (FAILED(hr))
return;
}
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
thread_data->apt_flags |= IMM_APT_CREATED;
}
static void imm_couninit_thread(IMMThreadData *thread_data, BOOL cleanup)
{
TRACE("implicit COM deinitialization\n");
if (thread_data->apt_flags & IMM_APT_BROKEN)
return;
if (cleanup && thread_data->spy_cookie.QuadPart)
{
CoRevokeInitializeSpy(thread_data->spy_cookie);
thread_data->spy_cookie.QuadPart = 0;
}
if (!(thread_data->apt_flags & IMM_APT_INIT))
return;
thread_data->apt_flags &= ~IMM_APT_INIT;
if (thread_data->apt_flags & IMM_APT_CREATED)
{
thread_data->apt_flags &= ~IMM_APT_CREATED;
if (thread_data->apt_flags & IMM_APT_CAN_FREE)
CoUninitialize();
}
if (cleanup)
thread_data->apt_flags = 0;
}
static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface)
{
return CONTAINING_RECORD(iface, IMMThreadData, 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)
{
return 2;
}
static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
{
return 1;
}
static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
DWORD coinit, DWORD refs)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if ((thread_data->apt_flags & IMM_APT_CREATED) &&
!(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
{
imm_couninit_thread(thread_data, TRUE);
thread_data->apt_flags |= IMM_APT_BROKEN;
}
return S_OK;
}
static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
HRESULT hr, DWORD coinit, DWORD refs)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if ((thread_data->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
hr = S_OK;
if (SUCCEEDED(hr))
thread_data->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)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if (refs == 1 && !thread_data->windowRefs)
imm_couninit_thread(thread_data, FALSE);
else if (!refs)
thread_data->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 IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
{
IMMThreadData *data;
DWORD process;
if (hwnd)
{
if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
if (process != GetCurrentProcessId()) return NULL;
}
else if (thread)
{
HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
if (!h) return NULL;
process = GetProcessIdOfThread(h);
CloseHandle(h);
if (process != GetCurrentProcessId()) return NULL;
}
else
thread = GetCurrentThreadId();
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
if (data->threadID == thread) return data;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
data->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
data->threadID = thread;
list_add_head(&ImmThreadDataList,&data->entry);
TRACE("Thread Data Created (%x)\n",thread);
return data;
}
static BOOL IMM_IsDefaultContext(HIMC imc)
{
InputContextData *data = get_imc_data(imc);
if (!data)
return FALSE;
return data->threadDefault;
}
static void IMM_FreeThreadData(void)
{
IMMThreadData *data;
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
{
if (data->threadID == GetCurrentThreadId())
{
list_remove(&data->entry);
LeaveCriticalSection(&threaddata_cs);
IMM_DestroyContext(data->defaultContext);
imm_couninit_thread(data, TRUE);
HeapFree(GetProcessHeap(),0,data);
TRACE("Thread Data Destroyed\n");
return;
}
}
LeaveCriticalSection(&threaddata_cs);
}
static HMODULE load_graphics_driver(void)
{
static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{";
static const WCHAR displayW[] = L"}\\0000";
HMODULE ret = 0;
HKEY hkey;
DWORD size;
WCHAR path[MAX_PATH];
WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ));
if (!guid_atom) return 0;
memcpy( key, key_pathW, sizeof(key_pathW) );
if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
lstrcatW( key, displayW );
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
size = sizeof(path);
if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
ret = LoadLibraryW( path );
RegCloseKey( hkey );
TRACE( "%s %p\n", debugstr_w(path), ret );
return ret;
}
/* ImmHkl loading and freeing */
#define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
static ImmHkl *IMM_GetImmHkl(HKL hkl)
{
ImmHkl *ptr;
WCHAR filename[MAX_PATH];
TRACE("Seeking ime for keyboard %p\n",hkl);
LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
{
if (ptr->hkl == hkl)
return ptr;
}
/* not found... create it */
ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
ptr->hkl = hkl;
if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
if (!ptr->hIME) ptr->hIME = load_graphics_driver();
if (ptr->hIME)
{
LOAD_FUNCPTR(ImeInquire);
if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
{
FreeLibrary(ptr->hIME);
ptr->hIME = NULL;
}
else
{
LOAD_FUNCPTR(ImeDestroy);
LOAD_FUNCPTR(ImeSelect);
if (!ptr->pImeSelect || !ptr->pImeDestroy)
{
FreeLibrary(ptr->hIME);
ptr->hIME = NULL;
}
else
{
LOAD_FUNCPTR(ImeConfigure);
LOAD_FUNCPTR(ImeEscape);
LOAD_FUNCPTR(ImeSetActiveContext);
LOAD_FUNCPTR(ImeToAsciiEx);
LOAD_FUNCPTR(NotifyIME);
LOAD_FUNCPTR(ImeRegisterWord);
LOAD_FUNCPTR(ImeUnregisterWord);
LOAD_FUNCPTR(ImeEnumRegisterWord);
LOAD_FUNCPTR(ImeSetCompositionString);
LOAD_FUNCPTR(ImeConversionList);
LOAD_FUNCPTR(ImeProcessKey);
LOAD_FUNCPTR(ImeGetRegisterWordStyle);
LOAD_FUNCPTR(ImeGetImeMenuItems);
/* make sure our classname is WCHAR */
if (!is_kbd_ime_unicode(ptr))
{
WCHAR bufW[17];
MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
-1, bufW, 17);
lstrcpyW(ptr->imeClassName, bufW);
}
}
}
}
list_add_head(&ImmHklList,&ptr->entry);
return ptr;
}
#undef LOAD_FUNCPTR
HWND WINAPI __wine_get_ui_window(HKL hkl)
{
ImmHkl *immHkl = IMM_GetImmHkl(hkl);
return immHkl->UIWnd;
}
static void IMM_FreeAllImmHkl(void)
{
ImmHkl *ptr,*cursor2;
LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
{
list_remove(&ptr->entry);
if (ptr->hIME)
{
ptr->pImeDestroy(1);
FreeLibrary(ptr->hIME);
}
if (ptr->UIWnd)
DestroyWindow(ptr->UIWnd);
HeapFree(GetProcessHeap(),0,ptr);
}
}
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
{
TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
{
return FALSE;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
IMM_FreeThreadData();
break;
case DLL_PROCESS_DETACH:
if (lpReserved) break;
IMM_FreeThreadData();
IMM_FreeAllImmHkl();
break;
}
return TRUE;
}
/* for posting messages as the IME */
static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND target = GetFocus();
if (!target)
PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
else
PostMessageW(target, msg, wParam, lParam);
}
/* for sending messages as the IME */
static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND target = GetFocus();
if (!target)
SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
else
SendMessageW(target, msg, wParam, lParam);
}
static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
{
HWND target;
target = data->IMC.hWnd;
if (!target) target = GetFocus();
if (target)
return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
return 0;
}
static HIMCC ImmCreateBlankCompStr(void)
{
HIMCC rc;
LPCOMPOSITIONSTRING ptr;
rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
ptr = ImmLockIMCC(rc);
memset(ptr,0,sizeof(COMPOSITIONSTRING));
ptr->dwSize = sizeof(COMPOSITIONSTRING);
ImmUnlockIMCC(rc);
return rc;
}
static InputContextData* get_imc_data(HIMC hIMC)
{
InputContextData *data = hIMC;
if (hIMC == NULL)
return NULL;
if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
return data;
}
static HIMC get_default_context( HWND hwnd )
{
HIMC ret;
IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
if (!thread_data) return 0;
if (thread_data->defaultContext)
{
ret = thread_data->defaultContext;
LeaveCriticalSection(&threaddata_cs);
return ret;
}
/* can't create a default context in another thread */
if (thread_data->threadID != GetCurrentThreadId())
{
LeaveCriticalSection(&threaddata_cs);
return 0;
}
LeaveCriticalSection(&threaddata_cs);
ret = ImmCreateContext();
if (!ret) return 0;
((InputContextData*)ret)->threadDefault = TRUE;
/* thread_data is in the current thread so we can assume it's still valid */
EnterCriticalSection(&threaddata_cs);
if (thread_data->defaultContext) /* someone beat us */
{
IMM_DestroyContext( ret );
ret = thread_data->defaultContext;
}
else thread_data->defaultContext = ret;
LeaveCriticalSection(&threaddata_cs);
return ret;
}
static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
{
InputContextData *data;
if (hWnd)
{
DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
if (thread != GetCurrentThreadId()) return TRUE;
}
data = get_imc_data(hIMC);
if (data && data->threadID != GetCurrentThreadId())
return TRUE;
return FALSE;
}
/***********************************************************************
* ImmSetActiveContext (IMM32.@)
*/
BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
{
InputContextData *data = get_imc_data(himc);
IMMThreadData *thread_data;
TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
if (himc && !data && activate)
return FALSE;
thread_data = IMM_GetThreadData(hwnd, 0);
if (thread_data)
{
imm_coinit_thread(thread_data);
LeaveCriticalSection(&threaddata_cs);
}
if (data)
{
data->IMC.hWnd = activate ? hwnd : NULL;
if (data->immKbd->hIME && data->immKbd->pImeSetActiveContext)
data->immKbd->pImeSetActiveContext(himc, activate);
}
if (IsWindow(hwnd))
{
SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL);
/* TODO: send WM_IME_NOTIFY */
}
return TRUE;
}
/***********************************************************************
* ImmAssociateContext (IMM32.@)
*/
HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
HIMC defaultContext;
HIMC old;
TRACE("(%p, %p):\n", hWnd, hIMC);
if (!IsWindow(hWnd) || (hIMC && !data))
return NULL;
if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
return NULL;
old = GetPropW(hWnd, szwWineIMCProperty);
defaultContext = get_default_context( hWnd );
if (!old)
old = defaultContext;
else if (old == (HIMC)-1)
old = NULL;
/* If already associated just return */
if (old == hIMC)
return hIMC;
if (!hIMC) /* Meaning disable imm for that window*/
SetPropW(hWnd, szwWineIMCProperty, (HANDLE)-1);
else if (hIMC == defaultContext)
RemovePropW(hWnd, szwWineIMCProperty);
else
SetPropW(hWnd, szwWineIMCProperty, hIMC);
if (GetActiveWindow() == hWnd)
{
ImmSetActiveContext(hWnd, old, FALSE);
ImmSetActiveContext(hWnd, hIMC, TRUE);
}
return old;
}
/*
* Helper function for ImmAssociateContextEx
*/
static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
{
HIMC hImc = (HIMC)lParam;
ImmAssociateContext(hwnd,hImc);
return TRUE;
}
/***********************************************************************
* ImmAssociateContextEx (IMM32.@)
*/
BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
{
TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
if (!hWnd)
return FALSE;
switch (dwFlags)
{
case 0:
ImmAssociateContext(hWnd,hIMC);
return TRUE;
case IACE_DEFAULT:
{
HIMC defaultContext = get_default_context( hWnd );
if (!defaultContext) return FALSE;
ImmAssociateContext(hWnd,defaultContext);
return TRUE;
}
case IACE_IGNORENOCONTEXT:
if (GetPropW(hWnd,szwWineIMCProperty))
ImmAssociateContext(hWnd,hIMC);
return TRUE;
case IACE_CHILDREN:
EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
return TRUE;
default:
FIXME("Unknown dwFlags 0x%x\n",dwFlags);
return FALSE;
}
}
/***********************************************************************
* ImmConfigureIMEA (IMM32.@)
*/
BOOL WINAPI ImmConfigureIMEA(
HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
return FALSE;
if (immHkl->hIME && immHkl->pImeConfigure)
{
if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
else
{
REGISTERWORDW rww;
REGISTERWORDA *rwa = lpData;
BOOL rc;
rww.lpReading = strdupAtoW(rwa->lpReading);
rww.lpWord = strdupAtoW(rwa->lpWord);
rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
HeapFree(GetProcessHeap(),0,rww.lpReading);
HeapFree(GetProcessHeap(),0,rww.lpWord);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmConfigureIMEW (IMM32.@)
*/
BOOL WINAPI ImmConfigureIMEW(
HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
return FALSE;
if (immHkl->hIME && immHkl->pImeConfigure)
{
if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
else
{
REGISTERWORDW *rww = lpData;
REGISTERWORDA rwa;
BOOL rc;
rwa.lpReading = strdupWtoA(rww->lpReading);
rwa.lpWord = strdupWtoA(rww->lpWord);
rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
HeapFree(GetProcessHeap(),0,rwa.lpReading);
HeapFree(GetProcessHeap(),0,rwa.lpWord);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmCreateContext (IMM32.@)
*/
HIMC WINAPI ImmCreateContext(void)
{
InputContextData *new_context;
LPGUIDELINE gl;
LPCANDIDATEINFO ci;
int i;
new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
/* Load the IME */
new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
if (!new_context->immKbd->hIME)
{
TRACE("IME dll could not be loaded\n");
HeapFree(GetProcessHeap(),0,new_context);
return 0;
}
/* the HIMCCs are never NULL */
new_context->IMC.hCompStr = ImmCreateBlankCompStr();
new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
ci = ImmLockIMCC(new_context->IMC.hCandInfo);
memset(ci,0,sizeof(CANDIDATEINFO));
ci->dwSize = sizeof(CANDIDATEINFO);
ImmUnlockIMCC(new_context->IMC.hCandInfo);
new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
gl = ImmLockIMCC(new_context->IMC.hGuideLine);
memset(gl,0,sizeof(GUIDELINE));
gl->dwSize = sizeof(GUIDELINE);
ImmUnlockIMCC(new_context->IMC.hGuideLine);
for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++)
new_context->IMC.cfCandForm[i].dwIndex = ~0u;
/* Initialize the IME Private */
new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
if (!new_context->immKbd->pImeSelect(new_context, TRUE))
{
TRACE("Selection of IME failed\n");
IMM_DestroyContext(new_context);
return 0;
}
new_context->threadID = GetCurrentThreadId();
SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
new_context->immKbd->uSelected++;
TRACE("Created context %p\n",new_context);
new_context->magic = WINE_IMC_VALID_MAGIC;
return new_context;
}
static BOOL IMM_DestroyContext(HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("Destroying %p\n",hIMC);
if (!data)
return FALSE;
data->immKbd->uSelected --;
data->immKbd->pImeSelect(hIMC, FALSE);
SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
ImmDestroyIMCC(data->IMC.hCompStr);
ImmDestroyIMCC(data->IMC.hCandInfo);
ImmDestroyIMCC(data->IMC.hGuideLine);
ImmDestroyIMCC(data->IMC.hPrivate);
ImmDestroyIMCC(data->IMC.hMsgBuf);
data->magic = 0;
HeapFree(GetProcessHeap(),0,data);
return TRUE;
}
/***********************************************************************
* ImmDestroyContext (IMM32.@)
*/
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{
if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
return IMM_DestroyContext(hIMC);
else
return FALSE;
}
static HWND imm_detach_default_window(IMMThreadData *thread_data)
{
HWND to_destroy;
imm_couninit_thread(thread_data, TRUE);
to_destroy = thread_data->hwndDefault;
thread_data->hwndDefault = NULL;
thread_data->windowRefs = 0;
return to_destroy;
}
/***********************************************************************
* ImmDisableIME (IMM32.@)
*/
BOOL WINAPI ImmDisableIME(DWORD idThread)
{
IMMThreadData *thread_data;
HWND to_destroy;
if (idThread == (DWORD)-1)
{
disable_ime = TRUE;
while (1)
{
to_destroy = 0;
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(thread_data, &ImmThreadDataList, IMMThreadData, entry)
{
if (thread_data->hwndDefault)
{
to_destroy = imm_detach_default_window(thread_data);
break;
}
}
LeaveCriticalSection(&threaddata_cs);
if (!to_destroy)
break;
DestroyWindow(to_destroy);
}
}
else
{
thread_data = IMM_GetThreadData(NULL, idThread);
if (!thread_data) return FALSE;
thread_data->disableIME = TRUE;
to_destroy = imm_detach_default_window(thread_data);
LeaveCriticalSection(&threaddata_cs);
if (to_destroy)
DestroyWindow(to_destroy);
}
return TRUE;
}
/***********************************************************************
* ImmEnumRegisterWordA (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordA(
HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
LPCSTR lpszReading, DWORD dwStyle,
LPCSTR lpszRegister, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
{
if (!is_kbd_ime_unicode(immHkl))
return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
(LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
else
{
LPWSTR lpszwReading = strdupAtoW(lpszReading);
LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
BOOL rc;
rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
lpszwReading, dwStyle, lpszwRegister,
lpData);
HeapFree(GetProcessHeap(),0,lpszwReading);
HeapFree(GetProcessHeap(),0,lpszwRegister);
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmEnumRegisterWordW (IMM32.@)
*/
UINT WINAPI ImmEnumRegisterWordW(
HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
LPCWSTR lpszReading, DWORD dwStyle,
LPCWSTR lpszRegister, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
{
if (is_kbd_ime_unicode(immHkl))
return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
lpszRegister, lpData);
else
{
LPSTR lpszaReading = strdupWtoA(lpszReading);
LPSTR lpszaRegister = strdupWtoA(lpszRegister);
BOOL rc;
rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
dwStyle, (LPCWSTR)lpszaRegister, lpData);
HeapFree(GetProcessHeap(),0,lpszaReading);
HeapFree(GetProcessHeap(),0,lpszaRegister);
return rc;
}
}
else
return 0;
}
static inline BOOL EscapeRequiresWA(UINT uEscape)
{
if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
uEscape == IME_ESC_IME_NAME ||
uEscape == IME_ESC_GETHELPFILENAME)
return TRUE;
return FALSE;
}
/***********************************************************************
* ImmEscapeA (IMM32.@)
*/
LRESULT WINAPI ImmEscapeA(
HKL hKL, HIMC hIMC,
UINT uEscape, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
if (immHkl->hIME && immHkl->pImeEscape)
{
if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
return immHkl->pImeEscape(hIMC,uEscape,lpData);
else
{
WCHAR buffer[81]; /* largest required buffer should be 80 */
LRESULT rc;
if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
{
MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
}
else
{
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
}
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmEscapeW (IMM32.@)
*/
LRESULT WINAPI ImmEscapeW(
HKL hKL, HIMC hIMC,
UINT uEscape, LPVOID lpData)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
if (immHkl->hIME && immHkl->pImeEscape)
{
if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
return immHkl->pImeEscape(hIMC,uEscape,lpData);
else
{
CHAR buffer[81]; /* largest required buffer should be 80 */
LRESULT rc;
if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
{
WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
}
else
{
rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
}
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetCandidateListA (IMM32.@)
*/
DWORD WINAPI ImmGetCandidateListA(
HIMC hIMC, DWORD dwIndex,
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
LPCANDIDATELIST candlist;
DWORD ret = 0;
TRACE("%p, %d, %p, %d\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 ( !is_himc_ime_unicode(data) )
{
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)
{
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
DWORD ret, count;
TRACE("%p, %p\n", hIMC, lpdwListCount);
if (!data || !lpdwListCount || !data->IMC.hCandInfo)
return 0;
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
*lpdwListCount = count = candinfo->dwCount;
if ( !is_himc_ime_unicode(data) )
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)
{
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
DWORD ret, count;
TRACE("%p, %p\n", hIMC, lpdwListCount);
if (!data || !lpdwListCount || !data->IMC.hCandInfo)
return 0;
candinfo = ImmLockIMCC(data->IMC.hCandInfo);
*lpdwListCount = count = candinfo->dwCount;
if ( is_himc_ime_unicode(data) )
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)
{
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
LPCANDIDATELIST candlist;
DWORD ret = 0;
TRACE("%p, %d, %p, %d\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 ( is_himc_ime_unicode(data) )
{
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 dwIndex, LPCANDIDATEFORM lpCandidate)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
if (!data || !lpCandidate)
return FALSE;
if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
return FALSE;
if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
return FALSE;
*lpCandidate = data->IMC.cfCandForm[dwIndex];
return TRUE;
}
/***********************************************************************
* ImmGetCompositionFontA (IMM32.@)
*/
BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
{
LOGFONTW lfW;
BOOL rc;
TRACE("(%p, %p):\n", hIMC, lplf);
rc = ImmGetCompositionFontW(hIMC,&lfW);
if (!rc || !lplf)
return FALSE;
memcpy(lplf,&lfW,sizeof(LOGFONTA));
WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
LF_FACESIZE, NULL, NULL);
return TRUE;
}
/***********************************************************************
* ImmGetCompositionFontW (IMM32.@)
*/
BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p):\n", hIMC, lplf);
if (!data || !lplf)
return FALSE;
*lplf = data->IMC.lfFont.W;
return TRUE;
}
/* Helpers for the GetCompositionString functions */
/* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
length is always in bytes. */
static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
INT dst_len, BOOL unicode)
{
int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
INT ret;
if (is_himc_ime_unicode(data) ^ unicode)
{
if (unicode)
ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
else
ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
ret *= char_size;
}
else
{
if (dst_len)
{
ret = min(src_len * char_size, dst_len);
memcpy(dst, src, ret);
}
else
ret = src_len * char_size;
}
return ret;
}
/* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
passed mode. String length is in characters, attributes are in byte arrays. */
static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
{
union
{
const void *str;
const WCHAR *strW;
const char *strA;
} string;
INT rc;
string.str = comp_string;
if (is_himc_ime_unicode(data) && !unicode)
{
rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
if (dst_len)
{
int i, j = 0, k = 0;
if (rc < dst_len)
dst_len = rc;
for (i = 0; i < str_len; ++i)
{
int len;
len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
for (; len > 0; --len)
{
dst[j++] = src[k];
if (j >= dst_len)
goto end;
}
++k;
}
end:
rc = j;
}
}
else if (!is_himc_ime_unicode(data) && unicode)
{
rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
if (dst_len)
{
int i, j = 0;
if (rc < dst_len)
dst_len = rc;
for (i = 0; i < str_len; ++i)
{
if (IsDBCSLeadByte(string.strA[i]))
continue;
dst[j++] = src[i];
if (j >= dst_len)
break;
}
rc = j;
}
}
else
{
memcpy(dst, src, min(src_len, dst_len));
rc = src_len;
}
return rc;
}
static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
LPBYTE target, INT tlen, BOOL unicode )
{
INT rc;
if (is_himc_ime_unicode(data) && !unicode)
{
if (tlen)
{
int i;
if (slen < tlen)
tlen = slen;
tlen /= sizeof (DWORD);
for (i = 0; i < tlen; ++i)
{
((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
((DWORD *)source)[i],
NULL, 0,
NULL, NULL);
}
rc = sizeof (DWORD) * i;
}
else
rc = slen;
}
else if (!is_himc_ime_unicode(data) && unicode)
{
if (tlen)
{
int i;
if (slen < tlen)
tlen = slen;
tlen /= sizeof (DWORD);
for (i = 0; i < tlen; ++i)
{
((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
((DWORD *)source)[i],
NULL, 0);
}
rc = sizeof (DWORD) * i;
}
else
rc = slen;
}
else
{
memcpy( target, source, min(slen,tlen));
rc = slen;
}
return rc;
}
static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
{
int rc;
if (is_himc_ime_unicode(data) && !unicode)
{
rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
}
else if (!is_himc_ime_unicode(data) && unicode)
{
rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
}
else
rc = offset;
return rc;
}
static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
DWORD dwBufLen, BOOL unicode)
{
LONG rc = 0;
InputContextData *data = get_imc_data(hIMC);
LPCOMPOSITIONSTRING compstr;
LPBYTE compdata;
TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
if (!data)
return FALSE;
if (!data->IMC.hCompStr)
return FALSE;
compdata = ImmLockIMCC(data->IMC.hCompStr);
compstr = (LPCOMPOSITIONSTRING)compdata;
switch (dwIndex)
{
case GCS_RESULTSTR:
TRACE("GCS_RESULTSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPSTR:
TRACE("GCS_COMPSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPATTR:
TRACE("GCS_COMPATTR\n");
rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPCLAUSE:
TRACE("GCS_COMPCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
compdata + compstr->dwCompStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTCLAUSE:
TRACE("GCS_RESULTCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
compdata + compstr->dwResultStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTREADSTR:
TRACE("GCS_RESULTREADSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_RESULTREADCLAUSE:
TRACE("GCS_RESULTREADCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
compdata + compstr->dwResultStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADSTR:
TRACE("GCS_COMPREADSTR\n");
rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADATTR:
TRACE("GCS_COMPREADATTR\n");
rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
lpBuf, dwBufLen, unicode);
break;
case GCS_COMPREADCLAUSE:
TRACE("GCS_COMPREADCLAUSE\n");
rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
compdata + compstr->dwCompStrOffset,
lpBuf, dwBufLen, unicode);
break;
case GCS_CURSORPOS:
TRACE("GCS_CURSORPOS\n");
rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
break;
case GCS_DELTASTART:
TRACE("GCS_DELTASTART\n");
rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
break;
default:
FIXME("Unhandled index 0x%x\n",dwIndex);
break;
}
ImmUnlockIMCC(data->IMC.hCompStr);
return rc;
}
/***********************************************************************
* ImmGetCompositionStringA (IMM32.@)
*/
LONG WINAPI ImmGetCompositionStringA(
HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
{
return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
}
/***********************************************************************
* ImmGetCompositionStringW (IMM32.@)
*/
LONG WINAPI ImmGetCompositionStringW(
HIMC hIMC, DWORD dwIndex,
LPVOID lpBuf, DWORD dwBufLen)
{
return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
}
/***********************************************************************
* ImmGetCompositionWindow (IMM32.@)
*/
BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCompForm);
if (!data)
return FALSE;
*lpCompForm = data->IMC.cfCompForm;
return TRUE;
}
/***********************************************************************
* ImmGetContext (IMM32.@)
*
*/
HIMC WINAPI ImmGetContext(HWND hWnd)
{
HIMC rc;
TRACE("%p\n", hWnd);
if (!IsWindow(hWnd))
{
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
rc = GetPropW(hWnd,szwWineIMCProperty);
if (rc == (HIMC)-1)
rc = NULL;
else if (rc == NULL)
rc = get_default_context( hWnd );
if (rc)
{
InputContextData *data = rc;
data->IMC.hWnd = hWnd;
}
TRACE("returning %p\n", rc);
return rc;
}
/***********************************************************************
* ImmGetConversionListA (IMM32.@)
*/
DWORD WINAPI ImmGetConversionListA(
HKL hKL, HIMC hIMC,
LPCSTR pSrc, LPCANDIDATELIST lpDst,
DWORD dwBufLen, UINT uFlag)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
dwBufLen, uFlag);
if (immHkl->hIME && immHkl->pImeConversionList)
{
if (!is_kbd_ime_unicode(immHkl))
return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
else
{
LPCANDIDATELIST lpwDst;
DWORD ret = 0, len;
LPWSTR pwSrc = strdupAtoW(pSrc);
len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
if ( lpwDst )
{
immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
HeapFree(GetProcessHeap(), 0, lpwDst);
}
HeapFree(GetProcessHeap(), 0, pwSrc);
return ret;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetConversionListW (IMM32.@)
*/
DWORD WINAPI ImmGetConversionListW(
HKL hKL, HIMC hIMC,
LPCWSTR pSrc, LPCANDIDATELIST lpDst,
DWORD dwBufLen, UINT uFlag)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
dwBufLen, uFlag);
if (immHkl->hIME && immHkl->pImeConversionList)
{
if (is_kbd_ime_unicode(immHkl))
return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
else
{
LPCANDIDATELIST lpaDst;
DWORD ret = 0, len;
LPSTR paSrc = strdupWtoA(pSrc);
len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
if ( lpaDst )
{
immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
HeapFree(GetProcessHeap(), 0, lpaDst);
}
HeapFree(GetProcessHeap(), 0, paSrc);
return ret;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetConversionStatus (IMM32.@)
*/
BOOL WINAPI ImmGetConversionStatus(
HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
if (!data)
return FALSE;
if (lpfdwConversion)
*lpfdwConversion = data->IMC.fdwConversion;
if (lpfdwSentence)
*lpfdwSentence = data->IMC.fdwSentence;
return TRUE;
}
static BOOL needs_ime_window(HWND hwnd)
{
WCHAR classW[8];
if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, L"IME"))
return FALSE;
if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
return TRUE;
}
/***********************************************************************
* __wine_register_window (IMM32.@)
*/
BOOL WINAPI __wine_register_window(HWND hwnd)
{
HWND new = NULL;
IMMThreadData *thread_data;
TRACE("(%p)\n", hwnd);
if (!needs_ime_window(hwnd))
return FALSE;
thread_data = IMM_GetThreadData(hwnd, 0);
if (!thread_data)
return FALSE;
if (thread_data->disableIME || disable_ime)
{
TRACE("IME for this thread is disabled\n");
LeaveCriticalSection(&threaddata_cs);
return FALSE;
}
thread_data->windowRefs++;
TRACE("windowRefs=%u, hwndDefault=%p\n",
thread_data->windowRefs, thread_data->hwndDefault);
/* Create default IME window */
if (thread_data->windowRefs == 1)
{
/* Do not create the window inside of a critical section */
LeaveCriticalSection(&threaddata_cs);
new = CreateWindowExW( 0, L"IME", L"Default IME",
WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
0, 0, 1, 1, 0, 0, 0, 0);
/* thread_data is in the current thread so we can assume it's still valid */
EnterCriticalSection(&threaddata_cs);
/* See if anyone beat us */
if (thread_data->hwndDefault == NULL)
{
thread_data->hwndDefault = new;
new = NULL;
TRACE("Default is %p\n", thread_data->hwndDefault);
}
}
LeaveCriticalSection(&threaddata_cs);
/* Clean up an unused new window outside of the critical section */
if (new != NULL)
DestroyWindow(new);
return TRUE;
}
/***********************************************************************
* __wine_unregister_window (IMM32.@)
*/
void WINAPI __wine_unregister_window(HWND hwnd)
{
HWND to_destroy = 0;
IMMThreadData *thread_data;
TRACE("(%p)\n", hwnd);
thread_data = IMM_GetThreadData(hwnd, 0);
if (!thread_data) return;
thread_data->windowRefs--;
TRACE("windowRefs=%u, hwndDefault=%p\n",
thread_data->windowRefs, thread_data->hwndDefault);
/* Destroy default IME window */
if (thread_data->windowRefs == 0)
to_destroy = imm_detach_default_window(thread_data);
LeaveCriticalSection(&threaddata_cs);
if (to_destroy) DestroyWindow( to_destroy );
}
/***********************************************************************
* ImmGetDefaultIMEWnd (IMM32.@)
*/
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{
HWND ret;
IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
if (!thread_data)
return NULL;
ret = thread_data->hwndDefault;
LeaveCriticalSection(&threaddata_cs);
TRACE("Default is %p\n",ret);
return ret;
}
/***********************************************************************
* ImmGetDescriptionA (IMM32.@)
*/
UINT WINAPI ImmGetDescriptionA(
HKL hKL, LPSTR lpszDescription, UINT uBufLen)
{
WCHAR *buf;
DWORD len;
TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
/* find out how many characters in the unicode buffer */
len = ImmGetDescriptionW( hKL, NULL, 0 );
if (!len)
return 0;
/* allocate a buffer of that size */
buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
if( !buf )
return 0;
/* fetch the unicode buffer */
len = ImmGetDescriptionW( hKL, buf, len + 1 );
/* convert it back to ANSI */
len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
lpszDescription, uBufLen, NULL, NULL );
HeapFree( GetProcessHeap(), 0, buf );
if (len == 0)
return 0;
return len - 1;
}
/***********************************************************************
* ImmGetDescriptionW (IMM32.@)
*/
UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
{
FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
if (!hKL) return 0;
if (!uBufLen) return lstrlenW(L"Wine XIM" );
lstrcpynW( lpszDescription, L"Wine XIM", uBufLen );
return lstrlenW( lpszDescription );
}
/***********************************************************************
* ImmGetGuideLineA (IMM32.@)
*/
DWORD WINAPI ImmGetGuideLineA(
HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
{
FIXME("(%p, %d, %s, %d): 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, %d, %s, %d): stub\n",
hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/***********************************************************************
* ImmGetIMEFileNameA (IMM32.@)
*/
UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
{
LPWSTR bufW = NULL;
UINT wBufLen = uBufLen;
UINT rc;
if (uBufLen && lpszFileName)
bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
else /* We need this to get the number of byte required */
{
bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
wBufLen = MAX_PATH;
}
rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
if (rc > 0)
{
if (uBufLen && lpszFileName)
rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
uBufLen, NULL, NULL);
else /* get the length */
rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
NULL);
}
HeapFree(GetProcessHeap(),0,bufW);
return rc;
}
/***********************************************************************
* ImmGetIMEFileNameW (IMM32.@)
*/
UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
{
HKEY hkey;
DWORD length;
DWORD rc;
WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
return 0;
}
length = 0;
rc = RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, NULL, &length);
if (rc != ERROR_SUCCESS)
{
RegCloseKey(hkey);
SetLastError(rc);
return 0;
}
if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
{
RegCloseKey(hkey);
if (lpszFileName)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
else
return length / sizeof(WCHAR);
}
RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, lpszFileName, &length);
RegCloseKey(hkey);
return length / sizeof(WCHAR);
}
/***********************************************************************
* ImmGetOpenStatus (IMM32.@)
*/
BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
static int i;
if (!data)
return FALSE;
TRACE("(%p): semi-stub\n", hIMC);
if (!i++)
FIXME("(%p): semi-stub\n", hIMC);
return data->IMC.fOpen;
}
/***********************************************************************
* ImmGetProperty (IMM32.@)
*/
DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
{
DWORD rc = 0;
ImmHkl *kbd;
TRACE("(%p, %d)\n", hKL, fdwIndex);
kbd = IMM_GetImmHkl(hKL);
if (kbd && kbd->hIME)
{
switch (fdwIndex)
{
case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
case IGP_UI: rc = 0; break;
default: rc = 0;
}
}
return rc;
}
/***********************************************************************
* ImmGetRegisterWordStyleA (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleA(
HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
{
if (!is_kbd_ime_unicode(immHkl))
return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
else
{
STYLEBUFW sbw;
UINT rc;
rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
lpStyleBuf->szDescription, 32, NULL, NULL);
lpStyleBuf->dwStyle = sbw.dwStyle;
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetRegisterWordStyleW (IMM32.@)
*/
UINT WINAPI ImmGetRegisterWordStyleW(
HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
{
if (is_kbd_ime_unicode(immHkl))
return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
else
{
STYLEBUFA sba;
UINT rc;
rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
lpStyleBuf->szDescription, 32);
lpStyleBuf->dwStyle = sba.dwStyle;
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetStatusWindowPos (IMM32.@)
*/
BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpptPos);
if (!data || !lpptPos)
return FALSE;
*lpptPos = data->IMC.ptStatusWndPos;
return TRUE;
}
/***********************************************************************
* ImmGetVirtualKey (IMM32.@)
*/
UINT WINAPI ImmGetVirtualKey(HWND hWnd)
{
OSVERSIONINFOA version;
InputContextData *data = ImmGetContext( hWnd );
TRACE("%p\n", hWnd);
if ( data )
return data->lastVK;
version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA( &version );
switch(version.dwPlatformId)
{
case VER_PLATFORM_WIN32_WINDOWS:
return VK_PROCESSKEY;
case VER_PLATFORM_WIN32_NT:
return 0;
default:
FIXME("%d not supported\n",version.dwPlatformId);
return VK_PROCESSKEY;
}
}
/***********************************************************************
* ImmInstallIMEA (IMM32.@)
*/
HKL WINAPI ImmInstallIMEA(
LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
{
LPWSTR lpszwIMEFileName;
LPWSTR lpszwLayoutText;
HKL hkl;
TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
debugstr_a(lpszLayoutText));
lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
lpszwLayoutText = strdupAtoW(lpszLayoutText);
hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
HeapFree(GetProcessHeap(),0,lpszwLayoutText);
return hkl;
}
/***********************************************************************
* ImmInstallIMEW (IMM32.@)
*/
HKL WINAPI ImmInstallIMEW(
LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
{
INT lcid = GetUserDefaultLCID();
INT count;
HKL hkl;
DWORD rc;
HKEY hkey;
WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
debugstr_w(lpszLayoutText));
/* Start with 2. e001 will be blank and so default to the wine internal IME */
count = 2;
while (count < 0xfff)
{
DWORD disposition = 0;
hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
break;
else if (rc == ERROR_SUCCESS)
RegCloseKey(hkey);
count++;
}
if (count == 0xfff)
{
WARN("Unable to find slot to install IME\n");
return 0;
}
if (rc == ERROR_SUCCESS)
{
rc = RegSetValueExW(hkey, L"Ime File", 0, REG_SZ, (const BYTE*)lpszIMEFileName,
(lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hkey, L"Layout Text", 0, REG_SZ, (const BYTE*)lpszLayoutText,
(lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
RegCloseKey(hkey);
return hkl;
}
else
{
WARN("Unable to set IME registry values\n");
return 0;
}
}
/***********************************************************************
* ImmIsIME (IMM32.@)
*/
BOOL WINAPI ImmIsIME(HKL hKL)
{
ImmHkl *ptr;
TRACE("(%p):\n", hKL);
ptr = IMM_GetImmHkl(hKL);
return (ptr && ptr->hIME);
}
/***********************************************************************
* ImmIsUIMessageA (IMM32.@)
*/
BOOL WINAPI ImmIsUIMessageA(
HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
{
TRACE("(%p, %x, %ld, %ld)\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, %ld, %ld)\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)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %d, %d)\n",
hIMC, dwAction, dwIndex, dwValue);
if (hIMC == NULL)
{
SetLastError(ERROR_SUCCESS);
return FALSE;
}
if (!data || ! data->immKbd->pNotifyIME)
{
return FALSE;
}
return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
}
/***********************************************************************
* ImmRegisterWordA (IMM32.@)
*/
BOOL WINAPI ImmRegisterWordA(
HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
debugstr_a(lpszRegister));
if (immHkl->hIME && immHkl->pImeRegisterWord)
{
if (!is_kbd_ime_unicode(immHkl))
return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
(LPCWSTR)lpszRegister);
else
{
LPWSTR lpszwReading = strdupAtoW(lpszReading);
LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
BOOL rc;
rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
HeapFree(GetProcessHeap(),0,lpszwReading);
HeapFree(GetProcessHeap(),0,lpszwRegister);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmRegisterWordW (IMM32.@)
*/
BOOL WINAPI ImmRegisterWordW(
HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
debugstr_w(lpszRegister));
if (immHkl->hIME && immHkl->pImeRegisterWord)
{
if (is_kbd_ime_unicode(immHkl))
return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
else
{
LPSTR lpszaReading = strdupWtoA(lpszReading);
LPSTR lpszaRegister = strdupWtoA(lpszRegister);
BOOL rc;
rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
(LPCWSTR)lpszaRegister);
HeapFree(GetProcessHeap(),0,lpszaReading);
HeapFree(GetProcessHeap(),0,lpszaRegister);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* 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)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/***********************************************************************
* ImmRequestMessageW(IMM32.@)
*/
LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/***********************************************************************
* ImmSetCandidateWindow (IMM32.@)
*/
BOOL WINAPI ImmSetCandidateWindow(
HIMC hIMC, LPCANDIDATEFORM lpCandidate)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCandidate);
if (!data || !lpCandidate)
return FALSE;
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
TRACE("\t%x, %x, %s, %s\n",
lpCandidate->dwIndex, lpCandidate->dwStyle,
wine_dbgstr_point(&lpCandidate->ptCurrentPos),
wine_dbgstr_rect(&lpCandidate->rcArea));
if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
return FALSE;
data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
return TRUE;
}
/***********************************************************************
* ImmSetCompositionFontA (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lplf);
if (!data || !lplf)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
LF_FACESIZE);
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
return TRUE;
}
/***********************************************************************
* ImmSetCompositionFontW (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lplf);
if (!data || !lplf)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
data->IMC.lfFont.W = *lplf;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
return TRUE;
}
/***********************************************************************
* ImmSetCompositionStringA (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionStringA(
HIMC hIMC, DWORD dwIndex,
LPCVOID lpComp, DWORD dwCompLen,
LPCVOID lpRead, DWORD dwReadLen)
{
DWORD comp_len;
DWORD read_len;
WCHAR *CompBuffer = NULL;
WCHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
if (!data)
return FALSE;
if (!(dwIndex == SCS_SETSTR ||
dwIndex == SCS_CHANGEATTR ||
dwIndex == SCS_CHANGECLAUSE ||
dwIndex == SCS_SETRECONVERTSTRING ||
dwIndex == SCS_QUERYRECONVERTSTRING))
return FALSE;
if (!is_himc_ime_unicode(data))
return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
dwCompLen, lpRead, dwReadLen);
comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
if (comp_len)
{
CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
}
read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
if (read_len)
{
ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
}
rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
ReadBuffer, read_len);
HeapFree(GetProcessHeap(), 0, CompBuffer);
HeapFree(GetProcessHeap(), 0, ReadBuffer);
return rc;
}
/***********************************************************************
* ImmSetCompositionStringW (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionStringW(
HIMC hIMC, DWORD dwIndex,
LPCVOID lpComp, DWORD dwCompLen,
LPCVOID lpRead, DWORD dwReadLen)
{
DWORD comp_len;
DWORD read_len;
CHAR *CompBuffer = NULL;
CHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
if (!data)
return FALSE;
if (!(dwIndex == SCS_SETSTR ||
dwIndex == SCS_CHANGEATTR ||
dwIndex == SCS_CHANGECLAUSE ||
dwIndex == SCS_SETRECONVERTSTRING ||
dwIndex == SCS_QUERYRECONVERTSTRING))
return FALSE;
if (is_himc_ime_unicode(data))
return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
dwCompLen, lpRead, dwReadLen);
comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
NULL);
if (comp_len)
{
CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
NULL, NULL);
}
read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
NULL);
if (read_len)
{
ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
NULL, NULL);
}
rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
ReadBuffer, read_len);
HeapFree(GetProcessHeap(), 0, CompBuffer);
HeapFree(GetProcessHeap(), 0, ReadBuffer);
return rc;
}
/***********************************************************************
* ImmSetCompositionWindow (IMM32.@)
*/
BOOL WINAPI ImmSetCompositionWindow(
HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
{
BOOL reshow = FALSE;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCompForm);
if (lpCompForm)
TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
wine_dbgstr_point(&lpCompForm->ptCurrentPos),
wine_dbgstr_rect(&lpCompForm->rcArea));
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
data->IMC.cfCompForm = *lpCompForm;
if (IsWindowVisible(data->immKbd->UIWnd))
{
reshow = TRUE;
ShowWindow(data->immKbd->UIWnd,SW_HIDE);
}
/* FIXME: this is a partial stub */
if (reshow)
ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
return TRUE;
}
/***********************************************************************
* ImmSetConversionStatus (IMM32.@)
*/
BOOL WINAPI ImmSetConversionStatus(
HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
{
DWORD oldConversion, oldSentence;
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
if ( fdwConversion != data->IMC.fdwConversion )
{
oldConversion = data->IMC.fdwConversion;
data->IMC.fdwConversion = fdwConversion;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
}
if ( fdwSentence != data->IMC.fdwSentence )
{
oldSentence = data->IMC.fdwSentence;
data->IMC.fdwSentence = fdwSentence;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
}
return TRUE;
}
/***********************************************************************
* ImmSetOpenStatus (IMM32.@)
*/
BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %d\n", hIMC, fOpen);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
if (data->immKbd->UIWnd == NULL)
{
/* create the ime window */
data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
0, data->immKbd->hIME, 0);
SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
}
else if (fOpen)
SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
if (!fOpen != !data->IMC.fOpen)
{
data->IMC.fOpen = fOpen;
ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
}
return TRUE;
}
/***********************************************************************
* ImmSetStatusWindowPos (IMM32.@)
*/
BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpptPos);
if (!data || !lpptPos)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (IMM_IsCrossThreadAccess(NULL, hIMC))
return FALSE;
TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
data->IMC.ptStatusWndPos = *lpptPos;
ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
return TRUE;
}
/***********************************************************************
* ImmCreateSoftKeyboard(IMM32.@)
*/
HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
{
FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/***********************************************************************
* ImmDestroySoftKeyboard(IMM32.@)
*/
BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
{
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, %d): stub\n", hWnd, dwHotKeyID);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* ImmUnregisterWordA (IMM32.@)
*/
BOOL WINAPI ImmUnregisterWordA(
HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
debugstr_a(lpszUnregister));
if (immHkl->hIME && immHkl->pImeUnregisterWord)
{
if (!is_kbd_ime_unicode(immHkl))
return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
(LPCWSTR)lpszUnregister);
else
{
LPWSTR lpszwReading = strdupAtoW(lpszReading);
LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
BOOL rc;
rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
HeapFree(GetProcessHeap(),0,lpszwReading);
HeapFree(GetProcessHeap(),0,lpszwUnregister);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmUnregisterWordW (IMM32.@)
*/
BOOL WINAPI ImmUnregisterWordW(
HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
{
ImmHkl *immHkl = IMM_GetImmHkl(hKL);
TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
debugstr_w(lpszUnregister));
if (immHkl->hIME && immHkl->pImeUnregisterWord)
{
if (is_kbd_ime_unicode(immHkl))
return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
else
{
LPSTR lpszaReading = strdupWtoA(lpszReading);
LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
BOOL rc;
rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
(LPCWSTR)lpszaUnregister);
HeapFree(GetProcessHeap(),0,lpszaReading);
HeapFree(GetProcessHeap(),0,lpszaUnregister);
return rc;
}
}
else
return FALSE;
}
/***********************************************************************
* ImmGetImeMenuItemsA (IMM32.@)
*/
DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
DWORD dwSize)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
{
if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
(IMEMENUITEMINFOW*)lpImeParentMenu,
(IMEMENUITEMINFOW*)lpImeMenu, dwSize);
else
{
IMEMENUITEMINFOW lpImeParentMenuW;
IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
DWORD rc;
if (lpImeParentMenu)
parent = &lpImeParentMenuW;
if (lpImeMenu)
{
int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
dwSize = count * sizeof(IMEMENUITEMINFOW);
lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
}
else
lpImeMenuW = NULL;
rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
parent, lpImeMenuW, dwSize);
if (lpImeParentMenu)
{
memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
-1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
NULL, NULL);
}
if (lpImeMenu && rc)
{
unsigned int i;
for (i = 0; i < rc; i++)
{
memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
-1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
NULL, NULL);
}
}
HeapFree(GetProcessHeap(),0,lpImeMenuW);
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmGetImeMenuItemsW (IMM32.@)
*/
DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
DWORD dwSize)
{
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
{
if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
lpImeParentMenu, lpImeMenu, dwSize);
else
{
IMEMENUITEMINFOA lpImeParentMenuA;
IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
DWORD rc;
if (lpImeParentMenu)
parent = &lpImeParentMenuA;
if (lpImeMenu)
{
int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
dwSize = count * sizeof(IMEMENUITEMINFOA);
lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
}
else
lpImeMenuA = NULL;
rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
(IMEMENUITEMINFOW*)parent,
(IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
if (lpImeParentMenu)
{
memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
-1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
}
if (lpImeMenu && rc)
{
unsigned int i;
for (i = 0; i < rc; i++)
{
memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
-1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
}
}
HeapFree(GetProcessHeap(),0,lpImeMenuA);
return rc;
}
}
else
return 0;
}
/***********************************************************************
* ImmLockIMC(IMM32.@)
*/
LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
if (!data)
return NULL;
data->dwLock++;
return &data->IMC;
}
/***********************************************************************
* ImmUnlockIMC(IMM32.@)
*/
BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
{
InputContextData *data = get_imc_data(hIMC);
if (!data)
return FALSE;
if (data->dwLock)
data->dwLock--;
return TRUE;
}
/***********************************************************************
* ImmGetIMCLockCount(IMM32.@)
*/
DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
{
InputContextData *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)
{
InputContextData *data = get_imc_data(hIMC);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
if (data->IMC.dwNumMsgBuf > 0)
{
LPTRANSMSG lpTransMsg;
HIMCC hMsgBuf;
DWORD i, dwNumMsgBuf;
/* We are going to detach our hMsgBuff so that if processing messages
generates new messages they go into a new buffer */
hMsgBuf = data->IMC.hMsgBuf;
dwNumMsgBuf = data->IMC.dwNumMsgBuf;
data->IMC.hMsgBuf = ImmCreateIMCC(0);
data->IMC.dwNumMsgBuf = 0;
lpTransMsg = ImmLockIMCC(hMsgBuf);
for (i = 0; i < dwNumMsgBuf; i++)
ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
ImmUnlockIMCC(hMsgBuf);
ImmDestroyIMCC(hMsgBuf);
}
return TRUE;
}
/***********************************************************************
* ImmTranslateMessage(IMM32.@)
* ( Undocumented, call internally and from user32.dll )
*/
BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
{
InputContextData *data;
HIMC imc = ImmGetContext(hwnd);
BYTE state[256];
UINT scancode;
LPVOID list = 0;
UINT msg_count;
UINT uVirtKey;
static const DWORD list_count = 10;
TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
if (imc)
data = imc;
else
return FALSE;
if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx || data->lastVK == VK_PROCESSKEY)
return FALSE;
GetKeyboardState(state);
scancode = lKeyData >> 0x10 & 0xff;
list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
((DWORD*)list)[0] = list_count;
if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
{
WCHAR chr;
if (!is_himc_ime_unicode(data))
ToAscii(data->lastVK, scancode, state, &chr, 0);
else
ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
uVirtKey = MAKELONG(data->lastVK,chr);
}
else
uVirtKey = data->lastVK;
msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
TRACE("%i messages generated\n",msg_count);
if (msg_count && msg_count <= list_count)
{
UINT i;
LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
for (i = 0; i < msg_count; i++)
ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
}
else if (msg_count > list_count)
ImmGenerateMessage(imc);
HeapFree(GetProcessHeap(),0,list);
data->lastVK = VK_PROCESSKEY;
return (msg_count > 0);
}
/***********************************************************************
* ImmProcessKey(IMM32.@)
* ( Undocumented, called from user32.dll )
*/
BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
{
InputContextData *data;
HIMC imc = ImmGetContext(hwnd);
BYTE state[256];
TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
if (imc)
data = imc;
else
return FALSE;
/* Make sure we are inputting to the correct keyboard */
if (data->immKbd->hkl != hKL)
{
ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
if (new_hkl)
{
data->immKbd->pImeSelect(imc, FALSE);
data->immKbd->uSelected--;
data->immKbd = new_hkl;
data->immKbd->pImeSelect(imc, TRUE);
data->immKbd->uSelected++;
}
else
return FALSE;
}
if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
return FALSE;
GetKeyboardState(state);
if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
{
data->lastVK = vKey;
return TRUE;
}
data->lastVK = VK_PROCESSKEY;
return FALSE;
}
/***********************************************************************
* ImmDisableTextFrameService(IMM32.@)
*/
BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
{
FIXME("Stub\n");
return FALSE;
}
/***********************************************************************
* ImmEnumInputContext(IMM32.@)
*/
BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
{
FIXME("Stub\n");
return FALSE;
}
/***********************************************************************
* ImmGetHotKey(IMM32.@)
*/
BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
{
FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
return FALSE;
}
/***********************************************************************
* ImmDisableLegacyIME(IMM32.@)
*/
BOOL WINAPI ImmDisableLegacyIME(void)
{
FIXME("stub\n");
return TRUE;
}