/* * 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 "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" WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_IME 0xcafe1337 static void (*pX11DRV_ForceXIMReset)(HWND); typedef struct tagIMCCInternal { DWORD dwLock; DWORD dwSize; } IMCCInternal; typedef struct tagInputContextData { BOOL bInternalState; BOOL bRead; BOOL bInComposition; HFONT textfont; DWORD dwLock; INPUTCONTEXT IMC; } InputContextData; static InputContextData *root_context = NULL; static HWND hwndDefault = NULL; static HANDLE hImeInst; static const WCHAR WC_IMECLASSNAME[] = {'I','M','E',0}; static ATOM atIMEClass = 0; /* MSIME messages */ static UINT WM_MSIME_SERVICE; static UINT WM_MSIME_RECONVERTOPTIONS; static UINT WM_MSIME_MOUSE; static UINT WM_MSIME_RECONVERTREQUEST; static UINT WM_MSIME_RECONVERT; static UINT WM_MSIME_QUERYPOSITION; static UINT WM_MSIME_DOCUMENTFEED; /* * prototypes */ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable); static void ImmInternalPostIMEMessage(UINT, WPARAM, LPARAM); static void ImmInternalSetOpenStatus(BOOL fOpen); static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len); static VOID IMM_PostResult(InputContextData *data) { unsigned int i; LPCOMPOSITIONSTRING compstr; LPBYTE compdata; LPWSTR ResultStr; HIMCC newCompStr; TRACE("Posting result as IME_CHAR\n"); compdata = ImmLockIMCC(root_context->IMC.hCompStr); compstr = (LPCOMPOSITIONSTRING)compdata; ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset); for (i = 0; i < compstr->dwResultStrLen; i++) ImmInternalPostIMEMessage (WM_IME_CHAR, ResultStr[i], 1); ImmUnlockIMCC(root_context->IMC.hCompStr); /* clear the buffer */ newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; } static void IMM_Register(void) { WNDCLASSW wndClass; ZeroMemory(&wndClass, sizeof(WNDCLASSW)); wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hImeInst; wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); wndClass.hIcon = NULL; wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1); wndClass.lpszMenuName = 0; wndClass.lpszClassName = WC_IMECLASSNAME; atIMEClass = RegisterClassW(&wndClass); } static void IMM_Unregister(void) { if (atIMEClass) { UnregisterClassW(WC_IMECLASSNAME, NULL); } } static void IMM_RegisterMessages(void) { WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); } BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) { HMODULE x11drv; TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved); switch (fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); hImeInst = hInstDLL; IMM_RegisterMessages(); x11drv = GetModuleHandleA("winex11.drv"); if (x11drv) pX11DRV_ForceXIMReset = (void *)GetProcAddress( x11drv, "ForceXIMReset"); break; case DLL_PROCESS_DETACH: if (hwndDefault) { DestroyWindow(hwndDefault); hwndDefault = 0; } IMM_Unregister(); break; } return TRUE; } /* for posting messages as the IME */ static void ImmInternalPostIMEMessage(UINT msg, WPARAM wParam, LPARAM lParam) { HWND target = GetFocus(); if (!target) PostMessageW(root_context->IMC.hWnd,msg,wParam,lParam); else PostMessageW(target, msg, wParam, lParam); } static LRESULT ImmInternalSendIMENotify(WPARAM notify, LPARAM lParam) { HWND target; target = root_context->IMC.hWnd; if (!target) target = GetFocus(); if (target) return SendMessageW(target, WM_IME_NOTIFY, notify, lParam); return 0; } static void ImmInternalSetOpenStatus(BOOL fOpen) { TRACE("Setting internal state to %s\n",(fOpen)?"OPEN":"CLOSED"); if (root_context->IMC.fOpen && fOpen == FALSE) { ShowWindow(hwndDefault,SW_HIDE); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = NULL; } root_context->IMC.fOpen = fOpen; root_context->bInternalState = fOpen; ImmInternalSendIMENotify(IMN_SETOPENSTATUS, 0); } static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, LPBYTE target, LPBYTE source, DWORD* lenParam, DWORD* offsetParam, BOOL wchars ) { if (origLen > 0 && origOffset > 0) { int truelen = origLen; if (wchars) truelen *= sizeof(WCHAR); memcpy(&target[currentOffset], &source[origOffset], truelen); *lenParam = origLen; *offsetParam = currentOffset; currentOffset += truelen; } return currentOffset; } static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len) { /* we need to make sure the CompStr, CompClaus and CompAttr fields are all * set and correct */ int needed_size; HIMCC rc; LPBYTE newdata = NULL; LPBYTE olddata = NULL; LPCOMPOSITIONSTRING new_one; LPCOMPOSITIONSTRING lpcs = NULL; INT current_offset = 0; TRACE("%s, %i\n",debugstr_wn(compstr,len),len); if (old == NULL && compstr == NULL && len == 0) return NULL; if (old != NULL) { olddata = ImmLockIMCC(old); lpcs = (LPCOMPOSITIONSTRING)olddata; } needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + len + sizeof(DWORD) * 2; if (lpcs != NULL) { needed_size += lpcs->dwCompReadAttrLen; needed_size += lpcs->dwCompReadClauseLen; needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD); needed_size += lpcs->dwResultReadClauseLen; needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD); needed_size += lpcs->dwResultClauseLen; needed_size += lpcs->dwResultStrLen * sizeof(DWORD); needed_size += lpcs->dwPrivateSize; } rc = ImmCreateIMCC(needed_size); newdata = ImmLockIMCC(rc); new_one = (LPCOMPOSITIONSTRING)newdata; new_one->dwSize = needed_size; current_offset = sizeof(COMPOSITIONSTRING); if (lpcs != NULL) { current_offset = updateField(lpcs->dwCompReadAttrLen, lpcs->dwCompReadAttrOffset, current_offset, newdata, olddata, &new_one->dwCompReadAttrLen, &new_one->dwCompReadAttrOffset, FALSE); current_offset = updateField(lpcs->dwCompReadClauseLen, lpcs->dwCompReadClauseOffset, current_offset, newdata, olddata, &new_one->dwCompReadClauseLen, &new_one->dwCompReadClauseOffset, FALSE); current_offset = updateField(lpcs->dwCompReadStrLen, lpcs->dwCompReadStrOffset, current_offset, newdata, olddata, &new_one->dwCompReadStrLen, &new_one->dwCompReadStrOffset, TRUE); /* new CompAttr, CompClause, CompStr, dwCursorPos */ new_one->dwDeltaStart = 0; current_offset = updateField(lpcs->dwResultReadClauseLen, lpcs->dwResultReadClauseOffset, current_offset, newdata, olddata, &new_one->dwResultReadClauseLen, &new_one->dwResultReadClauseOffset, FALSE); current_offset = updateField(lpcs->dwResultReadStrLen, lpcs->dwResultReadStrOffset, current_offset, newdata, olddata, &new_one->dwResultReadStrLen, &new_one->dwResultReadStrOffset, TRUE); current_offset = updateField(lpcs->dwResultClauseLen, lpcs->dwResultClauseOffset, current_offset, newdata, olddata, &new_one->dwResultClauseLen, &new_one->dwResultClauseOffset, FALSE); current_offset = updateField(lpcs->dwResultStrLen, lpcs->dwResultStrOffset, current_offset, newdata, olddata, &new_one->dwResultStrLen, &new_one->dwResultStrOffset, TRUE); current_offset = updateField(lpcs->dwPrivateSize, lpcs->dwPrivateOffset, current_offset, newdata, olddata, &new_one->dwPrivateSize, &new_one->dwPrivateOffset, FALSE); } /* set new data */ /* CompAttr */ new_one->dwCompAttrLen = len; if (len > 0) { new_one->dwCompAttrOffset = current_offset; memset(&newdata[current_offset],ATTR_INPUT,len); current_offset += len; } /* CompClause */ if (len > 0) { new_one->dwCompClauseLen = sizeof(DWORD) * 2; new_one->dwCompClauseOffset = current_offset; *(DWORD*)(&newdata[current_offset]) = 0; current_offset += sizeof(DWORD); *(DWORD*)(&newdata[current_offset]) = len; current_offset += sizeof(DWORD); } /* CompStr */ new_one->dwCompStrLen = len; if (len > 0) { new_one->dwCompStrOffset = current_offset; memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR)); } /* CursorPos */ new_one->dwCursorPos = len; ImmUnlockIMCC(rc); if (lpcs) ImmUnlockIMCC(old); return rc; } static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len) { /* we need to make sure the ResultStr and ResultClause fields are all * set and correct */ int needed_size; HIMCC rc; LPBYTE newdata = NULL; LPBYTE olddata = NULL; LPCOMPOSITIONSTRING new_one; LPCOMPOSITIONSTRING lpcs = NULL; INT current_offset = 0; TRACE("%s, %i\n",debugstr_wn(resultstr,len),len); if (old == NULL && resultstr == NULL && len == 0) return NULL; if (old != NULL) { olddata = ImmLockIMCC(old); lpcs = (LPCOMPOSITIONSTRING)olddata; } needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + sizeof(DWORD) * 2; if (lpcs != NULL) { needed_size += lpcs->dwCompReadAttrLen; needed_size += lpcs->dwCompReadClauseLen; needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD); needed_size += lpcs->dwCompAttrLen; needed_size += lpcs->dwCompClauseLen; needed_size += lpcs->dwCompStrLen * sizeof(DWORD); needed_size += lpcs->dwResultReadClauseLen; needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD); needed_size += lpcs->dwPrivateSize; } rc = ImmCreateIMCC(needed_size); newdata = ImmLockIMCC(rc); new_one = (LPCOMPOSITIONSTRING)newdata; new_one->dwSize = needed_size; current_offset = sizeof(COMPOSITIONSTRING); if (lpcs != NULL) { current_offset = updateField(lpcs->dwCompReadAttrLen, lpcs->dwCompReadAttrOffset, current_offset, newdata, olddata, &new_one->dwCompReadAttrLen, &new_one->dwCompReadAttrOffset, FALSE); current_offset = updateField(lpcs->dwCompReadClauseLen, lpcs->dwCompReadClauseOffset, current_offset, newdata, olddata, &new_one->dwCompReadClauseLen, &new_one->dwCompReadClauseOffset, FALSE); current_offset = updateField(lpcs->dwCompReadStrLen, lpcs->dwCompReadStrOffset, current_offset, newdata, olddata, &new_one->dwCompReadStrLen, &new_one->dwCompReadStrOffset, TRUE); current_offset = updateField(lpcs->dwCompAttrLen, lpcs->dwCompAttrOffset, current_offset, newdata, olddata, &new_one->dwCompAttrLen, &new_one->dwCompAttrOffset, FALSE); current_offset = updateField(lpcs->dwCompClauseLen, lpcs->dwCompClauseOffset, current_offset, newdata, olddata, &new_one->dwCompClauseLen, &new_one->dwCompClauseOffset, FALSE); current_offset = updateField(lpcs->dwCompStrLen, lpcs->dwCompStrOffset, current_offset, newdata, olddata, &new_one->dwCompStrLen, &new_one->dwCompStrOffset, TRUE); new_one->dwCursorPos = lpcs->dwCursorPos; new_one->dwDeltaStart = 0; current_offset = updateField(lpcs->dwResultReadClauseLen, lpcs->dwResultReadClauseOffset, current_offset, newdata, olddata, &new_one->dwResultReadClauseLen, &new_one->dwResultReadClauseOffset, FALSE); current_offset = updateField(lpcs->dwResultReadStrLen, lpcs->dwResultReadStrOffset, current_offset, newdata, olddata, &new_one->dwResultReadStrLen, &new_one->dwResultReadStrOffset, TRUE); /* new ResultClause , ResultStr */ current_offset = updateField(lpcs->dwPrivateSize, lpcs->dwPrivateOffset, current_offset, newdata, olddata, &new_one->dwPrivateSize, &new_one->dwPrivateOffset, FALSE); } /* set new data */ /* ResultClause */ if (len > 0) { new_one->dwResultClauseLen = sizeof(DWORD) * 2; new_one->dwResultClauseOffset = current_offset; *(DWORD*)(&newdata[current_offset]) = 0; current_offset += sizeof(DWORD); *(DWORD*)(&newdata[current_offset]) = len; current_offset += sizeof(DWORD); } /* ResultStr */ new_one->dwResultStrLen = len; if (len > 0) { new_one->dwResultStrOffset = current_offset; memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR)); } ImmUnlockIMCC(rc); if (lpcs) ImmUnlockIMCC(old); return rc; } /*********************************************************************** * ImmAssociateContext (IMM32.@) */ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; WARN("(%p, %p): semi-stub\n", hWnd, hIMC); if (!hIMC) return NULL; /* * WINE SPECIFIC! MAY CONFLICT * associate the root context we have an XIM created */ if (hWnd == 0x000) { root_context = (InputContextData*)hIMC; } /* * If already associated just return */ if (data->IMC.hWnd == hWnd) return hIMC; 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); } /* * TODO: We need to keep track of the old context associated * with a window and return it for now we will return NULL; */ return NULL; } /*********************************************************************** * ImmAssociateContextEx (IMM32.@) */ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) { FIXME("(%p, %p, %d): stub\n", hWnd, hIMC, dwFlags); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmConfigureIMEA (IMM32.@) */ BOOL WINAPI ImmConfigureIMEA( HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmConfigureIMEW (IMM32.@) */ BOOL WINAPI ImmConfigureIMEW( HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmCreateContext (IMM32.@) */ HIMC WINAPI ImmCreateContext(void) { InputContextData *new_context; new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData)); return (HIMC)new_context; } /*********************************************************************** * ImmDestroyContext (IMM32.@) */ BOOL WINAPI ImmDestroyContext(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; TRACE("Destroying %p\n",hIMC); if (hIMC) { ImmDestroyIMCC(root_context->IMC.hCompStr); ImmDestroyIMCC(root_context->IMC.hCandInfo); ImmDestroyIMCC(root_context->IMC.hGuideLine); ImmDestroyIMCC(root_context->IMC.hPrivate); ImmDestroyIMCC(root_context->IMC.hMsgBuf); if (data->textfont) { DeleteObject(data->textfont); data->textfont = NULL; } HeapFree(GetProcessHeap(),0,data); } return TRUE; } /*********************************************************************** * 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) { FIXME("(%p, %p, %s, %d, %s, %p): stub\n", hKL, lpfnEnumProc, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmEnumRegisterWordW (IMM32.@) */ UINT WINAPI ImmEnumRegisterWordW( HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister, LPVOID lpData) { FIXME("(%p, %p, %s, %d, %s, %p): stub\n", hKL, lpfnEnumProc, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmEscapeA (IMM32.@) */ LRESULT WINAPI ImmEscapeA( HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) { FIXME("(%p, %p, %d, %p): stub\n", hKL, hIMC, uEscape, lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmEscapeW (IMM32.@) */ LRESULT WINAPI ImmEscapeW( HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) { FIXME("(%p, %p, %d, %p): stub\n", hKL, hIMC, uEscape, lpData ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetCandidateListA (IMM32.@) */ DWORD WINAPI ImmGetCandidateListA( HIMC hIMC, DWORD deIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) { FIXME("(%p, %d, %p, %d): stub\n", hIMC, deIndex, lpCandList, dwBufLen ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetCandidateListCountA (IMM32.@) */ DWORD WINAPI ImmGetCandidateListCountA( HIMC hIMC, LPDWORD lpdwListCount) { FIXME("(%p, %p): stub\n", hIMC, lpdwListCount); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetCandidateListCountW (IMM32.@) */ DWORD WINAPI ImmGetCandidateListCountW( HIMC hIMC, LPDWORD lpdwListCount) { FIXME("(%p, %p): stub\n", hIMC, lpdwListCount); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetCandidateListW (IMM32.@) */ DWORD WINAPI ImmGetCandidateListW( HIMC hIMC, DWORD deIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) { FIXME("(%p, %d, %p, %d): stub\n", hIMC, deIndex, lpCandList, dwBufLen ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetCandidateWindow (IMM32.@) */ BOOL WINAPI ImmGetCandidateWindow( HIMC hIMC, DWORD dwBufLen, LPCANDIDATEFORM lpCandidate) { FIXME("(%p, %d, %p): stub\n", hIMC, dwBufLen, lpCandidate); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmGetCompositionFontA (IMM32.@) */ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { FIXME("(%p, %p): stub\n", hIMC, lplf); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmGetCompositionFontW (IMM32.@) */ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { FIXME("(%p, %p): stub\n", hIMC, lplf); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmGetCompositionStringA (IMM32.@) */ LONG WINAPI ImmGetCompositionStringA( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) { CHAR *buf; LONG rc = 0; InputContextData *data = (InputContextData*)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; if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 && compstr->dwResultStrOffset > 0) { LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset); TRACE("GSC_RESULTSTR %p %i\n",ResultStr, compstr->dwResultStrLen); buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwResultStrLen * 3 ); rc = WideCharToMultiByte(CP_ACP, 0, ResultStr, compstr->dwResultStrLen , buf, compstr->dwResultStrLen * 3, NULL, NULL); if (dwBufLen >= rc) memcpy(lpBuf,buf,rc); data->bRead = TRUE; HeapFree( GetProcessHeap(), 0, buf ); } else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 && compstr->dwCompStrOffset > 0) { LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); TRACE("GSC_COMPSTR %p %i\n", CompString, compstr->dwCompStrLen); buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwCompStrLen * 3 ); rc = WideCharToMultiByte(CP_ACP, 0, CompString, compstr->dwCompStrLen, buf, compstr->dwCompStrLen * 3, NULL, NULL); if (dwBufLen >= rc) memcpy(lpBuf,buf,rc); HeapFree( GetProcessHeap(), 0, buf ); } else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 && compstr->dwCompAttrOffset > 0) { LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset); TRACE("GSC_COMPATTR %p %i\n", Compattr , compstr->dwCompAttrLen); rc = compstr->dwCompAttrLen; if (dwBufLen >= rc) memcpy(lpBuf,Compattr,rc); } else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 && compstr->dwCompClauseOffset > 0) { LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset); TRACE("GSC_COMPCLAUSE %p %i\n", Compclause, compstr->dwCompClauseLen); rc = compstr->dwCompClauseLen; if (dwBufLen >= compstr->dwCompClauseLen) memcpy(lpBuf,Compclause,rc); } else if (dwIndex == GCS_RESULTCLAUSE && compstr->dwResultClauseLen > 0 && compstr->dwResultClauseOffset > 0) { LPWSTR Resultclause = (LPWSTR)(compdata + compstr->dwResultClauseOffset); TRACE("GSC_RESULTCLAUSE %p %i\n", Resultclause, compstr->dwResultClauseLen); rc = compstr->dwResultClauseLen; if (dwBufLen >= compstr->dwResultClauseLen) memcpy(lpBuf,Resultclause,rc); } else if (dwIndex == GCS_CURSORPOS) { TRACE("GSC_CURSORPOS\n"); rc = compstr->dwCursorPos; } else if (dwIndex == GCS_DELTASTART) { TRACE("GCS_DELTASTART\n"); rc = compstr->dwDeltaStart; } else { FIXME("Unhandled index 0x%x\n",dwIndex); } ImmUnlockIMCC(data->IMC.hCompStr); return rc; } /*********************************************************************** * ImmGetCompositionStringW (IMM32.@) */ LONG WINAPI ImmGetCompositionStringW( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) { LONG rc = 0; InputContextData *data = (InputContextData*)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; if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 && compstr->dwResultStrOffset > 0) { LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset); data->bRead = TRUE; rc = compstr->dwResultStrLen * sizeof(WCHAR); if (dwBufLen >= rc) memcpy(lpBuf,ResultStr,rc); } else if (dwIndex == GCS_RESULTREADSTR && compstr->dwResultReadStrLen > 0 && compstr->dwResultReadStrOffset > 0) { LPWSTR ResultReadString = (LPWSTR)(compdata + compstr->dwResultReadStrOffset); rc = compstr->dwResultReadStrLen * sizeof(WCHAR); if (dwBufLen >= rc) memcpy(lpBuf,ResultReadString,rc); } else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 && compstr->dwCompStrOffset > 0) { LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); rc = compstr->dwCompStrLen * sizeof(WCHAR); if (dwBufLen >= rc) memcpy(lpBuf,CompString,rc); } else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 && compstr->dwCompAttrOffset > 0) { LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset); rc = compstr->dwCompAttrLen; if (dwBufLen >= rc) memcpy(lpBuf,Compattr,rc); } else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 && compstr->dwCompClauseOffset > 0) { LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset); rc = compstr->dwCompClauseLen; if (dwBufLen >= compstr->dwCompClauseLen) memcpy(lpBuf,Compclause,rc); } else if (dwIndex == GCS_COMPREADSTR && compstr->dwCompReadStrLen > 0 && compstr->dwCompReadStrOffset > 0) { LPWSTR CompReadString = (LPWSTR)(compdata + compstr->dwCompReadStrOffset); rc = compstr->dwCompReadStrLen * sizeof(WCHAR); if (dwBufLen >= rc) memcpy(lpBuf,CompReadString,rc); } else if (dwIndex == GCS_CURSORPOS) { TRACE("GSC_CURSORPOS\n"); rc = compstr->dwCursorPos; } else if (dwIndex == GCS_DELTASTART) { TRACE("GCS_DELTASTART\n"); rc = compstr->dwDeltaStart; } else { FIXME("Unhandled index 0x%x\n",dwIndex); } ImmUnlockIMCC(data->IMC.hCompStr); return rc; } /*********************************************************************** * ImmGetCompositionWindow (IMM32.@) */ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { InputContextData *data = (InputContextData*)hIMC; TRACE("(%p, %p)\n", hIMC, lpCompForm); if (!data) return FALSE; memcpy(lpCompForm,&(data->IMC.cfCompForm),sizeof(COMPOSITIONFORM)); return 1; } /*********************************************************************** * ImmGetContext (IMM32.@) * */ HIMC WINAPI ImmGetContext(HWND hWnd) { TRACE("%p\n", hWnd); if (!root_context) return NULL; root_context->IMC.hWnd = hWnd; return (HIMC)root_context; } /*********************************************************************** * ImmGetConversionListA (IMM32.@) */ DWORD WINAPI ImmGetConversionListA( HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { FIXME("(%p, %p, %s, %p, %d, %d): stub\n", hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetConversionListW (IMM32.@) */ DWORD WINAPI ImmGetConversionListW( HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { FIXME("(%p, %p, %s, %p, %d, %d): stub\n", hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetConversionStatus (IMM32.@) */ BOOL WINAPI ImmGetConversionStatus( HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) { TRACE("(%p, %p, %p): best guess\n", hIMC, lpfdwConversion, lpfdwSentence); if (lpfdwConversion) *lpfdwConversion = IME_CMODE_NATIVE; if (lpfdwSentence) *lpfdwSentence = IME_SMODE_NONE; return TRUE; } /*********************************************************************** * ImmGetDefaultIMEWnd (IMM32.@) */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { static int shown = 0; if (!shown) { FIXME("(%p - %p %p ): semi-stub\n", hWnd,hwndDefault, root_context); shown = 1; } if (hwndDefault == NULL) { static const WCHAR the_name[] = {'I','M','E','\0'}; IMM_Register(); hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, WC_IMECLASSNAME, the_name, WS_POPUP, 0, 0, 1, 1, 0, 0, hImeInst, 0); TRACE("Default created (%p)\n",hwndDefault); } return hwndDefault; } /*********************************************************************** * 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 ); /* 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 ); return len; } /*********************************************************************** * 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 (!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) { FIXME("(%p, %p, %d): stub\n", hKL, lpszFileName, uBufLen); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetIMEFileNameW (IMM32.@) */ UINT WINAPI ImmGetIMEFileNameW( HKL hKL, LPWSTR lpszFileName, UINT uBufLen) { FIXME("(%p, %p, %d): stub\n", hKL, lpszFileName, uBufLen); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetOpenStatus (IMM32.@) */ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; if (!data) return FALSE; FIXME("(%p): semi-stub\n", hIMC); return data->IMC.fOpen; } /*********************************************************************** * ImmGetProperty (IMM32.@) */ DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) { DWORD rc = 0; TRACE("(%p, %d)\n", hKL, fdwIndex); switch (fdwIndex) { case IGP_PROPERTY: TRACE("(%s)\n", "IGP_PROPERTY"); rc = IME_PROP_UNICODE | IME_PROP_AT_CARET; break; case IGP_CONVERSION: FIXME("(%s)\n", "IGP_CONVERSION"); rc = IME_CMODE_NATIVE; break; case IGP_SENTENCE: FIXME("%s)\n", "IGP_SENTENCE"); rc = IME_SMODE_AUTOMATIC; break; case IGP_SETCOMPSTR: TRACE("(%s)\n", "IGP_SETCOMPSTR"); rc = 0; break; case IGP_SELECT: TRACE("(%s)\n", "IGP_SELECT"); rc = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE; break; case IGP_GETIMEVERSION: TRACE("(%s)\n", "IGP_GETIMEVERSION"); rc = IMEVER_0400; break; case IGP_UI: TRACE("(%s)\n", "IGP_UI"); rc = 0; break; default: rc = 0; } return rc; } /*********************************************************************** * ImmGetRegisterWordStyleA (IMM32.@) */ UINT WINAPI ImmGetRegisterWordStyleA( HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf) { FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetRegisterWordStyleW (IMM32.@) */ UINT WINAPI ImmGetRegisterWordStyleW( HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf) { FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } /*********************************************************************** * ImmGetStatusWindowPos (IMM32.@) */ BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { FIXME("(%p, %p): stub\n", hIMC, lpptPos); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmGetVirtualKey (IMM32.@) */ UINT WINAPI ImmGetVirtualKey(HWND hWnd) { OSVERSIONINFOA version; FIXME("(%p): stub\n", hWnd); 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) { FIXME("(%s, %s): stub\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return NULL; } /*********************************************************************** * ImmInstallIMEW (IMM32.@) */ HKL WINAPI ImmInstallIMEW( LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText) { FIXME("(%s, %s): stub\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return NULL; } /*********************************************************************** * ImmIsIME (IMM32.@) */ BOOL WINAPI ImmIsIME(HKL hKL) { TRACE("(%p): semi-stub\n", hKL); /* * FIXME: Dead key locales will return TRUE here when they should not * There is probably a more proper way to check this. */ return (root_context != NULL); } /*********************************************************************** * ImmIsUIMessageA (IMM32.@) */ BOOL WINAPI ImmIsUIMessageA( HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL rc = FALSE; 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_KEYUP) || (msg == WM_MSIME_SERVICE) || (msg == WM_MSIME_RECONVERTOPTIONS) || (msg == WM_MSIME_MOUSE) || (msg == WM_MSIME_RECONVERTREQUEST) || (msg == WM_MSIME_RECONVERT) || (msg == WM_MSIME_QUERYPOSITION) || (msg == WM_MSIME_DOCUMENTFEED)) { if (!hwndDefault) ImmGetDefaultIMEWnd(NULL); if (hWndIME == NULL) PostMessageA(hwndDefault, msg, wParam, lParam); rc = TRUE; } return rc; } /*********************************************************************** * ImmIsUIMessageW (IMM32.@) */ BOOL WINAPI ImmIsUIMessageW( HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL rc = FALSE; TRACE("(%p, %d, %ld, %ld): stub\n", hWndIME, msg, wParam, lParam); if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) || (msg == WM_MSIME_SERVICE) || (msg == WM_MSIME_RECONVERTOPTIONS) || (msg == WM_MSIME_MOUSE) || (msg == WM_MSIME_RECONVERTREQUEST) || (msg == WM_MSIME_RECONVERT) || (msg == WM_MSIME_QUERYPOSITION) || (msg == WM_MSIME_DOCUMENTFEED)) rc = TRUE; return rc; } /*********************************************************************** * ImmNotifyIME (IMM32.@) */ BOOL WINAPI ImmNotifyIME( HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { BOOL rc = FALSE; TRACE("(%p, %d, %d, %d)\n", hIMC, dwAction, dwIndex, dwValue); if (!root_context) return rc; switch(dwAction) { case NI_CHANGECANDIDATELIST: FIXME("%s\n","NI_CHANGECANDIDATELIST"); break; case NI_CLOSECANDIDATE: FIXME("%s\n","NI_CLOSECANDIDATE"); break; case NI_COMPOSITIONSTR: switch (dwIndex) { case CPS_CANCEL: TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_CANCEL"); { BOOL send; if (pX11DRV_ForceXIMReset) pX11DRV_ForceXIMReset(root_context->IMC.hWnd); send = (root_context->IMC.hCompStr!=NULL); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = NULL; if (send) ImmInternalPostIMEMessage(WM_IME_COMPOSITION, 0, GCS_COMPSTR); rc = TRUE; } break; case CPS_COMPLETE: TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_COMPLETE"); if (hIMC != (HIMC)FROM_IME && pX11DRV_ForceXIMReset) pX11DRV_ForceXIMReset(root_context->IMC.hWnd); { HIMCC newCompStr; DWORD cplen = 0; LPWSTR cpstr; LPCOMPOSITIONSTRING cs = NULL; LPBYTE cdata = NULL; /* clear existing result */ newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; if (root_context->IMC.hCompStr) { cdata = ImmLockIMCC(root_context->IMC.hCompStr); cs = (LPCOMPOSITIONSTRING)cdata; cplen = cs->dwCompStrLen; cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]); ImmUnlockIMCC(root_context->IMC.hCompStr); } if (cplen > 0) { WCHAR param = cpstr[0]; newCompStr = updateResultStr(root_context->IMC.hCompStr, cpstr, cplen); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; root_context->bRead = FALSE; ImmInternalPostIMEMessage(WM_IME_COMPOSITION, 0, GCS_COMPSTR); ImmInternalPostIMEMessage(WM_IME_COMPOSITION, param, GCS_RESULTSTR|GCS_RESULTCLAUSE); } ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION, 0, 0); root_context->bInComposition = FALSE; } break; case CPS_CONVERT: FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_CONVERT"); break; case CPS_REVERT: FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_REVERT"); break; default: ERR("%s - %s (%i)\n","NI_COMPOSITIONSTR","UNKNOWN",dwIndex); break; } break; case NI_IMEMENUSELECTED: FIXME("%s\n", "NI_IMEMENUSELECTED"); break; case NI_OPENCANDIDATE: FIXME("%s\n", "NI_OPENCANDIDATE"); break; case NI_SELECTCANDIDATESTR: FIXME("%s\n", "NI_SELECTCANDIDATESTR"); break; case NI_SETCANDIDATE_PAGESIZE: FIXME("%s\n", "NI_SETCANDIDATE_PAGESIZE"); break; case NI_SETCANDIDATE_PAGESTART: FIXME("%s\n", "NI_SETCANDIDATE_PAGESTART"); break; default: ERR("Unknown\n"); } return rc; } /*********************************************************************** * ImmRegisterWordA (IMM32.@) */ BOOL WINAPI ImmRegisterWordA( HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister) { FIXME("(%p, %s, %d, %s): stub\n", hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmRegisterWordW (IMM32.@) */ BOOL WINAPI ImmRegisterWordW( HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) { FIXME("(%p, %s, %d, %s): stub\n", hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmReleaseContext (IMM32.@) */ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) { static int shown = 0; if (!shown) { FIXME("(%p, %p): stub\n", hWnd, hIMC); shown = 1; } return TRUE; } /*********************************************************************** * ImmSetCandidateWindow (IMM32.@) */ BOOL WINAPI ImmSetCandidateWindow( HIMC hIMC, LPCANDIDATEFORM lpCandidate) { FIXME("(%p, %p): stub\n", hIMC, lpCandidate); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmSetCompositionFontA (IMM32.@) */ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { InputContextData *data = (InputContextData*)hIMC; TRACE("(%p, %p)\n", hIMC, lplf); if (!data) return FALSE; memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, LF_FACESIZE); ImmInternalSendIMENotify(IMN_SETCOMPOSITIONFONT, 0); if (data->textfont) { DeleteObject(data->textfont); data->textfont = NULL; } data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W); return TRUE; } /*********************************************************************** * ImmSetCompositionFontW (IMM32.@) */ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { InputContextData *data = (InputContextData*)hIMC; TRACE("(%p, %p)\n", hIMC, lplf); if (!data) return FALSE; memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTW)); ImmInternalSendIMENotify(IMN_SETCOMPOSITIONFONT, 0); if (data->textfont) { DeleteObject(data->textfont); data->textfont = NULL; } data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W); 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; TRACE("(%p, %d, %p, %d, %p, %d): stub\n", 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 flags = 0; WCHAR wParam = 0; TRACE("(%p, %d, %p, %d, %p, %d): stub\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); if (hIMC != (HIMC)FROM_IME) FIXME("PROBLEM: This only sets the wine level string\n"); /* * Explanation: * this sets the composition string in the imm32.dll level * of the composition buffer. we cannot manipulate the xim level * buffer, which means that once the xim level buffer changes again * any call to this function from the application will be lost */ if (lpRead && dwReadLen) FIXME("Reading string unimplemented\n"); /* * app operating this api to also receive the message from xim */ if (dwIndex == SCS_SETSTR) { HIMCC newCompStr; if (!root_context->bInComposition) { ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION, 0, 0); root_context->bInComposition = TRUE; } flags = GCS_COMPSTR; if (dwCompLen && lpComp) { newCompStr = updateCompStr(root_context->IMC.hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR)); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; wParam = ((const WCHAR*)lpComp)[0]; flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART; } else { newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0); ImmDestroyIMCC(root_context->IMC.hCompStr); root_context->IMC.hCompStr = newCompStr; } } UpdateDataInDefaultIMEWindow(hwndDefault,FALSE); ImmInternalPostIMEMessage(WM_IME_COMPOSITION, wParam, flags); return TRUE; } /*********************************************************************** * ImmSetCompositionWindow (IMM32.@) */ BOOL WINAPI ImmSetCompositionWindow( HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { BOOL reshow = FALSE; InputContextData *data = (InputContextData*)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) return FALSE; memcpy(&data->IMC.cfCompForm,lpCompForm,sizeof(COMPOSITIONFORM)); if (IsWindowVisible(hwndDefault)) { reshow = TRUE; ShowWindow(hwndDefault,SW_HIDE); } /* FIXME: this is a partial stub */ if (reshow) ShowWindow(hwndDefault,SW_SHOWNOACTIVATE); ImmInternalSendIMENotify(IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; } /*********************************************************************** * ImmSetConversionStatus (IMM32.@) */ BOOL WINAPI ImmSetConversionStatus( HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) { static int shown = 0; if (!shown) { FIXME("(%p, %d, %d): stub\n", hIMC, fdwConversion, fdwSentence ); shown = 1; } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmSetOpenStatus (IMM32.@) */ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { InputContextData *data = (InputContextData*)hIMC; TRACE("%p %d\n", hIMC, fOpen); if (hIMC == (HIMC)FROM_IME) { ImmInternalSetOpenStatus(fOpen); ImmInternalSendIMENotify(IMN_SETOPENSTATUS, 0); return TRUE; } if (!data) return FALSE; if (fOpen != data->bInternalState) { if (fOpen == FALSE && pX11DRV_ForceXIMReset) pX11DRV_ForceXIMReset(data->IMC.hWnd); if (fOpen == FALSE) ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION,0,0); else ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION,0,0); ImmInternalSetOpenStatus(fOpen); ImmInternalSetOpenStatus(!fOpen); if (data->IMC.fOpen == FALSE) ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION,0,0); else ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION,0,0); return FALSE; } return TRUE; } /*********************************************************************** * ImmSetStatusWindowPos (IMM32.@) */ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { FIXME("(%p, %p): stub\n", hIMC, lpptPos); 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) { FIXME("(%p, %s, %d, %s): stub\n", hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszUnregister) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmUnregisterWordW (IMM32.@) */ BOOL WINAPI ImmUnregisterWordW( HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) { FIXME("(%p, %s, %d, %s): stub\n", hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister) ); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /*********************************************************************** * ImmGetImeMenuItemsA (IMM32.@) */ DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize) { FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize); return 0; } /*********************************************************************** * ImmGetImeMenuItemsW (IMM32.@) */ DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize) { FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize); return 0; } /*********************************************************************** * ImmLockIMC(IMM32.@) */ LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; if (!data) return NULL; data->dwLock++; return &data->IMC; } /*********************************************************************** * ImmUnlockIMC(IMM32.@) */ BOOL WINAPI ImmUnlockIMC(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; data->dwLock--; return (data->dwLock!=0); } /*********************************************************************** * ImmGetIMCLockCount(IMM32.@) */ DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; return data->dwLock; } /*********************************************************************** * ImmCreateIMCC(IMM32.@) */ HIMCC WINAPI ImmCreateIMCC(DWORD size) { IMCCInternal *internal; int real_size = size + sizeof(IMCCInternal); internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size); if (internal == NULL) return NULL; internal->dwSize = size; return (HIMCC)internal; } /*********************************************************************** * ImmDestroyIMCC(IMM32.@) */ HIMCC WINAPI ImmDestroyIMCC(HIMCC block) { HeapFree(GetProcessHeap(),0,block); return NULL; } /*********************************************************************** * ImmLockIMCC(IMM32.@) */ LPVOID WINAPI ImmLockIMCC(HIMCC imcc) { IMCCInternal *internal; internal = (IMCCInternal*) imcc; internal->dwLock ++; return internal + 1; } /*********************************************************************** * ImmUnlockIMCC(IMM32.@) */ BOOL WINAPI ImmUnlockIMCC(HIMCC imcc) { IMCCInternal *internal; internal = (IMCCInternal*) imcc; internal->dwLock --; return (internal->dwLock!=0); } /*********************************************************************** * ImmGetIMCCLockCount(IMM32.@) */ DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc) { IMCCInternal *internal; internal = (IMCCInternal*) imcc; return internal->dwLock; } /*********************************************************************** * ImmReSizeIMCC(IMM32.@) */ HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size) { IMCCInternal *internal,*newone; int real_size = size + sizeof(IMCCInternal); internal = (IMCCInternal*) imcc; newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size); newone->dwSize = size; return newone; } /*********************************************************************** * ImmGetIMCCSize(IMM32.@) */ DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) { IMCCInternal *internal; internal = (IMCCInternal*) imcc; return internal->dwSize; } /***** * Internal functions to help with IME window management */ static void PaintDefaultIMEWnd(HWND hwnd) { PAINTSTRUCT ps; RECT rect; HDC hdc = BeginPaint(hwnd,&ps); LPCOMPOSITIONSTRING compstr; LPBYTE compdata = NULL; HMONITOR monitor; MONITORINFO mon_info; INT offX=0, offY=0; GetClientRect(hwnd,&rect); FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); compdata = ImmLockIMCC(root_context->IMC.hCompStr); compstr = (LPCOMPOSITIONSTRING)compdata; if (compstr->dwCompStrLen && compstr->dwCompStrOffset) { SIZE size; POINT pt; HFONT oldfont = NULL; LPWSTR CompString; CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); if (root_context->textfont) oldfont = SelectObject(hdc,root_context->textfont); GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size); pt.x = size.cx; pt.y = size.cy; LPtoDP(hdc,&pt,1); /* * How this works based on tests on windows: * CFS_POINT: then we start our window at the point and grow it as large * as it needs to be for the string. * CFS_RECT: we still use the ptCurrentPos as a starting point and our * window is only as large as we need for the string, but we do not * grow such that our window exceeds the given rect. Wrapping if * needed and possible. If our ptCurrentPos is outside of our rect * then no window is displayed. * CFS_FORCE_POSITION: appears to behave just like CFS_POINT * maybe becase the default MSIME does not do any IME adjusting. */ if (root_context->IMC.cfCompForm.dwStyle != CFS_DEFAULT) { POINT cpt = root_context->IMC.cfCompForm.ptCurrentPos; ClientToScreen(root_context->IMC.hWnd,&cpt); rect.left = cpt.x; rect.top = cpt.y; rect.right = rect.left + pt.x; rect.bottom = rect.top + pt.y; offX=offY=10; monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY); } else /* CFS_DEFAULT */ { /* Windows places the default IME window in the bottom left */ HWND target = root_context->IMC.hWnd; if (!target) target = GetFocus(); GetWindowRect(target,&rect); rect.top = rect.bottom; rect.right = rect.left + pt.x + 20; rect.bottom = rect.top + pt.y + 20; offX=offY=10; monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY); } if (root_context->IMC.cfCompForm.dwStyle == CFS_RECT) { RECT client; client =root_context->IMC.cfCompForm.rcArea; MapWindowPoints( root_context->IMC.hWnd, 0, (POINT *)&client, 2 ); IntersectRect(&rect,&rect,&client); /* TODO: Wrap the input if needed */ } if (root_context->IMC.cfCompForm.dwStyle == CFS_DEFAULT) { /* make sure we are on the desktop */ mon_info.cbSize = sizeof(mon_info); GetMonitorInfoW(monitor, &mon_info); if (rect.bottom > mon_info.rcWork.bottom) { int shift = rect.bottom - mon_info.rcWork.bottom; rect.top -= shift; rect.bottom -= shift; } if (rect.left < 0) { rect.right -= rect.left; rect.left = 0; } if (rect.right > mon_info.rcWork.right) { int shift = rect.right - mon_info.rcWork.right; rect.left -= shift; rect.right -= shift; } } SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE); TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen); if (oldfont) SelectObject(hdc,oldfont); } ImmUnlockIMCC(root_context->IMC.hCompStr); EndPaint(hwnd,&ps); } static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable) { LPCOMPOSITIONSTRING compstr; if (root_context->IMC.hCompStr) compstr = ImmLockIMCC(root_context->IMC.hCompStr); else compstr = NULL; if (compstr == NULL || compstr->dwCompStrLen == 0) ShowWindow(hwndDefault,SW_HIDE); else if (showable) ShowWindow(hwndDefault,SW_SHOWNOACTIVATE); RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE); if (compstr != NULL) ImmUnlockIMCC(root_context->IMC.hCompStr); } /* * The window proc for the default IME window */ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT rc = 0; TRACE("Incoming Message 0x%x (0x%08x, 0x%08x)\n", msg, (UINT)wParam, (UINT)lParam); switch(msg) { case WM_PAINT: PaintDefaultIMEWnd(hwnd); return FALSE; case WM_NCCREATE: return TRUE; case WM_CREATE: SetWindowTextA(hwnd,"Wine Ime Active"); return TRUE; case WM_SETFOCUS: if (wParam) SetFocus((HWND)wParam); else FIXME("Received focus, should never have focus\n"); break; case WM_IME_COMPOSITION: TRACE("IME message %s, 0x%x, 0x%x (%i)\n", "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam, root_context->bRead); if (lParam & GCS_RESULTSTR) IMM_PostResult(root_context); else UpdateDataInDefaultIMEWindow(hwnd,TRUE); break; case WM_IME_STARTCOMPOSITION: TRACE("IME message %s, 0x%x, 0x%x\n", "WM_IME_STARTCOMPOSITION", (UINT)wParam, (UINT)lParam); root_context->IMC.hWnd = GetFocus(); ShowWindow(hwndDefault,SW_SHOWNOACTIVATE); break; case WM_IME_ENDCOMPOSITION: TRACE("IME message %s, 0x%x, 0x%x\n", "WM_IME_ENDCOMPOSITION", (UINT)wParam, (UINT)lParam); ShowWindow(hwndDefault,SW_HIDE); break; case WM_IME_SELECT: TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_SELECT", (UINT)wParam, (UINT)lParam); break; case WM_IME_CONTROL: TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_CONTROL", (UINT)wParam, (UINT)lParam); rc = 1; break; case WM_IME_NOTIFY: TRACE("!! IME NOTIFY\n"); break; default: TRACE("Non-standard message 0x%x\n",msg); } /* check the MSIME messages */ if (msg == WM_MSIME_SERVICE) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_SERVICE", (UINT)wParam, (UINT)lParam); rc = FALSE; } else if (msg == WM_MSIME_RECONVERTOPTIONS) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTOPTIONS", (UINT)wParam, (UINT)lParam); } else if (msg == WM_MSIME_MOUSE) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_MOUSE", (UINT)wParam, (UINT)lParam); } else if (msg == WM_MSIME_RECONVERTREQUEST) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTREQUEST", (UINT)wParam, (UINT)lParam); } else if (msg == WM_MSIME_RECONVERT) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERT", (UINT)wParam, (UINT)lParam); } else if (msg == WM_MSIME_QUERYPOSITION) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_QUERYPOSITION", (UINT)wParam, (UINT)lParam); } else if (msg == WM_MSIME_DOCUMENTFEED) { TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_DOCUMENTFEED", (UINT)wParam, (UINT)lParam); } /* DefWndProc if not an IME message */ else if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) rc = DefWindowProcW(hwnd,msg,wParam,lParam); return rc; }