-- v2: server: Enumerate desktop processes for rawinput messages. server: Keep a list of threads connected to each desktop. server: Send hardware input to the visible input desktop. server: Keep track of the winstation input desktop. win32u: Introduce new NtUserSwitchDesktop syscall stub. user32/tests: Run in-desktop tests from a new thread.
From: Rémi Bernon rbernon@codeweavers.com
To avoid the new process inheriting the old desktop as default. Changes the todos in the tests as it fixes the thread input not being attached, but then exposes a different todo.
This works around an issue with the way Wine implements its process default desktop when handles aren't inherited: it uses the old process desktop right away instead of using the one provided in the process startup info. --- dlls/user32/tests/input.c | 60 ++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index be95bd150b4..d0a3a9f6f55 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -428,15 +428,52 @@ static void run_in_process_( const char *file, int line, char **argv, const char CloseHandle( info.hProcess ); }
+struct run_in_desktop_params +{ + const char *file; + int line; + + HDESK desktop; + char *cmdline; + STARTUPINFOA *startup; +}; + +static DWORD WINAPI run_in_desktop_thread( void *args ) +{ + struct run_in_desktop_params *params = args; + PROCESS_INFORMATION info = {0}; + HDESK old_desktop; + DWORD ret; + + old_desktop = GetThreadDesktop( GetCurrentThreadId() ); + ok_(params->file, params->line)( old_desktop != NULL, "GetThreadDesktop error %lu\n", GetLastError() ); + ret = SetThreadDesktop( params->desktop ); + ok_(params->file, params->line)( !!ret, "SetThreadDesktop failed, error %lu\n", GetLastError() ); + + ret = CreateProcessA( NULL, params->cmdline, NULL, NULL, FALSE, 0, NULL, NULL, params->startup, &info ); + ok_(params->file, params->line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (ret) + { + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); + } + + ret = SetThreadDesktop( old_desktop ); + ok_(params->file, params->line)( !!ret, "SetThreadDesktop failed, error %lu\n", GetLastError() ); + return 0; +} + #define run_in_desktop( a, b, c ) run_in_desktop_( __FILE__, __LINE__, a, b, c ) static void run_in_desktop_( const char *file, int line, char **argv, const char *args, BOOL input ) { + struct run_in_desktop_params params = {.file = file, .line = line}; const char *desktop_name = "WineTest Desktop"; STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; - PROCESS_INFORMATION info = {0}; HDESK old_desktop, desktop; char cmdline[MAX_PATH * 2]; + HANDLE thread; DWORD ret;
old_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS ); @@ -451,13 +488,14 @@ static void run_in_desktop_( const char *file, int line, char **argv,
startup.lpDesktop = (char *)desktop_name; sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); - ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); - ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); - if (!ret) return;
- wait_child_process( info.hProcess ); - CloseHandle( info.hThread ); - CloseHandle( info.hProcess ); + params.startup = &startup; + params.cmdline = cmdline; + params.desktop = desktop; + thread = CreateThread( NULL, 0, run_in_desktop_thread, ¶ms, 0, NULL ); + ok_(file, line)( thread != NULL, "CreateThread error %lu\n", GetLastError() ); + ret = WaitForSingleObject( thread, INFINITE ); + ok_(file, line)( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu, error %lu\n", ret, GetLastError() );
if (input) { @@ -3855,19 +3893,19 @@ static void test_SendInput_mouse_messages(void) ok_ne( NULL, thread, HANDLE, "%p" );
ok_ret( 0, WaitForSingleObject( params.start_event, 5000 ) ); - todo_wine ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), TRUE ) ); + ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), TRUE ) ); ok_ret( 0, SendMessageW( params.hwnd, WM_USER, 0, 0 ) );
mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); wait_messages( 5, FALSE ); - button_down_hwnd[1].message.hwnd = hwnd; - ok_seq( button_down_hwnd ); + button_down_hwnd_todo[1].message.hwnd = hwnd; + ok_seq( button_down_hwnd_todo ); mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); wait_messages( 5, FALSE ); button_up_hwnd[1].message.hwnd = hwnd; ok_seq( button_up_hwnd );
- todo_wine ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), FALSE ) ); + ok_ret( 1, AttachThreadInput( thread_id, GetCurrentThreadId(), FALSE ) ); ok_ret( 1, SetEvent( params.end_event ) ); ok_ret( 0, WaitForSingleObject( thread, 5000 ) ); ok_ret( 1, CloseHandle( thread ) );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/user32.spec | 2 +- dlls/user32/win.c | 12 ----- dlls/win32u/main.c | 5 ++ dlls/win32u/win32syscalls.h | 98 +++++++++++++++++++------------------ dlls/win32u/win32u.spec | 2 +- dlls/win32u/winstation.c | 6 +++ dlls/wow64win/user.c | 7 +++ include/ntuser.h | 1 + 8 files changed, 71 insertions(+), 62 deletions(-)
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 042730845f1..14246b3e3e0 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -758,7 +758,7 @@ # @ stub SoftModalMessageBox @ stdcall SubtractRect(ptr ptr ptr) @ stdcall SwapMouseButton(long) -@ stdcall SwitchDesktop(long) +@ stdcall SwitchDesktop(long) NtUserSwitchDesktop @ stdcall SwitchToThisWindow(long long) # @ stub SysErrorBox @ stdcall SystemParametersInfoA(long long ptr long) diff --git a/dlls/user32/win.c b/dlls/user32/win.c index b8c04047333..f241d1371f3 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1571,18 +1571,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, WINDOWINFO *info ) return NtUserGetWindowInfo( hwnd, info ); }
-/****************************************************************************** - * SwitchDesktop (USER32.@) - * - * NOTES: Sets the current input or interactive desktop. - */ -BOOL WINAPI SwitchDesktop( HDESK hDesktop) -{ - FIXME("(hwnd %p) stub!\n", hDesktop); - return TRUE; -} - - /***************************************************************************** * UpdateLayeredWindowIndirect (USER32.@) */ diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 2dc66e5df11..2d0e41ba41c 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -2029,6 +2029,11 @@ BOOL SYSCALL_API NtUserShowWindowAsync( HWND hwnd, INT cmd ) __ASM_SYSCALL_FUNC( __id_NtUserShowWindowAsync ); }
+BOOL SYSCALL_API NtUserSwitchDesktop( HDESK handle ) +{ + __ASM_SYSCALL_FUNC( __id_NtUserSwitchDesktop ); +} + BOOL SYSCALL_API NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini ) { __ASM_SYSCALL_FUNC( __id_NtUserSystemParametersInfo ); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 543583356d9..96240a8fbdb 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -378,30 +378,31 @@ SYSCALL_ENTRY( 0x0176, NtUserShowScrollBar, 12 ) \ SYSCALL_ENTRY( 0x0177, NtUserShowWindow, 8 ) \ SYSCALL_ENTRY( 0x0178, NtUserShowWindowAsync, 8 ) \ - SYSCALL_ENTRY( 0x0179, NtUserSystemParametersInfo, 16 ) \ - SYSCALL_ENTRY( 0x017a, NtUserSystemParametersInfoForDpi, 20 ) \ - SYSCALL_ENTRY( 0x017b, NtUserThunkedMenuInfo, 8 ) \ - SYSCALL_ENTRY( 0x017c, NtUserThunkedMenuItemInfo, 24 ) \ - SYSCALL_ENTRY( 0x017d, NtUserToUnicodeEx, 28 ) \ - SYSCALL_ENTRY( 0x017e, NtUserTrackMouseEvent, 4 ) \ - SYSCALL_ENTRY( 0x017f, NtUserTrackPopupMenuEx, 24 ) \ - SYSCALL_ENTRY( 0x0180, NtUserTranslateAccelerator, 12 ) \ - SYSCALL_ENTRY( 0x0181, NtUserTranslateMessage, 8 ) \ - SYSCALL_ENTRY( 0x0182, NtUserUnhookWinEvent, 4 ) \ - SYSCALL_ENTRY( 0x0183, NtUserUnhookWindowsHookEx, 4 ) \ - SYSCALL_ENTRY( 0x0184, NtUserUnregisterClass, 12 ) \ - SYSCALL_ENTRY( 0x0185, NtUserUnregisterHotKey, 8 ) \ - SYSCALL_ENTRY( 0x0186, NtUserUpdateInputContext, 12 ) \ - SYSCALL_ENTRY( 0x0187, NtUserUpdateLayeredWindow, 40 ) \ - SYSCALL_ENTRY( 0x0188, NtUserValidateRect, 8 ) \ - SYSCALL_ENTRY( 0x0189, NtUserVkKeyScanEx, 8 ) \ - SYSCALL_ENTRY( 0x018a, NtUserWaitForInputIdle, 12 ) \ - SYSCALL_ENTRY( 0x018b, NtUserWaitMessage, 0 ) \ - SYSCALL_ENTRY( 0x018c, NtUserWindowFromDC, 4 ) \ - SYSCALL_ENTRY( 0x018d, NtUserWindowFromPoint, 8 ) \ - SYSCALL_ENTRY( 0x018e, __wine_get_file_outline_text_metric, 16 ) \ - SYSCALL_ENTRY( 0x018f, __wine_get_icm_profile, 16 ) \ - SYSCALL_ENTRY( 0x0190, __wine_send_input, 12 ) + SYSCALL_ENTRY( 0x0179, NtUserSwitchDesktop, 4 ) \ + SYSCALL_ENTRY( 0x017a, NtUserSystemParametersInfo, 16 ) \ + SYSCALL_ENTRY( 0x017b, NtUserSystemParametersInfoForDpi, 20 ) \ + SYSCALL_ENTRY( 0x017c, NtUserThunkedMenuInfo, 8 ) \ + SYSCALL_ENTRY( 0x017d, NtUserThunkedMenuItemInfo, 24 ) \ + SYSCALL_ENTRY( 0x017e, NtUserToUnicodeEx, 28 ) \ + SYSCALL_ENTRY( 0x017f, NtUserTrackMouseEvent, 4 ) \ + SYSCALL_ENTRY( 0x0180, NtUserTrackPopupMenuEx, 24 ) \ + SYSCALL_ENTRY( 0x0181, NtUserTranslateAccelerator, 12 ) \ + SYSCALL_ENTRY( 0x0182, NtUserTranslateMessage, 8 ) \ + SYSCALL_ENTRY( 0x0183, NtUserUnhookWinEvent, 4 ) \ + SYSCALL_ENTRY( 0x0184, NtUserUnhookWindowsHookEx, 4 ) \ + SYSCALL_ENTRY( 0x0185, NtUserUnregisterClass, 12 ) \ + SYSCALL_ENTRY( 0x0186, NtUserUnregisterHotKey, 8 ) \ + SYSCALL_ENTRY( 0x0187, NtUserUpdateInputContext, 12 ) \ + SYSCALL_ENTRY( 0x0188, NtUserUpdateLayeredWindow, 40 ) \ + SYSCALL_ENTRY( 0x0189, NtUserValidateRect, 8 ) \ + SYSCALL_ENTRY( 0x018a, NtUserVkKeyScanEx, 8 ) \ + SYSCALL_ENTRY( 0x018b, NtUserWaitForInputIdle, 12 ) \ + SYSCALL_ENTRY( 0x018c, NtUserWaitMessage, 0 ) \ + SYSCALL_ENTRY( 0x018d, NtUserWindowFromDC, 4 ) \ + SYSCALL_ENTRY( 0x018e, NtUserWindowFromPoint, 8 ) \ + SYSCALL_ENTRY( 0x018f, __wine_get_file_outline_text_metric, 16 ) \ + SYSCALL_ENTRY( 0x0190, __wine_get_icm_profile, 16 ) \ + SYSCALL_ENTRY( 0x0191, __wine_send_input, 12 )
#define ALL_SYSCALLS64 \ SYSCALL_ENTRY( 0x0000, NtGdiAbortDoc, 8 ) \ @@ -781,27 +782,28 @@ SYSCALL_ENTRY( 0x0176, NtUserShowScrollBar, 24 ) \ SYSCALL_ENTRY( 0x0177, NtUserShowWindow, 16 ) \ SYSCALL_ENTRY( 0x0178, NtUserShowWindowAsync, 16 ) \ - SYSCALL_ENTRY( 0x0179, NtUserSystemParametersInfo, 32 ) \ - SYSCALL_ENTRY( 0x017a, NtUserSystemParametersInfoForDpi, 40 ) \ - SYSCALL_ENTRY( 0x017b, NtUserThunkedMenuInfo, 16 ) \ - SYSCALL_ENTRY( 0x017c, NtUserThunkedMenuItemInfo, 48 ) \ - SYSCALL_ENTRY( 0x017d, NtUserToUnicodeEx, 56 ) \ - SYSCALL_ENTRY( 0x017e, NtUserTrackMouseEvent, 8 ) \ - SYSCALL_ENTRY( 0x017f, NtUserTrackPopupMenuEx, 48 ) \ - SYSCALL_ENTRY( 0x0180, NtUserTranslateAccelerator, 24 ) \ - SYSCALL_ENTRY( 0x0181, NtUserTranslateMessage, 16 ) \ - SYSCALL_ENTRY( 0x0182, NtUserUnhookWinEvent, 8 ) \ - SYSCALL_ENTRY( 0x0183, NtUserUnhookWindowsHookEx, 8 ) \ - SYSCALL_ENTRY( 0x0184, NtUserUnregisterClass, 24 ) \ - SYSCALL_ENTRY( 0x0185, NtUserUnregisterHotKey, 16 ) \ - SYSCALL_ENTRY( 0x0186, NtUserUpdateInputContext, 24 ) \ - SYSCALL_ENTRY( 0x0187, NtUserUpdateLayeredWindow, 80 ) \ - SYSCALL_ENTRY( 0x0188, NtUserValidateRect, 16 ) \ - SYSCALL_ENTRY( 0x0189, NtUserVkKeyScanEx, 16 ) \ - SYSCALL_ENTRY( 0x018a, NtUserWaitForInputIdle, 24 ) \ - SYSCALL_ENTRY( 0x018b, NtUserWaitMessage, 0 ) \ - SYSCALL_ENTRY( 0x018c, NtUserWindowFromDC, 8 ) \ - SYSCALL_ENTRY( 0x018d, NtUserWindowFromPoint, 16 ) \ - SYSCALL_ENTRY( 0x018e, __wine_get_file_outline_text_metric, 32 ) \ - SYSCALL_ENTRY( 0x018f, __wine_get_icm_profile, 32 ) \ - SYSCALL_ENTRY( 0x0190, __wine_send_input, 24 ) + SYSCALL_ENTRY( 0x0179, NtUserSwitchDesktop, 8 ) \ + SYSCALL_ENTRY( 0x017a, NtUserSystemParametersInfo, 32 ) \ + SYSCALL_ENTRY( 0x017b, NtUserSystemParametersInfoForDpi, 40 ) \ + SYSCALL_ENTRY( 0x017c, NtUserThunkedMenuInfo, 16 ) \ + SYSCALL_ENTRY( 0x017d, NtUserThunkedMenuItemInfo, 48 ) \ + SYSCALL_ENTRY( 0x017e, NtUserToUnicodeEx, 56 ) \ + SYSCALL_ENTRY( 0x017f, NtUserTrackMouseEvent, 8 ) \ + SYSCALL_ENTRY( 0x0180, NtUserTrackPopupMenuEx, 48 ) \ + SYSCALL_ENTRY( 0x0181, NtUserTranslateAccelerator, 24 ) \ + SYSCALL_ENTRY( 0x0182, NtUserTranslateMessage, 16 ) \ + SYSCALL_ENTRY( 0x0183, NtUserUnhookWinEvent, 8 ) \ + SYSCALL_ENTRY( 0x0184, NtUserUnhookWindowsHookEx, 8 ) \ + SYSCALL_ENTRY( 0x0185, NtUserUnregisterClass, 24 ) \ + SYSCALL_ENTRY( 0x0186, NtUserUnregisterHotKey, 16 ) \ + SYSCALL_ENTRY( 0x0187, NtUserUpdateInputContext, 24 ) \ + SYSCALL_ENTRY( 0x0188, NtUserUpdateLayeredWindow, 80 ) \ + SYSCALL_ENTRY( 0x0189, NtUserValidateRect, 16 ) \ + SYSCALL_ENTRY( 0x018a, NtUserVkKeyScanEx, 16 ) \ + SYSCALL_ENTRY( 0x018b, NtUserWaitForInputIdle, 24 ) \ + SYSCALL_ENTRY( 0x018c, NtUserWaitMessage, 0 ) \ + SYSCALL_ENTRY( 0x018d, NtUserWindowFromDC, 8 ) \ + SYSCALL_ENTRY( 0x018e, NtUserWindowFromPoint, 16 ) \ + SYSCALL_ENTRY( 0x018f, __wine_get_file_outline_text_metric, 32 ) \ + SYSCALL_ENTRY( 0x0190, __wine_get_icm_profile, 32 ) \ + SYSCALL_ENTRY( 0x0191, __wine_send_input, 24 ) diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 24dccb6ec1d..92c735c106c 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1270,7 +1270,7 @@ @ stub NtUserSlicerControl @ stub NtUserSoundSentry @ stub NtUserStopAndEndInertia -@ stub NtUserSwitchDesktop +@ stdcall -syscall NtUserSwitchDesktop(long) @ stdcall -syscall NtUserSystemParametersInfo(long long ptr long) @ stdcall -syscall NtUserSystemParametersInfoForDpi(long long ptr long long) @ stub NtUserTestForInteractiveUser diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b187b246941..d3c32a7fbd3 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -293,6 +293,12 @@ HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK acce return ret; }
+BOOL WINAPI NtUserSwitchDesktop( HDESK desktop ) +{ + FIXME( "desktop %p stub!\n", desktop ); + return TRUE; +} + /*********************************************************************** * NtUserGetObjectInformation (win32u.@) */ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 2dd811578f5..ff3f92c81fe 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -4472,6 +4472,13 @@ NTSTATUS WINAPI wow64_NtUserShowWindowAsync( UINT *args ) return NtUserShowWindowAsync( hwnd, cmd ); }
+NTSTATUS WINAPI wow64_NtUserSwitchDesktop( UINT *args ) +{ + HDESK handle = get_handle( &args ); + + return NtUserSwitchDesktop( handle ); +} + NTSTATUS WINAPI wow64_NtUserSystemParametersInfo( UINT *args ) { UINT action = get_ulong( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 31b93ef36e9..08bfa0ca3e2 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -783,6 +783,7 @@ W32KAPI BOOL WINAPI NtUserShowWindow( HWND hwnd, INT cmd ); W32KAPI BOOL WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd ); W32KAPI BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini ); W32KAPI BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi ); +W32KAPI BOOL WINAPI NtUserSwitchDesktop( HDESK desktop ); W32KAPI BOOL WINAPI NtUserThunkedMenuInfo( HMENU menu, const MENUINFO *info ); W32KAPI UINT WINAPI NtUserThunkedMenuItemInfo( HMENU menu, UINT pos, UINT flags, UINT method, MENUITEMINFOW *info, UNICODE_STRING *str );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/msg.c | 1 - dlls/user32/tests/winstation.c | 2 -- dlls/win32u/winstation.c | 10 ++++++- server/protocol.def | 6 +++++ server/user.h | 3 +++ server/winstation.c | 49 ++++++++++++++++++++++++++++++++-- 6 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index b699aaa6ff9..8ed608c5d3b 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -9806,7 +9806,6 @@ static DWORD WINAPI run_in_temp_desktop_thread_func(LPVOID param) curr_desktop_name, sizeof(curr_desktop_name), &length ); ok_(file, line)( result, "GetUserObjectInformationA(post_inp_desktop=%p) error %lu [rl = %lu]\n", post_inp_desktop, GetLastError(), length ); - todo_wine ok_(file, line)( strcmp( curr_desktop_name, temp_desktop_name ) == 0, "different desktop name: %s != %s (no switch or concurrent WineTest run?)\n", debugstr_a( curr_desktop_name ), debugstr_a( temp_desktop_name ) ); diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 805bf57ec6f..11ad7685e97 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -693,7 +693,6 @@ static void test_inputdesktop(void) memset(name, 0, sizeof(name)); ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); ok(ret, "GetUserObjectInformation failed!\n"); - todo_wine ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); ret = CloseDesktop(input_desk); ok(ret, "CloseDesktop failed!\n"); @@ -798,7 +797,6 @@ static void test_inputdesktop2(void) ok(hdesk != NULL, "OpenDesktop failed!\n"); SetLastError(0xdeadbeef); ret = SwitchDesktop(hdesk); - todo_wine ok(!ret, "Switch to desktop belong to non default winstation should fail!\n"); todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08lx\n", GetLastError()); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index d3c32a7fbd3..daf0d934a72 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -295,7 +295,15 @@ HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK acce
BOOL WINAPI NtUserSwitchDesktop( HDESK desktop ) { - FIXME( "desktop %p stub!\n", desktop ); + TRACE( "desktop %p\n", desktop ); + + SERVER_START_REQ( set_input_desktop ) + { + req->handle = wine_server_obj_handle( desktop ); + if (wine_server_call_err( req )) return FALSE; + } + SERVER_END_REQ; + return TRUE; }
diff --git a/server/protocol.def b/server/protocol.def index 8b51618ebe0..fa78e0487f8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2769,6 +2769,12 @@ enum coords_relative @END
+/* Changes the current input desktop */ +@REQ(set_input_desktop) + obj_handle_t handle; /* handle to the desktop */ +@END + + /* Close a desktop */ @REQ(close_desktop) obj_handle_t handle; /* handle to the desktop */ diff --git a/server/user.h b/server/user.h index 8fa55e09b0f..15bf08e1e4f 100644 --- a/server/user.h +++ b/server/user.h @@ -47,6 +47,7 @@ struct winstation unsigned int flags; /* winstation flags */ struct list entry; /* entry in global winstation list */ struct list desktops; /* list of desktops of this winstation */ + struct desktop *input_desktop; /* desktop receiving user input */ struct clipboard *clipboard; /* clipboard information */ struct atom_table *atom_table; /* global atom table */ struct namespace *desktop_names; /* namespace for desktops of this winstation */ @@ -66,6 +67,7 @@ struct desktop struct object obj; /* object header */ unsigned int flags; /* desktop flags */ struct winstation *winstation; /* winstation this desktop belongs to */ + timeout_t input_time; /* last time this desktop had the input */ struct list entry; /* entry in winstation list of desktops */ struct window *top_window; /* desktop window for this desktop */ struct window *msg_window; /* HWND_MESSAGE top window */ @@ -183,6 +185,7 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
/* windows station functions */
+extern int set_input_desktop( struct winstation *winstation, struct desktop *desktop ); extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct winstation *get_process_winstation( struct process *process, unsigned int access ); extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access ); diff --git a/server/winstation.c b/server/winstation.c index 5903497d61e..9cbccbef696 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -144,6 +144,7 @@ static struct winstation *create_winstation( struct object *root, const struct u { /* initialize it if it didn't already exist */ winstation->flags = flags; + winstation->input_desktop = NULL; winstation->clipboard = NULL; winstation->atom_table = NULL; list_add_tail( &winstation_list, &winstation->entry ); @@ -290,6 +291,7 @@ static int desktop_close_handle( struct object *obj, struct process *process, ob static void desktop_destroy( struct object *obj ) { struct desktop *desktop = (struct desktop *)obj; + struct winstation *winstation = desktop->winstation;
free_hotkeys( desktop, 0 ); if (desktop->top_window) free_window_handle( desktop->top_window ); @@ -297,7 +299,16 @@ static void desktop_destroy( struct object *obj ) if (desktop->global_hooks) release_object( desktop->global_hooks ); if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); - release_object( desktop->winstation ); + + if (desktop == winstation->input_desktop) + { + struct desktop *other, *found = NULL; + LIST_FOR_EACH_ENTRY(other, &winstation->desktops, struct desktop, entry) + if (!found || other->input_time > found->input_time) found = other; + set_input_desktop( winstation, found ); + } + + release_object( winstation ); }
/* retrieve the thread desktop, checking the handle access rights */ @@ -448,6 +459,21 @@ void release_thread_desktop( struct thread *thread, int close ) } }
+static struct desktop *get_input_desktop( struct winstation *winstation ) +{ + struct desktop *desktop; + if (!(desktop = winstation->input_desktop)) return NULL; + return (struct desktop *)grab_object( desktop ); +} + +int set_input_desktop( struct winstation *winstation, struct desktop *desktop ) +{ + if (!(winstation->flags & WSF_VISIBLE)) return 0; + winstation->input_desktop = desktop; + if (desktop) desktop->input_time = current_time; + return 1; +} + /* create a window station */ DECL_HANDLER(create_winstation) { @@ -528,6 +554,7 @@ DECL_HANDLER(create_desktop) { if ((desktop = create_desktop( &name, req->attributes, req->flags, winstation ))) { + if (!winstation->input_desktop) set_input_desktop( winstation, desktop ); reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes ); release_object( desktop ); } @@ -575,7 +602,7 @@ DECL_HANDLER(open_input_desktop) return; }
- if ((desktop = get_desktop_obj( current->process, current->process->desktop, 0 ))) + if ((desktop = get_input_desktop( winstation ))) { reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes ); release_object( desktop ); @@ -583,6 +610,24 @@ DECL_HANDLER(open_input_desktop) release_object( winstation ); }
+/* changes the current input desktop */ +DECL_HANDLER(set_input_desktop) +{ + /* FIXME: check access rights */ + struct winstation *winstation; + struct desktop *desktop; + + if (!(winstation = get_process_winstation( current->process, 0 ))) return; + + if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle, 0, &desktop_ops ))) + { + if (!set_input_desktop( winstation, desktop )) set_error( STATUS_ILLEGAL_FUNCTION ); + release_object( desktop ); + } + + release_object( winstation ); +} + /* close a desktop */ DECL_HANDLER(close_desktop) {
From: Rémi Bernon rbernon@codeweavers.com
When hwnd is specified, it is because it received a direct host input, so switch the input desktop to match the one that is receiving it.
We don't validate that the sending thread uses the same desktop as the target window: it may not even be the case for drivers with a separate thread that listens on input events. --- dlls/user32/tests/winstation.c | 6 ++---- server/queue.c | 35 ++++++++++++++++++++++------------ server/user.h | 2 ++ server/winstation.c | 10 +++++++++- 4 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 11ad7685e97..bcbb55ee918 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -652,9 +652,8 @@ static void test_inputdesktop(void) win_skip("Skip tests on NT4\n"); return; } - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %ld\n", ret); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret);
/* Set thread desktop back to the old thread desktop, SendInput should success. */ ret = SetThreadDesktop(old_thread_desk); @@ -699,9 +698,8 @@ static void test_inputdesktop(void)
SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %ld\n", ret); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret);
/* Set thread desktop to the new desktop, SendInput should success. */ ret = SetThreadDesktop(new_desk); diff --git a/server/queue.c b/server/queue.c index 6f38227aa84..49962dea264 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2764,25 +2764,37 @@ DECL_HANDLER(send_message) release_object( thread ); }
+static struct desktop *get_hardware_input_desktop( user_handle_t win ) +{ + struct desktop *desktop; + struct thread *thread; + + if (!win || !(thread = get_window_thread( win ))) + desktop = get_input_desktop( get_visible_winstation() ); + else + { + /* if window is specified, use its desktop to make it the input desktop */ + desktop = (struct desktop *)grab_object( thread->queue->input->desktop ); + release_object( thread ); + } + + return desktop; +} + /* send a hardware message to a thread queue */ DECL_HANDLER(send_hardware_message) { - struct thread *thread = NULL; struct desktop *desktop; unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = get_current_queue();
- if (!(desktop = get_thread_desktop( current, 0 ))) return; - - if (req->win) + if (!(desktop = get_hardware_input_desktop( req->win ))) return; + if ((origin == IMO_INJECTED && desktop != current->queue->input->desktop) || + !set_input_desktop( desktop->winstation, desktop )) { - if (!(thread = get_window_thread( req->win ))) return; - if (desktop != thread->queue->input->desktop) - { - /* don't allow queuing events to a different desktop */ - release_object( desktop ); - return; - } + release_object( desktop ); + set_error( STATUS_ACCESS_DENIED ); + return; }
reply->prev_x = desktop->cursor.x; @@ -2802,7 +2814,6 @@ DECL_HANDLER(send_hardware_message) default: set_error( STATUS_INVALID_PARAMETER ); } - if (thread) release_object( thread );
reply->new_x = desktop->cursor.x; reply->new_y = desktop->cursor.y; diff --git a/server/user.h b/server/user.h index 15bf08e1e4f..c3020af5586 100644 --- a/server/user.h +++ b/server/user.h @@ -185,6 +185,8 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
/* windows station functions */
+extern struct winstation *get_visible_winstation(void); +extern struct desktop *get_input_desktop( struct winstation *winsta ); extern int set_input_desktop( struct winstation *winstation, struct desktop *desktop ); extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct winstation *get_process_winstation( struct process *process, unsigned int access ); diff --git a/server/winstation.c b/server/winstation.c index 9cbccbef696..dbf6f0a9011 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -459,7 +459,15 @@ void release_thread_desktop( struct thread *thread, int close ) } }
-static struct desktop *get_input_desktop( struct winstation *winstation ) +struct winstation *get_visible_winstation(void) +{ + struct winstation *winsta; + LIST_FOR_EACH_ENTRY( winsta, &winstation_list, struct winstation, entry ) + if (winsta->flags & WSF_VISIBLE) return winsta; + return NULL; +} + +struct desktop *get_input_desktop( struct winstation *winstation ) { struct desktop *desktop; if (!(desktop = winstation->input_desktop)) return NULL;
From: Rémi Bernon rbernon@codeweavers.com
--- server/thread.h | 1 + server/user.h | 1 + server/winstation.c | 30 +++++++++++++++++------------- 3 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/server/thread.h b/server/thread.h index 8dcf966a90a..766ed78a72f 100644 --- a/server/thread.h +++ b/server/thread.h @@ -51,6 +51,7 @@ struct thread struct object obj; /* object header */ struct list entry; /* entry in system-wide thread list */ struct list proc_entry; /* entry in per-process thread list */ + struct list desktop_entry; /* entry in per-desktop thread list */ struct process *process; thread_id_t id; /* thread id */ struct list mutex_list; /* list of currently owned mutexes */ diff --git a/server/user.h b/server/user.h index c3020af5586..ae2d27a0311 100644 --- a/server/user.h +++ b/server/user.h @@ -69,6 +69,7 @@ struct desktop struct winstation *winstation; /* winstation this desktop belongs to */ timeout_t input_time; /* last time this desktop had the input */ struct list entry; /* entry in winstation list of desktops */ + struct list threads; /* list of threads connected to this desktop */ struct window *top_window; /* desktop window for this desktop */ struct window *msg_window; /* HWND_MESSAGE top window */ struct hook_table *global_hooks; /* table of global hooks on this desktop */ diff --git a/server/winstation.c b/server/winstation.c index dbf6f0a9011..06e6e8ac66e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -241,6 +241,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); + list_init( &desktop->threads ); } else { @@ -327,8 +328,10 @@ static void close_desktop_timeout( void *private ) }
/* add a user of the desktop and cancel the close timeout */ -static void add_desktop_user( struct desktop *desktop ) +static void add_desktop_thread( struct desktop *desktop, struct thread *thread ) { + list_add_tail( &desktop->threads, &thread->desktop_entry ); + if (thread->process->is_system) return; desktop->users++; if (desktop->close_timeout) { @@ -338,9 +341,13 @@ static void add_desktop_user( struct desktop *desktop ) }
/* remove a user of the desktop and start the close timeout if necessary */ -static void remove_desktop_user( struct desktop *desktop ) +static void remove_desktop_thread( struct desktop *desktop, struct thread *thread ) { struct process *process; + + list_remove( &thread->desktop_entry ); + if (thread->process->is_system) return; + assert( desktop->users > 0 ); desktop->users--;
@@ -355,7 +362,7 @@ void set_thread_default_desktop( struct thread *thread, struct desktop *desktop, if (thread->desktop) return; /* nothing to do */
thread->desktop = handle; - if (!thread->process->is_system) add_desktop_user( desktop ); + add_desktop_thread( desktop, thread ); }
/* set the process default desktop handle */ @@ -442,14 +449,11 @@ void release_thread_desktop( struct thread *thread, int close )
if (!(handle = thread->desktop)) return;
- if (!thread->process->is_system) + if (!(desktop = get_desktop_obj( thread->process, handle, 0 ))) clear_error(); /* ignore errors */ + else { - if (!(desktop = get_desktop_obj( thread->process, handle, 0 ))) clear_error(); /* ignore errors */ - else - { - remove_desktop_user( desktop ); - release_object( desktop ); - } + remove_desktop_thread( desktop, thread ); + release_object( desktop ); }
if (close) @@ -695,10 +699,10 @@ DECL_HANDLER(set_thread_desktop) else { current->desktop = req->handle; /* FIXME: should we close the old one? */ - if (!current->process->is_system && old_desktop != new_desktop) + if (old_desktop != new_desktop) { - add_desktop_user( new_desktop ); - if (old_desktop) remove_desktop_user( old_desktop ); + if (old_desktop) remove_desktop_thread( old_desktop, current ); + add_desktop_thread( new_desktop, current ); } }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dinput/tests/joystick8.c | 14 ------ server/process.h | 1 + server/queue.c | 86 ++++++++++++++++------------------- 3 files changed, 41 insertions(+), 60 deletions(-)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 788f59549c2..0e417c9540f 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -5758,23 +5758,16 @@ static DWORD WINAPI test_rawinput_desktop_thread( void *args ) rawbuffer_size = sizeof(rawbuffer); memset( rawbuffer, 0, sizeof(rawbuffer) ); res = msg_wait_for_events( 1, &rawinput_event, 100 ); - todo_wine ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); - todo_wine ok( rawinput_calls == 1, "got %u WM_INPUT messages\n", rawinput_calls );
rawinput = (RAWINPUT *)rawbuffer; - todo_wine ok( rawinput->header.dwType == RIM_TYPEHID, "got dwType %lu\n", rawinput->header.dwType ); - todo_wine ok( rawinput->header.dwSize == offsetof(RAWINPUT, data.hid.bRawData[desc.caps.InputReportByteLength * rawinput->data.hid.dwCount]), "got header.dwSize %lu\n", rawinput->header.dwSize ); - todo_wine ok( rawinput->header.hDevice != 0, "got hDevice %p\n", rawinput->header.hDevice ); ok( rawinput->header.wParam == 0, "got wParam %#Ix\n", rawinput->header.wParam ); - todo_wine ok( rawinput->data.hid.dwSizeHid == desc.caps.InputReportByteLength, "got dwSizeHid %lu\n", rawinput->data.hid.dwSizeHid ); - todo_wine ok( rawinput->data.hid.dwCount >= 1, "got dwCount %lu\n", rawinput->data.hid.dwCount );
@@ -5866,23 +5859,16 @@ static void test_rawinput_desktop( const char *path, BOOL input ) res = msg_wait_for_events( 1, &rawinput_event, 100 ); if (input) { - todo_wine ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); - todo_wine ok( rawinput_calls == 1, "got %u WM_INPUT messages\n", rawinput_calls );
rawinput = (RAWINPUT *)rawbuffer; - todo_wine ok( rawinput->header.dwType == RIM_TYPEHID, "got dwType %lu\n", rawinput->header.dwType ); - todo_wine ok( rawinput->header.dwSize == offsetof(RAWINPUT, data.hid.bRawData[desc.caps.InputReportByteLength * rawinput->data.hid.dwCount]), "got header.dwSize %lu\n", rawinput->header.dwSize ); - todo_wine ok( rawinput->header.hDevice != 0, "got hDevice %p\n", rawinput->header.hDevice ); ok( rawinput->header.wParam == 0, "got wParam %#Ix\n", rawinput->header.wParam ); - todo_wine ok( rawinput->data.hid.dwSizeHid == desc.caps.InputReportByteLength, "got dwSizeHid %lu\n", rawinput->data.hid.dwSizeHid ); - todo_wine ok( rawinput->data.hid.dwCount >= 1, "got dwCount %lu\n", rawinput->data.hid.dwCount ); } else diff --git a/server/process.h b/server/process.h index 97e0d455ece..5870f4187c3 100644 --- a/server/process.h +++ b/server/process.h @@ -60,6 +60,7 @@ struct process unsigned int is_system:1; /* is it a system process? */ unsigned int debug_children:1;/* also debug all child processes */ unsigned int is_terminating:1;/* is process terminating? */ + unsigned int desktop_enum:1; /* helper flag for desktop process enumeration */ data_size_t imagelen; /* length of image path in bytes */ WCHAR *image; /* main exe image full path */ struct job *job; /* job object associated with this process */ diff --git a/server/queue.c b/server/queue.c index 49962dea264..0fd415e6325 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1894,7 +1894,6 @@ static void rawhid_init( struct rawinput *rawinput, RAWHID *hid, const hw_input_ struct rawinput_message { struct thread *foreground; - struct desktop *desktop; struct hw_msg_source source; unsigned int time; unsigned int message; @@ -1910,12 +1909,10 @@ struct rawinput_message };
/* check if process is supposed to receive a WM_INPUT message and eventually queue it */ -static int queue_rawinput_message( struct process* process, void *arg ) +static void queue_rawinput_message( struct desktop *desktop, struct process *process, void *args ) { - const struct rawinput_message *raw_msg = arg; - const struct rawinput_device *device = NULL; - struct desktop *target_desktop = NULL, *desktop = NULL; - struct thread *target_thread = NULL, *foreground = NULL; + const struct rawinput_message *raw_msg = args; + const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct message *msg; data_size_t report_size = 0, data_size = 0; @@ -1940,26 +1937,16 @@ static int queue_rawinput_message( struct process* process, void *arg ) data_size = offsetof(RAWHID, bRawData[0]); report_size = raw_msg->data.hid.dwCount * raw_msg->data.hid.dwSizeHid; } - if (!device) return 0; - - if (raw_msg->message == WM_INPUT_DEVICE_CHANGE && !(device->flags & RIDEV_DEVNOTIFY)) return 0; - - if (raw_msg->desktop) desktop = (struct desktop *)grab_object( raw_msg->desktop ); - else if (!(desktop = get_desktop_obj( process, process->desktop, 0 ))) goto done; + if (!device) return;
- if (raw_msg->foreground) foreground = (struct thread *)grab_object( raw_msg->foreground ); - else if (!(foreground = get_foreground_thread( desktop, 0 ))) goto done; - - if (process != foreground->process) + if (raw_msg->message == WM_INPUT_DEVICE_CHANGE && !(device->flags & RIDEV_DEVNOTIFY)) return; + if (process != raw_msg->foreground->process) { - if (raw_msg->message == WM_INPUT && !(device->flags & RIDEV_INPUTSINK)) goto done; - if (!(target_thread = get_window_thread( device->target ))) goto done; - if (!(target_desktop = get_thread_desktop( target_thread, 0 ))) goto done; - if (target_desktop != desktop) goto done; + if (raw_msg->message == WM_INPUT && !(device->flags & RIDEV_INPUTSINK)) return; wparam = RIM_INPUTSINK; }
- if (!(msg = alloc_hardware_message( info, raw_msg->source, raw_msg->time, data_size + report_size ))) goto done; + if (!(msg = alloc_hardware_message( info, raw_msg->source, raw_msg->time, data_size + report_size ))) return; msg->win = device->target; msg->msg = raw_msg->message; msg->wparam = wparam; @@ -1978,13 +1965,22 @@ static int queue_rawinput_message( struct process* process, void *arg ) }
queue_hardware_message( desktop, msg, 1 ); +}
-done: - if (target_thread) release_object( target_thread ); - if (target_desktop) release_object( target_desktop ); - if (foreground) release_object( foreground ); - if (desktop) release_object( desktop ); - return 0; +static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_message *raw_msg ) +{ + struct thread *thread; + + LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + thread->process->desktop_enum = 1; + + LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + { + struct process *process = thread->process; + if (!process->desktop_enum) continue; + queue_rawinput_message( desktop, process, raw_msg ); + process->desktop_enum = 0; + } }
/* queue a hardware message for a mouse event */ @@ -1993,7 +1989,6 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons { const struct rawinput_device *device; struct hardware_msg_data *msg_data; - struct rawinput_message raw_msg; struct message *msg; struct thread *foreground; unsigned int i, time, flags; @@ -2046,9 +2041,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if ((foreground = get_foreground_thread( desktop, win ))) { - memset( &raw_msg, 0, sizeof(raw_msg) ); + struct rawinput_message raw_msg = {0}; raw_msg.foreground = foreground; - raw_msg.desktop = desktop; raw_msg.source = source; raw_msg.time = time; raw_msg.message = WM_INPUT; @@ -2056,7 +2050,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop->cursor.x, y - desktop->cursor.y, raw_msg.flags, input->mouse.data, input->mouse.info );
- enum_processes( queue_rawinput_message, &raw_msg ); + dispatch_rawinput_message( desktop, &raw_msg ); release_object( foreground ); }
@@ -2103,7 +2097,6 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c struct hw_msg_source source = { IMDT_KEYBOARD, origin }; const struct rawinput_device *device; struct hardware_msg_data *msg_data; - struct rawinput_message raw_msg; struct message *msg; struct thread *foreground; unsigned char vkey = input->kbd.vkey; @@ -2178,9 +2171,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
if ((foreground = get_foreground_thread( desktop, win ))) { - memset( &raw_msg, 0, sizeof(raw_msg) ); + struct rawinput_message raw_msg = {0}; raw_msg.foreground = foreground; - raw_msg.desktop = desktop; raw_msg.source = source; raw_msg.time = time; raw_msg.message = WM_INPUT; @@ -2188,7 +2180,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c rawkeyboard_init( &raw_msg.rawinput, &raw_msg.data.keyboard, input->kbd.scan, vkey, raw_msg.flags, message_code, input->kbd.info );
- enum_processes( queue_rawinput_message, &raw_msg ); + dispatch_rawinput_message( desktop, &raw_msg ); release_object( foreground ); }
@@ -2234,26 +2226,28 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ unsigned int origin, const hw_input_t *input ) { struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; - struct rawinput_message raw_msg; + struct thread *foreground; struct message *msg;
switch (input->hw.msg) { case WM_INPUT: case WM_INPUT_DEVICE_CHANGE: - memset( &raw_msg, 0, sizeof(raw_msg) ); - raw_msg.source = source; - raw_msg.time = get_tick_count(); - raw_msg.message = input->hw.msg; - raw_msg.hid_report = get_req_data(); if (input->hw.hid.length * input->hw.hid.count != get_req_data_size()) - { set_error( STATUS_INVALID_PARAMETER ); - return; + else if ((foreground = get_foreground_thread( desktop, win ))) + { + struct rawinput_message raw_msg = {0}; + raw_msg.foreground = foreground; + raw_msg.source = source; + raw_msg.time = get_tick_count(); + raw_msg.message = input->hw.msg; + raw_msg.hid_report = get_req_data(); + rawhid_init( &raw_msg.rawinput, &raw_msg.data.hid, input ); + + dispatch_rawinput_message( desktop, &raw_msg ); + release_object( foreground ); } - rawhid_init( &raw_msg.rawinput, &raw_msg.data.hid, input ); - - enum_processes( queue_rawinput_message, &raw_msg ); return; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=143031
Your paranoid android.
=== w8 (32 bit report) ===
dinput: joystick8.c:5604: Test failed: got dwCount 3
=== w10pro64 (32 bit report) ===
user32: input.c:4593: Test failed: 7:0: WaitForSingleObject returned 258 input.c:4537: Test failed: 7:0: expected that X highest bit is set, got 0x1 input.c:4538: Test failed: 7:0: expected that X keystate is set input.c:4538: Test failed: 7:0: expected that X keystate is set input.c:4545: Test failed: 7:0: expected that X keystate is set input.c:4545: Test failed: 7:0: expected that X keystate is set input.c:4537: Test failed: 7:1: expected that X highest bit is set, got 0 input.c:4538: Test failed: 7:1: expected that X keystate is set input.c:4538: Test failed: 7:1: expected that X keystate is set input.c:4545: Test failed: 7:1: expected that X keystate is set input.c:4545: Test failed: 7:1: expected that X keystate is set input.c:4537: Test failed: 7:2: expected that X highest bit is set, got 0x1 input.c:4538: Test failed: 7:2: expected that X keystate is set input.c:4538: Test failed: 7:2: expected that X keystate is set input.c:4545: Test failed: 7:2: expected that X keystate is set input.c:4545: Test failed: 7:2: expected that X keystate is set input.c:4537: Test failed: 7:3: expected that X highest bit is set, got 0 input.c:4538: Test failed: 7:3: expected that X keystate is set input.c:4538: Test failed: 7:3: expected that X keystate is set input.c:4545: Test failed: 7:3: expected that X keystate is set input.c:4545: Test failed: 7:3: expected that X keystate is set input.c:4537: Test failed: 8:0: expected that X highest bit is set, got 0x1 input.c:4538: Test failed: 8:0: expected that X keystate is set input.c:4538: Test failed: 8:0: expected that X keystate is set input.c:4545: Test failed: 8:0: expected that X keystate is set input.c:4545: Test failed: 8:0: expected that X keystate is set input.c:4537: Test failed: 8:1: expected that X highest bit is set, got 0 input.c:4538: Test failed: 8:1: expected that X keystate is set input.c:4538: Test failed: 8:1: expected that X keystate is set input.c:4545: Test failed: 8:1: expected that X keystate is set input.c:4545: Test failed: 8:1: expected that X keystate is set input.c:4537: Test failed: 8:2: expected that X highest bit is set, got 0x1 input.c:4538: Test failed: 8:2: expected that X keystate is set input.c:4538: Test failed: 8:2: expected that X keystate is set input.c:4545: Test failed: 8:2: expected that X keystate is set input.c:4545: Test failed: 8:2: expected that X keystate is set input.c:4537: Test failed: 8:3: expected that X highest bit is set, got 0 input.c:4538: Test failed: 8:3: expected that X keystate is set input.c:4538: Test failed: 8:3: expected that X keystate is set input.c:4545: Test failed: 8:3: expected that X keystate is set input.c:4545: Test failed: 8:3: expected that X keystate is set
=== w10pro64_zh_CN (64 bit report) ===
user32: input.c:3358: Test failed: 08040804 / 08090809: WaitForSingleObject returned 0x102 input.c:3381: Test failed: 08040804 / 08090809: got change_hkl 0000000000000000 input.c:3386: Test failed: 08040804 / 08090809: got tmp_layout 0000000008090809
v2: Remove another now succeeding todo_wine.
Windows test failure is a user32:win failure that happens randomly (https://test.winehq.org/data/8cb68e43dec6e6bb32fcdf82e03a6d4263dd2354/win21H...)
Fwiw this will also let the mouhid.sys driver send WM_POINTER* messages to the input desktop. As it's a service it has a different desktop, and will otherwise try to find a target window in its own desktop.
Right now, only rawinput messages are able to cross the desktop boundaries as we enumerate every process for them, but this is not correctly done according to tests and this MR is meant to fix that.
Also, the pointer messages are not rawinput messages -their rawinput HID reports are sent separately-, so we would have to add another process enumeration for them and I think implementing the input desktop properly is better.