From: Jacek Caban jacek@codeweavers.com
--- dlls/imm32/imm.c | 30 +++++++++++++++++------------- include/ntuser.h | 1 + 2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 42cf6a712f9..8bfa6267f16 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -123,8 +123,6 @@ struct coinit_spy } apt_flags; };
-static LONG spy_tls = TLS_OUT_OF_INDEXES; - static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
@@ -256,13 +254,18 @@ static DWORD convert_candidatelist_AtoW( return ret; }
+static struct coinit_spy *get_thread_coinit_spy(void) +{ + return NtUserGetThreadInfo()->client_imm; +} + static void imm_couninit_thread(BOOL cleanup) { struct coinit_spy *spy;
TRACE("implicit COM deinitialization\n");
- if (!(spy = TlsGetValue(spy_tls)) || (spy->apt_flags & IMM_APT_BROKEN)) + if (!(spy = get_thread_coinit_spy()) || (spy->apt_flags & IMM_APT_BROKEN)) return;
if (cleanup && spy->cookie.QuadPart) @@ -314,7 +317,11 @@ static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface) { struct coinit_spy *spy = impl_from_IInitializeSpy(iface); LONG ref = InterlockedDecrement(&spy->ref); - if (!ref) HeapFree(GetProcessHeap(), 0, spy); + if (!ref) + { + HeapFree(GetProcessHeap(), 0, spy); + NtUserGetThreadInfo()->client_imm = NULL; + } return ref; }
@@ -380,20 +387,15 @@ static void imm_coinit_thread(void)
TRACE("implicit COM initialization\n");
- if (spy_tls == TLS_OUT_OF_INDEXES) - { - DWORD tls = TlsAlloc(); - if (tls == TLS_OUT_OF_INDEXES) return; - if (InterlockedCompareExchange(&spy_tls, tls, TLS_OUT_OF_INDEXES)) TlsFree(tls); - } - if (!(spy = TlsGetValue(spy_tls))) + if (!(spy = get_thread_coinit_spy())) { if (!(spy = HeapAlloc(GetProcessHeap(), 0, sizeof(*spy)))) return; spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl; spy->ref = 1; spy->cookie.QuadPart = 0; spy->apt_flags = 0; - TlsSetValue(spy_tls, spy); + NtUserGetThreadInfo()->client_imm = spy; + }
if (spy->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN)) @@ -474,7 +476,8 @@ static void IMM_FreeThreadData(void) } LeaveCriticalSection(&threaddata_cs);
- if ((spy = TlsGetValue(spy_tls))) IInitializeSpy_Release(&spy->IInitializeSpy_iface); + if ((spy = get_thread_coinit_spy())) + IInitializeSpy_Release(&spy->IInitializeSpy_iface); }
static HMODULE load_graphics_driver(void) @@ -754,6 +757,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL); /* TODO: send WM_IME_NOTIFY */ } + SetLastError(0); return TRUE; }
diff --git a/include/ntuser.h b/include/ntuser.h index 713c7d071fc..672e3156536 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 */ + void *client_imm; /* client IMM thread info */ };
static inline struct ntuser_thread_info *NtUserGetThreadInfo(void)
From: Jacek Caban jacek@codeweavers.com
--- 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 + include/ntuser.h | 16 +++ 9 files changed, 197 insertions(+), 154 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8bfa6267f16..b9505111121 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); - - if (!IsWindow(hWnd) || (hIMC && !data)) - return NULL; - - if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) - return NULL; + TRACE("(%p, %p):\n", hwnd, imc);
- 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) - { - case 0: - ImmAssociateContext(hWnd,hIMC); - return TRUE; - case IACE_DEFAULT: + if (flags == IACE_CHILDREN) { - 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() { 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/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 );
From: Jacek Caban jacek@codeweavers.com
--- dlls/imm32/tests/imm32.c | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3f2e503b5e5..5bb51d90456 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -30,6 +30,7 @@ BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL);
static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD); +static UINT (WINAPI *pNtUserAssociateInputContext)(HWND,HIMC,ULONG); static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM); static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
@@ -303,6 +304,8 @@ static BOOL init(void) { pImmAssociateContextEx = (void*)GetProcAddress(hmod, "ImmAssociateContextEx"); pImmIsUIMessageA = (void*)GetProcAddress(hmod, "ImmIsUIMessageA"); pSendInput = (void*)GetProcAddress(huser, "SendInput"); + pNtUserAssociateInputContext = (void*)GetProcAddress(GetModuleHandleW(L"win32u.dll"), + "NtUserAssociateInputContext");
wc.cbSize = sizeof(WNDCLASSEXA); wc.style = 0; @@ -753,6 +756,81 @@ static void test_ImmAssociateContextEx(void) ImmReleaseContext(hwnd,imc); }
+/* similar to above, but using NtUserAssociateInputContext */ +static void test_NtUserAssociateInputContext(void) +{ + HIMC imc; + UINT rc; + + if (!pNtUserAssociateInputContext) + { + win_skip("NtUserAssociateInputContext not available\n"); + return; + } + + imc = ImmGetContext(hwnd); + if (imc) + { + HIMC retimc, newimc; + HWND focus; + + SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE); + SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE); + + ok(GetActiveWindow() == hwnd, "hwnd is not active\n"); + newimc = ImmCreateContext(); + ok(newimc != imc, "handles should not be the same\n"); + rc = pNtUserAssociateInputContext(NULL, NULL, 0); + ok(rc == 2, "NtUserAssociateInputContext returned %x\n", rc); + rc = pNtUserAssociateInputContext(hwnd, NULL, 0); + ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc); + rc = pNtUserAssociateInputContext(NULL, imc, 0); + ok(rc == 2, "NtUserAssociateInputContext returned %x\n", rc); + + rc = pNtUserAssociateInputContext(hwnd, imc, 0); + ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc); + retimc = ImmGetContext(hwnd); + ok(retimc == imc, "handles should be the same\n"); + ImmReleaseContext(hwnd,retimc); + + rc = pNtUserAssociateInputContext(hwnd, imc, 0); + ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc); + + rc = pNtUserAssociateInputContext(hwnd, newimc, 0); + ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc); + retimc = ImmGetContext(hwnd); + ok(retimc == newimc, "handles should be the same\n"); + ImmReleaseContext(hwnd,retimc); + + focus = CreateWindowA("button", "button", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(focus != NULL, "CreateWindow failed\n"); + SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); + SetFocus(focus); + CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE); + rc = pNtUserAssociateInputContext(hwnd, imc, 0); + ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc); + SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); + DestroyWindow(focus); + CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE); + + SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); + SetFocus(child); + CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE); + rc = pNtUserAssociateInputContext(hwnd, newimc, 0); + ok(rc == 0, "NtUserAssociateInputContext returned %x\n", rc); + SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); + SetFocus(hwnd); + CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE); + + rc = pNtUserAssociateInputContext(hwnd, NULL, IACE_DEFAULT); + ok(rc == 1, "NtUserAssociateInputContext returned %x\n", rc); + + SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE); + SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE); + } + ImmReleaseContext(hwnd,imc); +} + typedef struct _igc_threadinfo { HWND hwnd; HANDLE event; @@ -2331,6 +2409,7 @@ START_TEST(imm32) { test_ImmSetCompositionString(); test_ImmIME(); test_ImmAssociateContextEx(); + test_NtUserAssociateInputContext(); test_ImmThreads(); test_ImmIsUIMessage(); test_ImmGetContext();
From: Jacek Caban jacek@codeweavers.com
--- dlls/imm32/tests/imm32.c | 54 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5bb51d90456..a7663376eee 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2336,6 +2336,7 @@ static void test_com_initialization(void)
wnd = CreateWindowA("static", "static", WS_POPUP, 0, 0, 100, 100, 0, 0, 0, 0); ok(wnd != NULL, "CreateWindow failed\n"); + test_apttype(-1); ShowWindow(wnd, SW_SHOW); test_apttype(APTTYPE_MAINSTA); DestroyWindow(wnd); @@ -2368,15 +2369,47 @@ static DWORD WINAPI disable_ime_thread(void *arg) return 0; }
+static DWORD WINAPI check_not_disabled_ime_thread(void *arg) +{ + HWND def, hwnd; + + WaitForSingleObject(arg, INFINITE); + hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(hwnd != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + todo_wine + ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); + return 0; +} + +static DWORD WINAPI disable_ime_process(void *arg) +{ + BOOL r = ImmDisableIME(-1); + ok(r, "ImmDisableIME failed\n"); + return 0; +} + static void test_ImmDisableIME(void) { - HANDLE thread; - HWND def; + HANDLE thread, event; + DWORD tid; + HWND def, def2; BOOL r;
def = ImmGetDefaultIMEWnd(hwnd); ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n");
+ event = CreateEventW(NULL, TRUE, FALSE, FALSE); + thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + r = ImmDisableIME(tid); + todo_wine + ok(!r, "ImmDisableIME(tid) succeeded\n"); + SetEvent(event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(event); + thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); ok(thread != NULL, "CreateThread failed\n"); WaitForSingleObject(thread, INFINITE); @@ -2387,6 +2420,23 @@ static void test_ImmDisableIME(void) WaitForSingleObject(thread, INFINITE); CloseHandle(thread);
+ msg_spy_pump_msg_queue(); + thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + ok(IsWindow(def), "not a window\n"); + def2 = ImmGetDefaultIMEWnd(hwnd); + todo_wine + ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); + ok(IsWindow(def), "not a window\n"); + msg_spy_pump_msg_queue(); + todo_wine + ok(!IsWindow(def), "window is still valid\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); + r = ImmDisableIME(-1); ok(r, "ImmDisableIME(-1) failed\n"); def = ImmGetDefaultIMEWnd(hwnd);
From: Jacek Caban jacek@codeweavers.com
--- dlls/imm32/imm.c | 3 ++- dlls/imm32/tests/imm32.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b9505111121..e2febed018f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1022,7 +1022,7 @@ BOOL WINAPI ImmDisableIME(DWORD idThread) DestroyWindow(to_destroy); } } - else + else if (!idThread || idThread == GetCurrentThreadId()) { thread_data = IMM_GetThreadData(NULL, idThread); if (!thread_data) return FALSE; @@ -1033,6 +1033,7 @@ BOOL WINAPI ImmDisableIME(DWORD idThread) if (to_destroy) DestroyWindow(to_destroy); } + else return FALSE; return TRUE; }
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a7663376eee..c5409ce1708 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2377,7 +2377,6 @@ static DWORD WINAPI check_not_disabled_ime_thread(void *arg) hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); ok(hwnd != NULL, "CreateWindow failed\n"); def = ImmGetDefaultIMEWnd(hwnd); - todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); return 0; } @@ -2403,7 +2402,6 @@ static void test_ImmDisableIME(void) thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); ok(thread != NULL, "CreateThread failed\n"); r = ImmDisableIME(tid); - todo_wine ok(!r, "ImmDisableIME(tid) succeeded\n"); SetEvent(event); WaitForSingleObject(thread, INFINITE);
From: Jacek Caban jacek@codeweavers.com
--- dlls/imm32/imm.c | 219 +---------------------------------- dlls/imm32/imm32.spec | 6 +- dlls/imm32/tests/imm32.c | 2 - dlls/user32/misc.c | 4 - dlls/user32/user_main.c | 19 --- dlls/user32/user_private.h | 3 - dlls/win32u/class.c | 12 ++ dlls/win32u/gdiobj.c | 1 + dlls/win32u/imm.c | 176 ++++++++++++++++++++++++++++ dlls/win32u/input.c | 12 +- dlls/win32u/ntuser_private.h | 5 +- dlls/win32u/sysparams.c | 2 +- dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 5 + dlls/win32u/window.c | 12 +- dlls/win32u/wrappers.c | 6 + include/ntuser.h | 7 ++ 17 files changed, 228 insertions(+), 265 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e2febed018f..f70c8d398b9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -100,14 +100,6 @@ typedef struct _tagTRANSMSG { LPARAM lParam; } TRANSMSG, *LPTRANSMSG;
-typedef struct _tagIMMThreadData { - struct list entry; - DWORD threadID; - HWND hwndDefault; - BOOL disableIME; - DWORD windowRefs; -} IMMThreadData; - struct coinit_spy { IInitializeSpy IInitializeSpy_iface; @@ -123,20 +115,9 @@ struct coinit_spy };
static struct list ImmHklList = LIST_INIT(ImmHklList); -static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
static const WCHAR szImeRegFmt[] = L"System\CurrentControlSet\Control\Keyboard Layouts\%08lx";
-static CRITICAL_SECTION threaddata_cs; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &threaddata_cs, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") } -}; -static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; -static BOOL disable_ime; - static inline BOOL is_himc_ime_unicode(const InputContextData *data) { return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); @@ -412,38 +393,6 @@ static void imm_coinit_thread(void) spy->apt_flags |= IMM_APT_CREATED; }
-static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) -{ - IMMThreadData *data; - DWORD process; - - if (hwnd) - { - if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL; - if (process != GetCurrentProcessId()) return NULL; - } - else if (thread) - { - HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread); - if (!h) return NULL; - process = GetProcessIdOfThread(h); - CloseHandle(h); - if (process != GetCurrentProcessId()) return NULL; - } - else - thread = GetCurrentThreadId(); - - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) - if (data->threadID == thread) return data; - - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); - data->threadID = thread; - list_add_head(&ImmThreadDataList,&data->entry); - TRACE("Thread Data Created (%lx)\n",thread); - return data; -} - static BOOL IMM_IsDefaultContext(HIMC imc) { InputContextData *data = get_imc_data(imc); @@ -490,21 +439,6 @@ static BOOL free_input_context_data(HIMC hIMC) static void IMM_FreeThreadData(void) { struct coinit_spy *spy; - IMMThreadData *data; - - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) - { - if (data->threadID == GetCurrentThreadId()) - { - list_remove(&data->entry); - LeaveCriticalSection(&threaddata_cs); - HeapFree(GetProcessHeap(),0,data); - TRACE("Thread Data Destroyed\n"); - return; - } - } - LeaveCriticalSection(&threaddata_cs);
free_input_context_data(NtUserGetThreadInfo()->default_imc); if ((spy = get_thread_coinit_spy())) @@ -981,62 +915,6 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) return FALSE; }
-static HWND imm_detach_default_window(IMMThreadData *thread_data) -{ - HWND to_destroy; - - to_destroy = thread_data->hwndDefault; - thread_data->hwndDefault = NULL; - thread_data->windowRefs = 0; - return to_destroy; -} - -/*********************************************************************** - * ImmDisableIME (IMM32.@) - */ -BOOL WINAPI ImmDisableIME(DWORD idThread) -{ - IMMThreadData *thread_data; - HWND to_destroy; - - if (idThread == (DWORD)-1) - { - disable_ime = TRUE; - - while (1) - { - to_destroy = 0; - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(thread_data, &ImmThreadDataList, IMMThreadData, entry) - { - if (thread_data->hwndDefault) - { - to_destroy = imm_detach_default_window(thread_data); - break; - } - } - LeaveCriticalSection(&threaddata_cs); - - if (!to_destroy) - break; - DestroyWindow(to_destroy); - } - } - else if (!idThread || idThread == GetCurrentThreadId()) - { - thread_data = IMM_GetThreadData(NULL, idThread); - if (!thread_data) return FALSE; - thread_data->disableIME = TRUE; - to_destroy = imm_detach_default_window(thread_data); - LeaveCriticalSection(&threaddata_cs); - - if (to_destroy) - DestroyWindow(to_destroy); - } - else return FALSE; - return TRUE; -} - /*********************************************************************** * ImmEnumRegisterWordA (IMM32.@) */ @@ -1816,107 +1694,12 @@ BOOL WINAPI ImmGetConversionStatus( return TRUE; }
-static BOOL needs_ime_window(HWND hwnd) -{ - WCHAR classW[8]; - - if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, L"IME")) - return FALSE; - if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE; - - return TRUE; -} - -/*********************************************************************** - * __wine_register_window (IMM32.@) - */ -BOOL WINAPI __wine_register_window(HWND hwnd) -{ - HWND new = NULL; - IMMThreadData *thread_data; - TRACE("(%p)\n", hwnd); - - if (!needs_ime_window(hwnd)) - return FALSE; - - thread_data = IMM_GetThreadData(hwnd, 0); - if (!thread_data) - return FALSE; - - if (thread_data->disableIME || disable_ime) - { - TRACE("IME for this thread is disabled\n"); - LeaveCriticalSection(&threaddata_cs); - return FALSE; - } - thread_data->windowRefs++; - TRACE("windowRefs=%lu, hwndDefault=%p\n", - thread_data->windowRefs, thread_data->hwndDefault); - - /* Create default IME window */ - if (thread_data->windowRefs == 1) - { - /* Do not create the window inside of a critical section */ - LeaveCriticalSection(&threaddata_cs); - new = CreateWindowExW( 0, L"IME", L"Default IME", - WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, - 0, 0, 1, 1, 0, 0, 0, 0); - /* thread_data is in the current thread so we can assume it's still valid */ - EnterCriticalSection(&threaddata_cs); - /* See if anyone beat us */ - if (thread_data->hwndDefault == NULL) - { - thread_data->hwndDefault = new; - new = NULL; - TRACE("Default is %p\n", thread_data->hwndDefault); - } - } - - LeaveCriticalSection(&threaddata_cs); - - /* Clean up an unused new window outside of the critical section */ - if (new != NULL) - DestroyWindow(new); - return TRUE; -} - -/*********************************************************************** - * __wine_unregister_window (IMM32.@) - */ -void WINAPI __wine_unregister_window(HWND hwnd) -{ - HWND to_destroy = 0; - IMMThreadData *thread_data; - TRACE("(%p)\n", hwnd); - - thread_data = IMM_GetThreadData(hwnd, 0); - if (!thread_data) return; - - thread_data->windowRefs--; - TRACE("windowRefs=%lu, hwndDefault=%p\n", - thread_data->windowRefs, thread_data->hwndDefault); - - /* Destroy default IME window */ - if (thread_data->windowRefs == 0) - to_destroy = imm_detach_default_window(thread_data); - LeaveCriticalSection(&threaddata_cs); - - if (to_destroy) DestroyWindow( to_destroy ); -} - /*********************************************************************** * ImmGetDefaultIMEWnd (IMM32.@) */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { - HWND ret; - IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0); - if (!thread_data) - return NULL; - ret = thread_data->hwndDefault; - LeaveCriticalSection(&threaddata_cs); - TRACE("Default is %p\n",ret); - return ret; + return NtUserGetDefaultImeWindow(hWnd); }
/*********************************************************************** diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index e95731183ea..70b8aef3a95 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -9,8 +9,8 @@ @ stdcall ImmDestroyContext(long) @ stdcall ImmDestroyIMCC(long) @ stdcall ImmDestroySoftKeyboard(long) -@ stdcall ImmDisableIME(long) -@ stdcall ImmDisableIme(long) ImmDisableIME +@ stdcall ImmDisableIME(long) NtUserDisableThreadIme +@ stdcall ImmDisableIme(long) NtUserDisableThreadIme @ stdcall ImmDisableLegacyIME() @ stdcall ImmDisableTextFrameService(long) @ stdcall ImmEnumInputContext(long ptr long) @@ -115,5 +115,3 @@ ################################################################ # Wine internal extensions @ stdcall __wine_ime_wnd_proc(long long long long long) -@ stdcall __wine_register_window(long) -@ stdcall __wine_unregister_window(long) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c5409ce1708..17369ca9102 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2426,11 +2426,9 @@ static void test_ImmDisableIME(void)
ok(IsWindow(def), "not a window\n"); def2 = ImmGetDefaultIMEWnd(hwnd); - todo_wine ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); ok(IsWindow(def), "not a window\n"); msg_spy_pump_msg_queue(); - todo_wine ok(!IsWindow(def), "window is still valid\n"); def = ImmGetDefaultIMEWnd(hwnd); ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 31ec85c36eb..64a300f83ef 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -39,8 +39,6 @@ BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL);
#define IMM_INIT_MAGIC 0x19650412 static LRESULT (WINAPI *imm_ime_wnd_proc)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi); -BOOL (WINAPI *imm_register_window)(HWND) = NULL; -void (WINAPI *imm_unregister_window)(HWND) = NULL;
/* USER signal proc flags and codes */ /* See UserSignalProc for comments */ @@ -328,8 +326,6 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
/* this part is not compatible with native imm32.dll */ imm_ime_wnd_proc = (void*)GetProcAddress(imm32, "__wine_ime_wnd_proc"); - imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window"); - imm_unregister_window = (void*)GetProcAddress(imm32, "__wine_unregister_window"); if (!imm_ime_wnd_proc) FIXME("native imm32.dll not supported\n"); return TRUE; diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 26427bd2cf6..ae6a0d4c8e4 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -119,22 +119,6 @@ static void dpiaware_init(void) } }
-static void CDECL notify_ime( HWND hwnd, UINT param ) -{ - HWND ime_default = ImmGetDefaultIMEWnd( hwnd ); - if (ime_default) SendMessageW( ime_default, WM_IME_INTERNAL, param, HandleToUlong(hwnd) ); -} - -static BOOL WINAPI register_imm( HWND hwnd ) -{ - return imm_register_window( hwnd ); -} - -static void WINAPI unregister_imm( HWND hwnd ) -{ - imm_unregister_window( hwnd ); -} - static NTSTATUS try_finally( NTSTATUS (CDECL *func)( void *), void *arg, void (CALLBACK *finally_func)( BOOL )) { @@ -152,11 +136,8 @@ static const struct user_callbacks user_funcs = ImmProcessKey, ImmTranslateMessage, NtWaitForMultipleObjects, - notify_ime, post_dde_message, unpack_dde_message, - register_imm, - unregister_imm, try_finally, };
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 3be5b84b41b..e637bf01f5e 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -47,9 +47,6 @@ struct wm_char_mapping_data MSG get_msg; };
-extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; -extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN; - static inline struct user_thread_info *get_user_thread_info(void) { return (struct user_thread_info *)NtCurrentTeb()->Win32ClientInfo; diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 5af9e586e01..6a3f039bc3b 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -1007,6 +1007,18 @@ WORD get_class_word( HWND hwnd, INT offset ) return retvalue; }
+BOOL needs_ime_window( HWND hwnd ) +{ + static const WCHAR imeW[] = {'I','M','E',0}; + CLASS *class; + BOOL ret; + + if (!(class = get_class_ptr( hwnd, FALSE ))) return FALSE; + ret = !(class->style & CS_IME) && wcscmp( imeW, class->name ); + release_class_ptr( class ); + return ret; +} + static void register_builtins(void) { void *ret_ptr; diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 9aab651e551..fddaf898761 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1157,6 +1157,7 @@ static struct unix_funcs unix_funcs = NtUserDestroyCursor, NtUserDestroyMenu, NtUserDestroyWindow, + NtUserDisableThreadIme, NtUserDispatchMessage, NtUserDragDetect, NtUserDrawCaptionTemp, diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index c0fe5887ffd..94621bb2a5c 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -1,6 +1,8 @@ /* * Input Context implementation * + * Copyright 1998 Patrik Stridvall + * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart * Copyright 2022 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or @@ -22,6 +24,7 @@ #pragma makedep unix #endif
+#include <pthread.h> #include "win32u_private.h" #include "ntuser_private.h" #include "wine/debug.h" @@ -36,6 +39,18 @@ struct imc UINT_PTR client_ptr; };
+struct imm_thread_data +{ + struct list entry; + DWORD thread_id; + HWND default_hwnd; + BOOL disable_ime; + UINT window_cnt; +}; + +static struct list thread_data_list = LIST_INIT( thread_data_list ); +static pthread_mutex_t imm_mutex = PTHREAD_MUTEX_INITIALIZER; +static BOOL disable_ime;
static struct imc *get_imc_ptr( HIMC handle ) { @@ -215,3 +230,164 @@ HIMC get_window_input_context( HWND hwnd ) release_win_ptr( win ); return ret; } + +static HWND detach_default_window( struct imm_thread_data *thread_data ) +{ + HWND hwnd = thread_data->default_hwnd; + thread_data->default_hwnd = NULL; + thread_data->window_cnt = 0; + return hwnd; +} + +static struct imm_thread_data *get_imm_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->imm_thread_data) + { + struct imm_thread_data *data; + if (!(data = calloc( 1, sizeof( *data )))) return NULL; + data->thread_id = GetCurrentThreadId(); + + pthread_mutex_lock( &imm_mutex ); + list_add_tail( &thread_data_list, &data->entry ); + pthread_mutex_unlock( &imm_mutex ); + + thread_info->imm_thread_data = data; + } + return thread_info->imm_thread_data; +} + +BOOL register_imm_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data; + + TRACE( "(%p)\n", hwnd ); + + if (disable_ime || !needs_ime_window( hwnd )) + return FALSE; + + thread_data = get_imm_thread_data(); + if (!thread_data || thread_data->disable_ime) + return FALSE; + + TRACE( "window_cnt=%u, default_hwnd=%p\n", thread_data->window_cnt + 1, thread_data->default_hwnd ); + + /* Create default IME window */ + if (!thread_data->window_cnt++) + { + UNICODE_STRING class_name, name; + static const WCHAR imeW[] = {'I','M','E',0}; + static const WCHAR default_imeW[] = {'D','e','f','a','u','l','t',' ','I','M','E',0}; + + RtlInitUnicodeString( &class_name, imeW ); + RtlInitUnicodeString( &name, default_imeW ); + thread_data->default_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, &name, + WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, FALSE ); + } + + return TRUE; +} + +void unregister_imm_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data = get_user_thread_info()->imm_thread_data; + + if (!thread_data) return; + if (thread_data->default_hwnd == hwnd) + { + detach_default_window( thread_data ); + return; + } + + if (!(win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)) return; + + /* destroy default IME window */ + TRACE( "unregister IME window for %p\n", hwnd ); + if (!--thread_data->window_cnt) + { + HWND destroy_hwnd = detach_default_window( thread_data ); + if (destroy_hwnd) NtUserDestroyWindow( destroy_hwnd ); + } +} + +/*********************************************************************** + * NtUserDisableThreadIme (win32u.@) + */ +BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ) +{ + struct imm_thread_data *thread_data; + + if (thread_id == -1) + { + disable_ime = TRUE; + + pthread_mutex_lock( &imm_mutex ); + LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry ) + { + if (thread_data->thread_id == GetCurrentThreadId()) continue; + if (!thread_data->default_hwnd) continue; + NtUserMessageCall( thread_data->default_hwnd, WM_WINE_DESTROYWINDOW, 0, 0, + 0, NtUserSendNotifyMessage, FALSE ); + } + pthread_mutex_unlock( &imm_mutex ); + } + else if (!thread_id || thread_id == GetCurrentThreadId()) + { + if (!(thread_data = get_imm_thread_data())) return FALSE; + thread_data->disable_ime = TRUE; + } + else return FALSE; + + if ((thread_data = get_user_thread_info()->imm_thread_data)) + { + HWND destroy_hwnd = detach_default_window( thread_data ); + NtUserDestroyWindow( destroy_hwnd ); + } + return TRUE; +} + +HWND get_default_ime_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data; + HWND ret = 0; + + if (hwnd) + { + DWORD thread_id; + + if (!(thread_id = get_window_thread( hwnd, NULL ))) return 0; + + pthread_mutex_lock( &imm_mutex ); + LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry ) + { + if (thread_data->thread_id != thread_id) continue; + ret = thread_data->default_hwnd; + break; + } + pthread_mutex_unlock( &imm_mutex ); + } + else if ((thread_data = get_user_thread_info()->imm_thread_data)) + { + ret = thread_data->default_hwnd; + } + + TRACE( "default for %p is %p\n", hwnd, ret ); + return ret; +} + +void cleanup_imm_thread(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (thread_info->imm_thread_data) + { + pthread_mutex_lock( &imm_mutex ); + list_remove( &thread_info->imm_thread_data->entry ); + pthread_mutex_unlock( &imm_mutex ); + free( thread_info->imm_thread_data ); + thread_info->imm_thread_data = NULL; + } + + NtUserDestroyInputContext( thread_info->client_info.default_imc ); +} diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 6f0e4f45501..c41a41c605a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1551,7 +1551,7 @@ HWND get_focus(void) */ static HWND set_focus_window( HWND hwnd ) { - HWND previous = 0; + HWND previous = 0, ime_hwnd; BOOL ret;
SERVER_START_REQ( set_focus_window ) @@ -1568,7 +1568,10 @@ static HWND set_focus_window( HWND hwnd ) { send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
- if (user_callbacks) user_callbacks->notify_ime( previous, IME_INTERNAL_DEACTIVATE ); + ime_hwnd = get_default_ime_window( previous ); + if (ime_hwnd) + send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_DEACTIVATE, + HandleToUlong(previous) );
if (hwnd != get_focus()) return previous; /* changed by the message */ } @@ -1576,7 +1579,10 @@ static HWND set_focus_window( HWND hwnd ) { user_driver->pSetFocus(hwnd);
- if (user_callbacks) user_callbacks->notify_ime( hwnd, IME_INTERNAL_ACTIVATE ); + ime_hwnd = get_default_ime_window( hwnd ); + if (ime_hwnd) + send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE, + HandleToUlong(hwnd) );
if (previous) NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index ba1c0b68d17..780af425673 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -35,13 +35,10 @@ struct user_callbacks BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD); BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM); NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); - void (CDECL *notify_ime)( HWND hwnd, UINT param ); BOOL (CDECL *post_dde_message)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ); BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void **buffer, size_t size ); - BOOL (WINAPI *register_imm)( HWND hwnd ); - void (WINAPI *unregister_imm)( HWND hwnd ); NTSTATUS (CDECL *try_finally)( NTSTATUS (CDECL *func)( void *), void *arg, void (CALLBACK *finally_func)( BOOL )); }; @@ -154,6 +151,7 @@ struct user_thread_info struct received_message_info *receive_info; /* Message being currently received */ struct wm_char_mapping_data *wmchar_data; /* Data for WM_CHAR mappings */ struct user_key_state_info *key_state; /* Cache of global key state */ + struct imm_thread_data *imm_thread_data; /* IMM thread data */ HKL kbd_layout; /* Current keyboard layout */ DWORD kbd_layout_id; /* Current keyboard layout ID */ struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ @@ -273,6 +271,7 @@ WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) DECLSPEC_HIDDEN; void get_winproc_params( struct win_proc_params *params ) DECLSPEC_HIDDEN; struct dce *get_class_dce( struct tagCLASS *class ) DECLSPEC_HIDDEN; struct dce *set_class_dce( struct tagCLASS *class, struct dce *dce ) DECLSPEC_HIDDEN; +BOOL needs_ime_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void register_builtin_classes(void) DECLSPEC_HIDDEN;
/* cursoricon.c */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 69e39713102..2c1f8f4241f 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -4818,7 +4818,7 @@ static void thread_detach(void) free( thread_info->rawinput );
destroy_thread_windows(); - NtUserDestroyInputContext( thread_info->client_info.default_imc ); + cleanup_imm_thread(); NtClose( thread_info->server_queue );
exiting_thread_id = 0; diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 313361989ec..d74685ad603 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -837,7 +837,7 @@ @ stdcall NtUserDestroyWindow(long) @ stub NtUserDisableImmersiveOwner @ stub NtUserDisableProcessWindowFiltering -@ stub NtUserDisableThreadIme +@ stdcall NtUserDisableThreadIme(long) @ stub NtUserDiscardPointerFrameMessages @ stdcall NtUserDispatchMessage(ptr) @ stub NtUserDisplayConfigGetDeviceInfo diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 1f7bcb9e2e3..a0b3e8c2e9e 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -214,6 +214,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserDestroyCursor)( HCURSOR cursor, ULONG arg ); BOOL (WINAPI *pNtUserDestroyMenu)( HMENU handle ); BOOL (WINAPI *pNtUserDestroyWindow)( HWND hwnd ); + BOOL (WINAPI *pNtUserDisableThreadIme)( DWORD thread_id ); LRESULT (WINAPI *pNtUserDispatchMessage)( const MSG *msg ); BOOL (WINAPI *pNtUserDragDetect)( HWND hwnd, int x, int y ); BOOL (WINAPI *pNtUserDrawCaptionTemp)( HWND hwnd, HDC hdc, const RECT *rect, HFONT font, @@ -393,8 +394,12 @@ extern LRESULT call_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL extern BOOL unhook_windows_hook( INT id, HOOKPROC proc ) DECLSPEC_HIDDEN;
/* imm.c */ +extern void cleanup_imm_thread(void) DECLSPEC_HIDDEN; +extern HWND get_default_ime_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HIMC get_default_input_context(void) DECLSPEC_HIDDEN; extern HIMC get_window_input_context( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL register_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN;
/* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a8fca0678d0..fee1617ef10 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4680,12 +4680,7 @@ LRESULT destroy_window( HWND hwnd )
TRACE( "%p\n", hwnd );
- /* destroy default IME window */ - if (win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN) - { - TRACE("unregister IME window for %p\n", hwnd); - if (user_callbacks) user_callbacks->unregister_imm( hwnd ); - } + unregister_imm_window( hwnd );
/* free child windows */ if ((children = list_window_children( 0, hwnd, NULL, 0 ))) @@ -5262,7 +5257,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, /* create default IME window */
if (!is_desktop_window( hwnd ) && parent != get_hwnd_message_parent() && - user_callbacks && user_callbacks->register_imm( hwnd )) + register_imm_window( hwnd )) { TRACE( "register IME window for %p\n", hwnd ); win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 ); @@ -5377,6 +5372,9 @@ ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code ) case NtUserCallHwnd_DrawMenuBar: return draw_menu_bar( hwnd );
+ case NtUserCallHwnd_GetDefaultImeWindow: + return HandleToUlong( get_default_ime_window( hwnd )); + case NtUserCallHwnd_GetDpiForWindow: return get_dpi_for_window( hwnd );
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index ba6fa9ea0a0..609e893403b 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -849,6 +849,12 @@ BOOL WINAPI NtUserDestroyWindow( HWND hwnd ) return unix_funcs->pNtUserDestroyWindow( hwnd ); }
+BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ) +{ + if (!unix_funcs) return FALSE; + return unix_funcs->pNtUserDisableThreadIme( thread_id ); +} + LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ) { if (!unix_funcs) return 0; diff --git a/include/ntuser.h b/include/ntuser.h index 0528e0d90bf..281d88dfb1a 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -599,6 +599,7 @@ BOOL WINAPI NtUserDestroyCursor( HCURSOR cursor, ULONG arg ); BOOL WINAPI NtUserDestroyInputContext( HIMC handle ); BOOL WINAPI NtUserDestroyMenu( HMENU menu ); BOOL WINAPI NtUserDestroyWindow( HWND hwnd ); +BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ); LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ); BOOL WINAPI NtUserDragDetect( HWND hwnd, int x, int y ); BOOL WINAPI NtUserDrawCaptionTemp( HWND hwnd, HDC hdc, const RECT *rect, HFONT font, @@ -1055,6 +1056,7 @@ enum { NtUserCallHwnd_ArrangeIconicWindows, NtUserCallHwnd_DrawMenuBar, + NtUserCallHwnd_GetDefaultImeWindow, NtUserCallHwnd_GetDpiForWindow, NtUserCallHwnd_GetParent, NtUserCallHwnd_GetWindowContextHelpId, @@ -1083,6 +1085,11 @@ static inline DWORD NtUserGetWindowContextHelpId( HWND hwnd ) return NtUserCallHwnd( hwnd, NtUserCallHwnd_GetWindowContextHelpId ); }
+static inline HWND NtUserGetDefaultImeWindow( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserCallHwnd_GetDefaultImeWindow )); +} + static inline UINT NtUserGetDpiForWindow( HWND hwnd ) { return NtUserCallHwnd( hwnd, NtUserCallHwnd_GetDpiForWindow );
From: Jacek Caban jacek@codeweavers.com
--- dlls/user32/user_main.c | 15 +++++++++++++-- dlls/win32u/imm.c | 20 ++++++++++++++++++++ dlls/win32u/message.c | 9 ++++----- dlls/win32u/ntuser_private.h | 2 -- include/ntuser.h | 20 ++++++++++++++++++++ 5 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index ae6a0d4c8e4..f9bc4985368 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -133,8 +133,6 @@ static NTSTATUS try_finally( NTSTATUS (CDECL *func)( void *), void *arg,
static const struct user_callbacks user_funcs = { - ImmProcessKey, - ImmTranslateMessage, NtWaitForMultipleObjects, post_dde_message, unpack_dde_message, @@ -163,6 +161,17 @@ static NTSTATUS WINAPI User32DrawText( const struct draw_text_params *params, UL return DrawTextW( params->hdc, params->str, size / sizeof(WCHAR), params->rect, params->flags ); }
+static NTSTATUS WINAPI User32ImmProcessKey( const struct imm_process_key_params *params, ULONG size ) +{ + return ImmProcessKey( params->hwnd, params->hkl, params->vkey, params->key_data, 0 ); +} + +static NTSTATUS WINAPI User32ImmTranslateMessage( const struct imm_translate_message_params *params, + ULONG size ) +{ + return ImmTranslateMessage( params->hwnd, params->msg, params->wparam, params->key_data ); +} + static NTSTATUS WINAPI User32LoadImage( const struct load_image_params *params, ULONG size ) { HANDLE ret = LoadImageW( params->hinst, params->name, params->type, @@ -206,6 +215,8 @@ static const void *kernel_callback_table[NtUserCallCount] = User32DrawScrollBar, User32DrawText, User32FreeCachedClipboardData, + User32ImmProcessKey, + User32ImmTranslateMessage, User32LoadDriver, User32LoadImage, User32LoadSysMenu, diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 94621bb2a5c..5adfe3704aa 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -27,6 +27,7 @@ #include <pthread.h> #include "win32u_private.h" #include "ntuser_private.h" +#include "ddk/imm.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(imm); @@ -391,3 +392,22 @@ void cleanup_imm_thread(void)
NtUserDestroyInputContext( thread_info->client_info.default_imc ); } + +BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) +{ + struct imm_process_key_params params = + { .hwnd = hwnd, .hkl = hkl, .vkey = vkey, .key_data = key_data }; + void *ret_ptr; + ULONG ret_len; + return KeUserModeCallback( NtUserImmProcessKey, ¶ms, sizeof(params), &ret_ptr, &ret_len ); +} + +BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM key_data ) +{ + struct imm_translate_message_params params = + { .hwnd = hwnd, .msg = msg, .wparam = wparam, .key_data = key_data }; + void *ret_ptr; + ULONG ret_len; + return KeUserModeCallback( NtUserImmTranslateMessage, ¶ms, sizeof(params), + &ret_ptr, &ret_len ); +} diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 65f44783fe6..b8ea7cdce9f 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -32,6 +32,7 @@ #include "hidusage.h" #include "dbt.h" #include "dde.h" +#include "ddk/imm.h" #include "wine/server.h" #include "wine/debug.h"
@@ -1362,9 +1363,8 @@ static BOOL process_keyboard_message( MSG *msg, UINT hw_id, HWND hwnd_filter, if (remove) accept_hardware_message( hw_id ); msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt );
- if (remove && msg->message == WM_KEYDOWN && user_callbacks) - if (user_callbacks->pImmProcessKey( msg->hwnd, NtUserGetKeyboardLayout(0), - msg->wParam, msg->lParam, 0 )) + if (remove && msg->message == WM_KEYDOWN) + if (ImmProcessKey( msg->hwnd, NtUserGetKeyboardLayout(0), msg->wParam, msg->lParam, 0 )) msg->wParam = VK_PROCESSKEY;
return TRUE; @@ -2969,8 +2969,7 @@ BOOL WINAPI NtUserTranslateMessage( const MSG *msg, UINT flags ) return TRUE;
case VK_PROCESSKEY: - return user_callbacks && user_callbacks->pImmTranslateMessage( msg->hwnd, msg->message, - msg->wParam, msg->lParam ); + return ImmTranslateMessage( msg->hwnd, msg->message, msg->wParam, msg->lParam ); }
NtUserGetKeyboardState( state ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 780af425673..55f2a449be4 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -32,8 +32,6 @@ struct hardware_msg_data;
struct user_callbacks { - BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD); - BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM); NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); BOOL (CDECL *post_dde_message)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ); diff --git a/include/ntuser.h b/include/ntuser.h index 281d88dfb1a..d22799ebe01 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -37,6 +37,8 @@ enum NtUserDrawScrollBar, NtUserDrawText, NtUserFreeCachedClipboardData, + NtUserImmProcessKey, + NtUserImmTranslateMessage, NtUserLoadDriver, NtUserLoadImage, NtUserLoadSysMenu, @@ -181,6 +183,24 @@ struct free_cached_data_params HANDLE handle; };
+/* NtUserImmProcessKey params */ +struct imm_process_key_params +{ + HWND hwnd; + HKL hkl; + UINT vkey; + LPARAM key_data; +}; + +/* NtUserImmTranslateMessage params */ +struct imm_translate_message_params +{ + HWND hwnd; + UINT msg; + WPARAM wparam; + LPARAM key_data; +}; + /* NtUserLoadImage params */ struct load_image_params {
From: Jacek Caban jacek@codeweavers.com
--- dlls/user32/message.c | 14 +++++++------- dlls/user32/user_main.c | 20 ++++++++++++++++++-- dlls/user32/user_private.h | 2 +- dlls/win32u/message.c | 36 +++++++++++++++++++++++++++++++----- dlls/win32u/ntuser_private.h | 4 ---- include/ntuser.h | 30 ++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index eff0c4efbcf..f4e9b5b404e 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -477,7 +477,7 @@ BOOL post_dde_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD * Unpack a posted DDE message received from another process. */ BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, - void **buffer, size_t size ) + const void *buffer, size_t size ) { UINT_PTR uiLo, uiHi; HGLOBAL hMem = 0; @@ -491,9 +491,9 @@ BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam ULONGLONG hpack; /* hMem is being passed */ if (size != sizeof(hpack)) return FALSE; - if (!buffer || !*buffer) return FALSE; + if (!size) return FALSE; uiLo = *lparam; - memcpy( &hpack, *buffer, size ); + memcpy( &hpack, buffer, size ); hMem = unpack_ptr( hpack ); uiHi = (UINT_PTR)hMem; TRACE("recv dde-ack %Ix mem=%Ix[%Ix]\n", uiLo, uiHi, GlobalSize( hMem )); @@ -509,7 +509,7 @@ BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: - if ((!buffer || !*buffer) && message != WM_DDE_DATA) return FALSE; + if (!size && message != WM_DDE_DATA) return FALSE; uiHi = *lparam; if (size) { @@ -517,7 +517,7 @@ BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam return FALSE; if ((ptr = GlobalLock( hMem ))) { - memcpy( ptr, *buffer, size ); + memcpy( ptr, buffer, size ); GlobalUnlock( hMem ); } else @@ -533,11 +533,11 @@ BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam case WM_DDE_EXECUTE: if (size) { - if (!buffer || !*buffer) return FALSE; + if (!size) return FALSE; if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size ))) return FALSE; if ((ptr = GlobalLock( hMem ))) { - memcpy( ptr, *buffer, size ); + memcpy( ptr, buffer, size ); GlobalUnlock( hMem ); TRACE( "exec: pairing c=%08Ix s=%p\n", *lparam, hMem ); if (!dde_add_pair( (HGLOBAL)*lparam, hMem )) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index f9bc4985368..16ce5c6a854 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -134,8 +134,6 @@ static NTSTATUS try_finally( NTSTATUS (CDECL *func)( void *), void *arg, static const struct user_callbacks user_funcs = { NtWaitForMultipleObjects, - post_dde_message, - unpack_dde_message, try_finally, };
@@ -192,6 +190,12 @@ static NTSTATUS WINAPI User32FreeCachedClipboardData( const struct free_cached_d return 0; }
+static NTSTATUS WINAPI User32PostDDEMessage( const struct post_dde_message_params *params, ULONG size ) +{ + return post_dde_message( params->hwnd, params->msg, params->wparam, params->lparam, + params->dest_tid, params->type ); +} + static NTSTATUS WINAPI User32RenderSsynthesizedFormat( const struct render_synthesized_format_params *params, ULONG size ) { @@ -204,6 +208,16 @@ static BOOL WINAPI User32LoadDriver( const WCHAR *path, ULONG size ) return LoadLibraryW( path ) != NULL; }
+static NTSTATUS WINAPI User32UnpackDDEMessage( const struct unpack_dde_message_params *params, ULONG size ) +{ + struct unpack_dde_message_result *result = params->result; + result->wparam = params->wparam; + result->lparam = params->lparam; + size -= FIELD_OFFSET( struct unpack_dde_message_params, data ); + return unpack_dde_message( params->hwnd, params->message, &result->wparam, &result->lparam, + params->data, size ); +} + static const void *kernel_callback_table[NtUserCallCount] = { User32CallEnumDisplayMonitor, @@ -220,8 +234,10 @@ static const void *kernel_callback_table[NtUserCallCount] = User32LoadDriver, User32LoadImage, User32LoadSysMenu, + User32PostDDEMessage, User32RegisterBuiltinClasses, User32RenderSsynthesizedFormat, + User32UnpackDDEMessage, };
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index e637bf01f5e..2e09605cc03 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -60,7 +60,7 @@ struct tagWND; extern BOOL post_dde_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ) DECLSPEC_HIDDEN; extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, - void **buffer, size_t size ) DECLSPEC_HIDDEN; + const void *buffer, size_t size ) DECLSPEC_HIDDEN; extern void free_cached_data( UINT format, HANDLE handle ) DECLSPEC_HIDDEN; extern HANDLE render_synthesized_format( UINT format, UINT from ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b8ea7cdce9f..0045c8a54c0 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1827,9 +1827,26 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, } if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST) { - if (!user_callbacks->unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, - &info.msg.lParam, &buffer, size )) - continue; /* ignore it */ + struct unpack_dde_message_result result; + struct unpack_dde_message_params *params; + void *ret_ptr; + ULONG len; + BOOL ret; + + len = FIELD_OFFSET( struct unpack_dde_message_params, data[size] ); + if (!(params = malloc( len ))) + continue; + params->result = &result; + params->hwnd = info.msg.hwnd; + params->message = info.msg.message; + params->wparam = info.msg.wParam; + params->lparam = info.msg.lParam; + if (size) memcpy( params->data, buffer, size ); + ret = KeUserModeCallback( NtUserUnpackDDEMessage, params, len, &ret_ptr, &len ); + free( params ); + if (!ret) continue; /* ignore it */ + info.msg.wParam = result.wparam; + info.msg.lParam = result.lparam; } *msg = info.msg; msg->pt = point_phys_to_win_dpi( info.msg.hwnd, info.msg.pt ); @@ -2185,8 +2202,17 @@ static BOOL put_message_in_queue( const struct send_message_info *info, size_t * } else if (info->type == MSG_POSTED && info->msg >= WM_DDE_FIRST && info->msg <= WM_DDE_LAST) { - return user_callbacks && user_callbacks->post_dde_message( info->hwnd, info->msg, - info->wparam, info->lparam, info->dest_tid, info->type ); + struct post_dde_message_params params; + void *ret_ptr; + ULONG ret_len; + + params.hwnd = info->hwnd; + params.msg = info->msg; + params.wparam = info->wparam; + params.lparam = info->lparam; + params.dest_tid = info->dest_tid; + params.type = info->type; + return KeUserModeCallback( NtUserPostDDEMessage, ¶ms, sizeof(params), &ret_ptr, &ret_len ); }
SERVER_START_REQ( send_message ) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 55f2a449be4..9c23799c6bb 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -33,10 +33,6 @@ struct hardware_msg_data; struct user_callbacks { NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); - BOOL (CDECL *post_dde_message)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, - DWORD type ); - BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, - void **buffer, size_t size ); NTSTATUS (CDECL *try_finally)( NTSTATUS (CDECL *func)( void *), void *arg, void (CALLBACK *finally_func)( BOOL )); }; diff --git a/include/ntuser.h b/include/ntuser.h index d22799ebe01..8cd7833717f 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -42,8 +42,10 @@ enum NtUserLoadDriver, NtUserLoadImage, NtUserLoadSysMenu, + NtUserPostDDEMessage, NtUserRegisterBuiltinClasses, NtUserRenderSynthesizedFormat, + NtUserUnpackDDEMessage, /* win16 hooks */ NtUserCallFreeIcon, NtUserThunkLock, @@ -218,6 +220,17 @@ struct load_sys_menu_params BOOL mdi; };
+/* NtUserPostDDEMessage params */ +struct post_dde_message_params +{ + HWND hwnd; + UINT msg; + WPARAM wparam; + LPARAM lparam; + DWORD dest_tid; + DWORD type; +}; + /* NtUserRenderSynthesizedFormat params */ struct render_synthesized_format_params { @@ -225,6 +238,23 @@ struct render_synthesized_format_params UINT from; };
+/* NtUserUnpackDDEMessage params */ +struct unpack_dde_message_result +{ + WPARAM wparam; + LPARAM lparam; +}; + +struct unpack_dde_message_params +{ + struct unpack_dde_message_result *result; /* FIXME: Use NtCallbackReturn instead */ + HWND hwnd; + UINT message; + WPARAM wparam; + LPARAM lparam; + char data[1]; +}; + /* process DPI awareness contexts */ #define NTUSER_DPI_UNAWARE 0x00006010 #define NTUSER_DPI_SYSTEM_AWARE 0x00006011
Huw Davies (@huw) commented about dlls/imm32/imm.c:
return FALSE;
}
-/***********************************************************************
ImmCreateContext (IMM32.@)
- */
-HIMC WINAPI ImmCreateContext(void) +static InputContextData *alloc_input_context_data()
```suggestion:-0+0 static InputContextData *alloc_input_context_data(void) ```
Huw Davies (@huw) commented about dlls/win32u/win32u.spec:
@ stdcall -syscall NtUserAddClipboardFormatListener(long) @ stub NtUserAddVisualIdentifier @ stub NtUserAlterWindowStyle -@ stub NtUserAssociateInputContext +@ stdcall -syscall NtUserAssociateInputContext(long long long)
This is missing the wow64 thunks.