/* * 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 #include #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; }