1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-09 04:16:08 +00:00

win32u: Move window input context handling from imm32.

This commit is contained in:
Jacek Caban 2022-07-08 20:09:26 +02:00 committed by Alexandre Julliard
parent 3e8a4b671d
commit f5b3283e24
11 changed files with 207 additions and 154 deletions

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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 */

View File

@ -101,6 +101,7 @@ static void * const syscalls[] =
NtGdiSwapBuffers,
NtGdiTransformPoints,
NtUserAddClipboardFormatListener,
NtUserAssociateInputContext,
NtUserAttachThreadInput,
NtUserBuildHwndList,
NtUserCallMsgFilter,

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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 );

View File

@ -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 ) \

View File

@ -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 );

View File

@ -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 );