From 6dca48feaf8ea0cedd2df88af98f28179d096c02 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Wed, 2 Apr 2008 10:13:59 -0500 Subject: [PATCH] winex11: Add IME functionality to winex11drv. All XIM interaction will soon pass through this functionality instead of directly to imm32. --- dlls/winex11.drv/Makefile.in | 3 +- dlls/winex11.drv/ime.c | 1425 +++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/winex11.drv.spec | 18 + dlls/winex11.drv/x11drv.h | 14 + dlls/winex11.drv/x11drv_main.c | 2 + dlls/winex11.drv/xim.c | 2 + 6 files changed, 1463 insertions(+), 1 deletion(-) create mode 100644 dlls/winex11.drv/ime.c diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 8a3b50922ee..95301f78eb0 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = winex11.drv -IMPORTS = user32 gdi32 advapi32 kernel32 ntdll +IMPORTS = user32 gdi32 advapi32 imm32 kernel32 ntdll EXTRAINCL = @X_CFLAGS@ EXTRALIBS = @X_LIBS@ @X_PRE_LIBS@ @XLIB@ @X_EXTRA_LIBS@ @@ -21,6 +21,7 @@ C_SRCS = \ dib_src_swap.c \ event.c \ graphics.c \ + ime.c \ init.c \ keyboard.c \ mouse.c \ diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c new file mode 100644 index 00000000000..a1c229ef46e --- /dev/null +++ b/dlls/winex11.drv/ime.c @@ -0,0 +1,1425 @@ +/* + * The IME for interfacing with XIM + * + * Copyright 2008 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 + */ + +/* + * Notes: + * The normal flow for IMM/IME Processing is as follows. + * 1) The Keyboard Driver generates key messages which are first passed to + * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then + * it does not want the key and the keyboard driver then generates the + * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the + * key it returns non-zero. + * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to + * process the key. the IME modifies the HIMC structure to reflect the + * current state and generates any messages it needs the IMM to process. + * 3) IMM checks the messages and send them to the application in question. From + * here the IMM level deals with if the application is IME aware or not. + * + * This flow does not work well for the X11 driver and XIM. + * (It works fine for Mac) + * As such we will have to reroute step 1. Instead the x11drv driver will + * generate an XIM events and call directly into this IME implimenetaion. + * As such we will have to use the alternative ImmGenerateMessage path to be + * generate the messages that we want the IMM layer to send to the application. + */ + +#include "config.h" + +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/debug.h" +#include "imm.h" +#include "ddk/imm.h" +#include "winnls.h" +#include "x11drv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(imm); + +#define FROM_X11 ((HIMC)0xcafe1337) + +typedef struct _IMEPRIVATE { + BOOL bInComposition; + BOOL bInternalState; + HFONT textfont; + HWND hwndDefault; +} IMEPRIVATE, *LPIMEPRIVATE; + +typedef struct _tagTRANSMSG { + UINT message; + WPARAM wParam; + LPARAM lParam; +} TRANSMSG, *LPTRANSMSG; + +static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0}; + +static HIMC *hSelectedFrom = NULL; +static INT hSelectedCount = 0; +static BOOL hXIMPresent = FALSE; + +/* 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; + +static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +static void UpdateDataInDefaultIMEWindow(HIMC hHIMC, HWND hwnd, BOOL showable); + +static HIMC RealIMC(HIMC hIMC) +{ + if (hIMC == FROM_X11) + { + INT i; + HWND wnd = GetFocus(); + HIMC winHimc = ImmGetContext(wnd); + for (i = 0; i < hSelectedCount; i++) + if (winHimc == hSelectedFrom[i]) + return winHimc; + return NULL; + } + else + return hIMC; +} + +static LPINPUTCONTEXT LockRealIMC(HIMC hIMC) +{ + HIMC real_imc = RealIMC(hIMC); + if (real_imc) + return (LPINPUTCONTEXT)ImmLockIMC(real_imc); + else + return NULL; +} + +static BOOL UnlockRealIMC(HIMC hIMC) +{ + HIMC real_imc = RealIMC(hIMC); + if (real_imc) + return ImmUnlockIMC(real_imc); + else + return FALSE; +} + +static HIMCC ImeCreateBlankCompStr(void) +{ + HIMCC rc; + LPCOMPOSITIONSTRING ptr; + rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); + ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc); + memset(ptr,0,sizeof(COMPOSITIONSTRING)); + ptr->dwSize = sizeof(COMPOSITIONSTRING); + ImmUnlockIMCC(rc); + return rc; +} + +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; +} + +static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + LPINPUTCONTEXT lpIMC; + LPTRANSMSG lpTransMsg; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * + sizeof(TRANSMSG)); + if (!lpIMC->hMsgBuf) + return; + + lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf); + if (!lpTransMsg) + return; + + lpTransMsg += lpIMC->dwNumMsgBuf; + lpTransMsg->message = msg; + lpTransMsg->wParam = wParam; + lpTransMsg->lParam = lParam; + + ImmUnlockIMCC(lpIMC->hMsgBuf); + lpIMC->dwNumMsgBuf++; + + ImmGenerateMessage(RealIMC(hIMC)); + UnlockRealIMC(hIMC); +} + +static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length) +{ + LPINPUTCONTEXT lpIMC; + LPTRANSMSG lpTransMsg; + INT i; + + if (length <= 0) + return; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, + (lpIMC->dwNumMsgBuf + length) * + sizeof(TRANSMSG)); + if (!lpIMC->hMsgBuf) + return; + + lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf); + if (!lpTransMsg) + return; + + lpTransMsg += lpIMC->dwNumMsgBuf; + for (i = 0; i < length; i++) + { + lpTransMsg->message = WM_IME_CHAR; + lpTransMsg->wParam = String[i]; + lpTransMsg->lParam = 1; + lpTransMsg ++; + } + + ImmUnlockIMCC(lpIMC->hMsgBuf); + lpIMC->dwNumMsgBuf+=length; + + ImmGenerateMessage(RealIMC(hIMC)); + UnlockRealIMC(hIMC); +} + +static BOOL IME_RemoveFromSelected(HIMC hIMC) +{ + int i; + for (i = 0; i < hSelectedCount; i++) + if (hSelectedFrom[i] == hIMC) + { + if (i < hSelectedCount - 1) + memcpy(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC)); + hSelectedCount --; + return TRUE; + } + return FALSE; +} + +static void IME_AddToSelected(HIMC hIMC) +{ + hSelectedCount++; + if (hSelectedFrom) + hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC)); + else + hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC)); + hSelectedFrom[hSelectedCount-1] = hIMC; +} + +BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, + LPCWSTR lpszOption) +{ + TRACE("\n"); + if (!hXIMPresent) + { + ERR("No XIM in the back end\n"); + return FALSE; + } + lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE); + lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET; + lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE; + lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC; + lpIMEInfo->fdwUICaps = UI_CAP_2700; + /* Tell App we cannot accept ImeSetCompositionString calls */ + lpIMEInfo->fdwSCSCaps = 0; + lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; + + lstrcpyW(lpszUIClass,UI_CLASS_NAME); + + return TRUE; +} + +BOOL WINAPI ImeConfigure(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; +} + +DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource, + LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag) + +{ + FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource), + lpCandList, dwBufLen, uFlag); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +BOOL WINAPI ImeDestroy(UINT uForce) +{ + TRACE("\n"); + HeapFree(GetProcessHeap(),0,hSelectedFrom); + hSelectedFrom = NULL; + hSelectedCount = 0; + return TRUE; +} + +LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) +{ + FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, + CONST LPBYTE lpbKeyState) +{ + /* See the comment at the head of this file */ + TRACE("We do no processing via this route\n"); + return FALSE; +} + +BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) +{ + LPINPUTCONTEXT lpIMC; + TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE"); + + if (hIMC == FROM_X11) + { + ERR("ImeSelect should never be called from X11\n"); + return FALSE; + } + + if (!hXIMPresent) + { + ERR("No XIM in the back end\n"); + return FALSE; + } + + if (!hIMC) + return TRUE; + + /* not selected */ + if (!fSelect) + return IME_RemoveFromSelected(hIMC); + + IME_AddToSelected(hIMC); + + /* Initialize our structures */ + lpIMC = LockRealIMC(hIMC); + if (lpIMC != NULL) + { + LPIMEPRIVATE myPrivate; + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + myPrivate->bInComposition = FALSE; + myPrivate->bInternalState = FALSE; + myPrivate->textfont = NULL; + myPrivate->hwndDefault = NULL; + ImmUnlockIMCC(lpIMC->hPrivate); + UnlockRealIMC(hIMC); + } + + return TRUE; +} + +BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag) +{ + FIXME("Stub"); + return TRUE; +} + +UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, + CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey, + UINT fuState, HIMC hIMC) +{ + /* See the comment at the head of this file */ + TRACE("We do no processing via this route\n"); + return 0; +} + +BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) +{ + BOOL bRet = FALSE; + LPINPUTCONTEXT lpIMC; + + TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue); + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return FALSE; + + switch (dwAction) + { + case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break; + case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break; + case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break; + case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break; + case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break; + case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break; + case NI_CONTEXTUPDATED: + FIXME("NI_CONTEXTUPDATED:"); + switch (dwValue) + { + case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break; + case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break; + case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break; + case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break; + case IMC_SETCOMPOSITIONFONT: + { + LPIMEPRIVATE myPrivate; + TRACE("IMC_SETCOMPOSITIONFONT\n"); + + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + if (myPrivate->textfont) + { + DeleteObject(myPrivate->textfont); + myPrivate->textfont = NULL; + } + myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W); + ImmUnlockIMCC(lpIMC->hPrivate); + } + break; + case IMC_SETOPENSTATUS: + { + LPIMEPRIVATE myPrivate; + TRACE("IMC_SETOPENSTATUS\n"); + + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + if (lpIMC->fOpen != myPrivate->bInternalState) + { + if(lpIMC->fOpen == FALSE) + { + X11DRV_ForceXIMReset(lpIMC->hWnd); + GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0); + } + else + GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0); + } + bRet = TRUE; + } + break; + default: FIXME("Unknown\n"); break; + } + break; + case NI_COMPOSITIONSTR: + TRACE("NI_COMPOSITIONSTR:"); + switch (dwIndex) + { + case CPS_COMPLETE: + { + HIMCC newCompStr; + DWORD cplen = 0; + LPWSTR cpstr; + LPCOMPOSITIONSTRING cs = NULL; + LPBYTE cdata = NULL; + LPIMEPRIVATE myPrivate; + + TRACE("CPS_COMPLETE\n"); + + /* clear existing result */ + newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); + + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + + if (lpIMC->hCompStr) + { + cdata = ImmLockIMCC(lpIMC->hCompStr); + cs = (LPCOMPOSITIONSTRING)cdata; + cplen = cs->dwCompStrLen; + cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]); + ImmUnlockIMCC(lpIMC->hCompStr); + } + if (cplen > 0) + { + WCHAR param = cpstr[0]; + + newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + + GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, + GCS_COMPSTR); + + GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, + GCS_RESULTSTR|GCS_RESULTCLAUSE); + } + + GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); + + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + myPrivate->bInComposition = FALSE; + ImmUnlockIMCC(lpIMC->hPrivate); + + bRet = TRUE; + } + break; + case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break; + case CPS_REVERT: FIXME("CPS_REVERT\n"); break; + case CPS_CANCEL: + { + BOOL send; + LPCOMPOSITIONSTRING lpCompStr; + + TRACE("CPS_CANCEL\n"); + + X11DRV_ForceXIMReset(lpIMC->hWnd); + + lpCompStr = ImmLockIMCC(lpIMC->hCompStr); + send = (lpCompStr->dwCompStrLen != 0); + ImmUnlockIMCC(lpIMC->hCompStr); + + if (send) + { + HIMCC newCompStr; + newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, GCS_COMPSTR); + } + bRet = TRUE; + } + break; + default: FIXME("Unknown\n"); break; + } + break; + default: FIXME("Unknown Message\n"); break; + } + + UnlockRealIMC(hIMC); + return bRet; +} + +BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle, + LPCWSTR lpszRegister) +{ + FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, + debugstr_w(lpszRegister)); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle, + LPCWSTR lpszUnregister) +{ + FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, + debugstr_w(lpszUnregister)); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf) +{ + FIXME("(%d, %p): stub\n", nItem, lpStyleBuf); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc, + LPCWSTR lpszReading, DWORD dwStyle, + LPCWSTR lpszRegister, LPVOID lpData) +{ + FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc, + debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), + lpData); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, + DWORD dwCompLen, LPCVOID lpRead, + DWORD dwReadLen) +{ + LPINPUTCONTEXT lpIMC; + DWORD flags = 0; + WCHAR wParam = 0; + LPIMEPRIVATE myPrivate; + + TRACE("(%p, %d, %p, %d, %p, %d):\n", + hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); + + + if (hIMC != FROM_X11) + 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"); + + lpIMC = LockRealIMC(hIMC); + + if (lpIMC == NULL) + return FALSE; + + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + + if (dwIndex == SCS_SETSTR) + { + HIMCC newCompStr; + + if (!myPrivate->bInComposition) + { + GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); + myPrivate->bInComposition = TRUE; + } + + flags = GCS_COMPSTR; + + if (dwCompLen && lpComp) + { + newCompStr = updateCompStr(lpIMC->hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR)); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + + wParam = ((const WCHAR*)lpComp)[0]; + flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART; + } + else + { + newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + } + } + + UpdateDataInDefaultIMEWindow(hIMC, myPrivate->hwndDefault,FALSE); + + GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags); + ImmUnlockIMCC(lpIMC->hPrivate); + UnlockRealIMC(hIMC); + + return TRUE; +} + +DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, + LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, + DWORD dwSize) +{ + FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType, + lpImeParentMenu, lpImeMenu, dwSize); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +/* Interfaces to XIM and other parts of winex11drv */ + +void IME_RegisterClasses(HINSTANCE hImeInst) +{ + 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 = 2 * sizeof(LONG); + wndClass.hInstance = hImeInst; + wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); + wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1); + wndClass.lpszMenuName = 0; + wndClass.lpszClassName = UI_CLASS_NAME; + + RegisterClassW(&wndClass); + + 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"); +} + +void IME_UnregisterClasses(HINSTANCE hImeInst) +{ + UnregisterClassW(UI_CLASS_NAME, hImeInst); +} + +void IME_SetOpenStatus(BOOL fOpen) +{ + LPINPUTCONTEXT lpIMC; + LPIMEPRIVATE myPrivate; + + lpIMC = LockRealIMC(FROM_X11); + if (lpIMC == NULL) + return; + + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + + if (myPrivate->bInternalState && fOpen == FALSE) + { + ShowWindow(myPrivate->hwndDefault, SW_HIDE); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = ImeCreateBlankCompStr(); + } + myPrivate->bInternalState = fOpen; + + ImmUnlockIMCC(lpIMC->hPrivate); + UnlockRealIMC(FROM_X11); + + ImmSetOpenStatus(RealIMC(FROM_X11), fOpen); +} + +void IME_XIMPresent(BOOL present) +{ + hXIMPresent = present; +} + +LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam) +{ + LPINPUTCONTEXT lpIMC; + LRESULT rc = 0; + + if (!hSelectedFrom) + return rc; + + lpIMC = LockRealIMC(FROM_X11); + if (lpIMC) + rc = SendMessageW(lpIMC->hWnd,msg,wParam,lParam); + + UnlockRealIMC(FROM_X11); + return rc; +} + +INT IME_GetCursorPos() +{ + LPINPUTCONTEXT lpIMC; + INT rc = 0; + LPCOMPOSITIONSTRING compstr; + + if (!hSelectedFrom) + return rc; + + lpIMC = LockRealIMC(FROM_X11); + if (lpIMC) + { + compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr); + rc = compstr->dwCursorPos; + ImmUnlockIMCC(lpIMC->hCompStr); + } + UnlockRealIMC(FROM_X11); + return rc; +} + +void IME_UpdateAssociation(HWND focus) +{ + ImmGetContext(focus); + + if (!focus || !hSelectedFrom) + return; + + ImmAssociateContext(focus,RealIMC(FROM_X11)); +} + + +BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, + LPCVOID lpRead, DWORD dwReadLen) +{ + return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen, + lpRead, dwReadLen); +} + +BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue) +{ + return NotifyIME(FROM_X11, dwAction, dwIndex, dwValue); +} + +/***** + * Internal functions to help with IME window management + */ +static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) +{ + PAINTSTRUCT ps; + RECT rect; + HDC hdc; + LPCOMPOSITIONSTRING compstr; + LPBYTE compdata = NULL; + HMONITOR monitor; + MONITORINFO mon_info; + INT offX=0, offY=0; + LPINPUTCONTEXT lpIMC; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + hdc = BeginPaint(hwnd,&ps); + + GetClientRect(hwnd,&rect); + FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); + + compdata = ImmLockIMCC(lpIMC->hCompStr); + compstr = (LPCOMPOSITIONSTRING)compdata; + + if (compstr->dwCompStrLen && compstr->dwCompStrOffset) + { + SIZE size; + POINT pt; + HFONT oldfont = NULL; + LPWSTR CompString; + LPIMEPRIVATE myPrivate; + + CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + + if (myPrivate->textfont) + oldfont = SelectObject(hdc,myPrivate->textfont); + + ImmUnlockIMCC(lpIMC->hPrivate); + + 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 (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT) + { + POINT cpt = lpIMC->cfCompForm.ptCurrentPos; + ClientToScreen(lpIMC->hWnd,&cpt); + rect.left = cpt.x; + rect.top = cpt.y; + rect.right = rect.left + pt.x; + rect.bottom = rect.top + pt.y; + monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY); + } + else /* CFS_DEFAULT */ + { + /* Windows places the default IME window in the bottom left */ + HWND target = lpIMC->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 (lpIMC->cfCompForm.dwStyle == CFS_RECT) + { + RECT client; + client =lpIMC->cfCompForm.rcArea; + MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 ); + IntersectRect(&rect,&rect,&client); + /* TODO: Wrap the input if needed */ + } + + if (lpIMC->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(lpIMC->hCompStr); + + EndPaint(hwnd,&ps); + UnlockRealIMC(hIMC); +} + +static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) +{ + LPCOMPOSITIONSTRING compstr; + LPINPUTCONTEXT lpIMC; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + if (lpIMC->hCompStr) + compstr = ImmLockIMCC(lpIMC->hCompStr); + else + compstr = NULL; + + if (compstr == NULL || compstr->dwCompStrLen == 0) + ShowWindow(hwnd,SW_HIDE); + else if (showable) + ShowWindow(hwnd,SW_SHOWNOACTIVATE); + + RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE); + + if (compstr != NULL) + ImmUnlockIMCC(lpIMC->hCompStr); + + UnlockRealIMC(hIMC); +} + +static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) +{ + TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam); + if (lParam & GCS_RESULTSTR) + { + LPCOMPOSITIONSTRING compstr; + LPBYTE compdata; + LPWSTR ResultStr; + HIMCC newCompStr; + LPINPUTCONTEXT lpIMC; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + TRACE("Posting result as IME_CHAR\n"); + compdata = ImmLockIMCC(lpIMC->hCompStr); + compstr = (LPCOMPOSITIONSTRING)compdata; + ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset); + GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen); + ImmUnlockIMCC(lpIMC->hCompStr); + + /* clear the buffer */ + newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = newCompStr; + UnlockRealIMC(hIMC); + } + else + UpdateDataInDefaultIMEWindow(hIMC,hwnd,TRUE); +} + +static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd ) +{ + LPINPUTCONTEXT lpIMC; + + lpIMC = LockRealIMC(hIMC); + if (lpIMC == NULL) + return; + + TRACE("IME message WM_IME_STARTCOMPOSITION\n"); + lpIMC->hWnd = GetFocus(); + ShowWindow(hwnd,SW_SHOWNOACTIVATE); + UnlockRealIMC(hIMC); +} + +static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + switch (wParam) + { + case IMN_OPENSTATUSWINDOW: + FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n"); + break; + case IMN_CLOSESTATUSWINDOW: + FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n"); + break; + case IMN_OPENCANDIDATE: + FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n"); + break; + case IMN_CHANGECANDIDATE: + FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n"); + break; + case IMN_CLOSECANDIDATE: + FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n"); + break; + case IMN_SETCONVERSIONMODE: + FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n"); + break; + case IMN_SETSENTENCEMODE: + FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n"); + break; + case IMN_SETOPENSTATUS: + FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n"); + break; + case IMN_SETCANDIDATEPOS: + FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n"); + break; + case IMN_SETCOMPOSITIONFONT: + FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n"); + break; + case IMN_SETCOMPOSITIONWINDOW: + FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n"); + break; + case IMN_GUIDELINE: + FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n"); + break; + case IMN_SETSTATUSWINDOWPOS: + FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n"); + break; + default: + FIXME("WM_IME_NOTIFY:\n",wParam); + break; + } + return 0; +} + +static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + LRESULT rc = 0; + HIMC hIMC; + + TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam); + + /* + * Each UI window contains the current Input Context. + * This Input Context can be obtained by calling GetWindowLong + * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message. + * The UI window can refer to this Input Context and handles the + * messages. + */ + + hIMC = (HIMC)GetWindowLongW(hwnd,IMMGWL_IMC); + if (!hIMC) + hIMC = RealIMC(FROM_X11); + + /* if we have no hIMC there are many messages we cannot process */ + if (hIMC == NULL) + { + switch (msg) { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_NOTIFY: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: + return 0L; + default: + break; + } + } + + switch(msg) + { + case WM_CREATE: + { + LPIMEPRIVATE myPrivate; + LPINPUTCONTEXT lpIMC; + + SetWindowTextA(hwnd,"Wine Ime Active"); + + lpIMC = LockRealIMC(hIMC); + if (lpIMC) + { + myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate); + myPrivate->hwndDefault = hwnd; + ImmUnlockIMCC(lpIMC->hPrivate); + } + UnlockRealIMC(hIMC); + + return TRUE; + } + case WM_PAINT: + PaintDefaultIMEWnd(hIMC, hwnd); + return FALSE; + + case WM_NCCREATE: + return TRUE; + + case WM_SETFOCUS: + if (wParam) + SetFocus((HWND)wParam); + else + FIXME("Received focus, should never have focus\n"); + break; + case WM_IME_COMPOSITION: + DefaultIMEComposition(hIMC, hwnd, lParam); + break; + case WM_IME_STARTCOMPOSITION: + DefaultIMEStartComposition(hIMC, hwnd); + break; + case WM_IME_ENDCOMPOSITION: + TRACE("IME message %s, 0x%lx, 0x%lx\n", + "WM_IME_ENDCOMPOSITION", wParam, lParam); + ShowWindow(hwnd,SW_HIDE); + break; + case WM_IME_SELECT: + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam); + break; + case WM_IME_CONTROL: + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam); + rc = 1; + break; + case WM_IME_NOTIFY: + rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam); + break; + default: + TRACE("Non-standard message 0x%x\n",msg); + } + /* check the MSIME messages */ + if (msg == WM_MSIME_SERVICE) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam); + rc = FALSE; + } + else if (msg == WM_MSIME_RECONVERTOPTIONS) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam); + } + else if (msg == WM_MSIME_MOUSE) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam); + } + else if (msg == WM_MSIME_RECONVERTREQUEST) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam); + } + else if (msg == WM_MSIME_RECONVERT) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam); + } + else if (msg == WM_MSIME_QUERYPOSITION) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam); + } + else if (msg == WM_MSIME_DOCUMENTFEED) + { + TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam); + } + /* DefWndProc if not an IME message */ + 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; +} diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 13747cae78f..6d9c1be5876 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -145,3 +145,21 @@ @ cdecl wglShareLists(long long) X11DRV_wglShareLists @ cdecl wglUseFontBitmapsA(ptr long long long) X11DRV_wglUseFontBitmapsA @ cdecl wglUseFontBitmapsW(ptr long long long) X11DRV_wglUseFontBitmapsW + +#IME Interface +@ stdcall ImeInquire(ptr wstr wstr) +@ stdcall ImeConfigure(long long long ptr) +@ stdcall ImeDestroy(long) +@ stdcall ImeEscape(long long ptr) +@ stdcall ImeSelect(long long) +@ stdcall ImeSetActiveContext(long long) +@ stdcall ImeToAsciiEx(long long ptr ptr long long) +@ stdcall NotifyIME(long long long long) +@ stdcall ImeRegisterWord(wstr long wstr) +@ stdcall ImeUnregisterWord(wstr long wstr) +@ stdcall ImeEnumRegisterWord(ptr wstr long wstr ptr) +@ stdcall ImeSetCompositionString(long long ptr long ptr long) +@ stdcall ImeConversionList(long wstr ptr long long) +@ stdcall ImeProcessKey(long long long ptr) +@ stdcall ImeGetRegisterWordStyle(wstr long wstr) +@ stdcall ImeGetImeMenuItems(long long long ptr ptr long) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b47bdfa7784..f2ef1248179 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -277,6 +277,20 @@ extern BOOL destroy_glxpixmap(Display *display, XID glxpixmap); extern XIC X11DRV_CreateIC(XIM xim, Display *display, Window win); extern XIM X11DRV_SetupXIM(Display *display, const char *input_style); extern void X11DRV_XIMLookupChars( const char *str, DWORD count ); +extern void X11DRV_ForceXIMReset(HWND hwnd); + +/* IME support */ +extern void IME_RegisterClasses(HINSTANCE hImeInst); +extern void IME_UnregisterClasses(HINSTANCE hImeInst); +extern void IME_SetOpenStatus(BOOL fOpen); +extern void IME_XIMPresent(BOOL present); +extern LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam); +extern INT IME_GetCursorPos(); +extern void IME_UpdateAssociation(HWND focus); +extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, + DWORD dwCompLen, LPCVOID lpRead, + DWORD dwReadLen); +extern BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue); extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ); extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index d445e64405a..f90efed7ba3 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -672,12 +672,14 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { case DLL_PROCESS_ATTACH: ret = process_attach(); + IME_RegisterClasses(hinst); break; case DLL_THREAD_DETACH: thread_detach(); break; case DLL_PROCESS_DETACH: process_detach(); + IME_UnregisterClasses(hinst); break; } return ret; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index ad28bc5b504..44aefa88a9e 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -500,6 +500,8 @@ XIM X11DRV_SetupXIM(Display *display, const char *input_style) } wine_tsx11_unlock(); + IME_XIMPresent(TRUE); + IME_UpdateAssociation(NULL); if(!hImmDll) { -- 2.11.4.GIT