Doing first instead of https://gitlab.winehq.org/wine/wine/-/merge_requests/2637, as it should be more straightforward.
-- v4: winemac: Use the default IME implementation for NotifyIME. winex11: Move NotifyIME to the default IME implementation. win32u: Introduce new NtUserNotifyIMEStatus syscall. winex11: Simplify NotifyIME with NI_COMPOSITIONSTR / CPS_COMPLETE. winex11: Clear the composition string when input context is closed. winex11: Use a helper to change internal composition status.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/ime.c | 76 +++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 46 deletions(-)
diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 55485bfbfcf..bfca49ab22b 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -453,6 +453,25 @@ static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, UnlockRealIMC(hIMC); }
+static void ime_set_composition_status( HIMC himc, BOOL composition ) +{ + struct ime_private *priv; + INPUTCONTEXT *ctx; + UINT msg = 0; + + if (!(ctx = ImmLockIMC( himc ))) return; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; + else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; + priv->bInComposition = composition; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + + if (msg) GenerateIMEMessage( himc, msg, 0, 0 ); +} + static BOOL IME_RemoveFromSelected(HIMC hIMC) { int i; @@ -580,16 +599,8 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) X11DRV_CALL( xim_preedit_state, &preedit_params ); if (!lpIMC->fOpen) { - LPIMEPRIVATE myPrivate; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - X11DRV_CALL( xim_reset, lpIMC->hWnd ); - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); + X11DRV_CALL( xim_reset, lpIMC->hWnd ); + ime_set_composition_status( hIMC, FALSE ); }
break; @@ -602,7 +613,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_COMPLETE: { HIMCC newCompStr; - LPIMEPRIVATE myPrivate; WCHAR *str; UINT len;
@@ -614,7 +624,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr;
- myPrivate = ImmLockIMCC(lpIMC->hPrivate); if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { WCHAR param = str[0]; @@ -631,15 +640,10 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, GCS_RESULTSTR|GCS_RESULTCLAUSE); - - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); free( str ); } - else if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
- myPrivate->bInComposition = FALSE; - ImmUnlockIMCC(lpIMC->hPrivate); + ime_set_composition_status( hIMC, FALSE );
bRet = TRUE; } @@ -648,8 +652,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_REVERT: FIXME("CPS_REVERT\n"); break; case CPS_CANCEL: { - LPIMEPRIVATE myPrivate; - TRACE("CPS_CANCEL\n");
X11DRV_CALL( xim_reset, lpIMC->hWnd ); @@ -658,13 +660,7 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr();
- myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); + ime_set_composition_status( hIMC, FALSE ); bRet = TRUE; } break; @@ -685,7 +681,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, LPINPUTCONTEXT lpIMC; DWORD flags = 0; WCHAR wParam = 0; - LPIMEPRIVATE myPrivate;
TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -710,17 +705,11 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, if (lpIMC == NULL) return FALSE;
- myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (dwIndex == SCS_SETSTR) { HIMCC newCompStr;
- if (!myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); - myPrivate->bInComposition = TRUE; - } + ime_set_composition_status( hIMC, TRUE );
/* clear existing result */ newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); @@ -768,30 +757,25 @@ 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) + if (!open) { + struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate); ShowWindow(myPrivate->hwndDefault, SW_HIDE); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr(); - GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); + ImmUnlockIMCC(lpIMC->hPrivate); } - myPrivate->bInComposition = open;
- ImmUnlockIMCC(lpIMC->hPrivate); ImmUnlockIMC(imc); + + ime_set_composition_status( imc, open ); + return 0; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/ime.c | 49 ++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 30 deletions(-)
diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index bfca49ab22b..ece40f0dfc2 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -73,6 +73,20 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; }
+static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) +{ + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + ImmUnlockIMCC( ctx->hCompStr ); + } +} + static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_X11) @@ -107,18 +121,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; }
-static HIMCC ImeCreateBlankCompStr(void) -{ - HIMCC rc; - LPCOMPOSITIONSTRING ptr; - rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); - ptr = ImmLockIMCC(rc); - memset(ptr,0,sizeof(COMPOSITIONSTRING)); - ptr->dwSize = sizeof(COMPOSITIONSTRING); - ImmUnlockIMCC(rc); - return rc; -} - static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, LPBYTE target, LPBYTE source, DWORD* lenParam, DWORD* offsetParam, BOOL wchars ) @@ -591,8 +593,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) } break; case IMC_SETOPENSTATUS: - TRACE("IMC_SETOPENSTATUS\n"); - bRet = TRUE; preedit_params.hwnd = lpIMC->hWnd; preedit_params.open = lpIMC->fOpen; @@ -600,9 +600,9 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) if (!lpIMC->fOpen) { X11DRV_CALL( xim_reset, lpIMC->hWnd ); + input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); } - break; default: FIXME("Unknown\n"); break; } @@ -643,27 +643,17 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) free( str ); }
- ime_set_composition_status( hIMC, FALSE ); - + ImmSetOpenStatus( hIMC, FALSE ); bRet = TRUE; } break; case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break; case CPS_REVERT: FIXME("CPS_REVERT\n"); break; case CPS_CANCEL: - { - TRACE("CPS_CANCEL\n"); - - X11DRV_CALL( xim_reset, lpIMC->hWnd ); - - if (lpIMC->hCompStr) - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); - + input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); bRet = TRUE; - } - break; + break; default: FIXME("Unknown\n"); break; } break; @@ -767,8 +757,7 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) { struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate); ShowWindow(myPrivate->hwndDefault, SW_HIDE); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); + input_context_reset_comp_str( lpIMC ); ImmUnlockIMCC(lpIMC->hPrivate); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/ime.c | 67 ++++++++++++------------------------------ 1 file changed, 19 insertions(+), 48 deletions(-)
diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index ece40f0dfc2..900a6a3e5d3 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -52,27 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0;
-static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) -{ - COMPOSITIONSTRING *string; - WCHAR *text = NULL; - UINT len, off; - - if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; - len = result ? string->dwResultStrLen : string->dwCompStrLen; - off = result ? string->dwResultStrOffset : string->dwCompStrOffset; - - if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) - { - memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); - text[len] = 0; - *length = len; - } - - ImmUnlockIMCC( ctx->hCompStr ); - return text; -} - static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) { COMPOSITIONSTRING *compstr; @@ -612,35 +591,27 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { case CPS_COMPLETE: { - HIMCC newCompStr; - WCHAR *str; - UINT len; - - TRACE("CPS_COMPLETE\n"); - - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; + COMPOSITIONSTRING *compstr;
- if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) + if (!(compstr = ImmLockIMCC( lpIMC->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else { - 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); - free( str ); + WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); + COMPOSITIONSTRING tmp = *compstr; + UINT flags = 0; + + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = tmp.dwSize; + compstr->dwResultStrLen = tmp.dwCompStrLen; + compstr->dwResultStrOffset = tmp.dwCompStrOffset; + compstr->dwResultClauseLen = tmp.dwCompClauseLen; + compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; + ImmUnlockIMCC( lpIMC->hCompStr ); + + if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; + if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; + if (flags) GenerateIMEMessage( hIMC, WM_IME_COMPOSITION, wchr, flags ); }
ImmSetOpenStatus( hIMC, FALSE );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 11 +++++++++ dlls/win32u/imm.c | 8 +++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/winex11.drv/ime.c | 8 ++----- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/unixlib.h | 2 -- dlls/winex11.drv/x11drv.h | 3 +-- dlls/winex11.drv/x11drv_main.c | 18 --------------- dlls/winex11.drv/xim.c | 42 +++++++++++----------------------- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 9 ++++++++ include/ntuser.h | 1 + include/wine/gdi_driver.h | 2 ++ 14 files changed, 51 insertions(+), 58 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 5bae77da5f4..f0055b68d1e 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -716,6 +716,10 @@ static SHORT nulldrv_VkKeyScanEx( WCHAR ch, HKL layout ) return -256; /* use default implementation */ }
+static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ +} + static LRESULT nulldrv_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { return default_window_proc( hwnd, msg, wparam, lparam, FALSE ); @@ -1070,6 +1074,11 @@ static SHORT loaderdrv_VkKeyScanEx( WCHAR ch, HKL layout ) return load_driver()->pVkKeyScanEx( ch, layout ); }
+static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ + return load_driver()->pNotifyIMEStatus( hwnd, status ); +} + static LONG loaderdrv_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HWND hwnd, DWORD flags, LPVOID lparam ) { @@ -1176,6 +1185,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_ToUnicodeEx, loaderdrv_UnregisterHotKey, loaderdrv_VkKeyScanEx, + loaderdrv_NotifyIMEStatus, /* cursor/icon functions */ nulldrv_DestroyCursorIcon, loaderdrv_SetCursor, @@ -1255,6 +1265,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ToUnicodeEx); SET_USER_FUNC(UnregisterHotKey); SET_USER_FUNC(VkKeyScanEx); + SET_USER_FUNC(NotifyIMEStatus); SET_USER_FUNC(DestroyCursorIcon); SET_USER_FUNC(SetCursor); SET_USER_FUNC(GetCursorPos); diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 7dee4912e27..328a4a3eddf 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -421,6 +421,14 @@ NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, U return STATUS_SUCCESS; }
+/***************************************************************************** + * NtUserNotifyIMEStatus (win32u.@) + */ +void WINAPI NtUserNotifyIMEStatus( HWND hwnd, UINT status ) +{ + user_driver->pNotifyIMEStatus( hwnd, status ); +} + BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) { struct imm_process_key_params params = diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index f93ba9b804b..a550d32bce9 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -233,6 +233,7 @@ static void * const syscalls[] = NtUserMessageCall, NtUserMoveWindow, NtUserMsgWaitForMultipleObjectsEx, + NtUserNotifyIMEStatus, NtUserNotifyWinEvent, NtUserOpenClipboard, NtUserOpenDesktop, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 544f375d637..af3ac7468a9 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1087,7 +1087,7 @@ @ stdcall -syscall NtUserMoveWindow(long long long long long long) @ stdcall -syscall NtUserMsgWaitForMultipleObjectsEx(long ptr long long long) @ stub NtUserNavigateFocus -@ stub NtUserNotifyIMEStatus +@ stdcall -syscall NtUserNotifyIMEStatus(long long) @ stub NtUserNotifyProcessCreate @ stdcall -syscall NtUserNotifyWinEvent(long long long long) @ stdcall -syscall NtUserOpenClipboard(long long) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 900a6a3e5d3..cbd8908a12d 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -531,7 +531,6 @@ UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { - struct xim_preedit_state_params preedit_params; BOOL bRet = FALSE; LPINPUTCONTEXT lpIMC;
@@ -572,16 +571,13 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) } break; case IMC_SETOPENSTATUS: - bRet = TRUE; - preedit_params.hwnd = lpIMC->hWnd; - preedit_params.open = lpIMC->fOpen; - X11DRV_CALL( xim_preedit_state, &preedit_params ); if (!lpIMC->fOpen) { - X11DRV_CALL( xim_reset, lpIMC->hWnd ); input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); } + NtUserNotifyIMEStatus( lpIMC->hWnd, lpIMC->fOpen ); + bRet = TRUE; break; default: FIXME("Unknown\n"); break; } diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index e26cfb5a789..75499f6a820 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, + .pNotifyIMEStatus = X11DRV_NotifyIMEStatus, .pDestroyCursorIcon = X11DRV_DestroyCursorIcon, .pSetCursor = X11DRV_SetCursor, .pGetCursorPos = X11DRV_GetCursorPos, diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 7dc1d9f0ca7..20279bdb2ac 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -31,8 +31,6 @@ enum x11drv_funcs unix_tablet_get_packet, unix_tablet_info, unix_tablet_load_info, - unix_xim_preedit_state, - unix_xim_reset, unix_funcs_count, };
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9efaae3465b..7dcafc186f1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -209,6 +209,7 @@ extern UINT X11DRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl ) DECLSPEC extern INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl ) 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; extern void X11DRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL X11DRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN; @@ -848,8 +849,6 @@ extern NTSTATUS x11drv_tablet_attach_queue( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_get_packet( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_load_info( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_info( void *arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_xim_preedit_state( void *arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_xim_reset( void *arg ) DECLSPEC_HIDDEN;
extern NTSTATUS x11drv_client_func( enum x11drv_client_funcs func, const void *params, ULONG size ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index aa39ecf2228..3fd6dcab254 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -1330,8 +1330,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = x11drv_tablet_get_packet, x11drv_tablet_info, x11drv_tablet_load_info, - x11drv_xim_preedit_state, - x11drv_xim_reset, };
@@ -1408,20 +1406,6 @@ static NTSTATUS x11drv_wow64_tablet_info( void *arg ) return x11drv_tablet_info( ¶ms ); }
-static NTSTATUS x11drv_wow64_xim_preedit_state( void *arg ) -{ - struct - { - ULONG hwnd; - BOOL open; - } *params32 = arg; - struct xim_preedit_state_params params; - - params.hwnd = UlongToHandle( params32->hwnd ); - params.open = params32->open; - return x11drv_xim_preedit_state( ¶ms ); -} - const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { x11drv_create_desktop, @@ -1434,8 +1418,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = x11drv_wow64_tablet_get_packet, x11drv_wow64_tablet_info, x11drv_tablet_load_info, - x11drv_wow64_xim_preedit_state, - x11drv_xim_reset, };
C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count ); diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 3601cb8c680..b7ab69029b9 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -260,42 +260,26 @@ static int xic_status_draw( XIC xic, XPointer user, XPointer arg ) return 0; }
-NTSTATUS x11drv_xim_reset( void *hwnd ) -{ - XIC ic = X11DRV_get_ic(hwnd); - if (ic) - { - char* leftover; - TRACE("Forcing Reset %p\n",ic); - leftover = XmbResetIC(ic); - XFree(leftover); - } - return 0; -} - -NTSTATUS x11drv_xim_preedit_state( void *arg ) +/*********************************************************************** + * NotifyIMEStatus (X11DRV.@) + */ +void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) { - struct xim_preedit_state_params *params = arg; - XIC ic; - XIMPreeditState state; + XIMPreeditState state = status ? XIMPreeditEnable : XIMPreeditDisable; XVaNestedList attr; + XIC xic;
- ic = X11DRV_get_ic( params->hwnd ); - if (!ic) - return 0; + TRACE( "hwnd %p, status %#x\n", hwnd, status );
- if (params->open) - state = XIMPreeditEnable; - else - state = XIMPreeditDisable; + if (!(xic = X11DRV_get_ic( hwnd ))) return;
- attr = XVaCreateNestedList(0, XNPreeditState, state, NULL); - if (attr != NULL) + if ((attr = XVaCreateNestedList( 0, XNPreeditState, state, NULL ))) { - XSetICValues(ic, XNPreeditAttributes, attr, NULL); - XFree(attr); + XSetICValues( xic, XNPreeditAttributes, attr, NULL ); + XFree( attr ); } - return 0; + + if (!status) XFree( XmbResetIC( xic ) ); }
/*********************************************************************** diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 7e2b7af7846..b2d4b041779 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -219,6 +219,7 @@ SYSCALL_ENTRY( NtUserMessageCall ) \ SYSCALL_ENTRY( NtUserMoveWindow ) \ SYSCALL_ENTRY( NtUserMsgWaitForMultipleObjectsEx ) \ + SYSCALL_ENTRY( NtUserNotifyIMEStatus ) \ SYSCALL_ENTRY( NtUserNotifyWinEvent ) \ SYSCALL_ENTRY( NtUserOpenClipboard ) \ SYSCALL_ENTRY( NtUserOpenDesktop ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index e1ce2dd8321..68670acecc6 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3154,6 +3154,15 @@ NTSTATUS WINAPI wow64_NtUserMsgWaitForMultipleObjectsEx( UINT *args ) return NtUserMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); }
+NTSTATUS WINAPI wow64_NtUserNotifyIMEStatus( UINT *args ) +{ + HWND hwnd = get_handle( &args ); + ULONG status = get_ulong( &args ); + + NtUserNotifyIMEStatus( hwnd, status ); + return 0; +} + NTSTATUS WINAPI wow64_NtUserNotifyWinEvent( UINT *args ) { DWORD event = get_ulong( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 3d43eb476e4..6e0a75657c8 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -818,6 +818,7 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa BOOL WINAPI NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ); DWORD WINAPI NtUserMsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ); +void WINAPI NtUserNotifyIMEStatus( HWND hwnd, UINT status ); void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG child_id ); HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access ); BOOL WINAPI NtUserOpenClipboard( HWND hwnd, ULONG unk ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 0eb24fd4424..c6683c750ef 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -287,6 +287,8 @@ struct user_driver_funcs INT (*pToUnicodeEx)(UINT,UINT,const BYTE *,LPWSTR,int,UINT,HKL); void (*pUnregisterHotKey)(HWND, UINT, UINT); SHORT (*pVkKeyScanEx)(WCHAR, HKL); + /* IME functions */ + void (*pNotifyIMEStatus)(HWND,UINT); /* cursor/icon functions */ void (*pDestroyCursorIcon)(HCURSOR); void (*pSetCursor)(HCURSOR);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/ime.c | 140 +++++++++++++++++++++++++++++- dlls/winex11.drv/ime.c | 102 ---------------------- dlls/winex11.drv/winex11.drv.spec | 1 - 3 files changed, 137 insertions(+), 106 deletions(-)
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 3c4550c3cd9..44b1173b1db 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -83,6 +83,20 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; }
+static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) +{ + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + ImmUnlockIMCC( ctx->hCompStr ); + } +} + static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) { struct ime_private *priv; @@ -93,6 +107,47 @@ static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) return font; }
+static void ime_send_message( HIMC himc, UINT message, WPARAM wparam, LPARAM lparam ) +{ + INPUTCONTEXT *ctx; + TRANSMSG *msgs; + HIMCC himcc; + + if (!(ctx = ImmLockIMC( himc ))) return; + if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + 1) * sizeof(*msgs) ))) + WARN( "Failed to resize input context message buffer\n" ); + else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) ))) + WARN( "Failed to lock input context message buffer\n" ); + else + { + TRANSMSG msg = {.message = message, .wParam = wparam, .lParam = lparam}; + msgs[ctx->dwNumMsgBuf++] = msg; + ImmUnlockIMCC( ctx->hMsgBuf ); + } + + ImmUnlockIMC( himc ); + ImmGenerateMessage( himc ); +} + +static void ime_set_composition_status( HIMC himc, BOOL composition ) +{ + struct ime_private *priv; + INPUTCONTEXT *ctx; + UINT msg = 0; + + if (!(ctx = ImmLockIMC( himc ))) return; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; + else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; + priv->bInComposition = composition; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + + if (msg) ime_send_message( himc, msg, 0, 0 ); +} + static void ime_ui_paint( HIMC himc, HWND hwnd ) { PAINTSTRUCT ps; @@ -390,9 +445,88 @@ BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, D
BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - FIXME( "himc %p, action %lu, index %lu, value %lu stub!\n", himc, action, index, value ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + struct ime_private *priv; + INPUTCONTEXT *ctx; + + TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + switch (action) + { + case NI_CONTEXTUPDATED: + switch (value) + { + case IMC_SETCOMPOSITIONFONT: + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (priv->textfont) DeleteObject( priv->textfont ); + priv->textfont = CreateFontIndirectW( &ctx->lfFont.W ); + ImmUnlockIMCC( ctx->hPrivate ); + } + break; + case IMC_SETOPENSTATUS: + if (!ctx->fOpen) + { + input_context_reset_comp_str( ctx ); + ime_set_composition_status( himc, FALSE ); + } + NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen ); + break; + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + break; + + case NI_COMPOSITIONSTR: + switch (index) + { + case CPS_COMPLETE: + { + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); + COMPOSITIONSTRING tmp = *compstr; + UINT flags = 0; + + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = tmp.dwSize; + compstr->dwResultStrLen = tmp.dwCompStrLen; + compstr->dwResultStrOffset = tmp.dwCompStrOffset; + compstr->dwResultClauseLen = tmp.dwCompClauseLen; + compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; + ImmUnlockIMCC( ctx->hCompStr ); + + if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; + if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; + if (flags) ime_send_message( himc, WM_IME_COMPOSITION, wchr, flags ); + } + + ImmSetOpenStatus( himc, FALSE ); + break; + } + case CPS_CANCEL: + input_context_reset_comp_str( ctx ); + ImmSetOpenStatus( himc, FALSE ); + break; + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + break; + + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + + ImmUnlockIMC( himc ); + return TRUE; }
LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data ) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index cbd8908a12d..3cc73c3974c 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -529,108 +529,6 @@ UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; }
-BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) -{ - BOOL bRet = FALSE; - LPINPUTCONTEXT lpIMC; - - TRACE("%p %li %li %li\n",hIMC,dwAction,dwIndex,dwValue); - - lpIMC = LockRealIMC(hIMC); - if (lpIMC == NULL) - return FALSE; - - switch (dwAction) - { - case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break; - case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break; - case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break; - case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break; - case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break; - case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break; - case NI_CONTEXTUPDATED: - switch (dwValue) - { - case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break; - case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break; - case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break; - case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break; - case IMC_SETCOMPOSITIONFONT: - { - LPIMEPRIVATE myPrivate; - TRACE("IMC_SETCOMPOSITIONFONT\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->textfont) - { - DeleteObject(myPrivate->textfont); - myPrivate->textfont = NULL; - } - myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W); - ImmUnlockIMCC(lpIMC->hPrivate); - } - break; - case IMC_SETOPENSTATUS: - if (!lpIMC->fOpen) - { - input_context_reset_comp_str( lpIMC ); - ime_set_composition_status( hIMC, FALSE ); - } - NtUserNotifyIMEStatus( lpIMC->hWnd, lpIMC->fOpen ); - bRet = TRUE; - break; - default: FIXME("Unknown\n"); break; - } - break; - case NI_COMPOSITIONSTR: - switch (dwIndex) - { - case CPS_COMPLETE: - { - COMPOSITIONSTRING *compstr; - - if (!(compstr = ImmLockIMCC( lpIMC->hCompStr ))) - WARN( "Failed to lock input context composition string\n" ); - else - { - WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); - COMPOSITIONSTRING tmp = *compstr; - UINT flags = 0; - - memset( compstr, 0, sizeof(*compstr) ); - compstr->dwSize = tmp.dwSize; - compstr->dwResultStrLen = tmp.dwCompStrLen; - compstr->dwResultStrOffset = tmp.dwCompStrOffset; - compstr->dwResultClauseLen = tmp.dwCompClauseLen; - compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; - ImmUnlockIMCC( lpIMC->hCompStr ); - - if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; - if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; - if (flags) GenerateIMEMessage( hIMC, WM_IME_COMPOSITION, wchr, flags ); - } - - ImmSetOpenStatus( hIMC, FALSE ); - bRet = TRUE; - } - break; - case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break; - case CPS_REVERT: FIXME("CPS_REVERT\n"); break; - case CPS_CANCEL: - input_context_reset_comp_str( lpIMC ); - ime_set_composition_status( hIMC, FALSE ); - bRet = TRUE; - break; - default: FIXME("Unknown\n"); break; - } - break; - default: FIXME("Unknown Message\n"); break; - } - - UnlockRealIMC(hIMC); - return bRet; -} - BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen) diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index a753536eb3f..da502c4832e 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -13,6 +13,5 @@ #IME Interface @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall NotifyIME(long long long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeProcessKey(long long long ptr)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winemac.drv/event.c | 10 ++ dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/ime.c | 154 +----------------------------- dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_main.c | 9 -- dlls/winemac.drv/unixlib.h | 1 - dlls/winemac.drv/winemac.drv.spec | 1 - 7 files changed, 14 insertions(+), 163 deletions(-)
diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 03c49b34bae..15aa5b71c55 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -313,6 +313,16 @@ BOOL query_ime_char_rect(macdrv_query* query) }
+/*********************************************************************** + * NotifyIMEStatus (X11DRV.@) + */ +void macdrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ + TRACE_(imm)( "hwnd %p, status %#x\n", hwnd, status ); + if (!status) macdrv_clear_ime_text(); +} + + /*********************************************************************** * macdrv_query_event * diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index d22532fd3b7..9c594a5fff6 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -302,6 +302,7 @@ static const struct user_driver_funcs macdrv_funcs = .pUpdateClipboard = macdrv_UpdateClipboard, .pUpdateLayeredWindow = macdrv_UpdateLayeredWindow, .pVkKeyScanEx = macdrv_VkKeyScanEx, + .pNotifyIMEStatus = macdrv_NotifyIMEStatus, .pWindowMessage = macdrv_WindowMessage, .pWindowPosChanged = macdrv_WindowPosChanged, .pWindowPosChanging = macdrv_WindowPosChanging, diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 059a5c443f3..cf38aeadec3 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -687,156 +687,6 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; }
-BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) -{ - BOOL bRet = FALSE; - LPINPUTCONTEXT lpIMC; - - TRACE("%p %li %li %li\n", hIMC, dwAction, dwIndex, dwValue); - - lpIMC = LockRealIMC(hIMC); - if (lpIMC == NULL) - return FALSE; - - switch (dwAction) - { - case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break; - case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break; - case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break; - case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break; - case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break; - case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break; - case NI_CONTEXTUPDATED: - switch (dwValue) - { - case IMC_SETCOMPOSITIONWINDOW: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break; - case IMC_SETCONVERSIONMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break; - case IMC_SETSENTENCEMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break; - case IMC_SETCANDIDATEPOS: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break; - case IMC_SETCOMPOSITIONFONT: - { - LPIMEPRIVATE myPrivate; - TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->textfont) - { - DeleteObject(myPrivate->textfont); - myPrivate->textfont = NULL; - } - myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W); - ImmUnlockIMCC(lpIMC->hPrivate); - } - break; - case IMC_SETOPENSTATUS: - { - LPIMEPRIVATE myPrivate; - TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (lpIMC->fOpen != myPrivate->bInternalState && myPrivate->bInComposition) - { - if(lpIMC->fOpen == FALSE) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - else - { - GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0); - } - } - myPrivate->bInternalState = lpIMC->fOpen; - bRet = TRUE; - } - break; - default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break; - } - break; - case NI_COMPOSITIONSTR: - switch (dwIndex) - { - case CPS_COMPLETE: - { - HIMCC newCompStr; - LPIMEPRIVATE myPrivate; - WCHAR *str; - UINT len; - - TRACE("NI_COMPOSITIONSTR: 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]; - DWORD flags = GCS_COMPSTR; - - newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, flags); - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, - GCS_RESULTSTR | GCS_RESULTCLAUSE); - - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - free( str ); - } - else if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - - - myPrivate->bInComposition = FALSE; - ImmUnlockIMCC(lpIMC->hPrivate); - - bRet = TRUE; - } - break; - case CPS_CONVERT: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break; - case CPS_REVERT: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break; - case CPS_CANCEL: - { - LPIMEPRIVATE myPrivate; - - TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n"); - - MACDRV_CALL(ime_clear, NULL); - if (lpIMC->hCompStr) - ImmDestroyIMCC(lpIMC->hCompStr); - - lpIMC->hCompStr = ImeCreateBlankCompStr(); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); - bRet = TRUE; - } - break; - default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break; - } - break; - default: FIXME("Unknown Message\n"); break; - } - - UnlockRealIMC(hIMC); - return bRet; -} - static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid) { LPINPUTCONTEXT lpIMC; @@ -898,7 +748,7 @@ static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, } else { - NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); sendMessage = FALSE; }
@@ -926,7 +776,7 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DW
static void IME_NotifyComplete(void* hIMC) { - NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); }
/* Interfaces to other parts of the Mac driver */ diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 281d49c1e9a..70e02383044 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -167,6 +167,7 @@ extern INT macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyStat LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) DECLSPEC_HIDDEN; extern UINT macdrv_GetKeyboardLayoutList(INT size, HKL *list) DECLSPEC_HIDDEN; extern INT macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size) DECLSPEC_HIDDEN; +extern void macdrv_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_param, UINT flags) DECLSPEC_HIDDEN; extern BOOL macdrv_ProcessEvents(DWORD mask) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index a4b280283ee..15330736a85 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -605,13 +605,6 @@ NTSTATUS macdrv_client_func(enum macdrv_client_funcs id, const void *params, ULO }
-static NTSTATUS macdrv_ime_clear(void *arg) -{ - macdrv_clear_ime_text(); - return 0; -} - - static NTSTATUS macdrv_ime_using_input_method(void *arg) { return macdrv_using_input_method(); @@ -633,7 +626,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_clear, macdrv_ime_process_text_input, macdrv_ime_using_input_method, macdrv_init, @@ -759,7 +751,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_clear, wow64_ime_process_text_input, macdrv_ime_using_input_method, wow64_init, diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index ca5115f4982..948da19ded1 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -26,7 +26,6 @@ enum macdrv_funcs unix_dnd_have_format, unix_dnd_release, unix_dnd_retain, - unix_ime_clear, unix_ime_process_text_input, unix_ime_using_input_method, unix_init, diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index debaec8239d..5a9403c3cf5 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -6,4 +6,3 @@ @ stdcall ImeSelect(long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall NotifyIME(long long long long)
v4: Avoid breaking a CPS_CANCEL tests, clear the composition string even if the input context is closed.
On Wed May 10 10:26:35 2023 +0000, Rémi Bernon wrote:
Fwiw on winex11 XmbResetIC is usually broken and doesn't do the right thing, and XNPreeditState also doesn't have any effect with many XIM backends. We also pass the focused HWND to them, which ends up with X11DRV_get_ic failing most of the time as it's not the top-level window. I kept the calls, but I don't think they are very useful. This could be changed later, either by dropping them entirely, or maybe by sending an artificial Escape key press to XIM through a XFilterEvent call. As far as I can see this is the only way to force some IME, like IBus, to close their composition window without generating a result.
In ibus-hangul, the ESC key works as 'reset ic' and 'conversion mode change(hangul to english)'.
I report the results of my further investigation.
UIM:
It works exactly as per the Xlib specification. XmbResetIC returns a string, no additional xic callbacks.
fcitx5, ibus-anthy: ``` preedit_draw with empty_string preedit_done ``` Raises a callback to clear the client-side preedit buffer.
ibus-hangul, ibus-mozc: ``` preedit_draw with empty_string predit_done result_string ``` Treats the return of a string as an XIC callback.
After researching the developer's webpage, it seems that this is more intentional than just a bug - the story is too complicated to tell here.
I've written a workaround patch that takes these patterns into account. However, I am investigating if there is a better solution. As I've been looking at the ibus API, I expect to see this issue in the Wine ibus ime driver in the future. In any case, I think I'll need some workaround code.
Strictly speaking:
CPS_COMPLETE, CPS_CANCEL should be actions that use or discard the XmbResetIC() return string. For example, if we type 'N-I-H-O-N-G-O', and 'reset ic' is called after the 'N', we might think it should return an empty string because the 'N' is meaningless at this point. This should be decided on the IME side, so we shouldn't use a preedit_string that has already arrived.
This is why both CPS_COMPLETE and CPS_CANCEL exist. However, due to the current XmbResetIC behavior, we are not able to proceed with this discussion.
ImmSetCandidateWindow or IMC_SETCANDIDATEPOS :
The Xlib API does not provide functions for candidate strings, the candidate window is drawn by the xim server. Therefore, it is recommended to modify the value of xic XNPreeditAttributes::XNSpotLocation.
In this case, we need X11DRV_get_ic to work well.
On Wed May 10 11:00:52 2023 +0000, Byeongsik Jeon wrote:
In ibus-hangul, the ESC key works as 'reset ic' and 'conversion mode change(hangul to english)'. I report the results of my further investigation. UIM: It works exactly as per the Xlib specification. XmbResetIC returns a string, no additional xic callbacks. fcitx5, ibus-anthy:
preedit_draw with empty_string preedit_done
Raises a callback to clear the client-side preedit buffer. ibus-hangul, ibus-mozc:
preedit_draw with empty_string predit_done result_string
Treats the return of a string as an XIC callback. After researching the developer's webpage, it seems that this is more intentional than just a bug - the story is too complicated to tell here. I've written a workaround patch that takes these patterns into account. However, I am investigating if there is a better solution. When I've been looking at the ibus API, I expect to see this issue in the Wine ibus ime driver in the future. In any case, I think we will need some workaround code. Strictly speaking: CPS_COMPLETE, CPS_CANCEL should be actions that use or discard the XmbResetIC() return string. For example, if we type 'N-I-H-O-N-G-O', and 'reset ic' is called after the 'N', we might think it should return an empty string because the 'N' is meaningless at this point. This should be decided on the IME side, so we shouldn't use a preedit_string that has already arrived. This is why both CPS_COMPLETE and CPS_CANCEL exist. However, due to the current XmbResetIC behavior, we are not able to proceed with this discussion. ImmSetCandidateWindow or IMC_SETCANDIDATEPOS : The Xlib API does not provide functions for candidate info, the candidate window is drawn by the xim server. Therefore, it is recommended to modify the value of xic XNPreeditAttributes::XNSpotLocation. In this case, we need X11DRV_get_ic to work well.
I think these are details to fix later, they are currently broken and this MR doesn't fix it but also doesn't make it worse. For better compatibility and to workaround the host IME quirks, I think it'd be better to simply implement all of this on the PE side.
Some IME like ibus-mozc don't let us hide their completion panel, which causes some duplicate display, but I don't think there's any better solution especially when using the limited XIM API.
Fwiw regarding host IME window positioning, it is in some cases possible to use XNSpotLocation, but it then opens another can of worms with several IME engines which don't support it in a consistent way.
Is it necessary to introduce the NtUserNotifyIMEStatus syscall? Also, the parameter is winex11::xim specific, so it doesn't look generic.
I haven't actually done it, so I don't know what the challenges are. How does the implementation of this pattern look like? ``` BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { struct ime_driver_notify_ime_params = { .himc = himc, .action = action, .index = index, .value = value };
status = IME_DRIVER_UNIX_CALL( notify_ime, ¶ms ); if (status == SUCCESS) return TRUE; if (status != NOT_IMPLIMENTED_YIELD_TO_DEFAULT_ACTION) return FALSE;
/* builtin ime default action */ switch (action) { ...
```
I think it's time to move the imm.c::load_graphics_driver() ?
Is it necessary to introduce the NtUserNotifyIMEStatus syscall? Also, the parameter is winex11::xim specific, so it doesn't look generic.
Although undocumented it seems appropriate for this use. I don't know what the status parameter is, but I don't think it's specific to XIM in any way and it's simply the open status. We might want to pass more information in the future, adding composition and sentence mode maybe, but for now it isn't useful.
Like @jacek said on some other previous MR, it's easier and probably better to use win32u interface instead of a custom unixlib interface.
I think it's time to move the imm.c::load_graphics_driver() ?
I don't understand what you mean, after this MR there's still some exports that need to be moved to imm32. I will get rid of it when they are all moved.
On Wed May 10 11:56:07 2023 +0000, Rémi Bernon wrote:
Is it necessary to introduce the NtUserNotifyIMEStatus syscall? Also,
the parameter is winex11::xim specific, so it doesn't look generic. Although undocumented it seems appropriate for this use. I don't know what the status parameter is, but I don't think it's specific to XIM in any way and it's simply the open status. We might want to pass more information in the future, adding composition and sentence mode maybe, but for now it isn't useful. Like @jacek said on some other previous MR, it's easier and probably better to use win32u interface instead of a custom unixlib interface.
I think it's time to move the imm.c::load_graphics_driver() ?
I don't understand what you mean, after this MR there's still some exports that need to be moved to imm32. I will get rid of it when they are all moved.
OK. I didn't realize that NtUserNotifyIMEStatus was real. I thought it was something arbitrarily created to do PE->UNIX transition. I misunderstood it to be part of the Wine ime driver interface.
Is calling ImmSetOpenStatus on CPS_COMPLETE and CPS_CANCEL also native behavior? In this MR implementation, calling NtUserNotifyIMEStatus seems to be sufficient.
Is calling ImmSetOpenStatus on CPS_COMPLETE and CPS_CANCEL also native behavior? In this MR implementation, calling NtUserNotifyIMEStatus seems to be sufficient.
I believe it is, although it may also depend on the IME implementation. As far as I could test, calling CPS_COMPLETE / CPS_CANCEL during composition triggers IMN_SETOPENSTATUS messages too.
On Wed May 10 13:13:04 2023 +0000, Rémi Bernon wrote:
Is calling ImmSetOpenStatus on CPS_COMPLETE and CPS_CANCEL also native
behavior? In this MR implementation, calling NtUserNotifyIMEStatus seems to be sufficient. I believe it is, although it may also depend on the IME implementation. As far as I could test, calling CPS_COMPLETE / CPS_CANCEL during composition triggers IMN_SETOPENSTATUS messages too.
I tested a simple test program with spy++. IMN_SETOPENSTATUS is caught in the default ime window and ui wndow, not in the application window.
What is unusual is that the value of LPARAM is not zero, but has a different value each time it occurs. Also, in my tests, wparam == IMN_SETOPENSTATUS | IMN_CHANGECANDIATE.
My guess is that it's not caused by ImmSetOpenStatus, but somewhere else.
I think these are details to fix later, they are currently broken and this MR doesn't fix it but also doesn't make it worse.
This report was not meant to say anything that needs to be resolved in this MR, it's just information. I apologize for tainting the MR.
For better compatibility and to workaround the host IME quirks, I think it'd be better to simply implement all of this on the PE side.
Yes, the current Wine built-in ime structure is going in a good direction, so as long as the PE-UNIX interface is well designed, it can easily be combined with libhangul, etc.
It doesn't even require a lot of additional code. Even if application issues arise, Wine will be in full control.