-- v6: winex11: Use EM_REPLACESEL to set IME composition strings. include: Add some immdev.h definitions. 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. imm32: Only send GCS_CURSORPOS when cursor position changes. 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 builtin IME UI window in win32u struct imc. imm32: Add a struct ime field to track whether IME is builtin.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d29684f34a2..d7b9326bd1b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -52,6 +52,7 @@ struct ime
HKL hkl; HMODULE module; + BOOL is_builtin; struct list entry;
IMEINFO info; @@ -470,7 +471,6 @@ BOOL WINAPI ImmFreeLayout( HKL hkl ) BOOL WINAPI ImmLoadIME( HKL hkl ) { WCHAR buffer[MAX_PATH] = {0}; - BOOL use_default_ime; struct ime *ime;
TRACE( "hkl %p\n", hkl ); @@ -482,11 +482,10 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) return !!ime; }
- if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE; - else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE; - else use_default_ime = FALSE; + if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) ime->is_builtin = TRUE; + else if (!(ime->module = LoadLibraryW( buffer ))) ime->is_builtin = TRUE;
- if (use_default_ime) + if (ime->is_builtin) { if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) ); if (!(ime->module = load_graphics_driver())) ime->module = LoadLibraryW( L"imm32" ); @@ -494,7 +493,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl )
#define LOAD_FUNCPTR( f ) \ if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \ - !(ime->p##f = use_default_ime ? (void *)f : NULL)) \ + !(ime->p##f = ime->is_builtin ? (void *)f : NULL)) \ { \ LeaveCriticalSection( &ime_cs ); \ WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 28 ++++++++++++++++++++++++---- dlls/win32u/imm.c | 11 +++++++++++ include/ntuser.h | 1 + 3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d7b9326bd1b..1ce9cbdc570 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -622,11 +622,21 @@ static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc ) return &entry->context; }
+static BOOL CALLBACK enum_himc_set_builtin_ui( HIMC himc, LPARAM lparam ) +{ + NtUserUpdateInputContext( himc, NtUserInputContextBuiltinUI, lparam ); + return TRUE; +} + static void imc_release_ime( struct imc *imc, struct ime *ime ) { INPUTCONTEXT *ctx;
- if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); + if (imc->ui_hwnd) + { + ImmEnumInputContext( 0, enum_himc_set_builtin_ui, (LPARAM)0 ); + DestroyWindow( imc->ui_hwnd ); + } imc->ui_hwnd = NULL; ime->pImeSelect( imc->handle, FALSE );
@@ -1017,7 +1027,10 @@ static HWND get_ime_ui_window(void) 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 ); + + if (ime->is_builtin) ImmEnumInputContext( 0, enum_himc_set_builtin_ui, (LPARAM)imc->ui_hwnd ); } + return imc->ui_hwnd; }
@@ -1026,10 +1039,17 @@ static HWND get_ime_ui_window(void) */ HIMC WINAPI ImmCreateContext(void) { - struct imc *new_context; + struct imc *imc; + struct ime *ime; + HIMC himc; + + if (!(imc = create_input_context( 0 ))) return 0; + himc = imc->handle; + + if ((imc = default_input_context()) && (ime = imc_select_ime( imc )) && ime->is_builtin) + NtUserUpdateInputContext( himc, NtUserInputContextBuiltinUI, (UINT_PTR)imc->ui_hwnd );
- if (!(new_context = create_input_context(0))) return 0; - return new_context->handle; + return himc; }
static BOOL IMM_DestroyContext(HIMC hIMC) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 7dee4912e27..bf04cf82b92 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -40,6 +40,8 @@ struct imc struct user_object obj; DWORD thread_id; UINT_PTR client_ptr; + + HWND builtin_ui; /* IME UI window when builtin IME is used */ };
struct imm_thread_data @@ -80,6 +82,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->builtin_ui = 0; if (!(handle = alloc_user_handle( &imc->obj, NTUSER_OBJ_IMC ))) { free( imc ); @@ -127,6 +130,10 @@ BOOL WINAPI NtUserUpdateInputContext( HIMC handle, UINT attr, UINT_PTR value ) imc->client_ptr = value; break;
+ case NtUserInputContextBuiltinUI: + imc->builtin_ui = (HWND)value; + break; + default: FIXME( "unknown attr %u\n", attr ); ret = FALSE; @@ -156,6 +163,10 @@ UINT_PTR WINAPI NtUserQueryInputContext( HIMC handle, UINT attr ) ret = imc->thread_id; break;
+ case NtUserInputContextBuiltinUI: + ret = (UINT_PTR)imc->builtin_ui; + break; + default: FIXME( "unknown attr %u\n", attr ); ret = 0; diff --git a/include/ntuser.h b/include/ntuser.h index 3d43eb476e4..8da69cc1e76 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 { + NtUserInputContextBuiltinUI = -1, NtUserInputContextClientPtr, NtUserInputContextThreadId, };
From: Rémi Bernon rbernon@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 | 16 ++++++++++++---- include/ntuser.h | 3 +++ 8 files changed, 19 insertions(+), 16 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..db5a3a5a74b 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -72,6 +72,14 @@ static const char *debugstr_xim_style( XIMStyle style ) return wine_dbg_sprintf( "%s", buffer ); }
+/* return the builtin IME UI window associated with a window */ +static HWND get_builtin_ime_ui( HWND hwnd ) +{ + HIMC himc; + if (!(himc = NtUserGetWindowInputContext( hwnd ))) return 0; + return (HWND)NtUserQueryInputContext( himc, NtUserInputContextBuiltinUI ); +} + static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len) { /* Composition strings are edited in chunks */ @@ -131,12 +139,12 @@ 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 ); + if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); + else send_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, TRUE, 0 ); break; case XIMPreeditDisable: - x11drv_client_call( client_ime_set_open_status, FALSE ); - break; - default: + if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); + else send_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, FALSE, 0 ); break; }
diff --git a/include/ntuser.h b/include/ntuser.h index 8da69cc1e76..7038ad86d98 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
+/* builtin IME UI messages */ +#define WM_WINE_IME_SET_OPEN_STATUS (WM_USER + 0) + /* internal IME private */ typedef struct ime_private {
From: Rémi Bernon rbernon@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 | 7 ++++++- include/ntuser.h | 1 + 8 files changed, 29 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 db5a3a5a74b..072cf49457a 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -230,8 +230,13 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
if (!params) return 0; + if (!(hwnd = get_builtin_ime_ui( hwnd ))) + { + WARN( "No builtin IME UI, ignoring event.\n" ); + return 0; + }
- pos = x11drv_client_call( client_ime_get_cursor_pos, 0 ); + pos = send_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 7038ad86d98..fed74155c4a 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -493,6 +493,7 @@ enum wine_internal_message
/* builtin 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
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/ime.c | 40 +++++++++++++++++++++++++++++++++++ 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 | 10 +++++++-- include/ntuser.h | 1 + 8 files changed, 50 insertions(+), 31 deletions(-)
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 86834546a58..dcea00c788b 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,25 @@ 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; + + TRACE( "himc %p, new_pos %u\n", himc, new_pos ); + + if (!(ctx = ImmLockIMC( himc ))) return 0; + if ((string = ImmLockIMCC( ctx->hCompStr ))) + { + string->dwCursorPos = new_pos; + ImmUnlockIMCC( ctx->hCompStr ); + } + ImmUnlockIMC( himc ); + + ime_send_message( himc, WM_IME_COMPOSITION, new_pos, GCS_CURSORPOS ); + return 0; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -315,6 +353,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 072cf49457a..af9846661af 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -187,6 +187,11 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
if (!params) return 0; + if (!(hwnd = get_builtin_ime_ui( hwnd ))) + { + WARN( "No builtin IME UI, ignoring event.\n" ); + return 0; + }
if (!(text = params->text)) X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, NULL, 0 ); @@ -216,7 +221,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_message( hwnd, WM_WINE_IME_SET_CURSOR_POS, params->caret, 0 );
return 0; } @@ -264,7 +269,8 @@ 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_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 fed74155c4a..e7ebf786e25 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -494,6 +494,7 @@ enum wine_internal_message /* builtin 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
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/ime.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index dcea00c788b..77c485a2e83 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -284,19 +284,21 @@ 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 );
- ime_send_message( himc, WM_IME_COMPOSITION, new_pos, GCS_CURSORPOS ); - return 0; + 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 )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/ime.c | 65 +++++++++++++++++++++++++++++++++++ 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 | 10 ++++-- include/ntuser.h | 1 + 8 files changed, 75 insertions(+), 36 deletions(-)
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 77c485a2e83..e4e3c65aee4 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -83,6 +83,40 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; }
+static void input_context_set_comp_str( INPUTCONTEXT *ctx, BOOL result, const WCHAR *str, SIZE_T len ) +{ + UINT new_size = sizeof(COMPOSITIONSTRING); + COMPOSITIONSTRING old, *string; + HIMCC tmp; + + 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 (!(string = ImmLockIMCC( ctx->hCompStr ))) return; + old = *string; + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size > old.dwSize) + { + if (!(tmp = ImmReSizeIMCC( ctx->hCompStr, new_size ))) return; + ctx->hCompStr = tmp; + } + + if (!(string = ImmLockIMCC( ctx->hCompStr ))) return; + memset( string, 0, sizeof(COMPOSITIONSTRING) ); + string->dwSize = sizeof(COMPOSITIONSTRING); + ImmUnlockIMCC( ctx->hCompStr ); + + if (new_size < old.dwSize) + { + if (!(tmp = ImmReSizeIMCC( ctx->hCompStr, new_size ))) return; + ctx->hCompStr = tmp; + } +} + static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) { struct ime_private *priv; @@ -301,6 +335,35 @@ 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 ) +{ + struct ime_private *priv; + BOOL old_status = FALSE; + INPUTCONTEXT *ctx; + + 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 ); + } + if (new_status != old_status) input_context_set_comp_str( ctx, TRUE, NULL, 0 ); + ImmUnlockIMC( himc ); + + if (old_status < new_status) + ime_send_message( himc, WM_IME_STARTCOMPOSITION, 0, 0 ); + else if (old_status > new_status) + { + ShowWindow( hwnd, SW_HIDE ); + ime_send_message( himc, 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 +420,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 af9846661af..327ab6b5ce2 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -157,8 +157,11 @@ 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 ); ximInComposeMode = TRUE; + + if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); + else send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, TRUE, 0 ); + return -1; }
@@ -174,7 +177,10 @@ 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 ); + + if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); + else send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); + return 0; }
diff --git a/include/ntuser.h b/include/ntuser.h index e7ebf786e25..e00bfaee44b 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
From: Rémi Bernon rbernon@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 327ab6b5ce2..eedfdd06eac 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; @@ -80,38 +79,32 @@ static HWND get_builtin_ime_ui( HWND hwnd ) return (HWND)NtUserQueryInputContext( himc, NtUserInputContextBuiltinUI ); }
-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 ) @@ -172,11 +165,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;
if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); else send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); @@ -200,7 +192,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) }
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; @@ -220,7 +212,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 ); }
From: Rémi Bernon rbernon@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 eedfdd06eac..cba737c333f 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -85,11 +85,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; @@ -103,6 +103,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) ); } @@ -114,8 +115,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 );
From: Rémi Bernon rbernon@codeweavers.com
--- include/imm.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/imm.h b/include/imm.h index 500aea978d1..0e9545099cf 100644 --- a/include/imm.h +++ b/include/imm.h @@ -238,6 +238,11 @@ typedef struct _tagIMECHARPOSITION #define GCS_RESULTSTR 0x0800 #define GCS_RESULTCLAUSE 0x1000
+#define GCS_COMP (GCS_COMPSTR|GCS_COMPATTR|GCS_COMPCLAUSE) +#define GCS_COMPREAD (GCS_COMPREADSTR|GCS_COMPREADATTR|GCS_COMPREADCLAUSE) +#define GCS_RESULT (GCS_RESULTSTR|GCS_RESULTCLAUSE) +#define GCS_RESULTREAD (GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE) + /* style bit flags for WM_IME_COMPOSITION */ #define CS_INSERTCHAR 0x2000 #define CS_NOMOVECARET 0x4000
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/ime.c | 59 +++++++++++++++++++++++++++++++++++ dlls/imm32/imm_private.h | 1 + dlls/winex11.drv/dllmain.c | 2 -- dlls/winex11.drv/event.c | 4 +-- dlls/winex11.drv/ime.c | 54 -------------------------------- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/unixlib.h | 2 -- dlls/winex11.drv/x11drv.h | 3 +- dlls/winex11.drv/x11drv_dll.h | 2 -- dlls/winex11.drv/xim.c | 39 ++++++++++++++++------- include/ntuser.h | 1 + 11 files changed, 93 insertions(+), 76 deletions(-)
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index e4e3c65aee4..464b5bdc2bf 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -88,6 +88,7 @@ static void input_context_set_comp_str( INPUTCONTEXT *ctx, BOOL result, const WC UINT new_size = sizeof(COMPOSITIONSTRING); COMPOSITIONSTRING old, *string; HIMCC tmp; + BYTE *dst;
TRACE( "ctx %p, result %u, str %s\n", ctx, result, debugstr_wn(str, len) );
@@ -108,6 +109,46 @@ static void input_context_set_comp_str( INPUTCONTEXT *ctx, BOOL result, const WC if (!(string = ImmLockIMCC( ctx->hCompStr ))) return; memset( string, 0, sizeof(COMPOSITIONSTRING) ); string->dwSize = sizeof(COMPOSITIONSTRING); + + if (!result && len) + { + string->dwCursorPos = min( len, old.dwCursorPos ); + + string->dwCompStrLen = len; + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + string->dwSize += len * sizeof(WCHAR); + + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = len; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, len ); + string->dwSize += len; + } + else if (len) + { + string->dwResultStrLen = len; + string->dwResultStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultStrOffset; + memcpy( dst, str, len * sizeof(WCHAR) ); + string->dwSize += len * sizeof(WCHAR); + + string->dwResultClauseLen = 2 * sizeof(DWORD); + string->dwResultClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + } + ImmUnlockIMCC( ctx->hCompStr );
if (new_size < old.dwSize) @@ -364,6 +405,21 @@ static BOOL ime_set_composition_status( HIMC himc, HWND hwnd, BOOL new_status ) return old_status; }
+static BOOL ime_set_composition_text( HIMC himc, BOOL result, const WCHAR *str, UINT len ) +{ + DWORD flags = result ? GCS_RESULT : GCS_COMP | GCS_CURSORPOS | GCS_DELTASTART; + INPUTCONTEXT *ctx; + + TRACE( "himc %p, result %u, str %s\n", himc, result, debugstr_wn(str, len) ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + input_context_set_comp_str( ctx, result, str, len ); + ImmUnlockIMC( himc ); + + ime_send_message( himc, WM_IME_COMPOSITION, len ? str[0] : 0, flags ); + return TRUE; +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -422,6 +478,9 @@ 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, !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/event.c b/dlls/winex11.drv/event.c index 1ae39eb9edf..4ec37185751 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -49,8 +49,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(event); WINE_DECLARE_DEBUG_CHANNEL(xdnd);
-extern BOOL ximInComposeMode; - #define DndNotDnd -1 /* OffiX drag&drop */ #define DndUnknown 0 #define DndRawData 1 @@ -810,7 +808,7 @@ static void focus_out( Display *display , HWND hwnd ) int revert; XIC xic;
- if (ximInComposeMode) return; + if (xim_in_compose_mode) return;
x11drv_thread_data()->last_focus = hwnd; if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic ); 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..e007f07066a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -453,6 +453,7 @@ extern int xrender_error_base DECLSPEC_HIDDEN; extern char *process_name DECLSPEC_HIDDEN; extern Display *clipboard_display DECLSPEC_HIDDEN; extern WNDPROC client_foreign_window_proc DECLSPEC_HIDDEN; +extern BOOL xim_in_compose_mode DECLSPEC_HIDDEN;
/* atoms */
@@ -823,7 +824,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 cba737c333f..25ddb9ea940 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -42,7 +42,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); #define XICProc XIMProc #endif
-BOOL ximInComposeMode=FALSE; +BOOL xim_in_compose_mode = FALSE;
static DWORD preedit_len = 0; static DWORD preedit_max = 0; @@ -79,11 +79,11 @@ static HWND get_builtin_ime_ui( HWND hwnd ) return (HWND)NtUserQueryInputContext( himc, NtUserInputContextBuiltinUI ); }
-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) { @@ -105,21 +105,38 @@ 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_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 (!(hwnd = get_builtin_ime_ui( hwnd ))) + { + WARN( "No builtin IME UI, ignoring event.\n" ); + 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) ); + if (!xim_in_compose_mode) + { + send_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, TRUE, 0 ); + send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, TRUE, 0 ); + } + send_message( hwnd, WM_WINE_IME_SET_COMP_TEXT, FALSE, (LPARAM)output ); + if (!xim_in_compose_mode) + { + send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, FALSE, 0 ); + send_message( hwnd, WM_WINE_IME_SET_OPEN_STATUS, FALSE, 0 ); + } + free( output ); }
@@ -152,7 +169,7 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg )
TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
- ximInComposeMode = TRUE; + xim_in_compose_mode = TRUE;
if (!(hwnd = get_builtin_ime_ui( hwnd ))) WARN( "No builtin IME UI, ignoring event.\n" ); else send_message( hwnd, WM_WINE_IME_SET_COMP_STATUS, TRUE, 0 ); @@ -166,7 +183,7 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg )
TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
- ximInComposeMode = FALSE; + xim_in_compose_mode = FALSE; free( preedit_buf ); preedit_max = 0; preedit_len = 0; @@ -194,7 +211,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) }
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; @@ -214,7 +231,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 e00bfaee44b..331b2b6b4a5 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
v6: Use fixed flags when updating composition string, regardless of the actual changes.
Maybe there's a problem I'm not aware of.
Is there a problem with implementing this using WM_IME_INTERNAL?
Another topic, code works, but the hwnd used by the xic callback function is not valid, so it would be nice if it could be cleaned up. Is this because you don't like to use get_focus()?
Is there a problem with implementing this using WM_IME_INTERNAL?
We need to copy the string allocated from winex11 to some memory that is accessible to the win32 side. EM_REPLACESEL does that already and using WM_IME_INTERNAL we would have to add more code to do the same thing.
There may be some other ways such as notifying the IME then calling back into winex11 to get the string but I think it's more convoluted.
Another topic,
code works, but the hwnd used by the xic callback function is not valid, so it would be nice if it could be cleaned up. Is this because you don't like to use get_focus()?
I'm not sure to understand what you mean by invalid? get_focus could return a different window than the one which received the input event and I think we should follow X11 target window. Especially as I think that ultimately input events should be listened to in a separate thread.
We need to copy the string allocated from winex11 to some memory that is accessible to the win32 side. EM_REPLACESEL does that already and using WM_IME_INTERNAL we would have to add more code to do the same thing.
OK, thanks for the answer.
I'm not sure to understand what you mean by invalid? get_focus could return a different window than the one which received the input event and I think we should follow X11 target window. Especially as I think that ultimately input events should be listened to in a separate thread.
The reason I said invalid is because the hwnd in the xic callback is not the hwnd stored with IMMGWL_IMC. But it's OK, because ime_ui_wndow_proc will use the correct hwnd value. In my old personal code, I used the value received by ImeSetActiveContext.
How about in a Win32 -> X11 situation? This is the situation with the POC patch "Use NtUserGetAncestor() for the foreign window in X11DRV_get_ic()".
How about in a Win32 -> X11 situation?
This is the situation with the POC patch "Use NtUserGetAncestor() for the foreign window in X11DRV_get_ic()".
Yes in this scenario the hwnd we pass to X11DRV_get_ic isn't the correct one, I intend to change this later in the same way as you did it, but I'd like to have the unix -> win32 callback mechanism settled first.
The reason I said invalid is because the hwnd in the xic callback is not the hwnd stored with IMMGWL_IMC. But it's OK, because ime_ui_wndow_proc will use the correct hwnd value. In my old personal code, I used the value received by ImeSetActiveContext.
Yes we only need to target the right thread with the built-in IME UI messages. Then the currently active input context and its window will be used (there will be some minor things to fix there too).
So I understand that this still doesn't look right but I'm not sure exactly how?
Would it be a better approach to send this IME input through __wine_send_input and hardware messages, through some kind of HID-like interface? I think it might be more future-proof, and maybe something we want to do ultimately, but it makes some callbacks like winemac cursor rect query more difficult.
Like the win32u/imm.c::ImmProcessKey approach, would it be hard to implement ImmLockIMC, ImmLockIMCC? If implemented, wouldn't it eliminate the need for the WM_WINE_IME_* mechanism?
Sorry I can't be of much help.