From f5b3283e245b34ddbd3d5dc58095c1fce9492c7b Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Fri, 8 Jul 2022 20:09:26 +0200 Subject: [PATCH] win32u: Move window input context handling from imm32. --- dlls/imm32/imm.c | 252 ++++++++++++++--------------------- dlls/win32u/imm.c | 69 ++++++++++ dlls/win32u/ntuser_private.h | 1 + dlls/win32u/syscall.c | 1 + dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 4 + dlls/win32u/window.c | 5 + dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 9 ++ include/ntuser.h | 16 +++ 11 files changed, 207 insertions(+), 154 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8bfa6267f16..f809e771cf8 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -103,7 +103,6 @@ typedef struct _tagTRANSMSG { typedef struct _tagIMMThreadData { struct list entry; DWORD threadID; - HIMC defaultContext; HWND hwndDefault; BOOL disableIME; DWORD windowRefs; @@ -126,7 +125,6 @@ struct coinit_spy static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); -static const WCHAR szwWineIMCProperty[] = L"WineImmHIMCProperty"; static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; static CRITICAL_SECTION threaddata_cs; @@ -456,6 +454,39 @@ static BOOL IMM_IsDefaultContext(HIMC imc) return data->threadDefault; } +static InputContextData *query_imc_data(HIMC handle) +{ + InputContextData *ret; + + if (!handle) return NULL; + ret = (void *)NtUserQueryInputContext(handle, NtUserInputContextClientPtr); + return ret && ret->handle == handle ? ret : NULL; +} + +static BOOL free_input_context_data(HIMC hIMC) +{ + InputContextData *data = query_imc_data(hIMC); + + if (!data) + return FALSE; + + TRACE("Destroying %p\n", hIMC); + + data->immKbd->uSelected--; + data->immKbd->pImeSelect(hIMC, FALSE); + SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd); + + ImmDestroyIMCC(data->IMC.hCompStr); + ImmDestroyIMCC(data->IMC.hCandInfo); + ImmDestroyIMCC(data->IMC.hGuideLine); + ImmDestroyIMCC(data->IMC.hPrivate); + ImmDestroyIMCC(data->IMC.hMsgBuf); + + HeapFree(GetProcessHeap(), 0, data); + + return TRUE; +} + static void IMM_FreeThreadData(void) { struct coinit_spy *spy; @@ -468,7 +499,6 @@ static void IMM_FreeThreadData(void) { list_remove(&data->entry); LeaveCriticalSection(&threaddata_cs); - IMM_DestroyContext(data->defaultContext); HeapFree(GetProcessHeap(),0,data); TRACE("Thread Data Destroyed\n"); return; @@ -476,6 +506,7 @@ static void IMM_FreeThreadData(void) } LeaveCriticalSection(&threaddata_cs); + free_input_context_data(NtUserGetThreadInfo()->default_imc); if ((spy = get_thread_coinit_spy())) IInitializeSpy_Release(&spy->IInitializeSpy_iface); } @@ -664,56 +695,6 @@ static HIMCC ImmCreateBlankCompStr(void) return rc; } -static InputContextData *get_imc_data(HIMC handle) -{ - InputContextData *ret; - - if (!handle) return NULL; - ret = (void *)NtUserQueryInputContext( handle, NtUserInputContextClientPtr ); - return ret && ret->handle == handle ? ret : NULL; -} - -static HIMC get_default_context( HWND hwnd ) -{ - HIMC ret; - IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 ); - - if (!thread_data) return 0; - - if (thread_data->defaultContext) - { - ret = thread_data->defaultContext; - LeaveCriticalSection(&threaddata_cs); - return ret; - } - - /* can't create a default context in another thread */ - if (thread_data->threadID != GetCurrentThreadId()) - { - LeaveCriticalSection(&threaddata_cs); - return 0; - } - - LeaveCriticalSection(&threaddata_cs); - - ret = ImmCreateContext(); - if (!ret) return 0; - get_imc_data(ret)->threadDefault = TRUE; - - /* thread_data is in the current thread so we can assume it's still valid */ - EnterCriticalSection(&threaddata_cs); - - if (thread_data->defaultContext) /* someone beat us */ - { - IMM_DestroyContext( ret ); - ret = thread_data->defaultContext; - } - else thread_data->defaultContext = ret; - - LeaveCriticalSection(&threaddata_cs); - return ret; -} - static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) { InputContextData *data; @@ -764,44 +745,21 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) /*********************************************************************** * ImmAssociateContext (IMM32.@) */ -HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) +HIMC WINAPI ImmAssociateContext(HWND hwnd, HIMC imc) { - InputContextData *data = get_imc_data(hIMC); - HIMC defaultContext; HIMC old; + UINT ret; - TRACE("(%p, %p):\n", hWnd, hIMC); + TRACE("(%p, %p):\n", hwnd, imc); - if (!IsWindow(hWnd) || (hIMC && !data)) - return NULL; - - if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) - return NULL; - - old = GetPropW(hWnd, szwWineIMCProperty); - defaultContext = get_default_context( hWnd ); - if (!old) - old = defaultContext; - else if (old == (HIMC)-1) - old = NULL; - - /* If already associated just return */ - if (old == hIMC) - return hIMC; - - if (!hIMC) /* Meaning disable imm for that window*/ - SetPropW(hWnd, szwWineIMCProperty, (HANDLE)-1); - else if (hIMC == defaultContext) - RemovePropW(hWnd, szwWineIMCProperty); - else - SetPropW(hWnd, szwWineIMCProperty, hIMC); - - if (GetFocus() == hWnd) + old = NtUserGetWindowInputContext(hwnd); + ret = NtUserAssociateInputContext(hwnd, imc, 0); + if (ret == AICR_FOCUS_CHANGED) { - ImmSetActiveContext(hWnd, old, FALSE); - ImmSetActiveContext(hWnd, hIMC, TRUE); + ImmSetActiveContext(hwnd, old, FALSE); + ImmSetActiveContext(hwnd, imc, TRUE); } - return old; + return ret == AICR_FAILED ? 0 : old; } @@ -818,36 +776,30 @@ static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) /*********************************************************************** * ImmAssociateContextEx (IMM32.@) */ -BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) +BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags) { - TRACE("(%p, %p, 0x%lx):\n", hWnd, hIMC, dwFlags); + HIMC old; + UINT ret; - if (!hWnd) + TRACE("(%p, %p, 0x%lx):\n", hwnd, imc, flags); + + if (!hwnd) return FALSE; - switch (dwFlags) + if (flags == IACE_CHILDREN) { - case 0: - ImmAssociateContext(hWnd,hIMC); - return TRUE; - case IACE_DEFAULT: - { - HIMC defaultContext = get_default_context( hWnd ); - if (!defaultContext) return FALSE; - ImmAssociateContext(hWnd,defaultContext); + EnumChildWindows(hwnd, _ImmAssociateContextExEnumProc, (LPARAM)imc); return TRUE; } - case IACE_IGNORENOCONTEXT: - if (GetPropW(hWnd,szwWineIMCProperty)) - ImmAssociateContext(hWnd,hIMC); - return TRUE; - case IACE_CHILDREN: - EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC); - return TRUE; - default: - FIXME("Unknown dwFlags 0x%lx\n",dwFlags); - return FALSE; + + old = NtUserGetWindowInputContext(hwnd); + ret = NtUserAssociateInputContext(hwnd, imc, flags); + if (ret == AICR_FOCUS_CHANGED) + { + ImmSetActiveContext(hwnd, old, FALSE); + ImmSetActiveContext(hwnd, imc, TRUE); } + return ret != AICR_FAILED; } /*********************************************************************** @@ -920,32 +872,21 @@ BOOL WINAPI ImmConfigureIMEW( return FALSE; } -/*********************************************************************** - * ImmCreateContext (IMM32.@) - */ -HIMC WINAPI ImmCreateContext(void) +static InputContextData *alloc_input_context_data(void) { InputContextData *new_context; LPGUIDELINE gl; LPCANDIDATEINFO ci; - HIMC handle; int i; new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData)); - if (!(handle = NtUserCreateInputContext((UINT_PTR)new_context))) - { - HeapFree(GetProcessHeap(),0,new_context); - return 0; - } - /* Load the IME */ new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0)); if (!new_context->immKbd->hIME) { TRACE("IME dll could not be loaded\n"); - NtUserDestroyInputContext(handle); HeapFree(GetProcessHeap(),0,new_context); return 0; } @@ -973,10 +914,43 @@ HIMC WINAPI ImmCreateContext(void) new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps; new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps; - if (!new_context->immKbd->pImeSelect(handle, TRUE)) + return new_context; +} + +static InputContextData* get_imc_data(HIMC handle) +{ + InputContextData *ret; + + if ((ret = query_imc_data(handle)) || !handle) return ret; + if (!(ret = alloc_input_context_data())) return NULL; + ret->threadID = NtUserQueryInputContext(handle, NtUserInputContextThreadId); + ret->handle = handle; + ret->threadDefault = TRUE; + if (!NtUserUpdateInputContext(handle, NtUserInputContextClientPtr, (UINT_PTR)ret)) + { + free_input_context_data(ret); + return NULL; + } + return ret; +} + +/*********************************************************************** + * ImmCreateContext (IMM32.@) + */ +HIMC WINAPI ImmCreateContext(void) +{ + InputContextData *new_context; + + if (!(new_context = alloc_input_context_data())) return 0; + if (!(new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context))) + { + free_input_context_data(new_context); + return 0; + } + + if (!new_context->immKbd->pImeSelect(new_context->handle, TRUE)) { TRACE("Selection of IME failed\n"); - NtUserDestroyInputContext(handle); IMM_DestroyContext(new_context); return 0; } @@ -986,31 +960,13 @@ HIMC WINAPI ImmCreateContext(void) new_context->immKbd->uSelected++; TRACE("Created context %p\n",new_context); - return new_context->handle = handle; + return new_context->handle; } static BOOL IMM_DestroyContext(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); - - TRACE("Destroying %p\n",hIMC); - - if (!data) - return FALSE; - - data->immKbd->uSelected --; - data->immKbd->pImeSelect(hIMC, FALSE); - SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd); - - ImmDestroyIMCC(data->IMC.hCompStr); - ImmDestroyIMCC(data->IMC.hCandInfo); - ImmDestroyIMCC(data->IMC.hGuideLine); - ImmDestroyIMCC(data->IMC.hPrivate); - ImmDestroyIMCC(data->IMC.hMsgBuf); - - NtUserDestroyInputContext(data->handle); - HeapFree(GetProcessHeap(),0,data); - + if (!free_input_context_data(hIMC)) return FALSE; + NtUserDestroyInputContext(hIMC); return TRUE; } @@ -1748,17 +1704,7 @@ HIMC WINAPI ImmGetContext(HWND hWnd) TRACE("%p\n", hWnd); - if (!IsWindow(hWnd)) - { - SetLastError(ERROR_INVALID_WINDOW_HANDLE); - return NULL; - } - - rc = GetPropW(hWnd,szwWineIMCProperty); - if (rc == (HIMC)-1) - rc = NULL; - else if (rc == NULL) - rc = get_default_context( hWnd ); + rc = NtUserGetWindowInputContext(hWnd); if (rc) { diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 8778ea4f514..c0fe5887ffd 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -146,3 +146,72 @@ UINT_PTR WINAPI NtUserQueryInputContext( HIMC handle, UINT attr ) release_imc_ptr( imc ); return ret; } + +/****************************************************************************** + * NtUserAssociateInputContext (win32u.@) + */ +UINT WINAPI NtUserAssociateInputContext( HWND hwnd, HIMC ctx, ULONG flags ) +{ + WND *win; + UINT ret = AICR_OK; + + TRACE( "%p %p %x\n", hwnd, ctx, flags ); + + switch (flags) + { + case 0: + case IACE_IGNORENOCONTEXT: + case IACE_DEFAULT: + break; + + default: + FIXME( "unknown flags 0x%x\n", flags ); + return AICR_FAILED; + } + + if (flags == IACE_DEFAULT) + { + if (!(ctx = get_default_input_context())) return AICR_FAILED; + } + else if (ctx) + { + if (NtUserQueryInputContext( ctx, NtUserInputContextThreadId ) != GetCurrentThreadId()) + return AICR_FAILED; + } + + if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS || win == WND_DESKTOP) + return AICR_FAILED; + + if (ctx && win->tid != GetCurrentThreadId()) ret = AICR_FAILED; + else if (flags != IACE_IGNORENOCONTEXT || win->imc) + { + if (win->imc != ctx && get_focus() == hwnd) ret = AICR_FOCUS_CHANGED; + win->imc = ctx; + } + + release_win_ptr( win ); + return ret; +} + +HIMC get_default_input_context(void) +{ + struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); + if (!thread_info->default_imc) thread_info->default_imc = NtUserCreateInputContext( 0 ); + return thread_info->default_imc; +} + +HIMC get_window_input_context( HWND hwnd ) +{ + WND *win; + HIMC ret; + + if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS || win == WND_DESKTOP) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + ret = win->imc; + release_win_ptr( win ); + return ret; +} diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 490d59afb47..ba1c0b68d17 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -105,6 +105,7 @@ typedef struct tagWND HICON hIcon; /* window's icon */ HICON hIconSmall; /* window's small icon */ HICON hIconSmall2; /* window's secondary small icon, derived from hIcon */ + HIMC imc; /* window's input context */ UINT dpi; /* window DPI */ DPI_AWARENESS dpi_awareness; /* DPI awareness */ struct window_surface *surface; /* Window surface if any */ diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 5ba65e08de0..f5508f62d16 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -101,6 +101,7 @@ static void * const syscalls[] = NtGdiSwapBuffers, NtGdiTransformPoints, NtUserAddClipboardFormatListener, + NtUserAssociateInputContext, NtUserAttachThreadInput, NtUserBuildHwndList, NtUserCallMsgFilter, diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 9580452b50f..69e39713102 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -4818,6 +4818,7 @@ static void thread_detach(void) free( thread_info->rawinput ); destroy_thread_windows(); + NtUserDestroyInputContext( thread_info->client_info.default_imc ); NtClose( thread_info->server_queue ); exiting_thread_id = 0; diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 87447e59a28..313361989ec 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -753,7 +753,7 @@ @ stdcall -syscall NtUserAddClipboardFormatListener(long) @ stub NtUserAddVisualIdentifier @ stub NtUserAlterWindowStyle -@ stub NtUserAssociateInputContext +@ stdcall -syscall NtUserAssociateInputContext(long long long) @ stdcall -syscall NtUserAttachThreadInput(long long long) @ stub NtUserAutoPromoteMouseInPointer @ stub NtUserAutoRotateScreen diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index a690acadd8b..1f7bcb9e2e3 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -392,6 +392,10 @@ extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM l extern LRESULT call_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ) DECLSPEC_HIDDEN; extern BOOL unhook_windows_hook( INT id, HOOKPROC proc ) DECLSPEC_HIDDEN; +/* imm.c */ +extern HIMC get_default_input_context(void) DECLSPEC_HIDDEN; +extern HIMC get_window_input_context( HWND hwnd ) DECLSPEC_HIDDEN; + /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; extern LONG global_key_state_counter DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index e7ccbf7a928..a8fca0678d0 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -5163,6 +5163,8 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, if (win->dwStyle & WS_SYSMENU) NtUserSetSystemMenu( hwnd, 0 ); + win->imc = get_default_input_context(); + /* call the WH_CBT hook */ release_win_ptr( win ); @@ -5387,6 +5389,9 @@ ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code ) case NtUserCallHwnd_GetWindowDpiAwarenessContext: return (ULONG_PTR)get_window_dpi_awareness_context( hwnd ); + case NtUserCallHwnd_GetWindowInputContext: + return HandleToUlong( get_window_input_context( hwnd )); + case NtUserCallHwnd_GetWindowTextLength: return get_server_window_text( hwnd, NULL, 0 ); diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 43e2bc8c838..005037d71a5 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -88,6 +88,7 @@ SYSCALL_ENTRY( NtGdiSwapBuffers ) \ SYSCALL_ENTRY( NtGdiTransformPoints ) \ SYSCALL_ENTRY( NtUserAddClipboardFormatListener ) \ + SYSCALL_ENTRY( NtUserAssociateInputContext ) \ SYSCALL_ENTRY( NtUserAttachThreadInput ) \ SYSCALL_ENTRY( NtUserBuildHwndList ) \ SYSCALL_ENTRY( NtUserCallMsgFilter ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index cd5a805bea7..386458ccf0c 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -111,6 +111,15 @@ NTSTATUS WINAPI wow64_NtUserAddClipboardFormatListener( UINT *args ) return NtUserAddClipboardFormatListener( hwnd ); } +NTSTATUS WINAPI wow64_NtUserAssociateInputContext( UINT *args ) +{ + HWND hwnd = get_handle( &args ); + HIMC ctx = get_handle( &args ); + ULONG flags = get_ulong( &args ); + + return NtUserAssociateInputContext( hwnd, ctx, flags ); +} + NTSTATUS WINAPI wow64_NtUserAttachThreadInput( UINT *args ) { DWORD from = get_ulong( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 672e3156536..0528e0d90bf 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -63,6 +63,7 @@ struct ntuser_thread_info ULONG_PTR message_extra; /* value for GetMessageExtraInfo */ HWND top_window; /* desktop window */ HWND msg_window; /* HWND_MESSAGE parent window */ + HIMC default_imc; /* default input context */ void *client_imm; /* client IMM thread info */ }; @@ -368,6 +369,14 @@ enum input_context_attr NtUserInputContextThreadId, }; +/* NtUserAssociateInputContext result */ +enum associate_input_context_result +{ + AICR_OK, + AICR_FOCUS_CHANGED, + AICR_FAILED, +}; + /* internal messages codes */ enum wine_internal_message { @@ -546,6 +555,7 @@ struct packed_MDICREATESTRUCTW HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ); BOOL WINAPI NtUserAddClipboardFormatListener( HWND hwnd ); +UINT WINAPI NtUserAssociateInputContext( HWND hwnd, HIMC ctx, ULONG flags ); BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ); HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ); NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, @@ -1049,6 +1059,7 @@ enum NtUserCallHwnd_GetParent, NtUserCallHwnd_GetWindowContextHelpId, NtUserCallHwnd_GetWindowDpiAwarenessContext, + NtUserCallHwnd_GetWindowInputContext, NtUserCallHwnd_GetWindowTextLength, NtUserCallHwnd_IsWindow, NtUserCallHwnd_IsWindowEnabled, @@ -1088,6 +1099,11 @@ static inline DPI_AWARENESS_CONTEXT NtUserGetWindowDpiAwarenessContext( HWND hwn NtUserCallHwnd_GetWindowDpiAwarenessContext ); } +static inline HIMC NtUserGetWindowInputContext( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserCallHwnd_GetWindowInputContext )); +} + static inline INT NtUserGetWindowTextLength( HWND hwnd ) { return NtUserCallHwnd( hwnd, NtUserCallHwnd_GetWindowTextLength );