| /* |
| * 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 <stdarg.h> |
| #include <stdio.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" |
| #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; |
| BOOL disableIME; |
| DWORD windowRefs; |
| } IMMThreadData; |
| |
| static struct list ImmHklList = LIST_INIT(ImmHklList); |
| static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); |
| |
| static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; |
| |
| static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0}; |
| static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0}; |
| static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0}; |
| |
| static const WCHAR szwIME[] = {'I','M','E',0}; |
| static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0}; |
| |
| static CRITICAL_SECTION threaddata_cs; |
| static CRITICAL_SECTION_DEBUG critsect_debug = |
| { |
| 0, 0, &threaddata_cs, |
| { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, |
| 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") } |
| }; |
| static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; |
| static BOOL disable_ime; |
| |
| #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(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->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); |
| 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); |
| } |
| |
| /* 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; |
| } |
| |
| /*********************************************************************** |
| * ImmAssociateContext (IMM32.@) |
| */ |
| HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) |
| { |
| HIMC old = NULL; |
| InputContextData *data = get_imc_data(hIMC); |
| |
| TRACE("(%p, %p):\n", hWnd, hIMC); |
| |
| if(hIMC && !data) |
| return NULL; |
| |
| /* |
| * If already associated just return |
| */ |
| if (hIMC && data->IMC.hWnd == hWnd) |
| return hIMC; |
| |
| if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) |
| return NULL; |
| |
| if (hWnd) |
| { |
| HIMC defaultContext = get_default_context( hWnd ); |
| old = RemovePropW(hWnd,szwWineIMCProperty); |
| |
| if (old == NULL) |
| old = defaultContext; |
| else if (old == (HIMC)-1) |
| old = NULL; |
| |
| if (hIMC != defaultContext) |
| { |
| if (hIMC == NULL) /* Meaning disable imm for that window*/ |
| SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); |
| else |
| SetPropW(hWnd,szwWineIMCProperty,hIMC); |
| } |
| |
| if (old) |
| { |
| InputContextData *old_data = old; |
| if (old_data->IMC.hWnd == hWnd) |
| old_data->IMC.hWnd = NULL; |
| } |
| } |
| |
| if (!hIMC) |
| return old; |
| |
| SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL); |
| data->IMC.hWnd = hWnd; |
| SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL); |
| |
| return old; |
| } |
| |
| |
| /* |
| * Helper function for ImmAssociateContextEx |
| */ |
| static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) |
| { |
| HIMC hImc = (HIMC)lParam; |
| ImmAssociateContext(hwnd,hImc); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * ImmAssociateContextEx (IMM32.@) |
| */ |
| BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) |
| { |
| TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); |
| |
| if (!hWnd) |
| return FALSE; |
| |
| switch (dwFlags) |
| { |
| case 0: |
| ImmAssociateContext(hWnd,hIMC); |
| return TRUE; |
| case IACE_DEFAULT: |
| { |
| HIMC defaultContext = get_default_context( hWnd ); |
| if (!defaultContext) return FALSE; |
| ImmAssociateContext(hWnd,defaultContext); |
| return TRUE; |
| } |
| case IACE_IGNORENOCONTEXT: |
| if (GetPropW(hWnd,szwWineIMCProperty)) |
| ImmAssociateContext(hWnd,hIMC); |
| return TRUE; |
| case IACE_CHILDREN: |
| EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC); |
| return TRUE; |
| default: |
| FIXME("Unknown dwFlags 0x%x\n",dwFlags); |
| return FALSE; |
| } |
| } |
| |
| /*********************************************************************** |
| * ImmConfigureIMEA (IMM32.@) |
| */ |
| BOOL WINAPI ImmConfigureIMEA( |
| HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) |
| { |
| ImmHkl *immHkl = IMM_GetImmHkl(hKL); |
| |
| TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); |
| |
| if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) |
| return FALSE; |
| |
| if (immHkl->hIME && immHkl->pImeConfigure) |
| { |
| if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl)) |
| return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); |
| else |
| { |
| REGISTERWORDW rww; |
| REGISTERWORDA *rwa = lpData; |
| BOOL rc; |
| |
| rww.lpReading = strdupAtoW(rwa->lpReading); |
| rww.lpWord = strdupAtoW(rwa->lpWord); |
| rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww); |
| HeapFree(GetProcessHeap(),0,rww.lpReading); |
| HeapFree(GetProcessHeap(),0,rww.lpWord); |
| return rc; |
| } |
| } |
| else |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * ImmConfigureIMEW (IMM32.@) |
| */ |
| BOOL WINAPI ImmConfigureIMEW( |
| HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) |
| { |
| ImmHkl *immHkl = IMM_GetImmHkl(hKL); |
| |
| TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); |
| |
| if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) |
| return FALSE; |
| |
| if (immHkl->hIME && immHkl->pImeConfigure) |
| { |
| if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl)) |
| return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); |
| else |
| { |
| REGISTERWORDW *rww = lpData; |
| REGISTERWORDA rwa; |
| BOOL rc; |
| |
| rwa.lpReading = strdupWtoA(rww->lpReading); |
| rwa.lpWord = strdupWtoA(rww->lpWord); |
| rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa); |
| HeapFree(GetProcessHeap(),0,rwa.lpReading); |
| HeapFree(GetProcessHeap(),0,rwa.lpWord); |
| return rc; |
| } |
| } |
| else |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * ImmCreateContext (IMM32.@) |
| */ |
| HIMC WINAPI ImmCreateContext(void) |
| { |
| 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)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; |
| } |
| |
| /*********************************************************************** |
| * ImmDisableIME (IMM32.@) |
| */ |
| BOOL WINAPI ImmDisableIME(DWORD idThread) |
| { |
| if (idThread == (DWORD)-1) |
| disable_ime = TRUE; |
| else { |
| IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread); |
| if (!thread_data) return FALSE; |
| thread_data->disableIME = TRUE; |
| LeaveCriticalSection(&threaddata_cs); |
| } |
| 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; |
| |
| 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, sizeof(classW)/sizeof(classW[0])) && |
| !strcmpW(classW, szwIME)) |
| 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, szwIME, szwDefaultIME, |
| 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 && thread_data->hwndDefault) |
| { |
| to_destroy = thread_data->hwndDefault; |
| thread_data->hwndDefault = NULL; |
| } |
| 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 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) 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 >= (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; |
| } |
| |
| 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) |
| 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; |
| } |