From 9b4c09d8c43de61a5cf9e1918cc4d6373aa971f0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 14:29:18 +0200 Subject: [PATCH] winex11: Post internal WM_IME_NOTIFY wparam on composition updates. --- dlls/imm32/ime.c | 25 +++++++++++++++ dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/x11drv.h | 4 ++- dlls/winex11.drv/xim.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- include/ntuser.h | 1 + 6 files changed, 104 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 46f12ef6f45..35e94404b99 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -41,6 +41,7 @@ static const char *debugstr_imn( WPARAM wparam ) case IMN_GUIDELINE: return "IMN_GUIDELINE"; case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS"; case IMN_WINE_SET_OPEN_STATUS: return "IMN_WINE_SET_OPEN_STATUS"; + case IMN_WINE_SET_COMP_STRING: return "IMN_WINE_SET_COMP_STRING"; default: return wine_dbg_sprintf( "%#Ix", wparam ); } } @@ -338,6 +339,28 @@ static void ime_ui_start_composition( HIMC himc, HWND hwnd ) ImmUnlockIMC( himc ); } +static UINT ime_set_comp_string( HIMC himc, LPARAM lparam ) +{ + union + { + struct + { + UINT uMsgCount; + TRANSMSG TransMsg[10]; + }; + TRANSMSGLIST list; + } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; + UINT count; + + TRACE( "himc %p\n", himc ); + + count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); + if (count >= buffer.uMsgCount) + WARN( "ImeToAsciiEx returned %#x messages\n", count ); + + return count; +} + static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam ) { TRACE( "himc %p, hwnd %p, wparam %s, lparam %#Ix\n", hwnd, himc, debugstr_imn(wparam), lparam ); @@ -346,6 +369,8 @@ static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam { case IMN_WINE_SET_OPEN_STATUS: return ImmSetOpenStatus( himc, lparam ); + case IMN_WINE_SET_COMP_STRING: + return ime_set_comp_string( himc, lparam ); default: FIXME( "himc %p, hwnd %p, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_imn(wparam), lparam ); return 0; diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 75499f6a820..17957191e77 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -398,6 +398,7 @@ static const struct user_driver_funcs x11drv_funcs = .pMapVirtualKeyEx = X11DRV_MapVirtualKeyEx, .pToUnicodeEx = X11DRV_ToUnicodeEx, .pVkKeyScanEx = X11DRV_VkKeyScanEx, + .pImeToAsciiEx = X11DRV_ImeToAsciiEx, .pNotifyIMEStatus = X11DRV_NotifyIMEStatus, .pDestroyCursorIcon = X11DRV_DestroyCursorIcon, .pSetCursor = X11DRV_SetCursor, 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/x11drv.h b/dlls/winex11.drv/x11drv.h index 4b36c6096c4..b8b134357d6 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -208,6 +208,8 @@ extern INT X11DRV_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) DECLSPE extern UINT X11DRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl ) DECLSPEC_HIDDEN; extern INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl ) DECLSPEC_HIDDEN; +extern UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, + COMPOSITIONSTRING *compstr, HIMC himc ) DECLSPEC_HIDDEN; extern SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl ) DECLSPEC_HIDDEN; extern void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN; @@ -824,7 +826,7 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; extern BOOL xim_in_compose_mode(void) 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; extern void xim_set_focus( HWND hwnd, BOOL focus ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 760bbae42d8..1dde1fc936c 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -27,6 +27,8 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -42,6 +44,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); #define XICProc XIMProc #endif +struct ime_update +{ + struct list entry; + DWORD id; +}; + +static pthread_mutex_t ime_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct list ime_updates = LIST_INIT(ime_updates); +static DWORD ime_update_count; static WCHAR *ime_comp_buf; static XIMStyle input_style = 0; @@ -72,6 +83,21 @@ BOOL xim_in_compose_mode(void) return !!ime_comp_buf; } +static void post_ime_update( HWND hwnd ) +{ + UINT id; + struct ime_update *update; + + if (!(update = malloc( sizeof(struct ime_update) ))) return; + + pthread_mutex_lock( &ime_mutex ); + id = update->id = ++ime_update_count; + list_add_tail( &ime_updates, &update->entry ); + pthread_mutex_unlock( &ime_mutex ); + + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_COMP_STRING, id ); +} + static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { UINT len = ime_comp_buf ? wcslen( ime_comp_buf ) : 0; @@ -96,18 +122,20 @@ static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, len * sizeof(WCHAR) ); } -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, string %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; + post_ime_update( hwnd ); x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); + free( output ); } @@ -142,6 +170,8 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; else ERR( "Failed to allocate preedit buffer\n" ); + post_ime_update( hwnd ); + return -1; } @@ -155,6 +185,8 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) ime_comp_buf = NULL; x11drv_client_call( client_ime_set_composition_status, FALSE ); + post_ime_update( hwnd ); + return 0; } @@ -193,6 +225,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (text && str != text->string.multi_byte) free( str ); x11drv_client_call( client_ime_set_cursor_pos, params->caret ); + post_ime_update( hwnd ); return 0; } @@ -239,6 +272,8 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) x11drv_client_call( client_ime_set_cursor_pos, pos ); params->position = xim_caret_pos = pos; + post_ime_update( hwnd ); + return 0; } @@ -474,10 +509,46 @@ XIC X11DRV_get_ic( HWND hwnd ) void xim_set_focus( HWND hwnd, BOOL focus ) { + struct list updates = LIST_INIT(updates); + struct ime_update *update, *next; XIC xic; if (!(xic = X11DRV_get_ic( hwnd ))) return; if (focus) XSetICFocus( xic ); else XUnsetICFocus( xic ); + + pthread_mutex_lock( &ime_mutex ); + list_move_tail( &updates, &ime_updates ); + pthread_mutex_unlock( &ime_mutex ); + + LIST_FOR_EACH_ENTRY_SAFE( update, next, &updates, struct ime_update, entry ) free( update ); +} + +static struct ime_update *find_ime_update( UINT id ) +{ + struct ime_update *update; + LIST_FOR_EACH_ENTRY( update, &ime_updates, struct ime_update, entry ) + if (update->id == id) return update; + return NULL; +} + +/*********************************************************************** + * ImeToAsciiEx (X11DRV.@) + */ +UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) +{ + struct ime_update *update; + + TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc ); + + pthread_mutex_lock( &ime_mutex ); + + if ((update = find_ime_update( lparam ))) + list_remove( &update->entry ); + + pthread_mutex_unlock( &ime_mutex ); + + free( update ); + return 0; } diff --git a/include/ntuser.h b/include/ntuser.h index 890f8b0c8e8..dd0d687e416 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -494,6 +494,7 @@ enum wine_internal_message /* internal WM_IME_NOTIFY wparams, not compatible with Windows */ #define IMN_WINE_SET_OPEN_STATUS 0x000f +#define IMN_WINE_SET_COMP_STRING 0x0010 /* builtin IME driver calls */ enum wine_ime_call -- 2.11.4.GIT