From 9672b791eefc5f4ae396c9014d27406d82d07fa2 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Wed, 21 Jan 2004 02:22:26 +0000 Subject: [PATCH] Use X11 XIM callbacks to enable full IME support. Correct some timing issues with XIM input. Start to provide the framework for the MSIME messages. --- dlls/imm32/Makefile.in | 2 +- dlls/imm32/imm.c | 917 ++++++++++++++++++++++++++++++-------- dlls/imm32/imm32.spec | 13 +- dlls/x11drv/Makefile.in | 1 + dlls/x11drv/event.c | 4 + dlls/x11drv/keyboard.c | 17 +- dlls/x11drv/window.c | 17 +- dlls/x11drv/x11drv.h | 5 + dlls/x11drv/x11drv.spec | 3 + dlls/x11drv/x11drv_main.c | 20 +- dlls/x11drv/xim.c | 593 ++++++++++++++++++++++++ 11 files changed, 1388 insertions(+), 204 deletions(-) create mode 100644 dlls/x11drv/xim.c diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index a25c6ca9692..b3dec602a70 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = imm32.dll -IMPORTS = user32 kernel32 +IMPORTS = user32 gdi32 kernel32 ALTNAMES = imm.dll SPEC_SRCS16 = $(ALTNAMES:.dll=.spec) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 5c931f20fd8..341a0e54a3b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2,7 +2,7 @@ * IMM32 library * * Copyright 1998 Patrik Stridvall - * Copyright 2002 CodeWeavers, Aric Stewart + * Copyright 2002, 2003 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 @@ -32,46 +32,82 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); +#define FROM_IME 0xcafe1337 + +static void (WINAPI *pX11DRV_ForceXIMReset)(HWND); + typedef struct tagInputContextData { - LPBYTE CompositionString; - LPBYTE CompositionReadingString; - LPBYTE ResultString; - LPBYTE ResultReadingString; - DWORD dwCompStringSize; - DWORD dwCompReadStringSize; - DWORD dwResultStringSize; - DWORD dwResultReadStringSize; - HWND hwnd; - BOOL bOpen; - BOOL bRead; -} InputContextData; + LPBYTE CompositionString; + LPBYTE CompositionReadingString; + LPBYTE ResultString; + LPBYTE ResultReadingString; + DWORD dwCompStringSize; /* buffer size */ + DWORD dwCompStringLength; /* string length (in bytes) */ + DWORD dwCompReadStringSize; + DWORD dwResultStringSize; + DWORD dwResultReadStringSize; + HWND hwnd; + BOOL bOpen; + BOOL bInternalState; + BOOL bRead; + LOGFONTW font; + HFONT textfont; + COMPOSITIONFORM CompForm; +} InputContextData; static InputContextData *root_context = NULL; static HWND hwndDefault = NULL; static HANDLE hImeInst; -static const WCHAR WC_IMECLASSNAME[] = {'W','i','n','e','I','M','E','C','l','a','s','s',0}; +static const WCHAR WC_IMECLASSNAME[] = {'I','M','E',0}; -static LRESULT CALLBACK IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +/* 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); +static void ImmInternalPostIMEMessage(UINT, WPARAM, LPARAM); +static void ImmInternalSetOpenStatus(BOOL fOpen); static VOID IMM_PostResult(InputContextData *data) { int i; + TRACE("Posting result as IME_CHAR\n"); for (i = 0; i < data->dwResultStringSize / sizeof (WCHAR); i++) - SendMessageW(data->hwnd, WM_IME_CHAR, ((WCHAR*)data->ResultString)[i], 1); + ImmInternalPostIMEMessage (WM_IME_CHAR, ((WCHAR*)data->ResultString)[i], + 1); + + /* clear the buffer */ + if (data->dwResultStringSize) + HeapFree(GetProcessHeap(),0,data->ResultString); + data->dwResultStringSize = 0; + data->ResultString = NULL; } static void IMM_Register(void) { WNDCLASSW wndClass; ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_IME; - wndClass.lpfnWndProc = IME_WindowProc; + wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW; + wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; - wndClass.hCursor = NULL; + 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; RegisterClassW(&wndClass); } @@ -81,15 +117,31 @@ static void IMM_Unregister(void) 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, %lx, %p\n",hInstDLL,fdwReason,lpReserved); switch (fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstDLL); hImeInst = hInstDLL; + IMM_RegisterMessages(); + x11drv = GetModuleHandleA("x11drv.dll"); + if (x11drv) pX11DRV_ForceXIMReset = (void *)GetProcAddress( x11drv, "ForceXIMReset"); break; case DLL_PROCESS_DETACH: if (hwndDefault) @@ -103,6 +155,52 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) 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->hwnd,msg,wParam,lParam); + else + PostMessageW(target, msg, wParam, lParam); +} + + +static void ImmInternalSetOpenStatus(BOOL fOpen) +{ + TRACE("Setting internal state to %s\n",(fOpen)?"OPEN":"CLOSED"); + + root_context->bOpen = fOpen; + root_context->bInternalState = fOpen; + + if (fOpen == FALSE) + { + ShowWindow(hwndDefault,SW_HIDE); + + if (root_context->dwCompStringSize) + HeapFree(GetProcessHeap(),0,root_context->CompositionString); + if (root_context->dwCompReadStringSize) + HeapFree(GetProcessHeap(),0,root_context->CompositionReadingString); + if (root_context->dwResultStringSize) + HeapFree(GetProcessHeap(),0,root_context->ResultString); + if (root_context->dwResultReadStringSize) + HeapFree(GetProcessHeap(),0,root_context->ResultReadingString); + root_context->dwCompStringSize = 0; + root_context->dwCompStringLength = 0; + root_context->CompositionString = NULL; + root_context->dwCompReadStringSize = 0; + root_context->CompositionReadingString = NULL; + root_context->dwResultStringSize = 0; + root_context->ResultString = NULL; + root_context->dwResultReadStringSize = 0; + root_context->ResultReadingString = NULL; + } + else + ShowWindow(hwndDefault, SW_SHOWNOACTIVATE); + + SendMessageW(root_context->hwnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0); +} + /*********************************************************************** * ImmAssociateContext (IMM32.@) @@ -111,7 +209,7 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; - FIXME("(%p, %p): semi-stub\n",hWnd,hIMC); + WARN("(%p, %p): semi-stub\n",hWnd,hIMC); if (!data) return FALSE; @@ -215,6 +313,12 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) if (data->dwResultReadStringSize) HeapFree(GetProcessHeap(),0,data->ResultReadingString); + if (data->textfont) + { + DeleteObject(data->textfont); + data->textfont = NULL; + } + HeapFree(GetProcessHeap(),0,data); } return TRUE; @@ -371,29 +475,79 @@ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) LONG WINAPI ImmGetCompositionStringA( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) { - LONG rc; - LPBYTE wcstring=NULL; + CHAR *buf; + LONG rc = 0; + InputContextData *data = (InputContextData*)hIMC; - FIXME("(%p, %ld, %p, %ld): stub\n", - hIMC, dwIndex, lpBuf, dwBufLen); + TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen); - if (dwBufLen > 0) - wcstring = HeapAlloc(GetProcessHeap(),0,dwBufLen * 2); - - rc = ImmGetCompositionStringW(hIMC, dwIndex, wcstring, dwBufLen*2 ); + if (!data) + return FALSE; - if ((rc > dwBufLen) || (rc == 0)) + if (dwIndex == GCS_RESULTSTR) { - if (wcstring) - HeapFree(GetProcessHeap(),0,wcstring); + TRACE("GSC_RESULTSTR %p %li\n",data->ResultString, + data->dwResultStringSize); - return rc; + buf = HeapAlloc( GetProcessHeap(), 0, data->dwResultStringSize * 3 ); + rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)data->ResultString, + data->dwResultStringSize / sizeof(WCHAR), buf, + data->dwResultStringSize * 3, NULL, NULL); + if (dwBufLen >= rc) + memcpy(lpBuf,buf,rc); + + data->bRead = TRUE; + HeapFree( GetProcessHeap(), 0, buf ); } - - rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)wcstring, (rc / sizeof(WCHAR)), - lpBuf, dwBufLen, NULL, NULL); + else if (dwIndex == GCS_COMPSTR) + { + TRACE("GSC_COMPSTR %p %li\n",data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,wcstring); + buf = HeapAlloc( GetProcessHeap(), 0, data->dwCompStringLength * 3 ); + rc = WideCharToMultiByte(CP_ACP, 0,(LPWSTR)data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR), buf, + data->dwCompStringLength* 3, NULL, NULL); + if (dwBufLen >= rc) + memcpy(lpBuf,buf,rc); + HeapFree( GetProcessHeap(), 0, buf ); + } + else if (dwIndex == GCS_COMPATTR) + { + TRACE("GSC_COMPATTR %p %li\n",data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR)); + + rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR), NULL, + 0, NULL, NULL); + + if (dwBufLen >= rc) + { + int i=0; + for (i = 0; i < rc; i++) + ((LPBYTE)lpBuf)[i] = ATTR_INPUT; + } + } + else if (dwIndex == GCS_COMPCLAUSE) + { + TRACE("GSC_COMPCLAUSE %p %li\n",data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR)); + + rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)data->CompositionString, + data->dwCompStringLength/ sizeof(WCHAR), NULL, + 0, NULL, NULL); + + if (dwBufLen >= sizeof(DWORD)*2) + { + ((LPDWORD)lpBuf)[0] = 0; + ((LPDWORD)lpBuf)[1] = rc; + } + rc = sizeof(DWORD)*2; + } + else + { + FIXME("Unhandled index 0x%lx\n",dwIndex); + } return rc; } @@ -405,9 +559,10 @@ LONG WINAPI ImmGetCompositionStringW( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) { + LONG rc = 0; InputContextData *data = (InputContextData*)hIMC; - FIXME("(%p, 0x%lx, %p, %ld): stub\n", + TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen ); @@ -421,36 +576,59 @@ LONG WINAPI ImmGetCompositionStringW( if (dwBufLen >= data->dwResultStringSize) memcpy(lpBuf,data->ResultString,data->dwResultStringSize); - return data->dwResultStringSize; + rc = data->dwResultStringSize; } - - if (dwIndex == GCS_RESULTREADSTR) + else if (dwIndex == GCS_RESULTREADSTR) { if (dwBufLen >= data->dwResultReadStringSize) memcpy(lpBuf,data->ResultReadingString, data->dwResultReadStringSize); - return data->dwResultReadStringSize; + rc = data->dwResultReadStringSize; } - - if (dwIndex == GCS_COMPSTR) + else if (dwIndex == GCS_COMPSTR) { - if (dwBufLen >= data->dwCompStringSize) - memcpy(lpBuf,data->CompositionString,data->dwCompStringSize); - - return data->dwCompStringSize; - } + if (dwBufLen >= data->dwCompStringLength) + memcpy(lpBuf,data->CompositionString,data->dwCompStringLength); - if (dwIndex == GCS_COMPREADSTR) + rc = data->dwCompStringLength; + } + else if (dwIndex == GCS_COMPATTR) + { + int len = data->dwCompStringLength; + + if (dwBufLen >= len) + { + int i=0; + for (i = 0; i < len; i++) + ((LPBYTE)lpBuf)[i] = ATTR_INPUT; + } + + rc = len; + } + else if (dwIndex == GCS_COMPCLAUSE) + { + if (dwBufLen >= sizeof(DWORD)*2) + { + ((LPDWORD)lpBuf)[0] = 0; + ((LPDWORD)lpBuf)[1] = data->dwCompStringLength/sizeof(WCHAR); + } + rc = sizeof(DWORD)*2; + } + else if (dwIndex == GCS_COMPREADSTR) { if (dwBufLen >= data->dwCompReadStringSize) memcpy(lpBuf,data->CompositionReadingString, data->dwCompReadStringSize); - return data->dwCompReadStringSize; + rc = data->dwCompReadStringSize; + } + else + { + FIXME("Unhandled index 0x%lx\n",dwIndex); } - return 0; + return rc; } /*********************************************************************** @@ -458,17 +636,29 @@ LONG WINAPI ImmGetCompositionStringW( */ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { - FIXME("(%p, %p): stub\n", hIMC, lpCompForm); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + InputContextData *data = (InputContextData*)hIMC; + + TRACE("(%p, %p)\n", hIMC, lpCompForm); + + if (!data) + return FALSE; + + memcpy(lpCompForm,&(data->CompForm),sizeof(COMPOSITIONFORM)); + return 1; } /*********************************************************************** * ImmGetContext (IMM32.@) + * */ HIMC WINAPI ImmGetContext(HWND hWnd) { FIXME("(%p): stub\n", hWnd); + + if (!root_context) + return NULL; + + root_context->hwnd = hWnd; return (HIMC)root_context; } @@ -508,11 +698,12 @@ DWORD WINAPI ImmGetConversionListW( BOOL WINAPI ImmGetConversionStatus( HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) { - FIXME("(%p, %p, %p): stub\n", - hIMC, lpfdwConversion, lpfdwSentence - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + TRACE("(%p, %p, %p): best guess\n", hIMC, lpfdwConversion, lpfdwSentence); + if (lpfdwConversion) + *lpfdwConversion = IME_CMODE_NATIVE; + if (lpfdwSentence) + *lpfdwSentence = IME_SMODE_NONE; + return TRUE; } /*********************************************************************** @@ -520,15 +711,18 @@ BOOL WINAPI ImmGetConversionStatus( */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { - FIXME("(%p): semi-stub\n", hWnd); + FIXME("(%p - %p %p ): semi-stub\n", hWnd,hwndDefault, root_context); - if ((!hwndDefault) && (root_context)) + if (hwndDefault == NULL) { - static const WCHAR name[] = {'I','M','E',0}; - IMM_Register(); + static const WCHAR the_name[] = {'I','M','E','\0'}; - hwndDefault = CreateWindowW( WC_IMECLASSNAME, - name,WS_POPUPWINDOW,0,0,0,0,0,0,hImeInst,0); + IMM_Register(); + hwndDefault = CreateWindowExW( WS_EX_CLIENTEDGE, WC_IMECLASSNAME, + the_name, WS_POPUPWINDOW|WS_CAPTION, 0, 0, 120, 55, 0, 0, + hImeInst, 0); + + TRACE("Default created (0x%x)\n",(INT)hwndDefault); } return (HWND)hwndDefault; @@ -540,11 +734,29 @@ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) UINT WINAPI ImmGetDescriptionA( HKL hKL, LPSTR lpszDescription, UINT uBufLen) { - FIXME("(%p, %s, %d): stub\n", - hKL, debugstr_a(lpszDescription), uBufLen - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + 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; } /*********************************************************************** @@ -552,11 +764,13 @@ UINT WINAPI ImmGetDescriptionA( */ UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) { - FIXME("(%p, %s, %d): stub\n", - hKL, debugstr_w(lpszDescription), uBufLen - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + 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 ); } /*********************************************************************** @@ -590,9 +804,7 @@ DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBu UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) { - FIXME("(%p, %s, %d): stub\n", - hKL, debugstr_a(lpszFileName), uBufLen - ); + FIXME("(%p, %p, %d): stub\n", hKL, lpszFileName, uBufLen); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } @@ -603,9 +815,7 @@ UINT WINAPI ImmGetIMEFileNameA( UINT WINAPI ImmGetIMEFileNameW( HKL hKL, LPWSTR lpszFileName, UINT uBufLen) { - FIXME("(%p, %s, %d): stub\n", - hKL, debugstr_w(lpszFileName), uBufLen - ); + FIXME("(%p, %p, %d): stub\n", hKL, lpszFileName, uBufLen); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } @@ -617,10 +827,10 @@ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) { InputContextData *data = (InputContextData*)hIMC; + if (!data) + return FALSE; FIXME("(%p): semi-stub\n", hIMC); - if (!data) return FALSE; - return data->bOpen; } @@ -630,23 +840,38 @@ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) { DWORD rc = 0; - FIXME("(%p, %ld): semi-stub\n", hKL, fdwIndex); + TRACE("(%p, %ld)\n", hKL, fdwIndex); switch (fdwIndex) { case IGP_PROPERTY: - rc = IME_PROP_UNICODE | IME_PROP_SPECIAL_UI; + 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: - rc = SCS_CAP_COMPSTR; + 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; } @@ -751,11 +976,29 @@ BOOL WINAPI ImmIsIME(HKL hKL) BOOL WINAPI ImmIsUIMessageA( HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) { - FIXME("(%p, %d, %d, %ld): stub\n", - hWndIME, msg, wParam, lParam - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL rc = FALSE; + + TRACE("(%p, %x, %d, %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; } /*********************************************************************** @@ -764,11 +1007,19 @@ BOOL WINAPI ImmIsUIMessageA( BOOL WINAPI ImmIsUIMessageW( HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) { - FIXME("(%p, %d, %d, %ld): stub\n", - hWndIME, msg, wParam, lParam - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL rc = FALSE; + TRACE("(%p, %d, %d, %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; } /*********************************************************************** @@ -777,11 +1028,106 @@ BOOL WINAPI ImmIsUIMessageW( BOOL WINAPI ImmNotifyIME( HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { + BOOL rc = FALSE; FIXME("(%p, %ld, %ld, %ld): stub\n", - hIMC, dwAction, dwIndex, dwValue - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + hIMC, dwAction, dwIndex, dwValue); + + 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"); + if (pX11DRV_ForceXIMReset) + pX11DRV_ForceXIMReset(root_context->hwnd); + if (root_context->dwCompStringSize) + { + HeapFree(GetProcessHeap(),0, + root_context->CompositionString); + root_context->dwCompStringSize = 0; + root_context->dwCompStringLength = 0; + root_context->CompositionString = NULL; + 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->hwnd); + + if (root_context->dwResultStringSize) + { + HeapFree(GetProcessHeap(),0,root_context->ResultString); + root_context->dwResultStringSize = 0; + root_context->ResultString = NULL; + } + if (root_context->dwCompStringLength) + { + root_context->ResultString = HeapAlloc( + GetProcessHeap(), 0, root_context->dwCompStringLength); + root_context->dwResultStringSize = + root_context->dwCompStringLength; + + memcpy(root_context->ResultString, + root_context->CompositionString, + root_context->dwCompStringLength); + + HeapFree(GetProcessHeap(),0, + root_context->CompositionString); + + root_context->dwCompStringSize = 0; + root_context->dwCompStringLength = 0; + root_context->CompositionString = NULL; + root_context->bRead = FALSE; + + ImmInternalPostIMEMessage(WM_IME_COMPOSITION, 0, + GCS_COMPSTR); + + ImmInternalPostIMEMessage(WM_IME_COMPOSITION, + root_context->ResultString[0], + GCS_RESULTSTR|GCS_RESULTCLAUSE); + } + 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 (%li)\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; } /*********************************************************************** @@ -816,8 +1162,8 @@ BOOL WINAPI ImmRegisterWordW( BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) { FIXME("(%p, %p): stub\n", hWnd, hIMC); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + + return TRUE; } /*********************************************************************** @@ -836,9 +1182,26 @@ BOOL WINAPI ImmSetCandidateWindow( */ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { - FIXME("(%p, %p): stub\n", hIMC, lplf); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + InputContextData *data = (InputContextData*)hIMC; + TRACE("(%p, %p)\n", hIMC, lplf); + + if (!data) + return FALSE; + + memcpy(&data->font,lplf,sizeof(LOGFONTA)); + MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->font.lfFaceName, + LF_FACESIZE); + + SendMessageW(root_context->hwnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0); + + if (data->textfont) + { + DeleteObject(data->textfont); + data->textfont = NULL; + } + + data->textfont = CreateFontIndirectW(&data->font); + return TRUE; } /*********************************************************************** @@ -846,9 +1209,22 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) */ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { - FIXME("(%p, %p): stub\n", hIMC, lplf); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + InputContextData *data = (InputContextData*)hIMC; + TRACE("(%p, %p)\n", hIMC, lplf); + + if (!data) + return FALSE; + + memcpy(&data->font,lplf,sizeof(LOGFONTW)); + SendMessageW(root_context->hwnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0); + + if (data->textfont) + { + DeleteObject(data->textfont); + data->textfont = NULL; + } + data->textfont = CreateFontIndirectW(&data->font); + return TRUE; } /*********************************************************************** @@ -859,11 +1235,39 @@ BOOL WINAPI ImmSetCompositionStringA( LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen) { - FIXME("(%p, %ld, %p, %ld, %p, %ld): stub\n", - hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + DWORD comp_len; + DWORD read_len; + WCHAR *CompBuffer = NULL; + WCHAR *ReadBuffer = NULL; + BOOL rc; + + TRACE("(%p, %ld, %p, %ld, %p, %ld): stub\n", + hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); + + comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); + if (comp_len) + { + CompBuffer = (WCHAR*)HeapAlloc(GetProcessHeap(),0,comp_len); + MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len); + } + + read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0); + if (read_len) + { + ReadBuffer = (WCHAR*)HeapAlloc(GetProcessHeap(),0,read_len); + MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len); + } + + rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len, + ReadBuffer, read_len); + + if (CompBuffer) + HeapFree(GetProcessHeap(), 0, CompBuffer); + + if (ReadBuffer) + HeapFree(GetProcessHeap(), 0, ReadBuffer); + + return rc; } /*********************************************************************** @@ -874,61 +1278,60 @@ BOOL WINAPI ImmSetCompositionStringW( LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen) { - InputContextData *data = (InputContextData*)hIMC; + DWORD flags = 0; + WCHAR wParam = 0; - FIXME("(%p, %ld, %p, %ld, %p, %ld): semi-stub\n", - hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen - ); + TRACE("(%p, %ld, %p, %ld, %p, %ld): stub\n", + hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); - if (!data) - return FALSE; - if ((dwIndex == SCS_SETSTR)&&(dwCompLen || dwReadLen)) - SendMessageW(data->hwnd, WM_IME_STARTCOMPOSITION, 0, 0); + 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) { - INT send_comp = 0; + flags = GCS_COMPSTR; + if (root_context->dwCompStringLength) + HeapFree(GetProcessHeap(),0,root_context->CompositionString); - if (lpComp && dwCompLen) - { -/* if (data->dwCompStringSize) - HeapFree(GetProcessHeap(),0,data->CompositionString); - data->dwCompStringSize = dwCompLen; - data->CompositionString = HeapAlloc(GetProcessHeap(),0,dwCompLen); - memcpy(data->CompositionString,lpComp,dwCompLen); - send_comp |= GCS_COMPSTR; -*/ - data->bRead = FALSE; + root_context->dwCompStringLength = dwCompLen; + root_context->dwCompStringSize = dwCompLen; - if (data->dwResultStringSize) - HeapFree(GetProcessHeap(),0,data->ResultString); - data->dwResultStringSize= dwCompLen; - data->ResultString= HeapAlloc(GetProcessHeap(),0,dwCompLen); - memcpy(data->ResultString,lpComp,dwCompLen); - send_comp |= GCS_RESULTSTR; - } + if (dwCompLen && lpComp) + { + root_context->CompositionString = HeapAlloc(GetProcessHeap(), 0, + dwCompLen); + memcpy(root_context->CompositionString,lpComp,dwCompLen); - if (lpRead && dwReadLen) - { - if (data->dwCompReadStringSize) - HeapFree(GetProcessHeap(),0,data->CompositionReadingString); - data->dwCompReadStringSize= dwReadLen; - data->CompositionReadingString = HeapAlloc(GetProcessHeap(), 0, - dwReadLen); - memcpy(data->CompositionReadingString,lpRead,dwReadLen); - send_comp |= GCS_COMPREADSTR; - } + wParam = ((WCHAR*)lpComp)[0]; + flags |= GCS_COMPCLAUSE | GCS_COMPATTR; + } + else + root_context->CompositionString = NULL; - if (send_comp) - SendMessageW(data->hwnd, WM_IME_COMPOSITION, 0, send_comp); - - SendMessageW(data->hwnd, WM_IME_ENDCOMPOSITION, 0, 0); - - return TRUE; } - return FALSE; + + UpdateDataInDefaultIMEWindow(hwndDefault); + + ImmInternalPostIMEMessage(WM_IME_COMPOSITION, wParam, flags); + + return TRUE; } /*********************************************************************** @@ -937,9 +1340,32 @@ BOOL WINAPI ImmSetCompositionStringW( BOOL WINAPI ImmSetCompositionWindow( HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { - FIXME("(%p, %p): stub\n", hIMC, lpCompForm); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + BOOL reshow = FALSE; + InputContextData *data = (InputContextData*)hIMC; + + TRACE("(%p, %p)\n", hIMC, lpCompForm); + TRACE("\t%lx, (%li,%li), (%li,%li - %li,%li)\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->CompForm,lpCompForm,sizeof(COMPOSITIONFORM)); + + if (IsWindowVisible(hwndDefault)) + { + reshow = TRUE; + ShowWindow(hwndDefault,SW_HIDE); + } + + FIXME("STUB\n"); + + if (reshow) + ShowWindow(hwndDefault,SW_SHOWNOACTIVATE); + + SendMessageW(root_context->hwnd, WM_IME_NOTIFY,IMN_SETCOMPOSITIONWINDOW, 0); + return TRUE; } /*********************************************************************** @@ -962,14 +1388,44 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { InputContextData *data = (InputContextData*)hIMC; FIXME("Semi-Stub\n"); - if (data) + + if (hIMC == (HIMC)FROM_IME) { - data->bOpen = fOpen; - SendMessageW(data->hwnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0); + if (fOpen) + ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION, 0, 0); + + ImmInternalSetOpenStatus(fOpen); + + if (!fOpen) + ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION, 0, 0); + return TRUE; } - else + + if (!data) return FALSE; + + if (fOpen != data->bInternalState) + { + if (fOpen == FALSE && pX11DRV_ForceXIMReset) + pX11DRV_ForceXIMReset(data->hwnd); + + if (fOpen == FALSE) + ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION,0,0); + else + ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION,0,0); + + ImmInternalSetOpenStatus(fOpen); + ImmInternalSetOpenStatus(!fOpen); + + if (data->bOpen == FALSE) + ImmInternalPostIMEMessage(WM_IME_ENDCOMPOSITION,0,0); + else + ImmInternalPostIMEMessage(WM_IME_STARTCOMPOSITION,0,0); + + return FALSE; + } + return TRUE; } /*********************************************************************** @@ -1018,42 +1474,155 @@ BOOL WINAPI ImmUnregisterWordW( return FALSE; } + +/***** + * Internal functions to help with IME window management + */ +static void PaintDefaultIMEWnd(HWND hwnd) +{ + PAINTSTRUCT ps; + RECT rect; + HDC hdc = BeginPaint(hwnd,&ps); + GetClientRect(hwnd,&rect); + + if (root_context->dwCompStringLength && root_context->CompositionString) + { + SIZE size; + POINT pt; + HFONT oldfont = NULL; + + if (root_context->textfont) + oldfont = SelectObject(hdc,root_context->textfont); + + TextOutW(hdc, 0,0,(LPWSTR)root_context->CompositionString, + root_context->dwCompStringLength / sizeof(WCHAR)); + + GetTextExtentPoint32W(hdc, (LPWSTR)root_context->CompositionString, + root_context->dwCompStringLength / sizeof(WCHAR), + &size); + pt.x = size.cx; + pt.y = size.cy; + LPtoDP(hdc,&pt,1); + rect.left = pt.x; + + if (oldfont) + SelectObject(hdc,oldfont); + } + FillRect(hdc,&rect, (HBRUSH) (COLOR_WINDOW+1)); + EndPaint(hwnd,&ps); +} + +static void UpdateDataInDefaultIMEWindow(HWND hwnd) +{ + RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE); +} + /* * The window proc for the default IME window */ -static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, +static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - TRACE("Incoming Message 0x%x (0x%08x, 0x%08x)\n", uMsg, (UINT)wParam, + LRESULT rc = 0; + + TRACE("Incoming Message 0x%x (0x%08x, 0x%08x)\n", msg, (UINT)wParam, (UINT)lParam); - switch(uMsg) + 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\n", - "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam); + TRACE("IME message %s, 0x%x, 0x%x (%i)\n", + "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam, + root_context->bRead); + if ((lParam & GCS_RESULTSTR) && (!root_context->bRead)) + IMM_PostResult(root_context); + else + UpdateDataInDefaultIMEWindow(hwnd); break; case WM_IME_STARTCOMPOSITION: TRACE("IME message %s, 0x%x, 0x%x\n", "WM_IME_STARTCOMPOSITION", (UINT)wParam, (UINT)lParam); + root_context->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); - /* - * if the string has not been read, then send it as - * WM_IME_CHAR messages - */ - if (!root_context->bRead) - IMM_PostResult(root_context); + 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); } - return 0; + /* 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; } diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 166452da63b..f6e5641d668 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -21,22 +21,23 @@ @ stdcall ImmGetCompositionFontW(long ptr) @ stdcall ImmGetCompositionStringA (long long ptr long) @ stdcall ImmGetCompositionStringW (long long ptr long) +@ stdcall ImmGetCompositionString (long long ptr long) ImmGetCompositionStringA @ stdcall ImmGetCompositionWindow(long ptr) @ stdcall ImmGetContext(long) @ stdcall ImmGetConversionListA(long long str ptr long long) @ stdcall ImmGetConversionListW(long long wstr ptr long long) @ stdcall ImmGetConversionStatus(long ptr ptr) @ stdcall ImmGetDefaultIMEWnd(long) -@ stdcall ImmGetDescriptionA(long str long) -@ stdcall ImmGetDescriptionW(long wstr long) -@ stdcall ImmGetGuideLineA(long long str long) -@ stdcall ImmGetGuideLineW(long long wstr long) +@ stdcall ImmGetDescriptionA(long ptr long) +@ stdcall ImmGetDescriptionW(long ptr long) +@ stdcall ImmGetGuideLineA(long long ptr long) +@ stdcall ImmGetGuideLineW(long long ptr long) @ stub ImmGetHotKey @ stub ImmGetIMCCLockCount @ stub ImmGetIMCCSize @ stub ImmGetIMCLockCount -@ stdcall ImmGetIMEFileNameA(long str long) -@ stdcall ImmGetIMEFileNameW(long wstr long) +@ stdcall ImmGetIMEFileNameA(long ptr long) +@ stdcall ImmGetIMEFileNameW(long ptr long) @ stdcall ImmGetOpenStatus(long) @ stdcall ImmGetProperty(long long) @ stdcall ImmGetRegisterWordStyleA(long long ptr) diff --git a/dlls/x11drv/Makefile.in b/dlls/x11drv/Makefile.in index 87fc20e2b0b..933577f7a80 100644 --- a/dlls/x11drv/Makefile.in +++ b/dlls/x11drv/Makefile.in @@ -39,6 +39,7 @@ C_SRCS = \ x11drv_main.c \ xdnd.c \ xfont.c \ + xim.c \ xrandr.c \ xrender.c \ xvidmode.c diff --git a/dlls/x11drv/event.c b/dlls/x11drv/event.c index c1eef95573b..9cc9fb7a93e 100644 --- a/dlls/x11drv/event.c +++ b/dlls/x11drv/event.c @@ -54,6 +54,8 @@ WINE_DECLARE_DEBUG_CHANNEL(clipboard); /* X context to associate a hwnd to an X window */ extern XContext winContext; +extern BOOL ximInComposeMode; + #define DndNotDnd -1 /* OffiX drag&drop */ #define DndUnknown 0 #define DndRawData 1 @@ -532,6 +534,8 @@ static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event ) TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] ); if (event->detail == NotifyPointer) return; + if (ximInComposeMode) return; + x11drv_thread_data()->last_focus = hwnd; if ((xic = X11DRV_get_ic( hwnd ))) { diff --git a/dlls/x11drv/keyboard.c b/dlls/x11drv/keyboard.c index 3e527b8afec..d74600c2c9c 100644 --- a/dlls/x11drv/keyboard.c +++ b/dlls/x11drv/keyboard.c @@ -807,8 +807,8 @@ static const struct { {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz}, {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz}, {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty}, - {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty}, - {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty}, + {0xe0010411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty}, + {0xe0010411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty}, {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty}, {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty}, {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty}, @@ -1113,7 +1113,16 @@ void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event ) return; } - TRACE_(key)("state = %X\n", event->state); + TRACE_(key)("state = %X nbyte = %d, status 0x%x\n", event->state, ascii_chars, status); + + if (status == XBufferOverflow) + ERR("Buffer Overflow need %i!\n",ascii_chars); + + if (status == XLookupChars) + { + X11DRV_XIMLookupChars( Str, ascii_chars ); + return; + } /* If XKB extensions are used, the state mask for AltGr will use the group index instead of the modifier mask. The group index is set in bits @@ -1560,7 +1569,7 @@ HKL X11DRV_GetKeyboardLayout(DWORD dwThreadid) */ langid = PRIMARYLANGID(LANGIDFROMLCID(layout)); if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) - layout |= 0xe001 << 16; /* FIXME */ + layout = 0xe001 << 16; /* FIXME */ return (HKL)layout; } diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index 6f402366ed3..2b32f19d997 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -789,16 +789,6 @@ static Window create_whole_window( Display *display, WND *win ) return 0; } - if (is_top_level) - { - XIM xim = x11drv_thread_data()->xim; - if (xim) data->xic = XCreateIC( xim, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, data->whole_window, - XNFocusWindow, data->whole_window, - 0 ); - } - /* non-maximized child must be at bottom of Z order */ if ((win->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) { @@ -809,7 +799,12 @@ static Window create_whole_window( Display *display, WND *win ) wine_tsx11_unlock(); - if (is_top_level) X11DRV_set_wm_hints( display, win ); + if (is_top_level) + { + XIM xim = x11drv_thread_data()->xim; + if (xim) data->xic = X11DRV_CreateIC( xim, display, data->whole_window ); + X11DRV_set_wm_hints( display, win ); + } return data->whole_window; } diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index 03aee8b7885..f36599e3b17 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -234,6 +234,11 @@ extern void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev); extern void X11DRV_OpenGL_Init(Display *display); extern XVisualInfo *X11DRV_setup_opengl_visual(Display *display); +/* XIM support */ +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 int X11DRV_XDND_Event(HWND hWnd, XClientMessageEvent *event); /* exported dib functions for now */ diff --git a/dlls/x11drv/x11drv.spec b/dlls/x11drv/x11drv.spec index 3becd0ec74b..f521884d701 100644 --- a/dlls/x11drv/x11drv.spec +++ b/dlls/x11drv/x11drv.spec @@ -119,3 +119,6 @@ # X11 locks @ cdecl -norelay wine_tsx11_lock() @ cdecl -norelay wine_tsx11_unlock() + +# XIM +@ cdecl ForceXIMReset(long) X11DRV_ForceXIMReset diff --git a/dlls/x11drv/x11drv_main.c b/dlls/x11drv/x11drv_main.c index 8f6928f62b8..a94f977b8f8 100644 --- a/dlls/x11drv/x11drv_main.c +++ b/dlls/x11drv/x11drv_main.c @@ -104,6 +104,8 @@ static void *err_callback_arg; /* error callback argument */ static int err_callback_result; /* error callback result */ static unsigned long err_serial; /* serial number of first request */ static int (*old_error_handler)( Display *, XErrorEvent * ); +static int use_xim = 1; +static char input_style[20]; #define IS_OPTION_TRUE(ch) \ ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') @@ -308,6 +310,11 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) )) desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) )) + use_xim = IS_OPTION_TRUE( buffer[0] ); + + get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) ); + if (appkey) RegCloseKey( appkey ); RegCloseKey( hkey ); } @@ -460,15 +467,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) ); ExitProcess(1); } - fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */ - if ((data->xim = XOpenIM( data->display, NULL, NULL, NULL ))) - { - TRACE("X display of IM = %p\n", XDisplayOfIM(data->xim)); - TRACE("Using %s locale of Input Method\n", XLocaleOfIM(data->xim)); - } - else - WARN("Can't open input method\n"); + fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */ #ifdef HAVE_XKB if (use_xkb) @@ -480,6 +480,10 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) if (synchronous) XSynchronize( data->display, True ); wine_tsx11_unlock(); + + if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style ))) + WARN("Input Method is not available\n"); + if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE, FALSE, &data->display_fd )) { diff --git a/dlls/x11drv/xim.c b/dlls/x11drv/xim.c new file mode 100644 index 00000000000..f8cb1341292 --- /dev/null +++ b/dlls/x11drv/xim.c @@ -0,0 +1,593 @@ +/* + * Functions for further XIM control + * + * Copyright 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wingdi.h" +#include "winnls.h" +#include "x11drv.h" +#include "imm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(x11drv); + +/* this must match with imm32/imm.c */ +#define FROM_IME 0xcafe1337 + +BOOL ximInComposeMode=FALSE; + +static HIMC root_context; +static XIMStyle ximStyle = 0; +static XIMStyle ximStyleRoot = 0; + +/* moved here from imm32 for dll seperation */ +static DWORD dwCompStringLength = 0; +static LPBYTE CompositionString = NULL; +static DWORD dwCompStringSize = 0; +static LPBYTE ResultString = NULL; +static DWORD dwResultStringSize = 0; + +static HMODULE hImmDll = NULL; +static HIMC (WINAPI *pImmAssociateContext)(HWND,HIMC); +static HIMC (WINAPI *pImmCreateContext)(void); +static VOID (WINAPI *pImmSetOpenStatus)(HIMC,BOOL); +static BOOL (WINAPI *pImmSetCompositionString)(HIMC, DWORD, LPWSTR, + DWORD, LPWSTR, DWORD); +static VOID (WINAPI *pImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); + +/* WINE specific messages from the xim in x11drv level */ + +#define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea) +#define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing) +#define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing) +/* this uses all the callbacks to utilize full IME support */ +#define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing) +/* inorder to enable deadkey support */ +#define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing) + +/* + * here are the functions that sort of marshall calls into IMM32.DLL + */ +static void LoadImmDll() +{ + hImmDll = LoadLibraryA("imm32.dll"); + + pImmAssociateContext = (void *)GetProcAddress(hImmDll, "ImmAssociateContext"); + if (!pImmAssociateContext) + WARN("IMM: pImmAssociateContext not found in DLL\n"); + + pImmCreateContext = (void *)GetProcAddress(hImmDll, "ImmCreateContext"); + if (!pImmCreateContext) + WARN("IMM: pImmCreateContext not found in DLL\n"); + + pImmSetOpenStatus = (void *)GetProcAddress( hImmDll, "ImmSetOpenStatus"); + if (!pImmSetOpenStatus) + WARN("IMM: pImmSetOpenStatus not found in DLL\n"); + + pImmSetCompositionString =(void *)GetProcAddress(hImmDll, "ImmSetCompositionStringW"); + + if (!pImmSetCompositionString) + WARN("IMM: pImmSetCompositionStringW not found in DLL\n"); + + pImmNotifyIME = (void *)GetProcAddress( hImmDll, "ImmNotifyIME"); + + if (!pImmNotifyIME) + WARN("IMM: pImmNotifyIME not found in DLL\n"); +} + +static BOOL X11DRV_ImmSetInternalString(DWORD dwIndex, DWORD dwOffset, + DWORD selLength, LPWSTR lpComp, DWORD dwCompLen) +{ + /* Composition strings are edited in chunks */ + int byte_length = dwCompLen * sizeof(WCHAR); + int byte_offset = dwOffset * sizeof(WCHAR); + int byte_selection = selLength * sizeof(WCHAR); + BOOL rc = FALSE; + + TRACE("( %li, %li, %ld, %p, %ld):\n", dwOffset, selLength, dwIndex, lpComp, + dwCompLen ); + + if (dwIndex == GCS_COMPSTR) + { + int i,j; + LPBYTE ptr_new; + LPBYTE ptr_old; + + if ((dwCompLen == 0) && (selLength == 0)) + { + /* DO Nothing */ + } + /* deletion occurred */ + else if ((dwCompLen== 0) && (selLength != 0)) + { + if (dwCompStringLength) + { + for (i = 0; i < byte_selection; i++) + { + if (byte_offset+byte_selection+i < + dwCompStringLength) + { + CompositionString[byte_offset + i] = + CompositionString[byte_offset + byte_selection + i]; + } + else + CompositionString[byte_offset + i] = 0; + } + /* clean up the end */ + dwCompStringLength -= byte_selection; + + i = dwCompStringLength; + while (i < dwCompStringSize) + { + CompositionString[i++] = 0; + } + } + } + else + { + int byte_expansion = byte_length - byte_selection; + + if (byte_expansion + dwCompStringLength >= dwCompStringSize) + { + if (CompositionString) + CompositionString = + HeapReAlloc(GetProcessHeap(), 0, + CompositionString, + dwCompStringSize + + byte_expansion); + else + CompositionString = + HeapAlloc(GetProcessHeap(), 0, dwCompStringSize + + byte_expansion); + + memset(&(CompositionString[dwCompStringSize]), byte_expansion, + 0); + + dwCompStringSize += byte_expansion; + } + + ptr_new = ((LPBYTE)lpComp); + ptr_old = CompositionString + byte_offset + byte_selection; + + dwCompStringLength += byte_expansion; + + for (j=0,i = byte_offset; i < dwCompStringSize; i++) + { + if (j < byte_length) + { + CompositionString[i] = ptr_new[j++]; + } + else + { + if (ptr_old < CompositionString + dwCompStringSize) + { + CompositionString[i] = *ptr_old; + ptr_old++; + } + else + CompositionString[i] = 0; + } + } + } + + if (pImmSetCompositionString) + rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR, + (LPWSTR)CompositionString, dwCompStringLength, + NULL, 0); + } + else if ((dwIndex == GCS_RESULTSTR) && (lpComp) && (dwCompLen)) + { + if (dwResultStringSize) + HeapFree(GetProcessHeap(),0,ResultString); + dwResultStringSize= byte_length; + ResultString= HeapAlloc(GetProcessHeap(),0,byte_length); + memcpy(ResultString,lpComp,byte_length); + + if (pImmSetCompositionString) + rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR, + (LPWSTR)ResultString, dwResultStringSize, + NULL, 0); + + if (pImmNotifyIME) + pImmNotifyIME((HIMC)FROM_IME, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + } + + return rc; +} + +void X11DRV_XIMLookupChars( const char *str, DWORD count ) +{ + DWORD dwOutput; + WCHAR wcOutput[64]; + HWND focus; + + dwOutput = MultiByteToWideChar(CP_UNIXCP, 0, str, count, wcOutput, sizeof(wcOutput)); + + if (pImmAssociateContext && (focus = GetFocus())) + pImmAssociateContext(focus,root_context); + + X11DRV_ImmSetInternalString(GCS_RESULTSTR,0,0,wcOutput,dwOutput); +} + +static void X11DRV_ImmSetOpenStatus(BOOL fOpen) +{ + if (fOpen == FALSE) + { + if (dwCompStringSize) + HeapFree(GetProcessHeap(),0,CompositionString); + + dwCompStringSize = 0; + dwCompStringLength = 0; + CompositionString = NULL; + + if (dwResultStringSize) + HeapFree(GetProcessHeap(),0,ResultString); + + dwResultStringSize = 0; + ResultString = NULL; + } + + if (pImmSetOpenStatus) + pImmSetOpenStatus((HIMC)FROM_IME,fOpen); +} + +static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data) +{ + TRACE("PreEditStartCallback %p\n",ic); + X11DRV_ImmSetOpenStatus(TRUE); + ximInComposeMode = TRUE; + return -1; +} + +static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) +{ + TRACE("PreeditDoneCallback %p\n",ic); + ximInComposeMode = FALSE; + X11DRV_ImmSetOpenStatus(FALSE); +} + +static void XIMPreEditDrawCallback(XIM ic, XPointer client_data, + XIMPreeditDrawCallbackStruct *P_DR) +{ + DWORD dwOutput; + WCHAR wcOutput[64]; + + TRACE("PreEditDrawCallback %p\n",ic); + + if (P_DR) + { + int sel = P_DR->chg_first; + int len = P_DR->chg_length; + if (P_DR->text) + { + if (! P_DR->text->encoding_is_wchar) + { + TRACE("multibyte\n"); + dwOutput = MultiByteToWideChar(CP_UNIXCP, 0, + P_DR->text->string.multi_byte, -1, + wcOutput, 64); + + /* ignore null */ + dwOutput --; + X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, wcOutput, dwOutput); + } + else + { + FIXME("wchar PROBIBILY WRONG\n"); + X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, + (LPWSTR)P_DR->text->string.wide_char, + P_DR->text->length); + } + } + else + X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, NULL, 0); + } + TRACE("Finished\n"); +} + +static void XIMPreEditCaretCallback(XIC ic, XPointer client_data, + XIMPreeditCaretCallbackStruct *P_C) +{ + FIXME("PreeditCaretCalback %p\n",ic); +} + +void WINAPI X11DRV_ForceXIMReset(HWND hwnd) +{ + XIC ic = X11DRV_get_ic(hwnd); + if (ic) + { + char* leftover; + TRACE("Forcing Reset %p\n",ic); + wine_tsx11_lock(); + leftover = XmbResetIC(ic); + XFree(leftover); + wine_tsx11_unlock(); + } +} + +/*********************************************************************** +* X11DRV Ime creation +*/ +XIM X11DRV_SetupXIM(Display *display, const char *input_style) +{ + XIMStyle ximStyleRequest, ximStyleCallback, ximStyleNone; + XIMStyles *ximStyles = NULL; + INT i; + XIM xim; + + ximStyleRequest = STYLE_CALLBACK; + + if (!strcasecmp(input_style, "offthespot")) + ximStyleRequest = STYLE_OFFTHESPOT; + else if (!strcasecmp(input_style, "overthespot")) + ximStyleRequest = STYLE_OVERTHESPOT; + else if (!strcasecmp(input_style, "root")) + ximStyleRequest = STYLE_ROOT; + + wine_tsx11_lock(); + + if(!XSupportsLocale()) + { + WARN("X does not support locale.\n"); + goto err; + } + if(XSetLocaleModifiers("") == NULL) + { + WARN("Could not set locale modifiers.\n"); + goto err; + } + + xim = XOpenIM(display, NULL, NULL, NULL); + if (xim == NULL) + { + WARN("Could not open input method.\n"); + goto err; + } + + TRACE("X display of IM = %p\n", XDisplayOfIM(xim)); + TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim)); + + XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL); + if (ximStyles == 0) + { + WARN("Could not find supported input style.\n"); + } + else + { + TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles); + + ximStyleRoot = 0; + ximStyleNone = 0; + ximStyleCallback = 0; + + for (i = 0; i < ximStyles->count_styles; ++i) + { + int style = ximStyles->supported_styles[i]; + TRACE("ximStyles[%d] = %s%s%s%s%s\n", i, + (style&XIMPreeditArea)?"XIMPreeditArea ":"", + (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"", + (style&XIMPreeditPosition)?"XIMPreeditPosition ":"", + (style&XIMPreeditNothing)?"XIMPreeditNothing ":"", + (style&XIMPreeditNone)?"XIMPreeditNone ":""); + if (!ximStyle && (ximStyles->supported_styles[i] == + ximStyleRequest)) + { + ximStyle = ximStyleRequest; + TRACE("Setting Style: ximStyle = ximStyleRequest\n"); + } + else if (!ximStyleRoot &&(ximStyles->supported_styles[i] == + STYLE_ROOT)) + { + ximStyleRoot = STYLE_ROOT; + TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n"); + } + else if (!ximStyleCallback &&(ximStyles->supported_styles[i] == + STYLE_CALLBACK)) + { + ximStyleCallback = STYLE_CALLBACK; + TRACE("Setting Style: ximStyleCallback = STYLE_CALLBACK\n"); + } + else if (!ximStyleNone && (ximStyles->supported_styles[i] == + STYLE_NONE)) + { + TRACE("Setting Style: ximStyleNone = STYLE_NONE\n"); + ximStyleNone = STYLE_NONE; + } + } + XFree(ximStyles); + + if (ximStyle == 0) + ximStyle = ximStyleRoot; + + if (ximStyle == 0) + ximStyle = ximStyleNone; + + if (ximStyleCallback == 0) + { + TRACE("No callback style avalable\n"); + ximStyleCallback = ximStyle; + } + + } + + wine_tsx11_unlock(); + + LoadImmDll(); + + if (pImmCreateContext) + { + root_context = pImmCreateContext(); + if (pImmAssociateContext) + pImmAssociateContext(0,root_context); + } + + return xim; + +err: + wine_tsx11_unlock(); + return NULL; +} + + +XIC X11DRV_CreateIC(XIM xim, Display *display, Window win) +{ + XFontSet fontSet; + char **list; + int count; + XPoint spot = {0}; + XVaNestedList preedit = NULL; + XVaNestedList status = NULL; + XIC xic; + XIMCallback P_StartCB; + XIMCallback P_DoneCB; + XIMCallback P_DrawCB; + XIMCallback P_CaretCB; + LANGID langid = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())); + + wine_tsx11_lock(); + + /* use complex and slow XIC initialization method only for CJK */ + if (langid != LANG_CHINESE && + langid != LANG_JAPANESE && + langid != LANG_KOREAN) + { + xic = XCreateIC(xim, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, win, + XNFocusWindow, win, + 0); + wine_tsx11_unlock(); + return xic; + } + + fontSet = XCreateFontSet(display, + "*", /*FIXME*/ + &list, &count, NULL); + + TRACE("ximFontSet = 0x%x\n", (unsigned int) fontSet); + TRACE("list = 0x%x, count = %d\n", (unsigned int) list, count); + + if (list != NULL) + { + int i; + + for (i = 0; i < count; ++i) + { + TRACE("list[%d] = %s\n", i, list[i]); + } + XFreeStringList(list); + } + + /* create callbacks */ + P_StartCB.client_data = NULL; + P_StartCB.callback = (XIMProc)XIMPreEditStartCallback; + P_DoneCB.client_data = NULL; + P_DoneCB.callback = (XIMProc)XIMPreEditDoneCallback; + P_DrawCB.client_data = NULL; + P_DrawCB.callback = (XIMProc)XIMPreEditDrawCallback; + P_CaretCB.client_data = NULL; + P_CaretCB.callback = (XIMProc)XIMPreEditCaretCallback; + + if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0) + { + preedit = XVaCreateNestedList(0, + XNFontSet, fontSet, + XNSpotLocation, &spot, + XNPreeditStartCallback, &P_StartCB, + XNPreeditDoneCallback, &P_DoneCB, + XNPreeditDrawCallback, &P_DrawCB, + XNPreeditCaretCallback, &P_CaretCB, + NULL); + TRACE("preedit = 0x%x\n", (unsigned int) preedit); + } + else + { + preedit = XVaCreateNestedList(0, + XNPreeditStartCallback, &P_StartCB, + XNPreeditDoneCallback, &P_DoneCB, + XNPreeditDrawCallback, &P_DrawCB, + XNPreeditCaretCallback, &P_CaretCB, + NULL); + + TRACE("preedit = 0x%x\n", (unsigned int) preedit); + } + + if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0) + { + status = XVaCreateNestedList(0, + XNFontSet, fontSet, + NULL); + TRACE("status = 0x%x\n", (unsigned int) status); + } + + if (preedit != NULL && status != NULL) + { + xic = XCreateIC(xim, + XNInputStyle, ximStyle, + XNPreeditAttributes, preedit, + XNStatusAttributes, status, + XNClientWindow, win, + XNFocusWindow, win, + NULL); + } + else if (preedit != NULL) + { + xic = XCreateIC(xim, + XNInputStyle, ximStyle, + XNPreeditAttributes, preedit, + XNClientWindow, win, + XNFocusWindow, win, + NULL); + } + else if (status != NULL) + { + xic = XCreateIC(xim, + XNInputStyle, ximStyle, + XNStatusAttributes, status, + XNClientWindow, win, + XNFocusWindow, win, + NULL); + } + else + { + xic = XCreateIC(xim, + XNInputStyle, ximStyle, + XNClientWindow, win, + XNFocusWindow, win, + NULL); + } + + TRACE("xic = 0x%x\n", (unsigned int) xic); + + if (preedit != NULL) + XFree(preedit); + if (status != NULL) + XFree(status); + + wine_tsx11_unlock(); + + return xic; +}