[PATCH v2 0/9] MR2637: winex11: Use messages instead of user callbacks and handle them in the default IME UI window procedure.
-- v2: winex11: Use the new helper to set COMPOSITIONSTRING text. winex11: Use EM_REPLACESEL to set IME composition strings. winex11: Always zero terminate XIM composition string. winex11: Compute preedit text buffer sizes in WCHAR units. winex11: Use an IME UI message to set composition status. winex11: Use an IME UI message to set cursor pos. winex11: Use an IME UI message to get cursor pos. winex11: Use an IME UI message to set open status. win32u: Keep the IME UI window in win32u struct imc. https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/imm.c | 35 ++++++++++++++++++++++++++--------- dlls/win32u/imm.c | 10 ++++++++++ include/ntuser.h | 1 + 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d29684f34a2..42a6a568c1a 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -87,8 +87,6 @@ struct imc struct ime *ime; UINT lastVK; - - HWND ui_hwnd; /* IME UI window, on the default input context */ }; #define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -623,12 +621,25 @@ static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc ) return &entry->context; } +static BOOL CALLBACK enum_set_ui_window( HIMC himc, LPARAM lparam ) +{ + NtUserUpdateInputContext( himc, NtUserInputContextUIHwnd, lparam ); + return TRUE; +} + static void imc_release_ime( struct imc *imc, struct ime *ime ) { + HIMC default_himc = UlongToHandle( NtUserGetThreadInfo()->default_imc ); INPUTCONTEXT *ctx; + HWND hwnd; + + if (imc->handle != default_himc) NtUserUpdateInputContext( imc->handle, NtUserInputContextUIHwnd, 0 ); + else if ((hwnd = (HWND)NtUserQueryInputContext( default_himc, NtUserInputContextUIHwnd ))) + { + DestroyWindow( hwnd ); + ImmEnumInputContext( 0, enum_set_ui_window, 0 ); + } - if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); - imc->ui_hwnd = NULL; ime->pImeSelect( imc->handle, FALSE ); if ((ctx = ime_find_input_context( ime, imc->handle ))) *ctx = imc->IMC; @@ -651,11 +662,14 @@ static struct ime *imc_select_ime( struct imc *imc ) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else { + HIMC default_himc = UlongToHandle( NtUserGetThreadInfo()->default_imc ); + HWND hwnd = (HWND)NtUserQueryInputContext( default_himc, NtUserInputContextUIHwnd ); INPUTCONTEXT *ctx; if ((ctx = ime_find_input_context( imc->ime, imc->handle ))) imc->IMC = *ctx; else ime_save_input_context( imc->ime, imc->handle, &imc->IMC ); + NtUserUpdateInputContext( imc->handle, NtUserInputContextUIHwnd, (LPARAM)hwnd ); imc->ime->pImeSelect( imc->handle, TRUE ); } @@ -1010,16 +1024,19 @@ static HWND get_ime_ui_window(void) { struct imc *imc = default_input_context(); struct ime *ime; + HWND hwnd; if (!(ime = imc_select_ime( imc ))) return 0; - if (!imc->ui_hwnd) + if (!(hwnd = (HWND)NtUserQueryInputContext( imc->handle, NtUserInputContextUIHwnd ))) { - imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, - ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 ); - SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); + hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, + ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 ); + SetWindowLongPtrW( hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); + ImmEnumInputContext( 0, enum_set_ui_window, (LPARAM)hwnd ); } - return imc->ui_hwnd; + + return hwnd; } /*********************************************************************** diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 7dee4912e27..7be44306dda 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -40,6 +40,7 @@ struct imc struct user_object obj; DWORD thread_id; UINT_PTR client_ptr; + HWND ui_hwnd; }; struct imm_thread_data @@ -80,6 +81,7 @@ HIMC WINAPI NtUserCreateInputContext( UINT_PTR client_ptr ) if (!(imc = malloc( sizeof(*imc) ))) return 0; imc->client_ptr = client_ptr; imc->thread_id = GetCurrentThreadId(); + imc->ui_hwnd = 0; if (!(handle = alloc_user_handle( &imc->obj, NTUSER_OBJ_IMC ))) { free( imc ); @@ -127,6 +129,10 @@ BOOL WINAPI NtUserUpdateInputContext( HIMC handle, UINT attr, UINT_PTR value ) imc->client_ptr = value; break; + case NtUserInputContextUIHwnd: + imc->ui_hwnd = (HWND)value; + break; + default: FIXME( "unknown attr %u\n", attr ); ret = FALSE; @@ -156,6 +162,10 @@ UINT_PTR WINAPI NtUserQueryInputContext( HIMC handle, UINT attr ) ret = imc->thread_id; break; + case NtUserInputContextUIHwnd: + ret = (UINT_PTR)imc->ui_hwnd; + break; + default: FIXME( "unknown attr %u\n", attr ); ret = 0; diff --git a/include/ntuser.h b/include/ntuser.h index 3d43eb476e4..7356c6096e9 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -453,6 +453,7 @@ struct draw_scroll_bar_params /* NtUserUpdateInputContext param, not compatible with Window */ enum input_context_attr { + NtUserInputContextUIHwnd = -1, NtUserInputContextClientPtr, NtUserInputContextThreadId, }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/ime.c | 3 +++ dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 9 --------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 25 +++++++++++++++++-------- include/ntuser.h | 3 +++ 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 3c4550c3cd9..35edcfe7f46 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -291,6 +291,9 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_wm_ime(msg), debugstr_imc(wparam), lparam ); return 1; + + case WM_WINE_IME_SET_OPEN_STATUS: + return ImmSetOpenStatus( himc, wparam ); } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index 8a957494ce9..eccfd223ac3 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -61,6 +61,7 @@ static const char *debugstr_wm_ime( UINT msg ) case WM_IME_REQUEST: return "WM_IME_REQUEST"; case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN"; case WM_IME_KEYUP: return "WM_IME_KEYUP"; + case WM_WINE_IME_SET_OPEN_STATUS: return "WM_WINE_IME_SET_OPEN_STATUS"; default: if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 500a4a6bc44..54093d36b6e 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -33,7 +33,6 @@ static const callback_func callback_funcs[] = x11drv_ime_get_cursor_pos, x11drv_ime_set_composition_status, x11drv_ime_set_cursor_pos, - x11drv_ime_set_open_status, x11drv_ime_update_association, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 55485bfbfcf..72ada45f774 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -755,15 +755,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, /* Interfaces to XIM and other parts of winex11drv */ -NTSTATUS x11drv_ime_set_open_status( UINT open ) -{ - HIMC imc; - - imc = RealIMC(FROM_X11); - ImmSetOpenStatus(imc, open); - return 0; -} - NTSTATUS x11drv_ime_set_composition_status( UINT open ) { HIMC imc; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 7dc1d9f0ca7..ed5dbac6535 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -99,7 +99,6 @@ enum client_callback client_ime_get_cursor_pos, client_ime_set_composition_status, client_ime_set_cursor_pos, - client_ime_set_open_status, client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 047bb430d39..80fe9ab2a3d 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -39,7 +39,6 @@ extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_get_cursor_pos( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_open_status( UINT open ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index b7f5f696ba5..f4c75d653cf 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -72,6 +72,21 @@ static const char *debugstr_xim_style( XIMStyle style ) return wine_dbg_sprintf( "%s", buffer ); } +/* sends a message to the IME UI window */ +static LRESULT send_ime_ui_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + static const WCHAR WINE_IME_UI_CLASS[] = {'W','i','n','e',' ','I','M','E',0}; + WCHAR buffer[64]; + UNICODE_STRING name = {.Buffer = buffer, .MaximumLength = sizeof(buffer)}; + HIMC himc; + + if (!(himc = NtUserGetWindowInputContext( hwnd ))) return 0; + if (!(hwnd = (HWND)NtUserQueryInputContext( himc, NtUserInputContextUIHwnd ))) return 0; + if (!NtUserGetClassName( hwnd, 0, &name ) || wcscmp( buffer, WINE_IME_UI_CLASS )) return 0; + + return send_message( hwnd, msg, wparam, lparam ); +} + static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len) { /* Composition strings are edited in chunks */ @@ -130,14 +145,8 @@ static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg ) switch (state) { - case XIMPreeditEnable: - x11drv_client_call( client_ime_set_open_status, TRUE ); - break; - case XIMPreeditDisable: - x11drv_client_call( client_ime_set_open_status, FALSE ); - break; - default: - break; + case XIMPreeditEnable: send_ime_ui_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, TRUE, 0 ); break; + case XIMPreeditDisable: send_ime_ui_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, FALSE, 0 ); break; } return TRUE; diff --git a/include/ntuser.h b/include/ntuser.h index 7356c6096e9..f54a0eb902a 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -491,6 +491,9 @@ enum wine_internal_message #define IME_INTERNAL_HKL_ACTIVATE 0x19 #define IME_INTERNAL_HKL_DEACTIVATE 0x20 +/* default IME UI messages */ +#define WM_WINE_IME_SET_OPEN_STATUS (WM_USER + 0) + /* internal IME private */ typedef struct ime_private { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/ime.c | 21 +++++++++++++++++++++ dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 20 -------------------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 2 +- include/ntuser.h | 1 + 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 35edcfe7f46..86834546a58 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -242,6 +242,25 @@ static void ime_ui_start_composition( HIMC himc, HWND hwnd ) ImmUnlockIMC( himc ); } +static UINT ime_get_cursor_pos( HIMC himc ) +{ + COMPOSITIONSTRING *string; + INPUTCONTEXT *ctx; + UINT pos = 0; + + TRACE( "himc %p\n", himc ); + + if (!(ctx = ImmLockIMC( himc ))) return 0; + if ((string = ImmLockIMCC( ctx->hCompStr ))) + { + pos = string->dwCursorPos; + ImmUnlockIMCC( ctx->hCompStr ); + } + ImmUnlockIMC( himc ); + + return pos; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -294,6 +313,8 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP case WM_WINE_IME_SET_OPEN_STATUS: return ImmSetOpenStatus( himc, wparam ); + case WM_WINE_IME_GET_CURSOR_POS: + return ime_get_cursor_pos( himc ); } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index eccfd223ac3..4a3afce09ba 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -62,6 +62,7 @@ static const char *debugstr_wm_ime( UINT msg ) case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN"; case WM_IME_KEYUP: return "WM_IME_KEYUP"; case WM_WINE_IME_SET_OPEN_STATUS: return "WM_WINE_IME_SET_OPEN_STATUS"; + case WM_WINE_IME_GET_CURSOR_POS: return "WM_WINE_IME_GET_CURSOR_POS"; default: if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 54093d36b6e..a3375e60957 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -30,7 +30,6 @@ static const callback_func callback_funcs[] = { x11drv_dnd_drop_event, x11drv_dnd_leave_event, - x11drv_ime_get_cursor_pos, x11drv_ime_set_composition_status, x11drv_ime_set_cursor_pos, x11drv_ime_update_association, diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 72ada45f774..b92c13ff08a 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -786,26 +786,6 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) return 0; } -NTSTATUS x11drv_ime_get_cursor_pos( UINT arg ) -{ - LPINPUTCONTEXT lpIMC; - INT rc = 0; - LPCOMPOSITIONSTRING compstr; - - if (!hSelectedFrom) - return rc; - - lpIMC = LockRealIMC(FROM_X11); - if (lpIMC) - { - compstr = ImmLockIMCC(lpIMC->hCompStr); - rc = compstr->dwCursorPos; - ImmUnlockIMCC(lpIMC->hCompStr); - } - UnlockRealIMC(FROM_X11); - return rc; -} - NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) { LPINPUTCONTEXT lpIMC; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index ed5dbac6535..332c4e4b3fa 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -96,7 +96,6 @@ enum client_callback { client_dnd_drop_event, client_dnd_leave_event, - client_ime_get_cursor_pos, client_ime_set_composition_status, client_ime_set_cursor_pos, client_ime_update_association, diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 80fe9ab2a3d..2cc27abd362 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -36,7 +36,6 @@ extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) D extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_get_cursor_pos( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index f4c75d653cf..46ec8680eb8 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -232,7 +232,7 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) if (!params) return 0; - pos = x11drv_client_call( client_ime_get_cursor_pos, 0 ); + pos = send_ime_ui_message( hwnd, WM_WINE_IME_GET_CURSOR_POS, 0, 0 ); switch (params->direction) { case XIMForwardChar: diff --git a/include/ntuser.h b/include/ntuser.h index f54a0eb902a..b3824bec7a5 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -493,6 +493,7 @@ enum wine_internal_message /* default IME UI messages */ #define WM_WINE_IME_SET_OPEN_STATUS (WM_USER + 0) +#define WM_WINE_IME_GET_CURSOR_POS (WM_USER + 1) /* internal IME private */ typedef struct ime_private -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/ime.c | 42 +++++++++++++++++++++++++++++++++++ dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 26 ---------------------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 5 ++--- include/ntuser.h | 1 + 8 files changed, 46 insertions(+), 32 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 86834546a58..77c485a2e83 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -93,6 +93,25 @@ static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) return font; } +static void ime_send_message( HIMC himc, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + TRANSMSG *messages = NULL, message = {.message = msg, .wParam = wparam, .lParam = lparam}; + INPUTCONTEXT *ctx; + HIMCC tmp; + + TRACE( "himc %p, msg %#x, wparam %#Ix, lparam %#Ix\n", himc, msg, wparam, lparam ); + + if (!(ctx = ImmLockIMC( himc ))) return; + if (!(tmp = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + 1) * sizeof(message) ))) goto done; + if (!(messages = ImmLockIMCC( (ctx->hMsgBuf = tmp) ))) goto done; + messages[ctx->dwNumMsgBuf++] = message; + ImmUnlockIMCC( ctx->hMsgBuf ); + +done: + ImmUnlockIMC( himc ); + if (!messages || !ImmGenerateMessage( himc )) WARN( "Failed to generate himc %p messages, error %lu\n", himc, GetLastError() ); +} + static void ime_ui_paint( HIMC himc, HWND hwnd ) { PAINTSTRUCT ps; @@ -261,6 +280,27 @@ static UINT ime_get_cursor_pos( HIMC himc ) return pos; } +static UINT ime_set_cursor_pos( HIMC himc, UINT new_pos ) +{ + COMPOSITIONSTRING *string; + INPUTCONTEXT *ctx; + UINT pos = 0; + + TRACE( "himc %p, new_pos %u\n", himc, new_pos ); + + if (!(ctx = ImmLockIMC( himc ))) return 0; + if ((string = ImmLockIMCC( ctx->hCompStr ))) + { + pos = string->dwCursorPos; + string->dwCursorPos = new_pos; + ImmUnlockIMCC( ctx->hCompStr ); + } + ImmUnlockIMC( himc ); + + if (pos != new_pos) ime_send_message( himc, WM_IME_COMPOSITION, new_pos, GCS_CURSORPOS ); + return pos; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -315,6 +355,8 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP return ImmSetOpenStatus( himc, wparam ); case WM_WINE_IME_GET_CURSOR_POS: return ime_get_cursor_pos( himc ); + case WM_WINE_IME_SET_CURSOR_POS: + return ime_set_cursor_pos( himc, wparam ); } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index 4a3afce09ba..b10d04d77ff 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -63,6 +63,7 @@ static const char *debugstr_wm_ime( UINT msg ) case WM_IME_KEYUP: return "WM_IME_KEYUP"; case WM_WINE_IME_SET_OPEN_STATUS: return "WM_WINE_IME_SET_OPEN_STATUS"; case WM_WINE_IME_GET_CURSOR_POS: return "WM_WINE_IME_GET_CURSOR_POS"; + case WM_WINE_IME_SET_CURSOR_POS: return "WM_WINE_IME_SET_CURSOR_POS"; default: if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index a3375e60957..71fddfe4449 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -31,7 +31,6 @@ static const callback_func callback_funcs[] = x11drv_dnd_drop_event, x11drv_dnd_leave_event, x11drv_ime_set_composition_status, - x11drv_ime_set_cursor_pos, x11drv_ime_update_association, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index b92c13ff08a..cbf9c488f3a 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -786,32 +786,6 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) return 0; } -NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) -{ - LPINPUTCONTEXT lpIMC; - LPCOMPOSITIONSTRING compstr; - - if (!hSelectedFrom) - return 0; - - lpIMC = LockRealIMC(FROM_X11); - if (!lpIMC) - return 0; - - compstr = ImmLockIMCC(lpIMC->hCompStr); - if (!compstr) - { - UnlockRealIMC(FROM_X11); - return 0; - } - - compstr->dwCursorPos = pos; - ImmUnlockIMCC(lpIMC->hCompStr); - UnlockRealIMC(FROM_X11); - GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS); - return 0; -} - NTSTATUS x11drv_ime_update_association( UINT arg ) { HWND focus = UlongToHandle( arg ); diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 332c4e4b3fa..e48a2c61669 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -97,7 +97,6 @@ enum client_callback client_dnd_drop_event, client_dnd_leave_event, client_ime_set_composition_status, - client_ime_set_cursor_pos, client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 2cc27abd362..5180969eeb7 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -37,7 +37,6 @@ extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) D extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 46ec8680eb8..0e8c1d1293a 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -217,8 +217,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (str != text->string.multi_byte) free( str ); } - x11drv_client_call( client_ime_set_cursor_pos, params->caret ); - + send_ime_ui_message( hwnd, WM_WINE_IME_SET_CURSOR_POS, params->caret, 0 ); return 0; } @@ -260,7 +259,7 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) FIXME( "Not implemented\n" ); break; } - x11drv_client_call( client_ime_set_cursor_pos, pos ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_CURSOR_POS, pos, 0 ); params->position = pos; return 0; diff --git a/include/ntuser.h b/include/ntuser.h index b3824bec7a5..6f7e206be86 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -494,6 +494,7 @@ enum wine_internal_message /* default IME UI messages */ #define WM_WINE_IME_SET_OPEN_STATUS (WM_USER + 0) #define WM_WINE_IME_GET_CURSOR_POS (WM_USER + 1) +#define WM_WINE_IME_SET_CURSOR_POS (WM_USER + 2) /* internal IME private */ typedef struct ime_private -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/ime.c | 39 +++++++++++++++++++++++++++++++++++ dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 31 ---------------------------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 5 +++-- include/ntuser.h | 1 + 8 files changed, 44 insertions(+), 36 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 77c485a2e83..762d1e29190 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -301,6 +301,43 @@ static UINT ime_set_cursor_pos( HIMC himc, UINT new_pos ) return pos; } +static BOOL ime_set_composition_status( HIMC himc, HWND hwnd, BOOL new_status ) +{ + COMPOSITIONSTRING *string; + struct ime_private *priv; + BOOL old_status = FALSE; + INPUTCONTEXT *ctx; + HIMCC tmp; + + TRACE( "himc %p, hwnd %p, new_status %u\n", himc, hwnd, new_status ); + + if (!(ctx = ImmLockIMC( himc ))) return 0; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + old_status = priv->bInComposition; + priv->bInComposition = new_status; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + + if (new_status == old_status) return old_status; + if (old_status) ShowWindow( hwnd, SW_HIDE ); + + if (!(ctx = ImmLockIMC( himc ))) return old_status; + if (!new_status && (string = ImmLockIMCC( ctx->hCompStr ))) + { + memset( string, 0, sizeof(COMPOSITIONSTRING) ); + string->dwSize = sizeof(COMPOSITIONSTRING); + ImmUnlockIMCC( ctx->hCompStr ); + if ((tmp = ImmReSizeIMCC( ctx->hCompStr, sizeof(COMPOSITIONSTRING) ))) ctx->hCompStr = tmp; + else WARN( "Failed to shrink composition string for himc %p\n", himc ); + } + ImmUnlockIMC( himc ); + + ime_send_message( himc, new_status ? WM_IME_STARTCOMPOSITION : WM_IME_ENDCOMPOSITION, 0, 0 ); + return old_status; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -357,6 +394,8 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP return ime_get_cursor_pos( himc ); case WM_WINE_IME_SET_CURSOR_POS: return ime_set_cursor_pos( himc, wparam ); + case WM_WINE_IME_SET_COMP_STATUS: + return ime_set_composition_status( himc, hwnd, wparam ); } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index b10d04d77ff..876d92d4aa2 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -64,6 +64,7 @@ static const char *debugstr_wm_ime( UINT msg ) case WM_WINE_IME_SET_OPEN_STATUS: return "WM_WINE_IME_SET_OPEN_STATUS"; case WM_WINE_IME_GET_CURSOR_POS: return "WM_WINE_IME_GET_CURSOR_POS"; case WM_WINE_IME_SET_CURSOR_POS: return "WM_WINE_IME_SET_CURSOR_POS"; + case WM_WINE_IME_SET_COMP_STATUS: return "WM_WINE_IME_SET_COMP_STATUS"; default: if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 71fddfe4449..8445c21470e 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -30,7 +30,6 @@ static const callback_func callback_funcs[] = { x11drv_dnd_drop_event, x11drv_dnd_leave_event, - x11drv_ime_set_composition_status, x11drv_ime_update_association, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index cbf9c488f3a..09440140568 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -755,37 +755,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, /* Interfaces to XIM and other parts of winex11drv */ -NTSTATUS x11drv_ime_set_composition_status( UINT open ) -{ - HIMC imc; - LPINPUTCONTEXT lpIMC; - LPIMEPRIVATE myPrivate; - - imc = RealIMC(FROM_X11); - lpIMC = ImmLockIMC(imc); - if (lpIMC == NULL) - return 0; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (open && !myPrivate->bInComposition) - { - GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0); - } - else if (!open && myPrivate->bInComposition) - { - ShowWindow(myPrivate->hwndDefault, SW_HIDE); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); - GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); - } - myPrivate->bInComposition = open; - - ImmUnlockIMCC(lpIMC->hPrivate); - ImmUnlockIMC(imc); - return 0; -} - NTSTATUS x11drv_ime_update_association( UINT arg ) { HWND focus = UlongToHandle( arg ); diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index e48a2c61669..484ed4e5725 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -96,7 +96,6 @@ enum client_callback { client_dnd_drop_event, client_dnd_leave_event, - client_ime_set_composition_status, client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 5180969eeb7..a96e286ae83 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -36,7 +36,6 @@ extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) D extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 0e8c1d1293a..a7e2a0a2c26 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -158,7 +158,7 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); - x11drv_client_call( client_ime_set_composition_status, TRUE ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, TRUE, 0 ); ximInComposeMode = TRUE; return -1; } @@ -175,7 +175,8 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) dwCompStringSize = 0; dwCompStringLength = 0; CompositionString = NULL; - x11drv_client_call( client_ime_set_composition_status, FALSE ); + + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); return 0; } diff --git a/include/ntuser.h b/include/ntuser.h index 6f7e206be86..77f383d12ac 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -495,6 +495,7 @@ enum wine_internal_message #define WM_WINE_IME_SET_OPEN_STATUS (WM_USER + 0) #define WM_WINE_IME_GET_CURSOR_POS (WM_USER + 1) #define WM_WINE_IME_SET_CURSOR_POS (WM_USER + 2) +#define WM_WINE_IME_SET_COMP_STATUS (WM_USER + 3) /* internal IME private */ typedef struct ime_private -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/winex11.drv/xim.c | 54 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index a7e2a0a2c26..61998c22ad2 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -44,10 +44,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); BOOL ximInComposeMode=FALSE; -/* moved here from imm32 for dll separation */ -static DWORD dwCompStringLength = 0; -static LPBYTE CompositionString = NULL; -static DWORD dwCompStringSize = 0; +static DWORD preedit_len = 0; +static DWORD preedit_max = 0; +static WCHAR *preedit_buf = NULL; static XIMStyle input_style = 0; static XIMStyle input_style_req = XIMPreeditCallbacks | XIMStatusCallbacks; @@ -87,38 +86,32 @@ static LRESULT send_ime_ui_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l return send_message( hwnd, msg, wparam, lparam ); } -static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len) +static void xim_update_preedit_string( UINT offset, UINT old_len, WCHAR *text, UINT new_len ) { - /* Composition strings are edited in chunks */ - unsigned int byte_length = len * sizeof(WCHAR); - unsigned int byte_offset = offset * sizeof(WCHAR); - unsigned int byte_selection = selLength * sizeof(WCHAR); - int byte_expansion = byte_length - byte_selection; - LPBYTE ptr_new; + int diff = new_len - old_len; - TRACE("( %i, %i, %p, %d):\n", offset, selLength, lpComp, len ); + TRACE( "offset %u, old_len %u, text %s\n", offset, old_len, debugstr_wn(text, new_len) ); - if (byte_expansion + dwCompStringLength >= dwCompStringSize) + if (preedit_len + diff >= preedit_max) { - ptr_new = realloc( CompositionString, dwCompStringSize + byte_expansion ); - if (ptr_new == NULL) + WCHAR *tmp; + + if (!(tmp = realloc( preedit_buf, (preedit_max + diff) * sizeof(WCHAR) ))) { ERR("Couldn't expand composition string buffer\n"); return; } - CompositionString = ptr_new; - dwCompStringSize += byte_expansion; + preedit_buf = tmp; + preedit_max += diff; } - ptr_new = CompositionString + byte_offset; - memmove(ptr_new + byte_length, ptr_new + byte_selection, - dwCompStringLength - byte_offset - byte_selection); - if (lpComp) memcpy(ptr_new, lpComp, byte_length); - dwCompStringLength += byte_expansion; + memmove( preedit_buf + offset + new_len, preedit_buf + offset + old_len, + (preedit_len - offset - old_len) * sizeof(WCHAR) ); + if (text) memcpy( preedit_buf + offset, text, new_len * sizeof(WCHAR) ); + preedit_len += diff; - x11drv_client_func( client_func_ime_set_composition_string, - CompositionString, dwCompStringLength ); + x11drv_client_func( client_func_ime_set_composition_string, preedit_buf, preedit_len * sizeof(WCHAR) ); } void X11DRV_XIMLookupChars( const char *str, UINT count ) @@ -170,11 +163,10 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); ximInComposeMode = FALSE; - if (dwCompStringSize) - free( CompositionString ); - dwCompStringSize = 0; - dwCompStringLength = 0; - CompositionString = NULL; + free( preedit_buf ); + preedit_max = 0; + preedit_len = 0; + preedit_buf = NULL; send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); return 0; @@ -191,7 +183,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (!params) return 0; if (!(text = params->text)) - X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, NULL, 0 ); + xim_update_preedit_string( params->chg_first, params->chg_length, NULL, 0 ); else { size_t text_len; @@ -211,7 +203,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if ((output = malloc( text_len * sizeof(WCHAR) ))) { text_len = ntdll_umbstowcs( str, text_len, output, text_len ); - X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, output, text_len ); + xim_update_preedit_string( params->chg_first, params->chg_length, output, text_len ); free( output ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/winex11.drv/xim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 61998c22ad2..500d2924d77 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -92,11 +92,11 @@ static void xim_update_preedit_string( UINT offset, UINT old_len, WCHAR *text, U TRACE( "offset %u, old_len %u, text %s\n", offset, old_len, debugstr_wn(text, new_len) ); - if (preedit_len + diff >= preedit_max) + if (!preedit_buf || preedit_len + diff >= preedit_max) { WCHAR *tmp; - if (!(tmp = realloc( preedit_buf, (preedit_max + diff) * sizeof(WCHAR) ))) + if (!(tmp = realloc( preedit_buf, (preedit_max + diff + 1) * sizeof(WCHAR) ))) { ERR("Couldn't expand composition string buffer\n"); return; @@ -110,6 +110,7 @@ static void xim_update_preedit_string( UINT offset, UINT old_len, WCHAR *text, U (preedit_len - offset - old_len) * sizeof(WCHAR) ); if (text) memcpy( preedit_buf + offset, text, new_len * sizeof(WCHAR) ); preedit_len += diff; + preedit_buf[preedit_len] = 0; x11drv_client_func( client_func_ime_set_composition_string, preedit_buf, preedit_len * sizeof(WCHAR) ); } @@ -121,8 +122,9 @@ void X11DRV_XIMLookupChars( const char *str, UINT count ) TRACE("%p %u\n", str, count); - if (!(output = malloc( count * sizeof(WCHAR) ))) return; + if (!(output = malloc( (count + 1) * sizeof(WCHAR) ))) return; len = ntdll_umbstowcs( str, count, output, count ); + output[len] = 0; x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); free( output ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/imm32/ime.c | 111 +++++++++++++++++++++++++++++++++- dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 2 - dlls/winex11.drv/ime.c | 54 ----------------- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/unixlib.h | 2 - dlls/winex11.drv/x11drv.h | 2 +- dlls/winex11.drv/x11drv_dll.h | 2 - dlls/winex11.drv/xim.c | 17 +++--- include/ntuser.h | 1 + 10 files changed, 122 insertions(+), 72 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 762d1e29190..9c80c05121d 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -83,6 +83,86 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } +static DWORD input_context_set_comp_str( INPUTCONTEXT *ctx, BOOL result, const WCHAR *str, SIZE_T len ) +{ + DWORD flags = result ? GCS_RESULTSTR : GCS_COMPSTR; + UINT new_size = sizeof(COMPOSITIONSTRING); + COMPOSITIONSTRING old, *comp; + BYTE *dst; + + TRACE( "ctx %p, result %u, str %s\n", ctx, result, debugstr_wn(str, len) ); + + new_size += len * sizeof(WCHAR); + if (len) new_size += 2 * sizeof(DWORD); + if (!result) new_size += len; + + if (!(comp = ImmLockIMCC( ctx->hCompStr ))) goto error; + old = *comp; + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size > old.dwSize && !(ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, new_size ))) goto error; + + if (!(comp = ImmLockIMCC( ctx->hCompStr ))) goto error; + memset( comp, 0, sizeof(COMPOSITIONSTRING) ); + comp->dwSize = sizeof(COMPOSITIONSTRING); + + if (!result && len) + { + comp->dwCursorPos = min( len, old.dwCursorPos ); + + comp->dwCompStrLen = len; + comp->dwCompStrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + comp->dwSize += len * sizeof(WCHAR); + + comp->dwCompClauseLen = 2 * sizeof(DWORD); + comp->dwCompClauseOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + comp->dwSize += 2 * sizeof(DWORD); + + comp->dwCompAttrLen = len; + comp->dwCompAttrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompAttrOffset; + memset( dst, ATTR_INPUT, len ); + comp->dwSize += len; + } + else if (len) + { + comp->dwResultStrLen = len; + comp->dwResultStrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwResultStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + comp->dwSize += len * sizeof(WCHAR); + + comp->dwResultClauseLen = 2 * sizeof(DWORD); + comp->dwResultClauseOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwResultClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + comp->dwSize += 2 * sizeof(DWORD); + } + + if (comp->dwCursorPos != old.dwCursorPos) flags |= GCS_CURSORPOS; + if (comp->dwDeltaStart != old.dwDeltaStart) flags |= GCS_DELTASTART; + if (comp->dwCompStrLen != old.dwCompStrLen) flags |= GCS_COMPSTR; + if (comp->dwCompAttrLen != old.dwCompAttrLen) flags |= GCS_COMPATTR; + if (comp->dwCompClauseLen != old.dwCompClauseLen) flags |= GCS_COMPCLAUSE; + if (comp->dwResultStrLen != old.dwResultStrLen) flags |= GCS_RESULTSTR; + if (comp->dwResultClauseLen != old.dwResultClauseLen) flags |= GCS_RESULTCLAUSE; + + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size < old.dwSize && !(ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, new_size ))) goto error; + return flags; + +error: + WARN( "Failed to update result string, error %lu\n", GetLastError() ); + return 0; +} + static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) { struct ime_private *priv; @@ -338,6 +418,33 @@ static BOOL ime_set_composition_status( HIMC himc, HWND hwnd, BOOL new_status ) return old_status; } +static BOOL ime_set_composition_text( HIMC himc, HWND hwnd, BOOL result, const WCHAR *str, UINT len ) +{ + struct ime_private *priv; + BOOL old_status = FALSE; + INPUTCONTEXT *ctx; + DWORD flags; + + TRACE( "old_status %u, himc %p, result %u, str %s\n", old_status, himc, result, debugstr_wn(str, len) ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + old_status = priv->bInComposition; + ImmUnlockIMCC( ctx->hPrivate ); + } + flags = input_context_set_comp_str( ctx, result, str, len ); + ImmUnlockIMC( himc ); + + if (!old_status) ImmSetOpenStatus( himc, TRUE ); + if (!result || !old_status) ime_set_composition_status( himc, hwnd, TRUE ); + ime_send_message( himc, WM_IME_COMPOSITION, len ? str[0] : 0, flags ); + if (result || !old_status) ime_set_composition_status( himc, hwnd, FALSE ); + if (!old_status) ImmSetOpenStatus( himc, FALSE ); + + return TRUE; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -352,8 +459,6 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP { struct ime_private *priv; - SetWindowTextA( hwnd, "Wine Ime Active" ); - if (!(ctx = ImmLockIMC( himc ))) return TRUE; if ((priv = ImmLockIMCC( ctx->hPrivate ))) { @@ -396,6 +501,8 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP return ime_set_cursor_pos( himc, wparam ); case WM_WINE_IME_SET_COMP_STATUS: return ime_set_composition_status( himc, hwnd, wparam ); + case WM_WINE_IME_SET_COMP_TEXT: + return ime_set_composition_text( himc, hwnd, !wparam, (const WCHAR *)lparam, wcslen( (const WCHAR *)lparam ) ); } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index 876d92d4aa2..8ea40e1fb27 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -65,6 +65,7 @@ static const char *debugstr_wm_ime( UINT msg ) case WM_WINE_IME_GET_CURSOR_POS: return "WM_WINE_IME_GET_CURSOR_POS"; case WM_WINE_IME_SET_CURSOR_POS: return "WM_WINE_IME_SET_CURSOR_POS"; case WM_WINE_IME_SET_COMP_STATUS: return "WM_WINE_IME_SET_COMP_STATUS"; + case WM_WINE_IME_SET_COMP_TEXT: return "WM_WINE_IME_SET_COMP_TEXT"; default: if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 8445c21470e..7c463d4e401 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -48,8 +48,6 @@ static const kernel_callback kernel_callbacks[] = x11drv_dnd_enter_event, x11drv_dnd_position_event, x11drv_dnd_post_drop, - x11drv_ime_set_composition_string, - x11drv_ime_set_result, x11drv_systray_change_owner, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 09440140568..a69ad81eff5 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -765,57 +765,3 @@ NTSTATUS x11drv_ime_update_association( UINT arg ) ImmAssociateContext(focus,RealIMC(FROM_X11)); return 0; } - - -NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size ) -{ - return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0); -} - -NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len ) -{ - WCHAR *lpResult = params; - HIMC imc; - LPINPUTCONTEXT lpIMC; - HIMCC newCompStr; - LPIMEPRIVATE myPrivate; - BOOL inComp; - HWND focus; - - len /= sizeof(WCHAR); - if ((focus = GetFocus())) - x11drv_ime_update_association( HandleToUlong( focus )); - - imc = RealIMC(FROM_X11); - lpIMC = ImmLockIMC(imc); - if (lpIMC == NULL) - return 0; - - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - inComp = myPrivate->bInComposition; - ImmUnlockIMCC(lpIMC->hPrivate); - - if (!inComp) - { - ImmSetOpenStatus(imc, TRUE); - GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0); - } - - GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR); - GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE); - GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); - - if (!inComp) - ImmSetOpenStatus(imc, FALSE); - - ImmUnlockIMC(imc); - return 0; -} diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index b1c47d5258e..195cc65eddb 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1347,7 +1347,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (status == XLookupChars) { - X11DRV_XIMLookupChars( Str, ascii_chars ); + xim_set_result_string( hwnd, Str, ascii_chars ); if (buf != Str) free( Str ); return TRUE; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 484ed4e5725..de044a9416c 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -83,8 +83,6 @@ enum x11drv_client_funcs client_func_dnd_enter_event, client_func_dnd_position_event, client_func_dnd_post_drop, - client_func_ime_set_composition_string, - client_func_ime_set_result, client_func_systray_change_owner, client_func_last }; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9efaae3465b..d4581e21298 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -823,7 +823,7 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; /* XIM support */ extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; -extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; +extern void xim_set_result_string( HWND hwnd, const char *str, UINT count ) DECLSPEC_HIDDEN; extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; #define XEMBED_MAPPED (1 << 0) diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index a96e286ae83..fbd2a3e74b2 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -30,8 +30,6 @@ extern NTSTATUS WINAPI x11drv_dnd_enter_event( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_dnd_position_event( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_dnd_post_drop( void *data, ULONG size ) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI x11drv_ime_set_composition_string( void *params, ULONG size ) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 500d2924d77..c62fce18c80 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -86,11 +86,11 @@ static LRESULT send_ime_ui_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM l return send_message( hwnd, msg, wparam, lparam ); } -static void xim_update_preedit_string( UINT offset, UINT old_len, WCHAR *text, UINT new_len ) +static void xim_update_preedit_string( HWND hwnd, UINT offset, UINT old_len, WCHAR *text, UINT new_len ) { int diff = new_len - old_len; - TRACE( "offset %u, old_len %u, text %s\n", offset, old_len, debugstr_wn(text, new_len) ); + TRACE( "hwnd %p, offset %u, old_len %u, text %s\n", hwnd, offset, old_len, debugstr_wn(text, new_len) ); if (!preedit_buf || preedit_len + diff >= preedit_max) { @@ -112,21 +112,22 @@ static void xim_update_preedit_string( UINT offset, UINT old_len, WCHAR *text, U preedit_len += diff; preedit_buf[preedit_len] = 0; - x11drv_client_func( client_func_ime_set_composition_string, preedit_buf, preedit_len * sizeof(WCHAR) ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, TRUE, (LPARAM)preedit_buf ); } -void X11DRV_XIMLookupChars( const char *str, UINT count ) +void xim_set_result_string( HWND hwnd, const char *str, UINT count ) { WCHAR *output; DWORD len; - TRACE("%p %u\n", str, count); + TRACE( "hwnd %p, str %s\n", hwnd, debugstr_an(str, count) ); if (!(output = malloc( (count + 1) * sizeof(WCHAR) ))) return; len = ntdll_umbstowcs( str, count, output, count ); output[len] = 0; - x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, FALSE, (LPARAM)output ); + free( output ); } @@ -185,7 +186,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (!params) return 0; if (!(text = params->text)) - xim_update_preedit_string( params->chg_first, params->chg_length, NULL, 0 ); + xim_update_preedit_string( hwnd, params->chg_first, params->chg_length, NULL, 0 ); else { size_t text_len; @@ -205,7 +206,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if ((output = malloc( text_len * sizeof(WCHAR) ))) { text_len = ntdll_umbstowcs( str, text_len, output, text_len ); - xim_update_preedit_string( params->chg_first, params->chg_length, output, text_len ); + xim_update_preedit_string( hwnd, params->chg_first, params->chg_length, output, text_len ); free( output ); } diff --git a/include/ntuser.h b/include/ntuser.h index 77f383d12ac..3926b6d633d 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -496,6 +496,7 @@ enum wine_internal_message #define WM_WINE_IME_GET_CURSOR_POS (WM_USER + 1) #define WM_WINE_IME_SET_CURSOR_POS (WM_USER + 2) #define WM_WINE_IME_SET_COMP_STATUS (WM_USER + 3) +#define WM_WINE_IME_SET_COMP_TEXT EM_REPLACESEL /* internal IME private */ typedef struct ime_private -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/winex11.drv/ime.c | 435 +++++++++-------------------------------- 1 file changed, 90 insertions(+), 345 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index a69ad81eff5..f8d4a6a64c3 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -73,6 +73,86 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } +static DWORD input_context_set_comp_str( INPUTCONTEXT *ctx, BOOL result, const WCHAR *str, SIZE_T len ) +{ + DWORD flags = result ? GCS_RESULTSTR : GCS_COMPSTR; + UINT new_size = sizeof(COMPOSITIONSTRING); + COMPOSITIONSTRING old, *comp; + BYTE *dst; + + TRACE( "ctx %p, result %u, str %s\n", ctx, result, debugstr_wn(str, len) ); + + new_size += len * sizeof(WCHAR); + if (len) new_size += 2 * sizeof(DWORD); + if (!result) new_size += len; + + if (!(comp = ImmLockIMCC( ctx->hCompStr ))) goto error; + old = *comp; + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size > old.dwSize && !(ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, new_size ))) goto error; + + if (!(comp = ImmLockIMCC( ctx->hCompStr ))) goto error; + memset( comp, 0, sizeof(COMPOSITIONSTRING) ); + comp->dwSize = sizeof(COMPOSITIONSTRING); + + if (!result && len) + { + comp->dwCursorPos = min( len, old.dwCursorPos ); + + comp->dwCompStrLen = len; + comp->dwCompStrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + comp->dwSize += len * sizeof(WCHAR); + + comp->dwCompClauseLen = 2 * sizeof(DWORD); + comp->dwCompClauseOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + comp->dwSize += 2 * sizeof(DWORD); + + comp->dwCompAttrLen = len; + comp->dwCompAttrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwCompAttrOffset; + memset( dst, ATTR_INPUT, len ); + comp->dwSize += len; + } + else if (len) + { + comp->dwResultStrLen = len; + comp->dwResultStrOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwResultStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + comp->dwSize += len * sizeof(WCHAR); + + comp->dwResultClauseLen = 2 * sizeof(DWORD); + comp->dwResultClauseOffset = comp->dwSize; + dst = (BYTE *)comp + comp->dwResultClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + comp->dwSize += 2 * sizeof(DWORD); + } + + if (comp->dwCursorPos != old.dwCursorPos) flags |= GCS_CURSORPOS; + if (comp->dwDeltaStart != old.dwDeltaStart) flags |= GCS_DELTASTART; + if (comp->dwCompStrLen != old.dwCompStrLen) flags |= GCS_COMPSTR; + if (comp->dwCompAttrLen != old.dwCompAttrLen) flags |= GCS_COMPATTR; + if (comp->dwCompClauseLen != old.dwCompClauseLen) flags |= GCS_COMPCLAUSE; + if (comp->dwResultStrLen != old.dwResultStrLen) flags |= GCS_RESULTSTR; + if (comp->dwResultClauseLen != old.dwResultClauseLen) flags |= GCS_RESULTCLAUSE; + + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size < old.dwSize && !(ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, new_size ))) goto error; + return flags; + +error: + WARN( "Failed to update result string, error %lu\n", GetLastError() ); + return 0; +} + static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_X11) @@ -119,309 +199,6 @@ static HIMCC ImeCreateBlankCompStr(void) 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, LPCWSTR compstr, DWORD len) -{ - /* We need to make sure the CompStr, CompClause 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, %li\n",debugstr_wn(compstr,len),len); - - if (old == NULL && compstr == NULL && len == 0) - return NULL; - - if (compstr == NULL && len != 0) - { - ERR("compstr is NULL however we have a len! Please report\n"); - len = 0; - } - - 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(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultClauseLen; - needed_size += lpcs->dwResultStrLen * sizeof(WCHAR); - 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); - } - else - new_one->dwCompClauseLen = 0; - - /* 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, %li\n",debugstr_wn(resultstr,len),len); - - if (old == NULL && resultstr == NULL && len == 0) - return NULL; - - if (resultstr == NULL && len != 0) - { - ERR("resultstr is NULL however we have a len! Please report\n"); - len = 0; - } - - 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(WCHAR); - needed_size += lpcs->dwCompAttrLen; - needed_size += lpcs->dwCompClauseLen; - needed_size += lpcs->dwCompStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - 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); - } - else - new_one->dwResultClauseLen = 0; - - /* 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) { @@ -601,42 +378,25 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { case CPS_COMPLETE: { - HIMCC newCompStr; LPIMEPRIVATE myPrivate; WCHAR *str; UINT len; TRACE("CPS_COMPLETE\n"); - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { - WCHAR param = str[0]; - - newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); - 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); - + DWORD flags = input_context_set_comp_str( lpIMC, TRUE, str, len ); + GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, str[0], flags ); GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); free( str ); } - else if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); + else + { + input_context_set_comp_str( lpIMC, TRUE, NULL, 0 ); + if (myPrivate->bInComposition) GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); + } myPrivate->bInComposition = FALSE; ImmUnlockIMCC(lpIMC->hPrivate); @@ -714,35 +474,20 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, if (dwIndex == SCS_SETSTR) { - HIMCC newCompStr; - if (!myPrivate->bInComposition) { GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); myPrivate->bInComposition = TRUE; } - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - flags = GCS_COMPSTR; - if (dwCompLen && lpComp) { - newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR)); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - wParam = ((const WCHAR*)lpComp)[0]; - flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART; + flags = input_context_set_comp_str( lpIMC, FALSE, lpComp, dwCompLen / sizeof(WCHAR) ); + wParam = ((const WCHAR*)lpComp)[0]; } else { - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; + flags = input_context_set_comp_str( lpIMC, FALSE, NULL, 0 ); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/2637
v2: Use -1 for `NtUserInputContextUIHwnd` to avoid failing win32u tests. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2637#note_29702
I understand that there's something wrong about this, anything in particular? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2637#note_30019
Byeongsik Jeon (@bsjeon) commented about dlls/imm32/ime.c:
+ TRACE( "old_status %u, himc %p, result %u, str %s\n", old_status, himc, result, debugstr_wn(str, len) ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + old_status = priv->bInComposition; + ImmUnlockIMCC( ctx->hPrivate ); + } + flags = input_context_set_comp_str( ctx, result, str, len ); + ImmUnlockIMC( himc ); + + if (!old_status) ImmSetOpenStatus( himc, TRUE ); + if (!result || !old_status) ime_set_composition_status( himc, hwnd, TRUE ); + ime_send_message( himc, WM_IME_COMPOSITION, len ? str[0] : 0, flags ); + if (result || !old_status) ime_set_composition_status( himc, hwnd, FALSE ); + if (!old_status) ImmSetOpenStatus( himc, FALSE ); In x11drv_time_set_result() and in this code, WM_IME_COMPOSITION(GCS_RESULTSTR) is always followed by WM_IME_ENDCOMPOSITION. And, in this code, WM_IME_COMPOSITION(GCS_COMPSTR) is always preceded by WM_IME_STARTCOMPOSITION.
Is this intended? Overall, the IME message sequences are too dirty. In particular, for Korean input, preedit_string and result_string need to co-operate organically, which leads to a bad situation. Of course, this is an inherited problem from the old code. In my opinion, it makes sense that the x11drv_ime_set_result() code is for case where the input_style is not XIMPreditcallbacks. How about moving some code to xim_set_result_string()? For example, ``` +++ b/dlls/winex11.drv/xim.c @@ -126,7 +126,20 @@ void xim_set_result_string( HWND hwnd, const char *str, UINT count ) len = ntdll_umbstowcs( str, count, output, count ); output[len] = 0; - send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, FALSE, (LPARAM)output ); + if (input_style & XIMPreeditCallbacks) + { + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, FALSE, (LPARAM)output ); + } + else + { + send_ime_ui_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, TRUE, 0 ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, TRUE, 0 ); + + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, FALSE, (LPARAM)output ); + + send_ime_ui_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); + send_ime_ui_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, FALSE, 0 ); + } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2637#note_30020
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131878 Your paranoid android. === debian11 (build log) === Task: Patch failed to apply === debian11b (build log) === Task: Patch failed to apply
In x11drv_ime_set_result() and in this code, WM_IME_COMPOSITION(GCS_RESULTSTR) is always followed by WM_IME_ENDCOMPOSITION. And, in this code, WM_IME_COMPOSITION(GCS_COMPSTR) is always preceded by WM_IME_STARTCOMPOSITION.
Is this intended?
Kind of, composition string updates are indeed preceded by WM_IME_STARTCOMPOSITION but only if the composition status indicates that we were not composing already. I think that wasn't done before and I added it as I think WM_IME_COMPOSITION messages are only supposed to be sent between WM_IME_STARTCOMPOSITION and WM_IME_ENDCOMPOSITION.
Overall, the IME message sequences are too dirty. In particular, for Korean input, preedit_string and result_string need to co-operate organically, which leads to a bad situation. Of course, this is an inherited problem from the old code.
I'm not completely sure to see what is wrong here. Usually I think this should get you this kind of message sequence: WM_IME_STARTCOMPOSITION > WM_IME_COMPOSITION(GCS_COMPSTR) (* n) > WM_IME_COMPOSITION(GCS_RESULTSTR) > WM_IME_ENDCOMPOSITION, is this wrong in any way?
In my opinion, it makes sense that the x11drv_ime_set_result() code is for case where the input_style is not XIMPreditcallbacks. How about moving some code to xim_set_result_string()?
I think we may be missing a reliable open/composing status at this level, and we may end up sending `WM_WINE_IME_SET_COMP_TEXT` messages with a closed IME. Maybe in this case the message should be dropped. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/2637#note_30022
participants (3)
-
Byeongsik Jeon (@bsjeon) -
Marvin -
Rémi Bernon