/* * 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 */ #include #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "winerror.h" #include "wine/debug.h" #include "imm.h" #include "ddk/imm.h" #include "winnls.h" #include "winreg.h" #include "wine/list.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); #define IMM_INIT_MAGIC 0x19650412 BOOL WINAPI User32InitializeImmEntryTable(DWORD); #define MAKE_FUNCPTR(f) typeof(f) * p##f typedef struct _tagImmHkl{ struct list entry; HKL hkl; HMODULE hIME; IMEINFO imeInfo; WCHAR imeClassName[17]; /* 16 character max */ ULONG uSelected; HWND UIWnd; /* Function Pointers */ MAKE_FUNCPTR(ImeInquire); MAKE_FUNCPTR(ImeConfigure); MAKE_FUNCPTR(ImeDestroy); MAKE_FUNCPTR(ImeEscape); MAKE_FUNCPTR(ImeSelect); MAKE_FUNCPTR(ImeSetActiveContext); MAKE_FUNCPTR(ImeToAsciiEx); MAKE_FUNCPTR(NotifyIME); MAKE_FUNCPTR(ImeRegisterWord); MAKE_FUNCPTR(ImeUnregisterWord); MAKE_FUNCPTR(ImeEnumRegisterWord); MAKE_FUNCPTR(ImeSetCompositionString); MAKE_FUNCPTR(ImeConversionList); MAKE_FUNCPTR(ImeProcessKey); MAKE_FUNCPTR(ImeGetRegisterWordStyle); MAKE_FUNCPTR(ImeGetImeMenuItems); } ImmHkl; #undef MAKE_FUNCPTR 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; } IMMThreadData; static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0}; static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0}; static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0}; static const WCHAR szwIME[] = {'I','M','E',0}; static 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 }; #define is_himc_ime_unicode(p) (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE) #define is_kbd_ime_unicode(p) (p->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 IMMThreadData* IMM_GetThreadData(DWORD id) { IMMThreadData *data; if (!id) id = GetCurrentThreadId(); EnterCriticalSection(&threaddata_cs); LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) { if (data->threadID == id) return data; } data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMMThreadData)); data->threadID = id; list_add_head(&ImmThreadDataList,&data->entry); TRACE("Thread Data Created (%x)\n",id); return data; } static IMMThreadData* IMM_GetThreadDataForWindow(HWND hwnd) { DWORD process; DWORD thread = 0; if (hwnd) { thread = GetWindowThreadProcessId(hwnd, &process); if (process != GetCurrentProcessId()) return NULL; } return IMM_GetThreadData(thread); } 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); DestroyWindow(data->hwndDefault); HeapFree(GetProcessHeap(),0,data); TRACE("Thread Data Destroyed\n"); return; } } LeaveCriticalSection(&threaddata_cs); } static HMODULE load_graphics_driver(void) { static const WCHAR display_device_guid_propW[] = { '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_', 'd','e','v','i','c','e','_','g','u','i','d',0 }; static const WCHAR key_pathW[] = { 'S','y','s','t','e','m','\\', 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'C','o','n','t','r','o','l','\\', 'V','i','d','e','o','\\','{',0}; static const WCHAR displayW[] = {'}','\\','0','0','0','0',0}; static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0}; HMODULE ret = 0; HKEY hkey; DWORD size; WCHAR path[MAX_PATH]; WCHAR key[(sizeof(key_pathW) + sizeof(displayW)) / sizeof(WCHAR) + 40]; UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW )); if (!guid_atom) return 0; memcpy( key, key_pathW, sizeof(key_pathW) ); if (!GlobalGetAtomNameW( guid_atom, key + strlenW(key), 40 )) return 0; strcatW( key, displayW ); if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0; size = sizeof(path); if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path ); RegCloseKey( hkey ); TRACE( "%s %p\n", debugstr_w(path), ret ); return ret; } /* ImmHkl loading and freeing */ #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} static ImmHkl *IMM_GetImmHkl(HKL hkl) { ImmHkl *ptr; WCHAR filename[MAX_PATH]; TRACE("Seeking ime for keyboard %p\n",hkl); LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry) { if (ptr->hkl == hkl) return ptr; } /* not found... create it */ ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl)); ptr->hkl = hkl; if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); if (!ptr->hIME) ptr->hIME = load_graphics_driver(); if (ptr->hIME) { LOAD_FUNCPTR(ImeInquire); if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL)) { FreeLibrary(ptr->hIME); ptr->hIME = NULL; } else { LOAD_FUNCPTR(ImeDestroy); LOAD_FUNCPTR(ImeSelect); if (!ptr->pImeSelect || !ptr->pImeDestroy) { FreeLibrary(ptr->hIME); ptr->hIME = NULL; } else { LOAD_FUNCPTR(ImeConfigure); LOAD_FUNCPTR(ImeEscape); LOAD_FUNCPTR(ImeSetActiveContext); LOAD_FUNCPTR(ImeToAsciiEx); LOAD_FUNCPTR(NotifyIME); LOAD_FUNCPTR(ImeRegisterWord); LOAD_FUNCPTR(ImeUnregisterWord); LOAD_FUNCPTR(ImeEnumRegisterWord); LOAD_FUNCPTR(ImeSetCompositionString); LOAD_FUNCPTR(ImeConversionList); LOAD_FUNCPTR(ImeProcessKey); LOAD_FUNCPTR(ImeGetRegisterWordStyle); LOAD_FUNCPTR(ImeGetImeMenuItems); /* make sure our classname is WCHAR */ if (!is_kbd_ime_unicode(ptr)) { WCHAR bufW[17]; MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName, -1, bufW, 17); lstrcpyW(ptr->imeClassName, bufW); } } } } list_add_head(&ImmHklList,&ptr->entry); return ptr; } #undef LOAD_FUNCPTR 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); } 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 IMMThreadData* IMM_GetInitializedThreadData(HWND hWnd) { IMMThreadData* thread_data = IMM_GetThreadDataForWindow(hWnd); if (!thread_data) return NULL; if (!thread_data->defaultContext && thread_data->threadID == GetCurrentThreadId()) { HIMC defaultContext; LeaveCriticalSection(&threaddata_cs); defaultContext = ImmCreateContext(); if (defaultContext) ((InputContextData*)defaultContext)->threadDefault = TRUE; thread_data = IMM_GetThreadDataForWindow(hWnd); if (!thread_data) { IMM_DestroyContext(defaultContext); return NULL; } if (thread_data->defaultContext) /* someone beat us */ IMM_DestroyContext(defaultContext); else thread_data->defaultContext = defaultContext; } return thread_data; } static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) { InputContextData *data; if (hWnd) { DWORD thread = GetWindowThreadProcessId(hWnd, NULL); if (thread != GetCurrentThreadId()) return TRUE; } data = get_imc_data(hIMC); if (data && data->threadID != GetCurrentThreadId()) return TRUE; return FALSE; } /*********************************************************************** * ImmAssociateContext (IMM32.@) */ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) { HIMC old = NULL; InputContextData *data = get_imc_data(hIMC); IMMThreadData* thread_data = NULL; TRACE("(%p, %p):\n", hWnd, hIMC); if(hIMC && !data) return NULL; /* * If already associated just return */ if (hIMC && data->IMC.hWnd == hWnd) return hIMC; if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) return NULL; thread_data = IMM_GetInitializedThreadData(hWnd); if (!thread_data) return NULL; if (hWnd) { old = RemovePropW(hWnd,szwWineIMCProperty); if (old == NULL) old = thread_data->defaultContext; else if (old == (HIMC)-1) old = NULL; if (hIMC != thread_data->defaultContext) { if (hIMC == NULL) /* Meaning disable imm for that window*/ SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); else SetPropW(hWnd,szwWineIMCProperty,hIMC); } if (old) { InputContextData *old_data = old; if (old_data->IMC.hWnd == hWnd) old_data->IMC.hWnd = NULL; } } LeaveCriticalSection(&threaddata_cs); if (!hIMC) return old; if (IsWindow(data->IMC.hWnd)) { /* * Post a message that your context is switching */ SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL); } data->IMC.hWnd = hWnd; if (IsWindow(data->IMC.hWnd)) { /* * Post a message that your context is switching */ SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL); } return old; } /* * Helper function for ImmAssociateContextEx */ static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) { HIMC hImc = (HIMC)lParam; ImmAssociateContext(hwnd,hImc); return TRUE; } /*********************************************************************** * ImmAssociateContextEx (IMM32.@) */ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) { IMMThreadData* thread_data = NULL; HIMC defaultContext = NULL; TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); thread_data = IMM_GetInitializedThreadData(hWnd); if (!thread_data) return FALSE; defaultContext = thread_data->defaultContext; LeaveCriticalSection(&threaddata_cs); if (!hWnd) return FALSE; switch (dwFlags) { case 0: ImmAssociateContext(hWnd,hIMC); return TRUE; case IACE_DEFAULT: 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 < sizeof(new_context->IMC.cfCandForm) / sizeof(CANDIDATEFORM); 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)GetKeyboardLayout(0)); 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)GetKeyboardLayout(0)); 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; } /*********************************************************************** * ImmDisableIME (IMM32.@) */ BOOL WINAPI ImmDisableIME(DWORD idThread) { FIXME("(%d): stub\n", idThread); 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 >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) ) 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 >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) ) 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 >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) ) 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 */ static INT CopyCompStringIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE target, INT tlen, BOOL unicode ) { INT rc; if (is_himc_ime_unicode(data) && !unicode) rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)source, slen, (LPSTR)target, tlen, NULL, NULL); else if (!is_himc_ime_unicode(data) && unicode) rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)source, slen, (LPWSTR)target, tlen) * sizeof(WCHAR); else { int dlen = (unicode)?sizeof(WCHAR):sizeof(CHAR); memcpy( target, source, min(slen,tlen)*dlen); rc = slen*dlen; } return rc; } static INT CopyCompAttrIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, INT sslen, LPBYTE target, INT tlen, BOOL unicode ) { INT rc; if (is_himc_ime_unicode(data) && !unicode) { rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, sslen, NULL, 0, NULL, NULL); if (tlen) { const BYTE *src = source; LPBYTE dst = target; int i, j = 0, k = 0; if (rc < tlen) tlen = rc; for (i = 0; i < sslen; ++i) { int len; len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)ssource + i, 1, NULL, 0, NULL, NULL); for (; len > 0; --len) { dst[j++] = src[k]; if (j >= tlen) goto end; } ++k; } end: rc = j; } } else if (!is_himc_ime_unicode(data) && unicode) { rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, sslen, NULL, 0); if (tlen) { const BYTE *src = source; LPBYTE dst = target; int i, j = 0; if (rc < tlen) tlen = rc; for (i = 0; i < sslen; ++i) { if (IsDBCSLeadByte(((LPSTR)ssource)[i])) continue; dst[j++] = src[i]; if (j >= tlen) break; } rc = j; } } else { memcpy( target, source, min(slen,tlen)); rc = slen; } 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; IMMThreadData* thread_data; TRACE("%p\n", hWnd); if (!IsWindow(hWnd)) { SetLastError(ERROR_INVALID_WINDOW_HANDLE); return NULL; } thread_data = IMM_GetInitializedThreadData(hWnd); if (!thread_data) return NULL; rc = GetPropW(hWnd,szwWineIMCProperty); if (rc == (HIMC)-1) rc = NULL; else if (rc == NULL) rc = thread_data->defaultContext; if (rc) { InputContextData *data = rc; data->IMC.hWnd = hWnd; } LeaveCriticalSection(&threaddata_cs); 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; } /*********************************************************************** * ImmGetDefaultIMEWnd (IMM32.@) */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { HWND ret, new = NULL; IMMThreadData* thread_data = IMM_GetThreadDataForWindow(hWnd); if (!thread_data) return NULL; if (thread_data->hwndDefault == NULL && thread_data->threadID == GetCurrentThreadId()) { /* Do not create the window inside of a critical section */ LeaveCriticalSection(&threaddata_cs); new = CreateWindowExW( WS_EX_TOOLWINDOW, szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0); thread_data = IMM_GetThreadDataForWindow(hWnd); if (!thread_data) { DestroyWindow(new); return NULL; } /* See if anyone beat us */ if (thread_data->hwndDefault == NULL) { thread_data->hwndDefault = new; new = NULL; } } ret = thread_data->hwndDefault; LeaveCriticalSection(&threaddata_cs); TRACE("Default is %p\n",ret); /* Clean up an unused new window outside of the critical section */ if (new != NULL) { DestroyWindow(new); } 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 ASCII */ 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) { static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 }; FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen); if (!hKL) return 0; if (!uBufLen) return lstrlenW( name ); lstrcpynW( lpszDescription, name, 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[sizeof(szImeRegFmt)/sizeof(WCHAR)+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, szImeFileW, 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, szImeFileW, 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[sizeof(szImeRegFmt)/sizeof(WCHAR)+8]; TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)); /* Start with 2. e001 will be blank and so default to the wine internal IME */ count = 2; while (count < 0xfff) { DWORD disposition = 0; hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl); rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) break; else if (rc == ERROR_SUCCESS) RegCloseKey(hkey); count++; } if (count == 0xfff) { WARN("Unable to find slot to install IME\n"); return 0; } if (rc == ERROR_SUCCESS) { rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName, (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText, (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR)); RegCloseKey(hkey); return hkl; } else { WARN("Unable to set IME registry values\n"); return 0; } } /*********************************************************************** * ImmIsIME (IMM32.@) */ BOOL WINAPI ImmIsIME(HKL hKL) { 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) SetLastError(ERROR_INVALID_HANDLE); if (data && IsWindow(data->IMC.hWnd)) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 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) SetLastError(ERROR_INVALID_HANDLE); if (data && IsWindow(data->IMC.hWnd)) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 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; TRACE("\t%x, %x, (%i,%i), (%i,%i - %i,%i)\n", lpCandidate->dwIndex, lpCandidate->dwStyle, lpCandidate->ptCurrentPos.x, lpCandidate->ptCurrentPos.y, lpCandidate->rcArea.top, lpCandidate->rcArea.left, lpCandidate->rcArea.bottom, lpCandidate->rcArea.right); if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) ) 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; } 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; } 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); TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle, lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top, lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right); if (!data) { SetLastError(ERROR_INVALID_HANDLE); 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 ( 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 (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; } TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y); 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; DWORD i; lpTransMsg = ImmLockIMCC(data->IMC.hMsgBuf); for (i = 0; i < data->IMC.dwNumMsgBuf; i++) ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam); ImmUnlockIMCC(data->IMC.hMsgBuf); data->IMC.dwNumMsgBuf = 0; } 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) 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; }