winex11: Move IME UI proc to default IME implementation.

This commit is contained in:
Rémi Bernon 2023-04-01 21:59:00 +02:00 committed by Alexandre Julliard
parent a5117ed5cd
commit bc1b15211d
7 changed files with 422 additions and 461 deletions

View file

@ -19,29 +19,352 @@
#include <stdarg.h>
#include <stddef.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "imm.h"
#include "immdev.h"
#include "wine/debug.h"
#include "imm_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm);
static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length )
{
COMPOSITIONSTRING *string;
WCHAR *text = NULL;
UINT len, off;
if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL;
len = result ? string->dwResultStrLen : string->dwCompStrLen;
off = result ? string->dwResultStrOffset : string->dwCompStrOffset;
if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) )))
{
memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) );
text[len] = 0;
*length = len;
}
ImmUnlockIMCC( ctx->hCompStr );
return text;
}
static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc )
{
struct ime_private *priv;
HFONT font = NULL;
if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL;
if (priv->textfont) font = SelectObject( hdc, priv->textfont );
ImmUnlockIMCC( ctx->hPrivate );
return font;
}
static void ime_ui_paint( HIMC himc, HWND hwnd )
{
PAINTSTRUCT ps;
RECT rect;
HDC hdc;
HMONITOR monitor;
MONITORINFO mon_info;
INPUTCONTEXT *ctx;
POINT offset;
WCHAR *str;
UINT len;
if (!(ctx = ImmLockIMC( himc ))) return;
hdc = BeginPaint( hwnd, &ps );
GetClientRect( hwnd, &rect );
FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) );
if ((str = input_context_get_comp_str( ctx, FALSE, &len )))
{
HFONT font = input_context_select_ui_font( ctx, hdc );
SIZE size;
POINT pt;
GetTextExtentPoint32W( hdc, str, len, &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 because the default MSIME does not do any IME adjusting.
*/
if (ctx->cfCompForm.dwStyle != CFS_DEFAULT)
{
POINT cpt = ctx->cfCompForm.ptCurrentPos;
ClientToScreen( ctx->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 = ctx->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;
offset.x = offset.y = 10;
monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY );
}
if (ctx->cfCompForm.dwStyle == CFS_RECT)
{
RECT client;
client = ctx->cfCompForm.rcArea;
MapWindowPoints( ctx->hWnd, 0, (POINT *)&client, 2 );
IntersectRect( &rect, &rect, &client );
/* TODO: Wrap the input if needed */
}
if (ctx->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, offset.x, offset.y, str, len );
if (font) SelectObject( hdc, font );
free( str );
}
EndPaint( hwnd, &ps );
ImmUnlockIMC( himc );
}
static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd )
{
COMPOSITIONSTRING *string;
if (ctx->hCompStr) string = ImmLockIMCC( ctx->hCompStr );
else string = NULL;
if (!string || string->dwCompStrLen == 0)
ShowWindow( hwnd, SW_HIDE );
else
{
ShowWindow( hwnd, SW_SHOWNOACTIVATE );
RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE );
}
if (string) ImmUnlockIMCC( ctx->hCompStr );
ctx->hWnd = GetFocus();
}
static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam )
{
INPUTCONTEXT *ctx;
TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lparam );
if (lparam & GCS_RESULTSTR) return;
if (!(ctx = ImmLockIMC( himc ))) return;
ime_ui_update_window( ctx, hwnd );
ImmUnlockIMC( himc );
}
static void ime_ui_start_composition( HIMC himc, HWND hwnd )
{
INPUTCONTEXT *ctx;
TRACE( "IME message WM_IME_STARTCOMPOSITION\n" );
if (!(ctx = ImmLockIMC( himc ))) return;
ime_ui_update_window( ctx, hwnd );
ImmUnlockIMC( himc );
}
static LRESULT ime_ui_notify( 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: TRACE( "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:<Unknown 0x%Ix>\n", wparam ); break;
}
return 0;
}
static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC );
INPUTCONTEXT *ctx;
LRESULT ret = 0;
TRACE( "hwnd %p, himc %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, himc, msg, wparam, lparam );
/* if we have no himc there are many messages we cannot process */
if (!himc)
{
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:
{
struct ime_private *priv;
SetWindowTextA( hwnd, "Wine Ime Active" );
if (!(ctx = ImmLockIMC( himc ))) return TRUE;
if ((priv = ImmLockIMCC( ctx->hPrivate )))
{
priv->hwndDefault = hwnd;
ImmUnlockIMCC( ctx->hPrivate );
}
ImmUnlockIMC( himc );
return TRUE;
}
case WM_PAINT:
ime_ui_paint( 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:
ime_ui_composition( himc, hwnd, lparam );
break;
case WM_IME_STARTCOMPOSITION:
ime_ui_start_composition( himc, hwnd );
break;
case WM_IME_ENDCOMPOSITION:
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wparam, lparam );
ShowWindow( hwnd, SW_HIDE );
break;
case WM_IME_SELECT:
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wparam, lparam );
break;
case WM_IME_CONTROL:
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wparam, lparam );
ret = 1;
break;
case WM_IME_NOTIFY:
ret = ime_ui_notify( himc, hwnd, msg, wparam, lparam );
break;
default:
TRACE( "Non-standard message 0x%x\n", msg );
break;
}
/* check the MSIME messages */
if (msg == WM_MSIME_SERVICE)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wparam, lparam );
else if (msg == WM_MSIME_RECONVERTOPTIONS)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wparam, lparam );
else if (msg == WM_MSIME_MOUSE)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wparam, lparam );
else if (msg == WM_MSIME_RECONVERTREQUEST)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wparam, lparam );
else if (msg == WM_MSIME_RECONVERT)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wparam, lparam );
else if (msg == WM_MSIME_QUERYPOSITION)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wparam, lparam );
else if (msg == WM_MSIME_DOCUMENTFEED)
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wparam, lparam );
/* DefWndProc if not an IME message */
if (!ret && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
(msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
ret = DefWindowProcW( hwnd, msg, wparam, lparam );
return ret;
}
static WNDCLASSEXW ime_ui_class =
{
.cbSize = sizeof(WNDCLASSEXW),
.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW,
.lpfnWndProc = ime_ui_window_proc,
.cbWndExtra = 2 * sizeof(LONG_PTR),
.lpszClassName = L"Wine IME",
.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1),
};
BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags )
{
FIXME( "info %p, ui_class %p, flags %#lx stub!\n", info, ui_class, flags );
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
TRACE( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags );
ime_ui_class.hInstance = imm32_module;
ime_ui_class.hCursor = LoadCursorW( NULL, (LPWSTR)IDC_ARROW );
ime_ui_class.hIcon = LoadIconW( NULL, (LPWSTR)IDI_APPLICATION );
RegisterClassExW( &ime_ui_class );
wcscpy( ui_class, ime_ui_class.lpszClassName );
memset( info, 0, sizeof(*info) );
info->dwPrivateDataSize = sizeof(IMEPRIVATE);
info->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
info->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
info->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
info->fdwUICaps = UI_CAP_2700;
/* Tell App we cannot accept ImeSetCompositionString calls */
info->fdwSCSCaps = 0;
info->fdwSelectCaps = SELECT_CAP_CONVERSION;
return TRUE;
}
BOOL WINAPI ImeDestroy( UINT force )
{
FIXME( "force %u stub!\n", force );
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
TRACE( "force %u\n", force );
UnregisterClassW( ime_ui_class.lpszClassName, imm32_module );
return TRUE;
}
BOOL WINAPI ImeSelect( HIMC himc, BOOL select )

View file

@ -20,37 +20,24 @@
*/
#define COBJMACROS
#include <stdarg.h>
#include <stdio.h>
#include "initguid.h"
#include "objbase.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "ntuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "imm.h"
#include "immdev.h"
#include "winnls.h"
#include "winreg.h"
#include "wine/list.h"
#include "imm_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm);
#define IMM_INIT_MAGIC 0x19650412
BOOL WINAPI User32InitializeImmEntryTable(DWORD);
HMODULE imm32_module;
/* 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;
UINT WM_MSIME_SERVICE;
UINT WM_MSIME_RECONVERTOPTIONS;
UINT WM_MSIME_MOUSE;
UINT WM_MSIME_RECONVERTREQUEST;
UINT WM_MSIME_RECONVERT;
UINT WM_MSIME_QUERYPOSITION;
UINT WM_MSIME_DOCUMENTFEED;
struct ime
{
@ -709,28 +696,28 @@ static void IMM_FreeAllImmHkl(void)
}
}
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
{
TRACE("%p, %lx, %p\n",hInstDLL,fdwReason,lpReserved);
switch (fdwReason)
TRACE( "instance %p, reason %lx, reserved %p\n", instance, reason, reserved );
switch (reason)
{
case DLL_PROCESS_ATTACH:
if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
{
return FALSE;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
IMM_FreeThreadData();
break;
case DLL_PROCESS_DETACH:
if (lpReserved) break;
IMM_FreeThreadData();
IMM_FreeAllImmHkl();
break;
case DLL_PROCESS_ATTACH:
if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE;
imm32_module = instance;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
IMM_FreeThreadData();
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
IMM_FreeThreadData();
IMM_FreeAllImmHkl();
break;
}
return TRUE;
}

46
dlls/imm32/imm_private.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright 2023 Rémi Bernon for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stddef.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "winreg.h"
#include "imm.h"
#include "immdev.h"
#include "ntuser.h"
#include "objbase.h"
#include "wine/debug.h"
#include "wine/list.h"
extern HMODULE imm32_module;
/* MSIME messages */
extern UINT WM_MSIME_SERVICE;
extern UINT WM_MSIME_RECONVERTOPTIONS;
extern UINT WM_MSIME_MOUSE;
extern UINT WM_MSIME_RECONVERTREQUEST;
extern UINT WM_MSIME_RECONVERT;
extern UINT WM_MSIME_QUERYPOSITION;
extern UINT WM_MSIME_DOCUMENTFEED;

View file

@ -43,16 +43,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm);
#define FROM_MACDRV ((HIMC)0xcafe1337)
typedef struct ime_private
{
BOOL bInComposition;
BOOL bInternalState;
HFONT textfont;
HWND hwndDefault;
UINT repeat;
} IMEPRIVATE, *LPIMEPRIVATE;
static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0};
static HIMC *hSelectedFrom = NULL;

View file

@ -49,28 +49,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm);
#define FROM_X11 ((HIMC)0xcafe1337)
typedef struct ime_private
{
BOOL bInComposition;
BOOL bInternalState;
HFONT textfont;
HWND hwndDefault;
} IMEPRIVATE, *LPIMEPRIVATE;
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;
/* 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 WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length )
{
COMPOSITIONSTRING *string;
@ -92,19 +73,6 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *
return text;
}
static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc )
{
struct ime_private *priv;
HFONT font = NULL;
if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL;
if (priv->textfont) font = SelectObject( hdc, priv->textfont );
ImmUnlockIMCC( ctx->hPrivate );
return font;
}
static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
static HIMC RealIMC(HIMC hIMC)
{
if (hIMC == FROM_X11)
@ -139,34 +107,6 @@ static BOOL UnlockRealIMC(HIMC hIMC)
return FALSE;
}
static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context )
{
WNDCLASSW wndClass;
ZeroMemory(&wndClass, sizeof(WNDCLASSW));
wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = IME_WindowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
wndClass.hInstance = x11drv_module;
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");
return TRUE;
}
static HIMCC ImeCreateBlankCompStr(void)
{
HIMCC rc;
@ -537,35 +477,6 @@ static void IME_AddToSelected(HIMC hIMC)
hSelectedFrom[hSelectedCount-1] = hIMC;
}
BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags)
{
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
TRACE("\n");
InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL );
lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
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 ImeDestroy(UINT uForce)
{
TRACE("\n");
HeapFree(GetProcessHeap(),0,hSelectedFrom);
hSelectedFrom = NULL;
hSelectedCount = 0;
return TRUE;
}
BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
{
/* See the comment at the head of this file */
@ -994,307 +905,3 @@ NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len )
ImmUnlockIMC(imc);
return 0;
}
/*****
* Internal functions to help with IME window management
*/
static void PaintDefaultIMEWnd( HIMC hIMC, HWND hwnd )
{
PAINTSTRUCT ps;
RECT rect;
HDC hdc;
HMONITOR monitor;
MONITORINFO mon_info;
INT offX = 0, offY = 0;
LPINPUTCONTEXT lpIMC;
WCHAR *str;
UINT len;
lpIMC = ImmLockIMC( hIMC );
if (lpIMC == NULL) return;
hdc = BeginPaint( hwnd, &ps );
GetClientRect( hwnd, &rect );
FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) );
if ((str = input_context_get_comp_str( lpIMC, FALSE, &len )))
{
HFONT font = input_context_select_ui_font( lpIMC, hdc );
SIZE size;
POINT pt;
GetTextExtentPoint32W( hdc, str, len, &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 because 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, str, len );
if (font) SelectObject( hdc, font );
free( str );
}
EndPaint( hwnd, &ps );
ImmUnlockIMC( hIMC );
}
static void UpdateDefaultIMEWindow( INPUTCONTEXT *lpIMC, HWND hwnd )
{
LPCOMPOSITIONSTRING compstr;
if (lpIMC->hCompStr) compstr = ImmLockIMCC( lpIMC->hCompStr );
else compstr = NULL;
if (compstr == NULL || compstr->dwCompStrLen == 0)
ShowWindow( hwnd, SW_HIDE );
else
{
ShowWindow( hwnd, SW_SHOWNOACTIVATE );
RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE );
}
if (compstr != NULL) ImmUnlockIMCC( lpIMC->hCompStr );
lpIMC->hWnd = GetFocus();
}
static void DefaultIMEComposition( HIMC hIMC, HWND hwnd, LPARAM lParam )
{
INPUTCONTEXT *ctx;
TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lParam );
if (lParam & GCS_RESULTSTR) return;
if (!(ctx = ImmLockIMC( hIMC ))) return;
UpdateDefaultIMEWindow( ctx, hwnd );
ImmUnlockIMC( hIMC );
}
static void DefaultIMEStartComposition( HIMC hIMC, HWND hwnd )
{
INPUTCONTEXT *ctx;
TRACE( "IME message WM_IME_STARTCOMPOSITION\n" );
if (!(ctx = ImmLockIMC( hIMC ))) return;
UpdateDefaultIMEWindow( ctx, hwnd );
ImmUnlockIMC( 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: TRACE( "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:<Unknown 0x%Ix>\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%08Ix, 0x%08Ix)\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)GetWindowLongPtrW( hwnd, IMMGWL_IMC );
/* 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 = ImmLockIMC( hIMC );
if (lpIMC)
{
myPrivate = ImmLockIMCC( lpIMC->hPrivate );
myPrivate->hwndDefault = hwnd;
ImmUnlockIMCC( lpIMC->hPrivate );
}
ImmUnlockIMC( 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%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wParam, lParam );
ShowWindow( hwnd, SW_HIDE );
break;
case WM_IME_SELECT:
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wParam, lParam );
break;
case WM_IME_CONTROL:
TRACE( "IME message %s, 0x%Ix, 0x%Ix\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%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wParam, lParam );
rc = FALSE;
}
else if (msg == WM_MSIME_RECONVERTOPTIONS)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam );
}
else if (msg == WM_MSIME_MOUSE)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wParam, lParam );
}
else if (msg == WM_MSIME_RECONVERTREQUEST)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam );
}
else if (msg == WM_MSIME_RECONVERT)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wParam, lParam );
}
else if (msg == WM_MSIME_QUERYPOSITION)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wParam, lParam );
}
else if (msg == WM_MSIME_DOCUMENTFEED)
{
TRACE( "IME message %s, 0x%Ix, 0x%Ix\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;
}

View file

@ -11,8 +11,6 @@
@ cdecl wine_notify_icon(long ptr)
#IME Interface
@ stdcall ImeInquire(ptr ptr wstr)
@ stdcall ImeDestroy(long)
@ stdcall ImeSelect(long long)
@ stdcall ImeToAsciiEx(long long ptr ptr long long)
@ stdcall NotifyIME(long long long long)

View file

@ -490,6 +490,16 @@ enum wine_internal_message
#define IME_INTERNAL_HKL_ACTIVATE 0x19
#define IME_INTERNAL_HKL_DEACTIVATE 0x20
/* internal IME private */
typedef struct ime_private
{
BOOL bInComposition;
BOOL bInternalState;
HFONT textfont;
HWND hwndDefault;
UINT repeat;
} IMEPRIVATE, *LPIMEPRIVATE;
#define WM_SYSTIMER 0x0118
/* the various structures that can be sent in messages, in platform-independent layout */