From a61e9d60cea9b364d90830f134ff5dcc63b8963b Mon Sep 17 00:00:00 2001 From: GloriousEggroll Date: Tue, 21 Jan 2020 12:01:23 -0700 Subject: [PATCH] update to 5.0 pre-release --- FAudio | 2 +- dxvk | 2 +- .../bnet-beta_win10_crash_fix.patch | 157 + ...t-page-in-range-with-mincore-in-try_.patch | 52 - ...tep-after-failed-map-attempt-in-try_.patch | 26 - ...unctions-for-managing-free-area-list.patch | 260 - ...rea-list-for-virtual-memory-allocati.patch | 189 - ...y-exclude-natively-mapped-areas-from.patch | 90 - game-patches-testing/proton-prep.sh | 18 +- .../proton-rawinput.patch | 17080 +++++++++++++--- ...efault-DIPROP_BUFFERSIZE-buffer-size.patch | 187 - ...Use-an-SRW-lock-for-buffer_list_lock.patch | 166 - wine | 2 +- wine-staging | 2 +- 14 files changed, 14016 insertions(+), 4217 deletions(-) create mode 100644 game-patches-testing/game-patches/bnet-beta_win10_crash_fix.patch delete mode 100644 game-patches-testing/proton-hotfixes/0001-ntdll-Check-first-page-in-range-with-mincore-in-try_.patch delete mode 100644 game-patches-testing/proton-hotfixes/0002-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch delete mode 100644 game-patches-testing/proton-hotfixes/0003-libs-wine-Add-functions-for-managing-free-area-list.patch delete mode 100644 game-patches-testing/proton-hotfixes/0004-ntdll-Use-free-area-list-for-virtual-memory-allocati.patch delete mode 100644 game-patches-testing/proton-hotfixes/0005-ntdll-Permanently-exclude-natively-mapped-areas-from.patch delete mode 100644 game-patches-testing/wine-patches/0001-dinput-Support-default-DIPROP_BUFFERSIZE-buffer-size.patch delete mode 100644 game-patches-testing/wine-patches/0001-dsound-Use-an-SRW-lock-for-buffer_list_lock.patch diff --git a/FAudio b/FAudio index 2812317e4..df1349bd2 160000 --- a/FAudio +++ b/FAudio @@ -1 +1 @@ -Subproject commit 2812317e4ae6b03e12fa6c764f9790d2b90a2341 +Subproject commit df1349bd216a10191234c1c74315136be826c9a0 diff --git a/dxvk b/dxvk index 9e5e4c1cf..35a9934cd 160000 --- a/dxvk +++ b/dxvk @@ -1 +1 @@ -Subproject commit 9e5e4c1cfcbc0ac5e7f89adc645a63728faffdc3 +Subproject commit 35a9934cded3a20283150a8d9bdfbefce08d375f diff --git a/game-patches-testing/game-patches/bnet-beta_win10_crash_fix.patch b/game-patches-testing/game-patches/bnet-beta_win10_crash_fix.patch new file mode 100644 index 000000000..74326a710 --- /dev/null +++ b/game-patches-testing/game-patches/bnet-beta_win10_crash_fix.patch @@ -0,0 +1,157 @@ + +From: Derek Lesho +Subject: [PATCH] msctf: Always provide a context when from GetBase/Top. +Message-Id: <20200115213436.327681-1-dlesho@codeweavers.com> +Date: Wed, 15 Jan 2020 15:34:36 -0600 + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48405 +Signed-off-by: Derek Lesho +--- + dlls/msctf/documentmgr.c | 20 +++++++++++++++++--- + dlls/msctf/tests/inputprocessor.c | 26 ++++++++++++++++++++++++-- + 2 files changed, 41 insertions(+), 5 deletions(-) + +diff --git a/dlls/msctf/documentmgr.c b/dlls/msctf/documentmgr.c +index 44856db632..37d55557f5 100644 +--- a/dlls/msctf/documentmgr.c ++++ b/dlls/msctf/documentmgr.c +@@ -44,6 +44,7 @@ typedef struct tagDocumentMgr { + /* Aggregation */ + ITfCompartmentMgr *CompartmentMgr; + ++ ITfContext* initialContext; + ITfContext* contextStack[2]; /* limit of 2 contexts */ + ITfThreadMgrEventSink* ThreadMgrSink; + +@@ -87,6 +88,8 @@ static void DocumentMgr_Destructor(DocumentMgr *This) + ITfThreadMgr_Release(tm); + } + ++ if (This->initialContext) ++ ITfContext_Release(This->initialContext); + if (This->contextStack[0]) + ITfContext_Release(This->contextStack[0]); + if (This->contextStack[1]) +@@ -222,14 +225,21 @@ static HRESULT WINAPI DocumentMgr_Pop(ITfDocumentMgr *iface, DWORD dwFlags) + static HRESULT WINAPI DocumentMgr_GetTop(ITfDocumentMgr *iface, ITfContext **ppic) + { + DocumentMgr *This = impl_from_ITfDocumentMgr(iface); ++ ITfContext *tgt; ++ + TRACE("(%p)\n",This); + if (!ppic) + return E_INVALIDARG; + + if (This->contextStack[0]) +- ITfContext_AddRef(This->contextStack[0]); ++ tgt = This->contextStack[0]; ++ else ++ tgt = This->initialContext; ++ ++ if (tgt) ++ ITfContext_AddRef(tgt); + +- *ppic = This->contextStack[0]; ++ *ppic = tgt; + + return S_OK; + } +@@ -245,8 +255,10 @@ static HRESULT WINAPI DocumentMgr_GetBase(ITfDocumentMgr *iface, ITfContext **pp + + if (This->contextStack[1]) + tgt = This->contextStack[1]; +- else ++ else if (This->contextStack[0]) + tgt = This->contextStack[0]; ++ else ++ tgt = This->initialContext; + + if (tgt) + ITfContext_AddRef(tgt); +@@ -342,6 +354,7 @@ static const ITfSourceVtbl DocumentMgrSourceVtbl = + HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumentMgr **ppOut) + { + DocumentMgr *This; ++ DWORD cookie; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DocumentMgr)); + if (This == NULL) +@@ -354,6 +367,7 @@ HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink *ThreadMgrSink, ITfDocumen + list_init(&This->TransitoryExtensionSink); + + CompartmentMgr_Constructor((IUnknown*)&This->ITfDocumentMgr_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); ++ Context_Constructor(processId,NULL,&This->ITfDocumentMgr_iface, &This->initialContext, &cookie); + + *ppOut = &This->ITfDocumentMgr_iface; + TRACE("returning %p\n", *ppOut); +diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c +index 38c591ea40..52921ec7cd 100644 +--- a/dlls/msctf/tests/inputprocessor.c ++++ b/dlls/msctf/tests/inputprocessor.c +@@ -1639,10 +1639,10 @@ static HRESULT TextEditSink_Constructor(ITfTextEditSink **ppOut) + static void test_startSession(void) + { + HRESULT hr; +- DWORD cnt; ++ DWORD cnt, initial_ctx_cnt; + DWORD editCookie; + ITfDocumentMgr *dmtest; +- ITfContext *cxt,*cxt2,*cxt3,*cxtTest; ++ ITfContext *cxt,*cxt2,*cxt3,*cxtTest,*initial_ctx; + ITextStoreACP *ts = NULL; + TfClientId cid2 = 0; + ITfThreadMgrEx *tmex; +@@ -1684,6 +1684,23 @@ static void test_startSession(void) + hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm); + ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); + ++ test_OnPushContext = SINK_EXPECTED; ++ test_OnInitDocumentMgr = SINK_EXPECTED; ++ ++ /* For some reason, even when the object isn't initialized, this yields a context */ ++ hr = ITfDocumentMgr_GetBase(g_dm, &initial_ctx); ++ ok(SUCCEEDED(hr), "GetBase Failed\n"); ++ hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); ++ ok(SUCCEEDED(hr), "GetTop Failed\n"); ++ ok(cxtTest == initial_ctx, "GetTop != GetBase\n"); ++ ++ ok(initial_ctx != NULL, "Expected initial context\n"); ++ initial_ctx_cnt = check_context_refcount(initial_ctx); ++ hr = ITfContext_GetDocumentMgr(initial_ctx,&dmtest); ++ ok(hr == S_OK, "ITfContext_GetDocumentMgr failed with %x\n",hr); ++ ok(dmtest == g_dm, "Wrong documentmgr\n"); ++ ITfDocumentMgr_Release(dmtest); ++ + test_EnumDocumentMgr(g_tm,g_dm,NULL); + + hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dmtest); +@@ -1740,6 +1757,7 @@ static void test_startSession(void) + test_OnPushContext = SINK_EXPECTED; + test_ACP_AdviseSink = SINK_EXPECTED; + test_OnInitDocumentMgr = SINK_EXPECTED; ++ + hr = ITfDocumentMgr_Push(g_dm, cxt); + ok(SUCCEEDED(hr),"Push Failed\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); +@@ -1749,6 +1767,9 @@ static void test_startSession(void) + + test_EnumContexts(g_dm, cxt); + ++ /* the initial context is released with the document manager */ ++ ok(initial_ctx_cnt == check_context_refcount(initial_ctx), "Context ref count changed after documentmgr initialization\n"); ++ + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt, "Wrong context on top\n"); +@@ -1859,6 +1880,7 @@ static void test_startSession(void) + ITfContext_Release(cxt); + ITfContext_Release(cxt2); + ITfContext_Release(cxt3); ++ ITfContext_Release(initial_ctx); + ITextStoreACP_Release(ts); + } + + +-- +2.25.0 + diff --git a/game-patches-testing/proton-hotfixes/0001-ntdll-Check-first-page-in-range-with-mincore-in-try_.patch b/game-patches-testing/proton-hotfixes/0001-ntdll-Check-first-page-in-range-with-mincore-in-try_.patch deleted file mode 100644 index 8001ba530..000000000 --- a/game-patches-testing/proton-hotfixes/0001-ntdll-Check-first-page-in-range-with-mincore-in-try_.patch +++ /dev/null @@ -1,52 +0,0 @@ -From d28490dfc234c48fff16677b014d77dc605347a6 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Jan 2020 21:36:52 +0300 -Subject: [PATCH 1/5] ntdll: Check first page in range with mincore() in - try_map_free_area() before trying to map the range. - -Signed-off-by: Paul Gofman ---- - dlls/ntdll/virtual.c | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c -index 26452992ef..de11795f36 100644 ---- a/dlls/ntdll/virtual.c -+++ b/dlls/ntdll/virtual.c -@@ -591,15 +591,20 @@ static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end - static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - void *start, size_t size, int unix_prot ) - { -+ static unsigned char vec; - void *ptr; - - while (start && base <= start && (char*)start + size <= (char*)end) - { -- if ((ptr = wine_anon_mmap( start, size, unix_prot, 0 )) == start) -+ if (!mincore(start, page_size, &vec)) -+ { -+ ptr = NULL; -+ } -+ else if ((ptr = wine_anon_mmap( start, size, unix_prot, 0 )) == start) -+ { - return start; -- TRACE( "Found free area is already mapped, start %p.\n", start ); -- -- if (ptr == (void *)-1) -+ } -+ else if (ptr == (void *)-1) - { - ERR("wine_anon_mmap() error %s, start %p, size %p, unix_prot %#x.\n", - strerror(errno), start, (void *)size, unix_prot); -@@ -610,6 +615,8 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - munmap( ptr, size ); - } - -+ TRACE( "Found free area is already mapped, start %p, ptr %p.\n", start, ptr ); -+ - if ((step > 0 && (char *)end - (char *)start < step) || - (step < 0 && (char *)start - (char *)base < -step) || - step == 0) --- -2.24.1 - diff --git a/game-patches-testing/proton-hotfixes/0002-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch b/game-patches-testing/proton-hotfixes/0002-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch deleted file mode 100644 index 7278c2528..000000000 --- a/game-patches-testing/proton-hotfixes/0002-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch +++ /dev/null @@ -1,26 +0,0 @@ -From dac9f1fea44bee98f9d8c964eb9857e308649edc Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Jan 2020 21:39:23 +0300 -Subject: [PATCH 2/5] ntdll: Increase step after failed map attempt in - try_map_free_area(). - -Signed-off-by: Paul Gofman ---- - dlls/ntdll/virtual.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c -index de11795f36..50a88d283c 100644 ---- a/dlls/ntdll/virtual.c -+++ b/dlls/ntdll/virtual.c -@@ -622,6 +622,7 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - step == 0) - break; - start = (char *)start + step; -+ step *= 2; - } - - return NULL; --- -2.24.1 - diff --git a/game-patches-testing/proton-hotfixes/0003-libs-wine-Add-functions-for-managing-free-area-list.patch b/game-patches-testing/proton-hotfixes/0003-libs-wine-Add-functions-for-managing-free-area-list.patch deleted file mode 100644 index 55e451bb7..000000000 --- a/game-patches-testing/proton-hotfixes/0003-libs-wine-Add-functions-for-managing-free-area-list.patch +++ /dev/null @@ -1,260 +0,0 @@ -From d135e83bc8ca2b4e968695362816140a3a302687 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Jan 2020 21:28:57 +0300 -Subject: [PATCH 3/5] libs/wine: Add functions for managing free area list. - -Signed-off-by: Paul Gofman ---- - include/wine/library.h | 5 +++ - libs/wine/mmap.c | 75 ++++++++++++++++++++++++++++++++---------- - libs/wine/wine.map | 4 +++ - 3 files changed, 67 insertions(+), 17 deletions(-) - -diff --git a/include/wine/library.h b/include/wine/library.h -index c141d96392..3e10bb4dee 100644 ---- a/include/wine/library.h -+++ b/include/wine/library.h -@@ -89,6 +89,11 @@ extern int wine_mmap_is_in_reserved_area( void *addr, size_t size ); - extern int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, void *arg), - void *arg, int top_down ); - -+extern void wine_mmap_add_free_area( void *addr, size_t size ); -+extern void wine_mmap_remove_free_area( void *addr, size_t size, int unmap ); -+extern int wine_mmap_is_in_free_area( void *addr, size_t size ); -+extern int wine_mmap_enum_free_areas( int (*enum_func)(void *base, size_t size, void *arg), -+ void *arg, int top_down ); - #ifdef __i386__ - - /* LDT management */ -diff --git a/libs/wine/mmap.c b/libs/wine/mmap.c -index f2b5adc1d2..baa466c776 100644 ---- a/libs/wine/mmap.c -+++ b/libs/wine/mmap.c -@@ -52,7 +52,9 @@ struct reserved_area - size_t size; - }; - --static struct list reserved_areas = LIST_INIT(reserved_areas); -+static struct list reserved_areas_list = LIST_INIT(reserved_areas_list); -+static struct list free_areas_list = LIST_INIT(free_areas_list); -+ - #ifndef __APPLE__ - static const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */ - #endif -@@ -427,7 +429,7 @@ void mmap_init(void) - - reserve_malloc_space( 8 * 1024 * 1024 ); - -- if (!list_head( &reserved_areas )) -+ if (!list_head( &reserved_areas_list )) - { - /* if we don't have a preloader, try to reserve some space below 2Gb */ - reserve_area( (void *)0x00110000, (void *)0x40000000 ); -@@ -435,7 +437,7 @@ void mmap_init(void) - - /* check for a reserved area starting at the user space limit */ - /* to avoid wasting time trying to allocate it again */ -- LIST_FOR_EACH( ptr, &reserved_areas ) -+ LIST_FOR_EACH( ptr, &reserved_areas_list ) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if ((char *)area->base > user_space_limit) break; -@@ -466,7 +468,7 @@ void mmap_init(void) - - /* reserve the DOS area if not already done */ - -- ptr = list_head( &reserved_areas ); -+ ptr = list_head( &reserved_areas_list ); - if (ptr) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); -@@ -476,7 +478,7 @@ void mmap_init(void) - - #elif defined(__x86_64__) || defined(__aarch64__) - -- if (!list_head( &reserved_areas )) -+ if (!list_head( &reserved_areas_list )) - { - /* if we don't have a preloader, try to reserve the space now */ - reserve_area( (void *)0x000000010000, (void *)0x000068000000 ); -@@ -497,14 +499,14 @@ void mmap_init(void) - * Note: the reserved areas functions are not reentrant, caller is - * responsible for proper locking. - */ --void wine_mmap_add_reserved_area( void *addr, size_t size ) -+static void wine_mmap_add_area( struct list *areas, void *addr, size_t size ) - { - struct reserved_area *area; - struct list *ptr; - - if (!((char *)addr + size)) size--; /* avoid wrap-around */ - -- LIST_FOR_EACH( ptr, &reserved_areas ) -+ LIST_FOR_EACH( ptr, areas ) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if (area->base > addr) -@@ -524,7 +526,7 @@ void wine_mmap_add_reserved_area( void *addr, size_t size ) - area->size += size; - - /* try to merge with the next one too */ -- if ((ptr = list_next( &reserved_areas, ptr ))) -+ if ((ptr = list_next( areas, ptr ))) - { - struct reserved_area *next = LIST_ENTRY( ptr, struct reserved_area, entry ); - if ((char *)addr + size == (char *)next->base) -@@ -546,6 +548,15 @@ void wine_mmap_add_reserved_area( void *addr, size_t size ) - } - } - -+void wine_mmap_add_reserved_area( void *addr, size_t size ) -+{ -+ wine_mmap_add_area(&reserved_areas_list, addr, size); -+} -+ -+void wine_mmap_add_free_area( void *addr, size_t size ) -+{ -+ wine_mmap_add_area(&free_areas_list, addr, size); -+} - - /*********************************************************************** - * wine_mmap_remove_reserved_area -@@ -556,14 +567,14 @@ void wine_mmap_add_reserved_area( void *addr, size_t size ) - * Note: the reserved areas functions are not reentrant, caller is - * responsible for proper locking. - */ --void wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap ) -+static void wine_mmap_remove_area( struct list *areas, void *addr, size_t size, int unmap ) - { - struct reserved_area *area; - struct list *ptr; - - if (!((char *)addr + size)) size--; /* avoid wrap-around */ - -- ptr = list_head( &reserved_areas ); -+ ptr = list_head( areas ); - /* find the first area covering address */ - while (ptr) - { -@@ -584,7 +595,7 @@ void wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap ) - else - { - /* range contains the whole area -> remove area completely */ -- ptr = list_next( &reserved_areas, ptr ); -+ ptr = list_next( areas, ptr ); - if (unmap) munmap( area->base, area->size ); - list_remove( &area->entry ); - free( area ); -@@ -616,10 +627,19 @@ void wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap ) - } - } - } -- ptr = list_next( &reserved_areas, ptr ); -+ ptr = list_next( areas, ptr ); - } - } - -+void wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap ) -+{ -+ wine_mmap_remove_area(&reserved_areas_list, addr, size, unmap); -+} -+ -+void wine_mmap_remove_free_area( void *addr, size_t size, int unmap ) -+{ -+ wine_mmap_remove_area(&free_areas_list, addr, size, unmap); -+} - - /*********************************************************************** - * wine_mmap_is_in_reserved_area -@@ -631,12 +651,12 @@ void wine_mmap_remove_reserved_area( void *addr, size_t size, int unmap ) - * Note: the reserved areas functions are not reentrant, caller is - * responsible for proper locking. - */ --int wine_mmap_is_in_reserved_area( void *addr, size_t size ) -+static int wine_mmap_is_in_area( struct list *areas, void *addr, size_t size ) - { - struct reserved_area *area; - struct list *ptr; - -- LIST_FOR_EACH( ptr, &reserved_areas ) -+ LIST_FOR_EACH( ptr, areas ) - { - area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if (area->base > addr) break; -@@ -648,6 +668,15 @@ int wine_mmap_is_in_reserved_area( void *addr, size_t size ) - return 0; - } - -+int wine_mmap_is_in_reserved_area( void *addr, size_t size ) -+{ -+ return wine_mmap_is_in_area( &reserved_areas_list, addr, size ); -+} -+ -+int wine_mmap_is_in_free_area( void *addr, size_t size ) -+{ -+ return wine_mmap_is_in_area( &free_areas_list, addr, size ); -+} - - /*********************************************************************** - * wine_mmap_enum_reserved_areas -@@ -658,7 +687,7 @@ int wine_mmap_is_in_reserved_area( void *addr, size_t size ) - * Note: the reserved areas functions are not reentrant, caller is - * responsible for proper locking. - */ --int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, void *arg), void *arg, -+int wine_mmap_enum_areas( struct list *areas, int (*enum_func)(void *base, size_t size, void *arg), void *arg, - int top_down ) - { - int ret = 0; -@@ -666,7 +695,7 @@ int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, voi - - if (top_down) - { -- for (ptr = reserved_areas.prev; ptr != &reserved_areas; ptr = ptr->prev) -+ for (ptr = areas->prev; ptr != areas; ptr = ptr->prev) - { - struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if ((ret = enum_func( area->base, area->size, arg ))) break; -@@ -674,7 +703,7 @@ int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, voi - } - else - { -- for (ptr = reserved_areas.next; ptr != &reserved_areas; ptr = ptr->next) -+ for (ptr = areas->next; ptr != areas; ptr = ptr->next) - { - struct reserved_area *area = LIST_ENTRY( ptr, struct reserved_area, entry ); - if ((ret = enum_func( area->base, area->size, arg ))) break; -@@ -682,3 +711,15 @@ int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, voi - } - return ret; - } -+ -+int wine_mmap_enum_reserved_areas( int (*enum_func)(void *base, size_t size, void *arg), void *arg, -+ int top_down ) -+{ -+ return wine_mmap_enum_areas(&reserved_areas_list, enum_func, arg, top_down); -+} -+ -+int wine_mmap_enum_free_areas( int (*enum_func)(void *base, size_t size, void *arg), void *arg, -+ int top_down ) -+{ -+ return wine_mmap_enum_areas(&free_areas_list, enum_func, arg, top_down); -+} -diff --git a/libs/wine/wine.map b/libs/wine/wine.map -index 72ffed80c0..448ab98572 100644 ---- a/libs/wine/wine.map -+++ b/libs/wine/wine.map -@@ -112,6 +112,10 @@ WINE_1.0 - wine_mmap_enum_reserved_areas; - wine_mmap_is_in_reserved_area; - wine_mmap_remove_reserved_area; -+ wine_mmap_add_free_area; -+ wine_mmap_enum_free_areas; -+ wine_mmap_is_in_free_area; -+ wine_mmap_remove_free_area; - wine_pthread_get_functions; - wine_pthread_set_functions; - wine_set_fs; --- -2.24.1 - diff --git a/game-patches-testing/proton-hotfixes/0004-ntdll-Use-free-area-list-for-virtual-memory-allocati.patch b/game-patches-testing/proton-hotfixes/0004-ntdll-Use-free-area-list-for-virtual-memory-allocati.patch deleted file mode 100644 index a4b8d6e1d..000000000 --- a/game-patches-testing/proton-hotfixes/0004-ntdll-Use-free-area-list-for-virtual-memory-allocati.patch +++ /dev/null @@ -1,189 +0,0 @@ -From ee57eef3f4f6296a18b4224961ce6c310e06278e Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Jan 2020 21:42:21 +0300 -Subject: [PATCH 4/5] ntdll: Use free area list for virtual memory allocation. - -Signed-off-by: Paul Gofman ---- - dlls/ntdll/virtual.c | 108 +++++++++++++++++++++---------------------- - 1 file changed, 52 insertions(+), 56 deletions(-) - -diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c -index 50a88d283c..b7d8a88abb 100644 ---- a/dlls/ntdll/virtual.c -+++ b/dlls/ntdll/virtual.c -@@ -628,60 +628,6 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - return NULL; - } - -- --/*********************************************************************** -- * map_free_area -- * -- * Find a free area between views inside the specified range and map it. -- * The csVirtual section must be held by caller. -- */ --static void *map_free_area( void *base, void *end, size_t size, size_t mask, int top_down, -- int unix_prot ) --{ -- struct wine_rb_entry *first = find_view_inside_range( &base, &end, top_down ); -- ptrdiff_t step = top_down ? -(mask + 1) : (mask + 1); -- void *start; -- -- if (top_down) -- { -- start = ROUND_ADDR( (char *)end - size, mask ); -- if (start >= end || start < base) return NULL; -- -- while (first) -- { -- struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); -- if ((start = try_map_free_area( (char *)view->base + view->size, (char *)start + size, step, -- start, size, unix_prot ))) break; -- start = ROUND_ADDR( (char *)view->base - size, mask ); -- /* stop if remaining space is not large enough */ -- if (!start || start >= end || start < base) return NULL; -- first = wine_rb_prev( first ); -- } -- } -- else -- { -- start = ROUND_ADDR( (char *)base + mask, mask ); -- if (!start || start >= end || (char *)end - (char *)start < size) return NULL; -- -- while (first) -- { -- struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); -- if ((start = try_map_free_area( start, view->base, step, -- start, size, unix_prot ))) break; -- start = ROUND_ADDR( (char *)view->base + view->size + mask, mask ); -- /* stop if remaining space is not large enough */ -- if (!start || start >= end || (char *)end - (char *)start < size) return NULL; -- first = wine_rb_next( first ); -- } -- } -- -- if (!first) -- return try_map_free_area( base, end, step, start, size, unix_prot ); -- -- return start; --} -- -- - /*********************************************************************** - * find_reserved_free_area - * -@@ -896,6 +842,7 @@ static struct file_view *alloc_view(void) - */ - static void delete_view( struct file_view *view ) /* [in] View */ - { -+ wine_mmap_add_free_area(view->base, view->size); - if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size ); - set_page_vprot( view->base, view->size, 0 ); - wine_rb_remove( &views_tree, &view->entry ); -@@ -953,6 +900,7 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz - TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); - mprotect( base, size, unix_prot | PROT_EXEC ); - } -+ wine_mmap_remove_free_area(view->base, view->size, 0); - return STATUS_SUCCESS; - } - -@@ -1190,6 +1138,7 @@ struct alloc_area - int top_down; - void *limit; - void *result; -+ int unix_prot; - }; - - /*********************************************************************** -@@ -1231,6 +1180,41 @@ static int alloc_reserved_area_callback( void *start, size_t size, void *arg ) - return 0; - } - -+static int alloc_free_area_callback( void *base, size_t area_size, void *arg ) -+{ -+ struct alloc_area *alloc = arg; -+ void *end = (char *)base + area_size; -+ size_t size = alloc->size; -+ ptrdiff_t step = alloc->top_down ? -(alloc->mask + 1) : (alloc->mask + 1); -+ void *start; -+ -+ if (base < address_space_start) base = address_space_start; -+ if (is_beyond_limit( base, size, alloc->limit )) end = alloc->limit; -+ if (base >= end) return 0; -+ -+ if (alloc->top_down) -+ { -+ start = ROUND_ADDR( (char *)end - size, alloc->mask ); -+ if (start >= end || start < base) -+ return 0; -+ -+ if ((alloc->result = try_map_free_area( base, (char *)start + size, step, -+ start, size, alloc->unix_prot ))) -+ return 1; -+ } -+ else -+ { -+ start = ROUND_ADDR( (char *)base + alloc->mask, alloc->mask ); -+ if (!start || start >= end || (char *)end - (char *)start < size) -+ return 0; -+ -+ if ((alloc->result = try_map_free_area( start, end, step, -+ start, size, alloc->unix_prot ))) -+ return 1; -+ } -+ return 0; -+} -+ - /*********************************************************************** - * map_fixed_area - * -@@ -1318,6 +1302,7 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, - alloc.mask = mask; - alloc.top_down = top_down; - alloc.limit = (void*)(get_zero_bits_64_mask( zero_bits_64 ) & (UINT_PTR)user_space_limit); -+ alloc.unix_prot = VIRTUAL_GetUnixProt(vprot); - - if (is_win64 && !top_down) - { -@@ -1336,9 +1321,11 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, - - if (is_win64 || zero_bits_64) - { -- if (!(ptr = map_free_area( address_space_start, alloc.limit, size, mask, top_down, VIRTUAL_GetUnixProt(vprot) ))) -+ if (!wine_mmap_enum_free_areas( alloc_free_area_callback, &alloc, top_down )) - return STATUS_NO_MEMORY; -- TRACE( "got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size ); -+ -+ ptr = alloc.result; -+ TRACE( "got mem in free area %p-%p\n", ptr, (char *)ptr + size ); - goto done; - } - -@@ -2013,6 +2000,12 @@ static int alloc_virtual_heap( void *base, size_t size, void *arg ) - return (alloc->base != (void *)-1); - } - -+static int remove_reserved_area_from_free( void *base, size_t size, void *arg ) -+{ -+ wine_mmap_remove_free_area(base, size, 0); -+ return 0; -+} -+ - /*********************************************************************** - * virtual_init - */ -@@ -2071,6 +2064,9 @@ void virtual_init(void) - size = (char *)address_space_start - (char *)0x10000; - if (size && wine_mmap_is_in_reserved_area( (void*)0x10000, size ) == 1) - wine_anon_mmap( (void *)0x10000, size, PROT_READ | PROT_WRITE, MAP_FIXED ); -+ -+ wine_mmap_add_free_area(address_space_start, (char *)user_space_limit - (char *)address_space_start); -+ wine_mmap_enum_reserved_areas( remove_reserved_area_from_free, NULL, 0); - } - - --- -2.24.1 - diff --git a/game-patches-testing/proton-hotfixes/0005-ntdll-Permanently-exclude-natively-mapped-areas-from.patch b/game-patches-testing/proton-hotfixes/0005-ntdll-Permanently-exclude-natively-mapped-areas-from.patch deleted file mode 100644 index 5b26cdca2..000000000 --- a/game-patches-testing/proton-hotfixes/0005-ntdll-Permanently-exclude-natively-mapped-areas-from.patch +++ /dev/null @@ -1,90 +0,0 @@ -From df166f9e55d0eb325e32e70bf819e10942d7cd75 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 15 Jan 2020 17:05:09 +0300 -Subject: [PATCH 5/5] ntdll: Permanently exclude natively mapped areas from - free areas list. - -Signed-off-by: Paul Gofman ---- - dlls/ntdll/virtual.c | 28 ++++++++++++++++++++++------ - 1 file changed, 22 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c -index b7d8a88abb..3068fe7e47 100644 ---- a/dlls/ntdll/virtual.c -+++ b/dlls/ntdll/virtual.c -@@ -111,6 +111,9 @@ static const BYTE VIRTUAL_Win32Flags[16] = - - static struct wine_rb_tree views_tree; - -+static void *last_already_mapped; -+static size_t last_already_mapped_size; -+ - static RTL_CRITICAL_SECTION csVirtual; - static RTL_CRITICAL_SECTION_DEBUG critsect_debug = - { -@@ -591,16 +594,11 @@ static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end - static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - void *start, size_t size, int unix_prot ) - { -- static unsigned char vec; - void *ptr; - - while (start && base <= start && (char*)start + size <= (char*)end) - { -- if (!mincore(start, page_size, &vec)) -- { -- ptr = NULL; -- } -- else if ((ptr = wine_anon_mmap( start, size, unix_prot, 0 )) == start) -+ if ((ptr = wine_anon_mmap( start, size, unix_prot, 0 )) == start) - { - return start; - } -@@ -617,6 +615,13 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - - TRACE( "Found free area is already mapped, start %p, ptr %p.\n", start, ptr ); - -+ if (!last_already_mapped && step) -+ { -+ last_already_mapped = start; -+ last_already_mapped_size = step > 0 ? step : -step; -+ last_already_mapped_size = min(last_already_mapped_size, (char *)end - (char *)start); -+ } -+ - if ((step > 0 && (char *)end - (char *)start < step) || - (step < 0 && (char *)start - (char *)base < -step) || - step == 0) -@@ -1188,6 +1193,8 @@ static int alloc_free_area_callback( void *base, size_t area_size, void *arg ) - ptrdiff_t step = alloc->top_down ? -(alloc->mask + 1) : (alloc->mask + 1); - void *start; - -+ TRACE("base %p, area_size %p, size %p.\n", base, (void *)area_size, (void *)size); -+ - if (base < address_space_start) base = address_space_start; - if (is_beyond_limit( base, size, alloc->limit )) end = alloc->limit; - if (base >= end) return 0; -@@ -1319,11 +1326,20 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, - goto done; - } - -+ last_already_mapped = NULL; -+ - if (is_win64 || zero_bits_64) - { - if (!wine_mmap_enum_free_areas( alloc_free_area_callback, &alloc, top_down )) - return STATUS_NO_MEMORY; - -+ if (last_already_mapped) -+ { -+ TRACE("Permanently excluding %p - %p from free list.\n", -+ last_already_mapped, (char *)last_already_mapped + last_already_mapped_size - 1); -+ wine_mmap_remove_free_area(last_already_mapped, last_already_mapped_size, 0); -+ } -+ - ptr = alloc.result; - TRACE( "got mem in free area %p-%p\n", ptr, (char *)ptr + size ); - goto done; --- -2.24.1 - diff --git a/game-patches-testing/proton-prep.sh b/game-patches-testing/proton-prep.sh index a379850f0..fca5e2d8b 100755 --- a/game-patches-testing/proton-prep.sh +++ b/game-patches-testing/proton-prep.sh @@ -11,7 +11,7 @@ git clean -xdf #Don't apply wow patches for now, they tend to crash other vkd3d games #patch -Np1 < ../game-patches-testing/vkd3d-patches/Support_RS_1.0_Volatile.patch - #patch -Np1 < ../game-patches-testing/vkd3d-patches/wow-flicker.patch + patch -Np1 < ../game-patches-testing/vkd3d-patches/wow-flicker.patch cd .. # Valve DXVK patches @@ -53,13 +53,6 @@ -W user32-rawinput-hid \ -W winex11-key_translation - # Staging hotfix - patch -Np1 < ../game-patches-testing/proton-hotfixes/0001-ntdll-Check-first-page-in-range-with-mincore-in-try_.patch - patch -Np1 < ../game-patches-testing/proton-hotfixes/0002-ntdll-Increase-step-after-failed-map-attempt-in-try_.patch - patch -Np1 < ../game-patches-testing/proton-hotfixes/0003-libs-wine-Add-functions-for-managing-free-area-list.patch - patch -Np1 < ../game-patches-testing/proton-hotfixes/0004-ntdll-Use-free-area-list-for-virtual-memory-allocati.patch - patch -Np1 < ../game-patches-testing/proton-hotfixes/0005-ntdll-Permanently-exclude-natively-mapped-areas-from.patch - #VKD3D-WINE #Don't apply these for now,they are part of the wow patches #echo "applying vkd3d wine patches" @@ -104,6 +97,9 @@ patch -Np1 < ../game-patches-testing/game-patches/0001-bcrypt-Implement-BCryptSecretAgreement-with-libgcryp.patch patch -Np1 < ../game-patches-testing/game-patches/0002-bcrypt-Implement-BCryptSecretAgreement-with-libgcryp.patch + echo "bnet beta win10 crash fix" + patch -Np1 < ../game-patches-testing/game-patches/bnet-beta_win10_crash_fix.patch + #WINE FSYNC echo "applying fsync patches" patch -Np1 < ../game-patches-testing/proton-valve-patches/proton-fsync_staging.patch @@ -155,6 +151,9 @@ patch -Np1 < ../game-patches-testing/proton-valve-patches/proton-apply_LargeAddressAware_fix_for_Bayonetta.patch patch -Np1 < ../game-patches-testing/proton-valve-patches/proton-Set_amd_ags_x64_to_built_in_for_Wolfenstein_2.patch + #fix steep fullscreen + patch -Np1 < ../game-patches-testing/wine-patches/0001-Add-some-semi-stubs-in-user32.patch + #need for VR to compile patch -Np1 < ../game-patches-testing/proton-valve-patches/proton-wined3d.patch @@ -162,9 +161,6 @@ #WINE CUSTOM PATCHES #add your own custom patch lines below - #fix steep fullscreen - patch -Np1 < ../game-patches-testing/wine-patches/0001-Add-some-semi-stubs-in-user32.patch - ./tools/make_requests autoreconf -f diff --git a/game-patches-testing/proton-valve-patches/proton-rawinput.patch b/game-patches-testing/proton-valve-patches/proton-rawinput.patch index a2429d7e3..ac50c82d8 100644 --- a/game-patches-testing/proton-valve-patches/proton-rawinput.patch +++ b/game-patches-testing/proton-valve-patches/proton-rawinput.patch @@ -1,3232 +1,13848 @@ -From b6642329b98b06102fee55c3c696056803e6e35e Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Wed, 18 Dec 2019 21:17:37 +0100 -Subject: proton rawinput - - -diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h -index 114e3971ed..9116aaeab6 100644 ---- a/dlls/dinput/device_private.h -+++ b/dlls/dinput/device_private.h -@@ -70,6 +70,9 @@ struct IDirectInputDeviceImpl - int acquired; - DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */ - -+ BOOL use_raw_input; /* use raw input instead of low-level messages */ -+ RAWINPUTDEVICE raw_device; /* raw device to (un)register */ -+ - LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ - int queue_len; /* size of the queue - set in 'SetProperty' */ - int queue_head; /* position to write new event into queue */ -diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c -index 4d2d4afe10..9e3b9f4825 100644 ---- a/dlls/dinput/dinput_main.c -+++ b/dlls/dinput/dinput_main.c -@@ -98,6 +98,10 @@ static const struct dinput_device *dinput_devices[] = - - HINSTANCE DINPUT_instance; - -+static ATOM di_em_win_class; -+static const WCHAR di_em_winW[] = {'D','I','E','m','W','i','n',0}; -+static HWND di_em_win; -+ - static BOOL check_hook_thread(void); - static CRITICAL_SECTION dinput_hook_crit; - static struct list direct_input_list = LIST_INIT( direct_input_list ); -@@ -626,6 +630,59 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE - return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); - } - -+static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -+{ -+ IDirectInputImpl *dinput; -+ -+ TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam ); -+ -+ if (msg == WM_INPUT) -+ { -+ EnterCriticalSection( &dinput_hook_crit ); -+ LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) -+ { -+ IDirectInputDeviceImpl *dev; -+ -+ EnterCriticalSection( &dinput->crit ); -+ LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) -+ { -+ if (dev->acquired && dev->event_proc && dev->use_raw_input) -+ { -+ TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); -+ dev->event_proc( &dev->IDirectInputDevice8A_iface, GET_RAWINPUT_CODE_WPARAM(wparam), lparam ); -+ } -+ } -+ LeaveCriticalSection( &dinput->crit ); -+ } -+ LeaveCriticalSection( &dinput_hook_crit ); -+ } -+ -+ return DefWindowProcW(hwnd, msg, wparam, lparam); -+} -+ -+static void register_di_em_win_class(void) -+{ -+ static WNDCLASSEXW class; -+ -+ ZeroMemory(&class, sizeof(class)); -+ class.cbSize = sizeof(class); -+ class.lpfnWndProc = di_em_win_wndproc; -+ class.hInstance = DINPUT_instance; -+ class.lpszClassName = di_em_winW; -+ -+ if (!(di_em_win_class = RegisterClassExW( &class ))) -+ WARN( "Unable to register message window class\n" ); -+} -+ -+static void unregister_di_em_win_class(void) -+{ -+ if (!di_em_win_class) -+ return; -+ -+ if (!UnregisterClassW( MAKEINTRESOURCEW( di_em_win_class ), DINPUT_instance )) -+ WARN( "Unable to unregister message window class\n" ); -+} -+ - static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion) - { - if (!This->initialized) -@@ -1695,7 +1752,7 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) - - EnterCriticalSection( &dinput->crit ); - LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) -- if (dev->acquired && dev->event_proc) -+ if (dev->acquired && dev->event_proc && !dev->use_raw_input) - { - TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); - skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam ); -@@ -1748,6 +1805,9 @@ static DWORD WINAPI hook_thread_proc(void *param) - static HHOOK kbd_hook, mouse_hook; - MSG msg; - -+ di_em_win = CreateWindowW( MAKEINTRESOURCEW(di_em_win_class), di_em_winW, -+ 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); -+ - /* Force creation of the message queue */ - PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); - SetEvent(param); -@@ -1812,6 +1872,9 @@ static DWORD WINAPI hook_thread_proc(void *param) - DispatchMessageW(&msg); - } - -+ DestroyWindow( di_em_win ); -+ di_em_win = NULL; -+ - FreeLibraryAndExitThread(DINPUT_instance, 0); - } - -@@ -1893,6 +1956,23 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) - hook_thread_event = NULL; - } - -+ if (dev->use_raw_input) -+ { -+ if (acquired) -+ { -+ dev->raw_device.dwFlags = RIDEV_INPUTSINK; -+ dev->raw_device.hwndTarget = di_em_win; -+ } -+ else -+ { -+ dev->raw_device.dwFlags = RIDEV_REMOVE; -+ dev->raw_device.hwndTarget = NULL; -+ } -+ -+ if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) )) -+ WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage ); -+ } -+ - PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 ); - - LeaveCriticalSection(&dinput_hook_crit); -@@ -1919,9 +1999,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(inst); - DINPUT_instance = inst; -+ register_di_em_win_class(); - break; - case DLL_PROCESS_DETACH: - if (reserved) break; -+ unregister_di_em_win_class(); - DeleteCriticalSection(&dinput_hook_crit); - break; - } -diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c -index 2e0101face..b8b88f38c1 100644 ---- a/dlls/dinput/mouse.c -+++ b/dlls/dinput/mouse.c -@@ -246,6 +246,13 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) - list_add_tail(&dinput->devices_list, &newDevice->base.entry); - LeaveCriticalSection(&dinput->crit); - -+ if (dinput->dwVersion >= 0x0800) -+ { -+ newDevice->base.use_raw_input = TRUE; -+ newDevice->base.raw_device.usUsagePage = 1; /* HID generic device page */ -+ newDevice->base.raw_device.usUsage = 2; /* HID generic mouse */ -+ } -+ - return newDevice; - - failed: -@@ -318,7 +325,115 @@ static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM - { - MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; - SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface); -- int wdata = 0, inst_id = -1, ret = 0; -+ int wdata = 0, inst_id = -1, ret = 0, i; -+ -+ if (wparam == RIM_INPUT || wparam == RIM_INPUTSINK) -+ { -+ RAWINPUTHEADER raw_header; -+ RAWINPUT raw_input; -+ UINT size; -+ POINT rel, pt; -+ -+ static const USHORT mouse_button_flags[] = -+ { -+ RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP, -+ RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP, -+ RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP, -+ RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP, -+ RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP -+ }; -+ -+ TRACE("(%p) wp %08lx, lp %08lx\n", iface, wparam, lparam); -+ -+ size = sizeof(raw_header); -+ if (GetRawInputData( (HRAWINPUT)lparam, RID_HEADER, &raw_header, &size, sizeof(RAWINPUTHEADER) ) != sizeof(raw_header)) -+ { -+ WARN( "Unable to read raw input data header\n" ); -+ return 0; -+ } -+ -+ if (raw_header.dwType != RIM_TYPEMOUSE) -+ return 0; -+ -+ if (raw_header.dwSize > sizeof(raw_input)) -+ { -+ WARN( "Unexpected size for mouse raw input data\n" ); -+ return 0; -+ } -+ -+ size = raw_header.dwSize; -+ if (GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &raw_input, &size, sizeof(RAWINPUTHEADER) ) != raw_header.dwSize ) -+ { -+ WARN( "Unable to read raw input data\n" ); -+ return 0; -+ } -+ -+ if (raw_input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) -+ FIXME( "Unimplemented MOUSE_VIRTUAL_DESKTOP flag\n" ); -+ if (raw_input.data.mouse.usFlags & MOUSE_ATTRIBUTES_CHANGED) -+ FIXME( "Unimplemented MOUSE_ATTRIBUTES_CHANGED flag\n" ); -+ -+ EnterCriticalSection(&This->base.crit); -+ -+ rel.x = raw_input.data.mouse.lLastX; -+ rel.y = raw_input.data.mouse.lLastY; -+ if (raw_input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) -+ { -+ GetCursorPos(&pt); -+ rel.x -= pt.x; -+ rel.y -= pt.y; -+ } -+ -+ This->m_state.lX += rel.x; -+ This->m_state.lY += rel.y; -+ -+ if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) -+ { -+ pt.x = This->m_state.lX; -+ pt.y = This->m_state.lY; -+ } -+ else -+ { -+ pt = rel; -+ } -+ -+ if (rel.x) -+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, -+ pt.x, GetCurrentTime(), This->base.dinput->evsequence); -+ -+ if (rel.y) -+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, -+ pt.y, GetCurrentTime(), This->base.dinput->evsequence); -+ -+ if (rel.x || rel.y) -+ { -+ if ((This->warp_override == WARP_FORCE_ON) || -+ (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE))) -+ This->need_warp = TRUE; -+ } -+ -+ if (raw_input.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) -+ { -+ This->m_state.lZ += (wdata = (SHORT)raw_input.data.mouse.usButtonData); -+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, -+ wdata, GetCurrentTime(), This->base.dinput->evsequence); -+ ret = This->clipped; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(mouse_button_flags); ++i) -+ { -+ if (raw_input.data.mouse.usButtonFlags & mouse_button_flags[i]) -+ { -+ This->m_state.rgbButtons[i / 2] = 0x80 - (i % 2) * 0x80; -+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + (i / 2)) | DIDFT_PSHBUTTON, -+ This->m_state.rgbButtons[i / 2], GetCurrentTime(), This->base.dinput->evsequence); -+ } -+ } -+ -+ LeaveCriticalSection(&This->base.crit); -+ -+ return ret; -+ } - - TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y); - -diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c -index 0e905c8322..6a3271055c 100644 ---- a/dlls/hidclass.sys/device.c -+++ b/dlls/hidclass.sys/device.c -@@ -26,9 +26,11 @@ - #include "winuser.h" - #include "setupapi.h" - -+#include "wine/server.h" - #include "wine/debug.h" - #include "ddk/hidsdi.h" - #include "ddk/hidtypes.h" -+#include "ddk/ntifs.h" - #include "ddk/wdm.h" - - #include "initguid.h" -@@ -131,6 +133,8 @@ NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) - ext->is_mouse = TRUE; - } - -+ ext->link_handle = INVALID_HANDLE_VALUE; -+ - return STATUS_SUCCESS; - - error: -@@ -207,6 +211,8 @@ void HID_DeleteDevice(DEVICE_OBJECT *device) - IoCompleteRequest(irp, IO_NO_INCREMENT); - } - -+ CloseHandle(ext->link_handle); -+ - TRACE("Delete device(%p) %s\n", device, debugstr_w(ext->device_name)); - HeapFree(GetProcessHeap(), 0, ext->device_name); - RtlFreeUnicodeString(&ext->link_name); -@@ -241,6 +247,28 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U - return STATUS_BUFFER_OVERFLOW; - } - -+static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet) -+{ -+ BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; -+ -+ if (ext->link_handle == INVALID_HANDLE_VALUE) -+ return; -+ -+ SERVER_START_REQ(send_hardware_message) -+ { -+ req->win = 0; -+ req->flags = SEND_HWMSG_RAWINPUT; -+ req->input.type = HW_INPUT_HID; -+ req->input.hid.device = wine_server_obj_handle(ext->link_handle); -+ req->input.hid.usage_page = ext->preparseData->caps.UsagePage; -+ req->input.hid.usage = ext->preparseData->caps.Usage; -+ req->input.hid.length = packet->reportBufferLen; -+ wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen); -+ wine_server_call(req); -+ } -+ SERVER_END_REQ; -+} -+ - static void HID_Device_processQueue(DEVICE_OBJECT *device) - { - IRP *irp; -@@ -324,6 +352,7 @@ static DWORD CALLBACK hid_device_thread(void *args) - if (irp->IoStatus.u.Status == STATUS_SUCCESS) - { - RingBuffer_Write(ext->ring_buffer, packet); -+ HID_Device_sendRawInput(device, packet); - HID_Device_processQueue(device); - } - -@@ -370,6 +399,7 @@ static DWORD CALLBACK hid_device_thread(void *args) - else - packet->reportId = 0; - RingBuffer_Write(ext->ring_buffer, packet); -+ HID_Device_sendRawInput(device, packet); - HID_Device_processQueue(device); - } - -diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h -index 36d13c009d..f12e04d789 100644 ---- a/dlls/hidclass.sys/hid.h -+++ b/dlls/hidclass.sys/hid.h -@@ -46,6 +46,7 @@ typedef struct _BASE_DEVICE_EXTENSION { - ULONG poll_interval; - WCHAR *device_name; - UNICODE_STRING link_name; -+ HANDLE link_handle; - WCHAR device_id[MAX_DEVICE_ID_LEN]; - WCHAR instance_id[MAX_DEVICE_ID_LEN]; - struct ReportRingBuffer *ring_buffer; -diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c -index 1c130e8dd8..b84a358dba 100644 ---- a/dlls/hidclass.sys/pnp.c -+++ b/dlls/hidclass.sys/pnp.c -@@ -299,12 +299,28 @@ NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp) - case IRP_MN_START_DEVICE: - { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; -+ OBJECT_ATTRIBUTES attr; - - rc = minidriver->PNPDispatch(device, irp); - - IoSetDeviceInterfaceState(&ext->link_name, TRUE); - if (ext->is_mouse) - IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE); -+ -+ attr.Length = sizeof(attr); -+ attr.RootDirectory = 0; -+ attr.Attributes = OBJ_CASE_INSENSITIVE; -+ attr.ObjectName = &ext->link_name; -+ attr.SecurityDescriptor = NULL; -+ attr.SecurityQualityOfService = NULL; -+ NtOpenSymbolicLinkObject(&ext->link_handle, SYMBOLIC_LINK_QUERY, &attr); -+ ext->link_handle = ConvertToGlobalHandle(ext->link_handle); -+ -+ if (ext->link_handle == INVALID_HANDLE_VALUE) -+ ERR("Failed to open link %s, error %u.\n", debugstr_w(ext->link_name.Buffer), GetLastError()); -+ else -+ TRACE("Opened link handle: %p for %s\n", ext->link_handle, debugstr_w(ext->link_name.Buffer)); -+ - return rc; - } - case IRP_MN_REMOVE_DEVICE: -diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c -index 25d4040da0..9b8f8a4828 100644 ---- a/dlls/setupapi/devinst.c -+++ b/dlls/setupapi/devinst.c -@@ -101,6 +101,7 @@ static const WCHAR Linked[] = {'L','i','n','k','e','d',0}; - static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0}; - static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0}; - static const WCHAR backslashW[] = {'\\',0}; -+static const WCHAR hashW[] = {'#',0}; - static const WCHAR emptyW[] = {0}; - - struct driver -@@ -312,7 +313,6 @@ static WCHAR *get_iface_key_path(struct device_iface *iface) - - static WCHAR *get_refstr_key_path(struct device_iface *iface) - { -- static const WCHAR hashW[] = {'#',0}; - static const WCHAR slashW[] = {'\\',0}; - WCHAR *path, *ptr; - size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1; -@@ -2288,6 +2288,80 @@ static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet, - } - } - -+ -+/* iterate over all interfaces supported by this device instance. if any of -+ * them are "linked", return TRUE */ -+static BOOL is_device_instance_linked(HKEY interfacesKey, const WCHAR *deviceInstance) -+{ -+ LONG l; -+ DWORD class_idx = 0, device_idx, len, type; -+ HKEY class_key, device_key, link_key; -+ WCHAR class_keyname[40], device_keyname[MAX_DEVICE_ID_LEN]; -+ WCHAR interface_devinstance[MAX_DEVICE_ID_LEN]; -+ -+ while (1) -+ { -+ len = ARRAY_SIZE(class_keyname); -+ l = RegEnumKeyExW(interfacesKey, class_idx++, class_keyname, &len, NULL, NULL, NULL, NULL); -+ if (l) -+ break; -+ -+ l = RegOpenKeyExW(interfacesKey, class_keyname, 0, KEY_READ, &class_key); -+ if (l) -+ continue; -+ -+ device_idx = 0; -+ while (1) -+ { -+ len = ARRAY_SIZE(device_keyname); -+ l = RegEnumKeyExW(class_key, device_idx++, device_keyname, &len, NULL, NULL, NULL, NULL); -+ if (l) -+ break; -+ -+ l = RegOpenKeyExW(class_key, device_keyname, 0, KEY_READ, &device_key); -+ if (l) -+ continue; -+ -+ len = ARRAY_SIZE(interface_devinstance); -+ l = RegQueryValueExW(device_key, DeviceInstance, NULL, &type, (BYTE *)interface_devinstance, &len); -+ if (l || type != REG_SZ) -+ { -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ if (lstrcmpiW(interface_devinstance, deviceInstance)) -+ { -+ /* not our device instance */ -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ l = RegOpenKeyExW(device_key, hashW, 0, KEY_READ, &link_key); -+ if (l) -+ { -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ if (is_linked(link_key)) -+ { -+ RegCloseKey(link_key); -+ RegCloseKey(device_key); -+ RegCloseKey(class_key); -+ return TRUE; -+ } -+ -+ RegCloseKey(link_key); -+ RegCloseKey(device_key); -+ } -+ -+ RegCloseKey(class_key); -+ } -+ -+ return FALSE; -+} -+ - static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey, - const GUID *class, DWORD flags) -@@ -2296,6 +2370,7 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - DWORD i, len; - WCHAR deviceInstance[MAX_PATH]; - LONG l = ERROR_SUCCESS; -+ HKEY interfacesKey = SetupDiOpenClassRegKeyExW(NULL, KEY_READ, DIOCR_INTERFACE, NULL, NULL); - - TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName)); - -@@ -2332,7 +2407,9 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - {'%','s','\\','%','s','\\','%','s',0}; - - if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator, -- deviceName, deviceInstance) != -1) -+ deviceName, deviceInstance) != -1 && -+ (!(flags & DIGCF_PRESENT) || -+ is_device_instance_linked(interfacesKey, id))) - { - create_device(set, &deviceClass, id, FALSE); - } -@@ -2345,6 +2422,8 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - l = ERROR_SUCCESS; - } - } -+ -+ RegCloseKey(interfacesKey); - } - - static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet, -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index 340d20e58f..97a5ada922 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -122,9 +122,9 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) - * - * Internal SendInput function to allow the graphics driver to inject real events. - */ --BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ) -+BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags ) - { -- NTSTATUS status = send_hardware_message( hwnd, input, 0 ); -+ NTSTATUS status = send_hardware_message( hwnd, input, flags ); - if (status) SetLastError( RtlNtStatusToDosError(status) ); - return !status; - } -@@ -192,9 +192,9 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size ) - /* we need to update the coordinates to what the server expects */ - INPUT input = inputs[i]; - update_mouse_coords( &input ); -- status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED ); -+ status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - } -- else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED ); -+ else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - - if (status) - { -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index cc25d2f6c2..b6adddc99b 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2285,10 +2285,17 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * - { - struct user_thread_info *thread_info = get_user_thread_info(); - RAWINPUT *rawinput = thread_info->rawinput; -+ SIZE_T data_len = 0; -+ -+ if (msg_data->rawinput.type == RIM_TYPEHID) -+ { -+ data_len = msg_data->rawinput.hid.length; -+ rawinput = thread_info->rawinput = HeapReAlloc( GetProcessHeap(), 0, rawinput, sizeof(*rawinput) + data_len ); -+ } - - if (!rawinput) - { -- thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) ); -+ thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) + data_len ); - if (!(rawinput = thread_info->rawinput)) return FALSE; - } - -@@ -2383,6 +2390,16 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * - rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; - rawinput->data.keyboard.ExtraInformation = msg_data->info; - } -+ else if (msg_data->rawinput.type == RIM_TYPEHID) -+ { -+ rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + data_len; -+ rawinput->header.hDevice = rawinput_handle_from_device_handle(wine_server_ptr_handle(msg_data->rawinput.hid.device), TRUE); -+ rawinput->header.wParam = 0; -+ -+ rawinput->data.hid.dwSizeHid = data_len; -+ rawinput->data.hid.dwCount = 1; -+ memcpy(rawinput->data.hid.bRawData, msg_data + 1, data_len); -+ } - else - { - FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type); -@@ -3354,10 +3371,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) - { - req->win = wine_server_user_handle( hwnd ); - req->flags = flags; -- req->input.type = input->type; - switch (input->type) - { - case INPUT_MOUSE: -+ req->input.type = HW_INPUT_MOUSE; - req->input.mouse.x = input->u.mi.dx; - req->input.mouse.y = input->u.mi.dy; - req->input.mouse.data = input->u.mi.mouseData; -@@ -3366,6 +3383,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) - req->input.mouse.info = input->u.mi.dwExtraInfo; - break; - case INPUT_KEYBOARD: -+ req->input.type = HW_INPUT_KEYBOARD; - req->input.kbd.vkey = input->u.ki.wVk; - req->input.kbd.scan = input->u.ki.wScan; - req->input.kbd.flags = input->u.ki.dwFlags; -@@ -3373,6 +3391,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) - req->input.kbd.info = input->u.ki.dwExtraInfo; - break; - case INPUT_HARDWARE: -+ req->input.type = HW_INPUT_HARDWARE; - req->input.hw.msg = input->u.hi.uMsg; - req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); - break; -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index 85ff0c5e80..c6af2faa2a 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -43,6 +43,7 @@ struct hid_device - { - WCHAR *path; - HANDLE file; -+ HANDLE handle; - RID_DEVICE_INFO_HID info; - PHIDP_PREPARSED_DATA data; - }; -@@ -138,41 +139,63 @@ static struct hid_device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *ifa - device = &hid_devices[hid_devices_count++]; - device->path = path; - device->file = file; -+ device->handle = INVALID_HANDLE_VALUE; - - return device; - } - --static void find_hid_devices(void) -+extern DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags); -+static void find_hid_devices(BOOL); -+ -+HANDLE rawinput_handle_from_device_handle(HANDLE device, BOOL rescan) - { -- static ULONGLONG last_check; -+ WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1]; -+ OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer; -+ ULONG dummy; -+ unsigned int i; - -+ for (i = 0; i < hid_devices_count; ++i) -+ { -+ if (hid_devices[i].handle == device) -+ return &hid_devices[i]; -+ } -+ -+ if (NtQueryObject( device, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy ) || !info->Name.Buffer) -+ return NULL; -+ -+ /* replace \??\ with \\?\ to match hid_devices paths */ -+ if (info->Name.Length > 1 && info->Name.Buffer[0] == '\\' && info->Name.Buffer[1] == '?') -+ info->Name.Buffer[1] = '\\'; -+ -+ for (i = 0; i < hid_devices_count; ++i) -+ { -+ if (strcmpW(hid_devices[i].path, info->Name.Buffer) == 0) -+ { -+ hid_devices[i].handle = device; -+ return &hid_devices[i]; -+ } -+ } -+ -+ if (!rescan) -+ return NULL; -+ -+ find_hid_devices(TRUE); -+ -+ return rawinput_handle_from_device_handle(device, FALSE); -+} -+ -+static void find_hid_devices_by_guid(const GUID *guid) -+{ - SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) }; - struct hid_device *device; - HIDD_ATTRIBUTES attr; - HIDP_CAPS caps; -- GUID hid_guid; - HDEVINFO set; - DWORD idx; - -- if (GetTickCount64() - last_check < 2000) -- return; -- last_check = GetTickCount64(); -+ set = SetupDiGetClassDevsW(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); - -- HidD_GetHidGuid(&hid_guid); -- -- set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); -- -- EnterCriticalSection(&hid_devices_cs); -- -- /* destroy previous list */ -- for (idx = 0; idx < hid_devices_count; ++idx) -- { -- CloseHandle(hid_devices[idx].file); -- heap_free(hid_devices[idx].path); -- } -- -- hid_devices_count = 0; -- for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &hid_guid, idx, &iface); ++idx) -+ for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, guid, idx, &iface); ++idx) - { - if (!(device = add_device(set, &iface))) - continue; -@@ -194,10 +217,49 @@ static void find_hid_devices(void) - device->info.usUsage = caps.Usage; - } - -- LeaveCriticalSection(&hid_devices_cs); - SetupDiDestroyDeviceInfoList(set); - } - -+static void find_hid_devices(BOOL force) -+{ -+ static ULONGLONG last_check; -+ -+ DWORD idx; -+ GUID hid_guid; -+ -+ if (!force && GetTickCount64() - last_check < 2000) -+ return; -+ -+ HidD_GetHidGuid(&hid_guid); -+ -+ EnterCriticalSection(&hid_devices_cs); -+ -+ if (!force && GetTickCount64() - last_check < 2000) -+ { -+ LeaveCriticalSection(&hid_devices_cs); -+ return; -+ } -+ -+ last_check = GetTickCount64(); -+ -+ /* destroy previous list */ -+ for (idx = 0; idx < hid_devices_count; ++idx) -+ { -+ CloseHandle(hid_devices[idx].file); -+ heap_free(hid_devices[idx].path); -+ } -+ -+ hid_devices_count = 0; -+ -+ find_hid_devices_by_guid(&hid_guid); -+ -+ /* HACK: also look up the xinput-specific devices */ -+ hid_guid.Data4[7]++; -+ find_hid_devices_by_guid(&hid_guid); -+ -+ LeaveCriticalSection(&hid_devices_cs); -+} -+ - /*********************************************************************** - * GetRawInputDeviceList (USER32.@) - */ -@@ -219,7 +281,7 @@ UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_coun - return ~0U; - } - -- find_hid_devices(); -+ find_hid_devices(FALSE); - - if (!devices) - { -@@ -415,6 +477,7 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT - device, command, data, data_size); - - if (!data_size) return ~0U; -+ if (!device) return ~0U; - - /* each case below must set: - * *data_size: length (meaning defined by command) of data we want to copy -@@ -501,14 +564,65 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT - return *data_size; - } - -+static int compare_raw_input_devices(const void *ap, const void *bp) -+{ -+ const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap; -+ const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp; -+ -+ if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage; -+ if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage; -+ return 0; -+} -+ - /*********************************************************************** - * GetRegisteredRawInputDevices (USER32.@) - */ - UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size) - { -- FIXME("devices %p, device_count %p, size %u stub!\n", devices, device_count, size); -+ struct rawinput_device *d = NULL; -+ unsigned int count = ~0U; - -- return 0; -+ TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size); -+ -+ if (!device_count) -+ { -+ SetLastError(ERROR_INVALID_PARAMETER); -+ return ~0U; -+ } -+ -+ if (devices && !(d = HeapAlloc( GetProcessHeap(), 0, *device_count * sizeof(*d) ))) -+ return ~0U; -+ -+ SERVER_START_REQ( get_rawinput_devices ) -+ { -+ if (d) -+ wine_server_set_reply( req, d, *device_count * sizeof(*d) ); -+ -+ if (wine_server_call( req )) -+ goto done; -+ -+ if (!d || reply->device_count > *device_count) -+ { -+ *device_count = reply->device_count; -+ SetLastError( ERROR_INSUFFICIENT_BUFFER ); -+ goto done; -+ } -+ -+ for (count = 0; count < reply->device_count; ++count) -+ { -+ devices[count].usUsagePage = d[count].usage_page; -+ devices[count].usUsage = d[count].usage; -+ devices[count].dwFlags = d[count].flags; -+ devices[count].hwndTarget = wine_server_ptr_handle(d[count].target); -+ } -+ } -+ SERVER_END_REQ; -+ -+ qsort(devices, count, sizeof(*devices), compare_raw_input_devices); -+ -+done: -+ if (d) HeapFree( GetProcessHeap(), 0, d ); -+ return count; - } - - -diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec -index c08ad5ff4f..b59ba38133 100644 ---- a/dlls/user32/user32.spec -+++ b/dlls/user32/user32.spec -@@ -833,5 +833,5 @@ - # All functions must be prefixed with '__wine_' (for internal functions) - # or 'wine_' (for user-visible functions) to avoid namespace conflicts. - # --@ cdecl __wine_send_input(long ptr) -+@ cdecl __wine_send_input(long ptr long) - @ cdecl __wine_set_pixel_format(long long) -diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h -index 17d09dd2c1..372cb130c5 100644 ---- a/dlls/user32/user_private.h -+++ b/dlls/user32/user_private.h -@@ -377,4 +377,6 @@ static inline WCHAR *heap_strdupW(const WCHAR *src) - return dst; - } - -+extern HANDLE rawinput_handle_from_device_handle(HANDLE device, BOOL rescan); -+ - #endif /* __WINE_USER_PRIVATE_H */ -diff --git a/dlls/user32/win.c b/dlls/user32/win.c -index fbd53a76bd..6a676ff33e 100644 ---- a/dlls/user32/win.c -+++ b/dlls/user32/win.c -@@ -2091,6 +2091,7 @@ HWND WINAPI GetDesktopWindow(void) - WCHAR app[MAX_PATH + ARRAY_SIZE( explorer )]; - WCHAR cmdline[MAX_PATH + ARRAY_SIZE( explorer ) + ARRAY_SIZE( args )]; - WCHAR desktop[MAX_PATH]; -+ char *ld_preload; - HANDLE token; - void *redir; - -@@ -2127,6 +2128,12 @@ HWND WINAPI GetDesktopWindow(void) - if (!(token = __wine_create_default_token( FALSE ))) - ERR( "Failed to create limited token\n" ); - -+ /* HACK: Unset LD_PRELOAD before executing explorer.exe to disable buggy gameoverlayrenderer.so -+ * It's not going to work through the CreateProcessW env parameter, as it will not be used for the loader execv. -+ */ -+ if ((ld_preload = getenv("LD_PRELOAD"))) -+ unsetenv("LD_PRELOAD"); -+ - Wow64DisableWow64FsRedirection( &redir ); - if (CreateProcessAsUserW( token, app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, - NULL, windir, &si, &pi )) -@@ -2141,6 +2148,9 @@ HWND WINAPI GetDesktopWindow(void) - - if (token) CloseHandle( token ); - -+ /* HACK: Restore the previous value, just in case */ -+ if (ld_preload) setenv("LD_PRELOAD", ld_preload, 1); -+ - SERVER_START_REQ( get_desktop_window ) - { - req->force = 1; -diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c -index a0f3257f74..1af8a98f1f 100644 ---- a/dlls/wineandroid.drv/keyboard.c -+++ b/dlls/wineandroid.drv/keyboard.c -@@ -680,7 +680,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) - input.u.ki.time = 0; - input.u.ki.dwExtraInfo = 0; - -- __wine_send_input( hwnd, &input ); -+ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - } - - /*********************************************************************** -diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c -index 2fc258dfd9..d96f001432 100644 ---- a/dlls/wineandroid.drv/window.c -+++ b/dlls/wineandroid.drv/window.c -@@ -524,7 +524,7 @@ static int process_events( DWORD mask ) - } - SERVER_END_REQ; - } -- __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input ); -+ __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - } - break; - -@@ -538,7 +538,7 @@ static int process_events( DWORD mask ) - event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk, - event->data.kbd.input.u.ki.wScan ); - update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state ); -- __wine_send_input( 0, &event->data.kbd.input ); -+ __wine_send_input( 0, &event->data.kbd.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - break; - - default: -diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c -index dabe6654f9..2ed6e6f66a 100644 ---- a/dlls/winemac.drv/ime.c -+++ b/dlls/winemac.drv/ime.c -@@ -1427,10 +1427,10 @@ void macdrv_im_set_text(const macdrv_event *event) - { - input.ki.wScan = chars[i]; - input.ki.dwFlags = KEYEVENTF_UNICODE; -- __wine_send_input(hwnd, &input); -+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); - - input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; -- __wine_send_input(hwnd, &input); -+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); - } - } - -diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c -index bb408cb20c..41919baafc 100644 ---- a/dlls/winemac.drv/keyboard.c -+++ b/dlls/winemac.drv/keyboard.c -@@ -929,7 +929,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD fl - input.ki.time = time; - input.ki.dwExtraInfo = 0; - -- __wine_send_input(hwnd, &input); -+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); - } - - -diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c -index dd6443fe1b..91cafdf136 100644 ---- a/dlls/winemac.drv/mouse.c -+++ b/dlls/winemac.drv/mouse.c -@@ -165,7 +165,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, - input.mi.time = time; - input.mi.dwExtraInfo = 0; - -- __wine_send_input(top_level_hwnd, &input); -+ __wine_send_input(top_level_hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW); - } - - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index dd1d0847ae..4c2bf3ada7 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -155,9 +155,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] = - "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent" - }; - --/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ --BOOL keyboard_grabbed = FALSE; -- - int xinput2_opcode = 0; - - /* return the name of an X event */ -@@ -314,6 +311,24 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE - } - #endif - -+static int try_grab_pointer( Display *display ) -+{ -+ if (!grab_pointer) -+ return 1; -+ -+ /* if we are already clipping the cursor in the current thread, we should not -+ * call XGrabPointer here or it would change the confine-to window. */ -+ if (clipping_cursor && x11drv_thread_data()->clip_hwnd) -+ return 1; -+ -+ if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, -+ None, None, CurrentTime ) != GrabSuccess) -+ return 0; -+ -+ XUngrabPointer( display, CurrentTime ); -+ return 1; -+} -+ - /*********************************************************************** - * merge_events - * -@@ -321,6 +336,10 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE - */ - static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) - { -+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H -+ struct x11drv_thread_data *thread_data = x11drv_thread_data(); -+#endif -+ - switch (prev->type) - { - case ConfigureNotify: -@@ -352,19 +371,21 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) - case GenericEvent: - if (next->xcookie.extension != xinput2_opcode) break; - if (next->xcookie.evtype != XI_RawMotion) break; -- if (x11drv_thread_data()->warp_serial) break; -+ if (thread_data->xi2_rawinput_only) break; -+ if (thread_data->warp_serial) break; - return MERGE_KEEP; - } - break; - case GenericEvent: - if (prev->xcookie.extension != xinput2_opcode) break; - if (prev->xcookie.evtype != XI_RawMotion) break; -+ if (thread_data->xi2_rawinput_only) break; - switch (next->type) - { - case GenericEvent: - if (next->xcookie.extension != xinput2_opcode) break; - if (next->xcookie.evtype != XI_RawMotion) break; -- if (x11drv_thread_data()->warp_serial) break; -+ if (thread_data->warp_serial) break; - return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data ); - #endif - } -@@ -594,12 +615,20 @@ static void set_input_focus( struct x11drv_win_data *data ) - /********************************************************************** - * set_focus - */ --static void set_focus( Display *display, HWND hwnd, Time time ) -+static void set_focus( XEvent *event, HWND hwnd, Time time ) - { - HWND focus; - Window win; - GUITHREADINFO threadinfo; - -+ if (!try_grab_pointer( event->xany.display )) -+ { -+ /* ask the foreground window to release its grab before trying to get ours */ -+ SendMessageW( GetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); -+ XSendEvent( event->xany.display, event->xany.window, False, 0, event ); -+ return; -+ } -+ - TRACE( "setting foreground window to %p\n", hwnd ); - SetForegroundWindow( hwnd ); - -@@ -613,7 +642,7 @@ static void set_focus( Display *display, HWND hwnd, Time time ) - if (win) - { - TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); -- XSetInputFocus( display, win, RevertToParent, time ); -+ XSetInputFocus( event->xany.display, win, RevertToParent, time ); - } - } - -@@ -621,8 +650,10 @@ static void set_focus( Display *display, HWND hwnd, Time time ) - /********************************************************************** - * handle_manager_message - */ --static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) -+static void handle_manager_message( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; -+ - if (hwnd != GetDesktopWindow()) return; - if (systray_atom && event->data.l[1] == systray_atom) - change_systray_owner( event->display, event->data.l[2] ); -@@ -632,8 +663,9 @@ static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_wm_protocols - */ --static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) -+static void handle_wm_protocols( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - Atom protocol = (Atom)event->data.l[0]; - Time event_time = (Time)event->data.l[1]; - -@@ -709,7 +741,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) - MAKELONG(HTCAPTION,WM_LBUTTONDOWN) ); - if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) - { -- set_focus( event->display, hwnd, event_time ); -+ set_focus( xev, hwnd, event_time ); - return; - } - } -@@ -718,7 +750,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) - hwnd = GetForegroundWindow(); - if (!hwnd) hwnd = last_focus; - if (!hwnd) hwnd = GetDesktopWindow(); -- set_focus( event->display, hwnd, event_time ); -+ set_focus( xev, hwnd, event_time ); - return; - } - /* try to find some other window to give the focus to */ -@@ -726,7 +758,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) - if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); - if (!hwnd) hwnd = GetActiveWindow(); - if (!hwnd) hwnd = last_focus; -- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time ); -+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time ); - } - else if (protocol == x11drv_atom(_NET_WM_PING)) - { -@@ -775,30 +807,19 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (event->detail == NotifyPointer) return FALSE; - if (hwnd == GetDesktopWindow()) return FALSE; - -- switch (event->mode) -- { -- case NotifyGrab: -- WARN( "unexpected FocusIn event with NotifyGrab mode\n" ); -- break; -- case NotifyWhileGrabbed: -- keyboard_grabbed = TRUE; -- break; -- case NotifyNormal: -- keyboard_grabbed = FALSE; -- break; -- case NotifyUngrab: -- /* Focus was just restored but it can be right after super was -- * pressed and gnome-shell needs a bit of time to respond and -- * toggle the activity view. If we grab the cursor right away -- * it will cancel it and super key will do nothing. -- */ -- if (wm_is_mutter(event->display)) -- Sleep(100); -+ /* Focus was just restored but it can be right after super was -+ * pressed and gnome-shell needs a bit of time to respond and -+ * toggle the activity view. If we grab the cursor right away -+ * it will cancel it and super key will do nothing. -+ */ -+ if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) -+ Sleep(100); - -- keyboard_grabbed = FALSE; -- retry_grab_clipping_window(); -- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -- } -+ /* ask the foreground window to re-apply the current ClipCursor rect */ -+ SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR, 0, 0 ); -+ -+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - - if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic ); - if (use_take_focus) -@@ -813,9 +834,17 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); - if (!hwnd) hwnd = GetActiveWindow(); - if (!hwnd) hwnd = x11drv_thread_data()->last_focus; -- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime ); -+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); -+ return TRUE; -+ } -+ -+ if (!try_grab_pointer( event->display )) -+ { -+ XSendEvent( event->display, event->window, False, 0, xev ); -+ return FALSE; - } -- else SetForegroundWindow( hwnd ); -+ -+ SetForegroundWindow( hwnd ); - return TRUE; - } - -@@ -902,28 +931,10 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) - } - if (!hwnd) return FALSE; - -- switch (event->mode) -- { -- case NotifyUngrab: -- WARN( "unexpected FocusOut event with NotifyUngrab mode\n" ); -- break; -- case NotifyNormal: -- keyboard_grabbed = FALSE; -- break; -- case NotifyWhileGrabbed: -- keyboard_grabbed = TRUE; -- break; -- case NotifyGrab: -- keyboard_grabbed = TRUE; -- -- /* This will do nothing due to keyboard_grabbed == TRUE, but it -- * will save the current clipping rect so we can restore it on -- * FocusIn with NotifyUngrab mode. -- */ -- retry_grab_clipping_window(); -+ if (hwnd == GetForegroundWindow()) ungrab_clipping_window(); - -- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -- } -+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - - focus_out( event->display, hwnd ); - return TRUE; -@@ -1790,8 +1801,10 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_xembed_protocol - */ --static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) -+static void handle_xembed_protocol( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; -+ - switch (event->data.l[1]) - { - case XEMBED_EMBEDDED_NOTIFY: -@@ -1846,8 +1859,9 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_dnd_protocol - */ --static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) -+static void handle_dnd_protocol( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - Window root, child; - int root_x, root_y, child_x, child_y; - unsigned int u; -@@ -1866,8 +1880,8 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) - - struct client_message_handler - { -- int atom; /* protocol atom */ -- void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */ -+ int atom; /* protocol atom */ -+ void (*handler)(HWND, XEvent *); /* corresponding handler function */ - }; - - static const struct client_message_handler client_messages[] = -@@ -1903,7 +1917,7 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev ) - { - if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM]) - { -- client_messages[i].handler( hwnd, event ); -+ client_messages[i].handler( hwnd, xev ); - return TRUE; - } - } -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index 3c38784ebf..7856b04c8f 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1149,7 +1149,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f - input.u.ki.time = time; - input.u.ki.dwExtraInfo = 0; - -- __wine_send_input( hwnd, &input ); -+ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW ); - } - - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 68aecdf90c..cb3cd4b4fd 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -125,9 +125,6 @@ XContext cursor_context = 0; - static HWND cursor_window; - static HCURSOR last_cursor; - static DWORD last_cursor_change; --static RECT last_clip_rect; --static HWND last_clip_foreground_window; --static BOOL last_clip_refused; - static RECT clip_rect; - static Cursor create_cursor( HANDLE handle ); - -@@ -291,9 +288,9 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - - - /*********************************************************************** -- * enable_xinput2 -+ * X11DRV_XInput2_Enable - */ --static void enable_xinput2(void) -+void X11DRV_XInput2_Enable(void) - { - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); -@@ -306,12 +303,16 @@ static void enable_xinput2(void) - - if (data->xi2_state == xi_unknown) - { -- int major = 2, minor = 0; -- if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; -+ int major = 2, minor = 1; -+ if (!pXIQueryVersion( data->display, &major, &minor ) && major == 2 && minor > 0) -+ { -+ TRACE( "XInput2 v%d.%d available\n", major, minor ); -+ data->xi2_state = xi_disabled; -+ } - else - { - data->xi2_state = xi_unavailable; -- WARN( "X Input 2 not available\n" ); -+ WARN( "XInput v2.1 not available\n" ); - } - } - if (data->xi2_state == xi_unavailable) return; -@@ -319,11 +320,23 @@ static void enable_xinput2(void) - - mask.mask = mask_bits; - mask.mask_len = sizeof(mask_bits); -- mask.deviceid = XIAllDevices; -+ mask.deviceid = XIAllMasterDevices; - memset( mask_bits, 0, sizeof(mask_bits) ); -+ - XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); -- XISetMask( mask_bits, XI_ButtonPress ); -+ -+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) -+ { -+ XISetMask( mask_bits, XI_RawButtonPress ); -+ XISetMask( mask_bits, XI_RawButtonRelease ); -+ data->xi2_rawinput_only = TRUE; -+ } -+ else -+ { -+ XISetMask( mask_bits, XI_ButtonPress ); -+ data->xi2_rawinput_only = FALSE; -+ } - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - -@@ -331,24 +344,14 @@ static void enable_xinput2(void) - update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); - pXIFreeDeviceInfo( pointer_info ); - -- /* This device info list is only used to find the initial current slave if -- * no XI_DeviceChanged events happened. If any hierarchy change occurred that -- * might be relevant here (eg. user switching mice after (un)plugging), a -- * XI_DeviceChanged event will point us to the right slave. So this list is -- * safe to be obtained statically at enable_xinput2() time. -- */ -- if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices ); -- data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count ); -- data->xi2_current_slave = 0; -- - data->xi2_state = xi_enabled; - #endif - } - - /*********************************************************************** -- * disable_xinput2 -+ * X11DRV_XInput2_Disable - */ --static void disable_xinput2(void) -+void X11DRV_XInput2_Disable(void) - { - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); -@@ -361,17 +364,14 @@ static void disable_xinput2(void) - - mask.mask = NULL; - mask.mask_len = 0; -- mask.deviceid = XIAllDevices; -+ mask.deviceid = XIAllMasterDevices; - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); -- pXIFreeDeviceInfo( data->xi2_devices ); - data->x_rel_valuator.number = -1; - data->y_rel_valuator.number = -1; - data->x_rel_valuator.accum = 0; - data->y_rel_valuator.accum = 0; -- data->xi2_devices = NULL; - data->xi2_core_pointer = 0; -- data->xi2_current_slave = 0; - #endif - } - -@@ -385,14 +385,10 @@ static BOOL grab_clipping_window( const RECT *clip ) - { - static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; - struct x11drv_thread_data *data = x11drv_thread_data(); -- static DWORD timeout = 5000; -- static DWORD step = 100; -- DWORD time = 0; - Window clip_window; - HWND msg_hwnd = 0; - POINT pos; - RECT real_clip; -- INT ret; - - if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) - return TRUE; /* don't clip in the desktop process */ -@@ -404,21 +400,8 @@ static BOOL grab_clipping_window( const RECT *clip ) - GetModuleHandleW(0), NULL ))) - return TRUE; - -- if (keyboard_grabbed) -- { -- WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); -- last_clip_refused = TRUE; -- last_clip_foreground_window = GetForegroundWindow(); -- last_clip_rect = *clip; -- return FALSE; -- } -- else -- { -- last_clip_refused = FALSE; -- } -- - /* enable XInput2 unless we are already clipping */ -- if (!data->clip_hwnd) enable_xinput2(); -+ if (!data->clip_hwnd) X11DRV_XInput2_Enable(); - - if (data->xi2_state != xi_enabled) - { -@@ -460,25 +443,14 @@ static BOOL grab_clipping_window( const RECT *clip ) - clip->right < clip_rect.right || clip->bottom < clip_rect.bottom) - data->warp_serial = NextRequest( data->display ); - -- /* Some windows managers temporarily grab the pointer during window transition. Retry grabbing. */ -- do -- { -- ret = XGrabPointer( data->display, clip_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, -- GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime ); -- if (ret == AlreadyGrabbed || ret == GrabFrozen) -- { -- time += step; -- Sleep(step); -- } -- } while ((ret == AlreadyGrabbed || ret == GrabFrozen) && time < timeout); -- -- if (ret == GrabSuccess) -+ if (!XGrabPointer( data->display, clip_window, False, -+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask, -+ GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime )) - clipping_cursor = TRUE; - - if (!clipping_cursor) - { -- ERR("Failed to grab pointer\n"); -- disable_xinput2(); -+ X11DRV_XInput2_Disable(); - DestroyWindow( msg_hwnd ); - return FALSE; - } -@@ -521,20 +493,6 @@ void reset_clipping_window(void) - ClipCursor( NULL ); /* make sure the clip rectangle is reset too */ - } - --/*********************************************************************** -- * retry_grab_clipping_window -- * -- * Restore the current clip rectangle or retry the last one if it has -- * been refused because of an active keyboard grab. -- */ --void retry_grab_clipping_window(void) --{ -- if (clipping_cursor) -- ClipCursor( &clip_rect ); -- else if (last_clip_refused && GetForegroundWindow() == last_clip_foreground_window) -- ClipCursor( &last_clip_rect ); --} -- - BOOL CDECL X11DRV_ClipCursor( const RECT *clip ); - - /*********************************************************************** -@@ -560,7 +518,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) - TRACE( "clip hwnd reset from %p\n", hwnd ); - data->clip_hwnd = 0; - data->clip_reset = GetTickCount(); -- disable_xinput2(); -+ X11DRV_XInput2_Disable(); - DestroyWindow( hwnd ); - } - else if (hwnd == GetForegroundWindow()) /* request to clip */ -@@ -672,7 +630,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU - input->u.mi.dx = pt.x; - input->u.mi.dy = pt.y; - -- __wine_send_input( hwnd, input ); -+ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW ); - return; - } - -@@ -739,7 +697,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU - - input->u.mi.dx = pt.x; - input->u.mi.dy = pt.y; -- __wine_send_input( hwnd, input ); -+ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW ); - } - - #ifdef SONAME_LIBXCURSOR -@@ -1533,12 +1491,6 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) - TRACE("real setting to %u, %u\n", - pos.x, pos.y); - -- if (keyboard_grabbed) -- { -- WARN( "refusing to warp to %u, %u\n", pos.x, pos.y ); -- return FALSE; -- } -- - if (!clipping_cursor && - XGrabPointer( data->display, root_window, False, - PointerMotionMask | ButtonPressMask | ButtonReleaseMask, -@@ -1693,7 +1645,7 @@ void move_resize_window( HWND hwnd, int dir ) - input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - input.u.mi.time = GetTickCount(); - input.u.mi.dwExtraInfo = 0; -- __wine_send_input( hwnd, &input ); -+ __wine_send_input( hwnd, &input, SEND_HWMSG_WINDOW ); - } - - while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) -@@ -1837,7 +1789,6 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) - if (event->reason != XISlaveSwitch) return FALSE; - - update_relative_valuators( event->classes, event->num_classes ); -- data->xi2_current_slave = event->sourceid; - return TRUE; - } - -@@ -1859,30 +1810,12 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE; - if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; -- -- /* If there is no slave currently detected, no previous motion nor device -- * change events were received. Look it up now on the device list in this -- * case. -- */ -- if (!thread_data->xi2_current_slave) -- { -- XIDeviceInfo *devices = thread_data->xi2_devices; -- -- for (i = 0; i < thread_data->xi2_device_count; i++) -- { -- if (devices[i].use != XISlavePointer) continue; -- if (devices[i].deviceid != event->deviceid) continue; -- if (devices[i].attachment != thread_data->xi2_core_pointer) continue; -- thread_data->xi2_current_slave = event->deviceid; -- break; -- } -- } -- -- if (event->deviceid != thread_data->xi2_current_slave) return FALSE; -+ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; - - x_rel = &thread_data->x_rel_valuator; - y_rel = &thread_data->y_rel_valuator; - -+ input.type = INPUT_MOUSE; - input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -@@ -1940,10 +1873,44 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.u.mi.dx = pt.x; - input.u.mi.dy = pt.y; - -- TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum ); -+ if (!thread_data->xi2_rawinput_only) -+ { -+ TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum ); -+ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); -+ } -+ else -+ { -+ TRACE( "raw pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum ); -+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); -+ } -+ return TRUE; -+} -+ -+/*********************************************************************** -+ * X11DRV_RawButtonEvent -+ */ -+static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) -+{ -+ struct x11drv_thread_data *thread_data = x11drv_thread_data(); -+ XIRawEvent *event = cookie->data; -+ int button = event->detail - 1; -+ INPUT input; - -- input.type = INPUT_MOUSE; -- __wine_send_input( 0, &input ); -+ if (button >= NB_BUTTONS) return FALSE; -+ if (thread_data->xi2_state != xi_enabled) return FALSE; -+ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; -+ -+ TRACE( "raw button %u %s\n", button, event->evtype == XI_RawButtonRelease ? "up" : "down" ); -+ -+ input.type = INPUT_MOUSE; -+ input.u.mi.dx = 0; -+ input.u.mi.dy = 0; -+ input.u.mi.mouseData = event->evtype == XI_RawButtonRelease ? button_up_data[button] : button_down_data[button]; -+ input.u.mi.dwFlags = event->evtype == XI_RawButtonRelease ? button_up_flags[button] : button_down_flags[button]; -+ input.u.mi.time = EVENT_x11_time_to_win32_time(event->time); -+ input.u.mi.dwExtraInfo = 0; -+ -+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); - return TRUE; - } - -@@ -2011,6 +1978,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) - case XI_RawMotion: - ret = X11DRV_RawMotion( event ); - break; -+ case XI_RawButtonPress: -+ case XI_RawButtonRelease: -+ ret = X11DRV_RawButtonEvent( event ); -+ break; - - default: - TRACE( "Unhandled event %#x\n", event->evtype ); -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 115b287422..d7422a8c63 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2996,6 +2996,9 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) - return 0; - case WM_X11DRV_CLIP_CURSOR: - return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp ); -+ case WM_X11DRV_RELEASE_CURSOR: -+ ungrab_clipping_window(); -+ return 0; - default: - FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp ); - return 0; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index b9bdda88cd..adfbe9700f 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -198,6 +198,8 @@ extern BOOL CDECL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN; - - extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; - extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; -+extern void X11DRV_XInput2_Enable(void) DECLSPEC_HIDDEN; -+extern void X11DRV_XInput2_Disable(void) DECLSPEC_HIDDEN; - - extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, - const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits, -@@ -242,10 +244,10 @@ extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, - DWORD dwReadLen) DECLSPEC_HIDDEN; - extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN; - --extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; - extern void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection, - Atom *targets, UINT count, - void (*callback)( Atom, UINT, HANDLE )) DECLSPEC_HIDDEN; -@@ -343,12 +345,10 @@ struct x11drv_thread_data - DWORD clip_reset; /* time when clipping was last reset */ - HKL kbd_layout; /* active keyboard layout */ - enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ -- void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ -- int xi2_device_count; - struct x11drv_valuator_data x_rel_valuator; - struct x11drv_valuator_data y_rel_valuator; - int xi2_core_pointer; /* XInput2 core pointer id */ -- int xi2_current_slave; /* Current slave driving the Core pointer */ -+ int xi2_rawinput_only; - }; - - extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; -@@ -389,7 +389,6 @@ extern Colormap default_colormap DECLSPEC_HIDDEN; - extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN; - extern Window root_window DECLSPEC_HIDDEN; - extern BOOL clipping_cursor DECLSPEC_HIDDEN; --extern BOOL keyboard_grabbed DECLSPEC_HIDDEN; - extern unsigned int screen_bpp DECLSPEC_HIDDEN; - extern BOOL use_xkb DECLSPEC_HIDDEN; - extern BOOL usexrandr DECLSPEC_HIDDEN; -@@ -545,7 +544,8 @@ enum x11drv_window_messages - WM_X11DRV_SET_WIN_REGION, - WM_X11DRV_RESIZE_DESKTOP, - WM_X11DRV_SET_CURSOR, -- WM_X11DRV_CLIP_CURSOR -+ WM_X11DRV_CLIP_CURSOR, -+ WM_X11DRV_RELEASE_CURSOR - }; - - /* _NET_WM_STATE properties that we keep track of */ -@@ -662,7 +662,6 @@ extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; - extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; - extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; - extern void reset_clipping_window(void) DECLSPEC_HIDDEN; --extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; - extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; - extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; - extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 820668b045..90e907b8c8 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -645,6 +645,8 @@ void CDECL X11DRV_ThreadDetach(void) - - if (data) - { -+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) -+ X11DRV_XInput2_Disable(); - if (data->xim) XCloseIM( data->xim ); - if (data->font_set) XFreeFontSet( data->display, data->font_set ); - XCloseDisplay( data->display ); -@@ -719,6 +721,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) - TlsSetValue( thread_data_tls_index, data ); - - if (use_xim) X11DRV_SetupXIM(); -+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) -+ X11DRV_XInput2_Enable(); - - return data; - } -diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c -index 1f7f0d932b..960c9f75a3 100644 ---- a/dlls/winex11.drv/xdnd.c -+++ b/dlls/winex11.drv/xdnd.c -@@ -192,8 +192,9 @@ static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect) - * - * Handle an XdndEnter event. - */ --void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - int version; - Atom *xdndtypes; - unsigned long count = 0; -@@ -291,8 +292,9 @@ static HWND window_accepting_files(HWND hwnd) - * - * Handle an XdndPosition event. - */ --void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - XClientMessageEvent e; - int accept = 0; /* Assume we're not accepting */ - IDropTarget *dropTarget = NULL; -@@ -405,8 +407,9 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) - * - * Handle an XdndDrop event. - */ --void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - XClientMessageEvent e; - IDropTarget *dropTarget; - DWORD effect = XDNDDropEffect; -@@ -499,7 +502,7 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) - * - * Handle an XdndLeave event. - */ --void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) - { - IDropTarget *dropTarget; - -diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h -index f0c8f88732..1df698df4c 100644 ---- a/include/wine/server_protocol.h -+++ b/include/wine/server_protocol.h -@@ -305,6 +305,13 @@ struct hardware_msg_data - int y; - unsigned int data; - } mouse; -+ struct -+ { -+ int type; -+ obj_handle_t device; -+ unsigned int length; -+ -+ } hid; - } rawinput; - }; - -@@ -351,7 +358,19 @@ typedef union - unsigned int msg; - lparam_t lparam; - } hw; -+ struct -+ { -+ int type; -+ obj_handle_t device; -+ unsigned char usage_page; -+ unsigned char usage; -+ unsigned int length; -+ } hid; - } hw_input_t; -+#define HW_INPUT_MOUSE 0 -+#define HW_INPUT_KEYBOARD 1 -+#define HW_INPUT_HARDWARE 2 -+#define HW_INPUT_HID 3 - - typedef union - { -@@ -3233,6 +3252,7 @@ struct send_hardware_message_request - user_handle_t win; - hw_input_t input; - unsigned int flags; -+ /* VARARG(data,bytes); */ - char __pad_52[4]; - }; - struct send_hardware_message_reply -@@ -3247,6 +3267,8 @@ struct send_hardware_message_reply - char __pad_28[4]; - }; - #define SEND_HWMSG_INJECTED 0x01 -+#define SEND_HWMSG_RAWINPUT 0x02 -+#define SEND_HWMSG_WINDOW 0x04 - - - -@@ -5825,6 +5847,19 @@ struct update_rawinput_devices_reply - }; - - -+struct get_rawinput_devices_request -+{ -+ struct request_header __header; -+ char __pad_12[4]; -+}; -+struct get_rawinput_devices_reply -+{ -+ struct reply_header __header; -+ unsigned int device_count; -+ /* VARARG(devices,rawinput_devices); */ -+ char __pad_12[4]; -+}; -+ - - struct get_suspend_context_request - { -@@ -6465,6 +6500,7 @@ enum request - REQ_free_user_handle, - REQ_set_cursor, - REQ_update_rawinput_devices, -+ REQ_get_rawinput_devices, - REQ_get_suspend_context, - REQ_set_suspend_context, - REQ_create_job, -@@ -6792,6 +6828,7 @@ union generic_request - struct free_user_handle_request free_user_handle_request; - struct set_cursor_request set_cursor_request; - struct update_rawinput_devices_request update_rawinput_devices_request; -+ struct get_rawinput_devices_request get_rawinput_devices_request; - struct get_suspend_context_request get_suspend_context_request; - struct set_suspend_context_request set_suspend_context_request; - struct create_job_request create_job_request; -@@ -7117,6 +7154,7 @@ union generic_reply - struct free_user_handle_reply free_user_handle_reply; - struct set_cursor_reply set_cursor_reply; - struct update_rawinput_devices_reply update_rawinput_devices_reply; -+ struct get_rawinput_devices_reply get_rawinput_devices_reply; - struct get_suspend_context_reply get_suspend_context_reply; - struct set_suspend_context_reply set_suspend_context_reply; - struct create_job_reply create_job_reply; -diff --git a/include/winuser.h b/include/winuser.h -index 51c73d25c2..10cebfa97d 100644 ---- a/include/winuser.h -+++ b/include/winuser.h -@@ -4389,7 +4389,7 @@ static inline BOOL WINAPI SetRectEmpty(LPRECT rect) - WORD WINAPI SYSTEM_KillSystemTimer( WORD ); - - #ifdef __WINESRC__ --WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input ); -+WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags ); - #endif - - #ifdef __cplusplus -diff --git a/server/protocol.def b/server/protocol.def -index ccbb57e8ad..610efa8cb8 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -321,6 +321,13 @@ struct hardware_msg_data - int y; /* y coordinate */ - unsigned int data; /* mouse data */ - } mouse; -+ struct -+ { -+ int type; /* RIM_TYPEHID */ -+ obj_handle_t device; -+ unsigned int length; /* HID report length */ -+ /* followed by length bytes of HID report data */ -+ } hid; - } rawinput; - }; - -@@ -344,7 +351,7 @@ typedef union - int type; - struct - { -- int type; /* INPUT_KEYBOARD */ -+ int type; /* HW_INPUT_KEYBOARD */ - unsigned short vkey; /* virtual key code */ - unsigned short scan; /* scan code */ - unsigned int flags; /* event flags */ -@@ -353,7 +360,7 @@ typedef union - } kbd; - struct - { -- int type; /* INPUT_MOUSE */ -+ int type; /* HW_INPUT_MOUSE */ - int x; /* coordinates */ - int y; - unsigned int data; /* mouse data */ -@@ -363,11 +370,23 @@ typedef union - } mouse; - struct - { -- int type; /* INPUT_HARDWARE */ -+ int type; /* HW_INPUT_HARDWARE */ - unsigned int msg; /* message code */ - lparam_t lparam; /* message param */ - } hw; -+ struct -+ { -+ int type; /* HW_INPUT_HID */ -+ obj_handle_t device; -+ unsigned char usage_page; -+ unsigned char usage; -+ unsigned int length; -+ } hid; - } hw_input_t; -+#define HW_INPUT_MOUSE 0 -+#define HW_INPUT_KEYBOARD 1 -+#define HW_INPUT_HARDWARE 2 -+#define HW_INPUT_HID 3 - - typedef union - { -@@ -2361,6 +2380,7 @@ enum message_type - user_handle_t win; /* window handle */ - hw_input_t input; /* input data */ - unsigned int flags; /* flags (see below) */ -+ VARARG(data,bytes); /* hid report data */ - @REPLY - int wait; /* do we need to wait for a reply? */ - int prev_x; /* previous cursor position */ -@@ -2370,6 +2390,8 @@ enum message_type - VARARG(keystate,bytes); /* global state array for all the keys */ - @END - #define SEND_HWMSG_INJECTED 0x01 -+#define SEND_HWMSG_RAWINPUT 0x02 -+#define SEND_HWMSG_WINDOW 0x04 - - - /* Get a message from the current queue */ -@@ -3985,6 +4007,12 @@ struct handle_info - VARARG(devices,rawinput_devices); - @END - -+/* Retrieve the list of registered rawinput devices */ -+@REQ(get_rawinput_devices) -+@REPLY -+ unsigned int device_count; -+ VARARG(devices,rawinput_devices); -+@END - - /* Retrieve the suspended context of a thread */ - @REQ(get_suspend_context) -diff --git a/server/queue.c b/server/queue.c -index 2bc11789b2..848089dca7 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -409,13 +409,13 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ - - /* allocate a hardware message and its data */ - static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_source source, -- unsigned int time ) -+ unsigned int time, data_size_t extra_len ) - { - struct hardware_msg_data *msg_data; - struct message *msg; - - if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL; -- if (!(msg_data = mem_alloc( sizeof(*msg_data) ))) -+ if (!(msg_data = mem_alloc( sizeof(*msg_data) + extra_len ))) - { - free( msg ); - return NULL; -@@ -424,9 +424,9 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour - msg->type = MSG_HARDWARE; - msg->time = time; - msg->data = msg_data; -- msg->data_size = sizeof(*msg_data); -+ msg->data_size = sizeof(*msg_data) + extra_len; - -- memset( msg_data, 0, sizeof(*msg_data) ); -+ memset( msg_data, 0, sizeof(*msg_data) + extra_len ); - msg_data->info = info; - msg_data->source = source; - return msg; -@@ -438,7 +438,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) - static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - struct message *msg; - -- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; -+ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; - - msg->msg = WM_MOUSEMOVE; - msg->x = x; -@@ -1597,11 +1597,11 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru - return win; - } - --static struct rawinput_device_entry *find_rawinput_device( unsigned short usage_page, unsigned short usage ) -+static struct rawinput_device_entry *find_rawinput_device( struct process *process, unsigned short usage_page, unsigned short usage ) - { - struct rawinput_device_entry *e; - -- LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) -+ LIST_FOR_EACH_ENTRY( e, &process->rawinput_devices, struct rawinput_device_entry, entry ) - { - if (e->device.usage_page != usage_page || e->device.usage != usage) continue; - return e; -@@ -1614,7 +1614,7 @@ static void update_rawinput_device(const struct rawinput_device *device) - { - struct rawinput_device_entry *e; - -- if (!(e = find_rawinput_device( device->usage_page, device->usage ))) -+ if (!(e = find_rawinput_device( current->process, device->usage_page, device->usage ))) - { - if (!(e = mem_alloc( sizeof(*e) ))) return; - list_add_tail( ¤t->process->rawinput_devices, &e->entry ); -@@ -1719,7 +1719,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa - struct msg_queue *queue; - struct message *msg; - timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */ -- int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; -+ int id = (input->type == HW_INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; - - if (!(hook_thread = get_first_global_hook( id ))) return 0; - if (!(queue = hook_thread->queue)) return 0; -@@ -1737,7 +1737,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa - msg->data_size = hardware_msg->data_size; - msg->result = NULL; - -- if (input->type == INPUT_KEYBOARD) -+ if (input->type == HW_INPUT_KEYBOARD) - { - unsigned short vkey = input->kbd.vkey; - if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET; -@@ -1758,12 +1758,79 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa - return 1; - } - -+struct rawinput_message -+{ -+ struct desktop *desktop; -+ struct hw_msg_source source; -+ unsigned int time; -+ unsigned char usage_page; -+ unsigned char usage; -+ struct hardware_msg_data data; -+ const void *extra; -+ data_size_t extra_len; -+}; -+ -+static int queue_rawinput_message( struct process* process, void* user ) -+{ -+ const struct rawinput_message* raw_msg = user; -+ const struct rawinput_device_entry *entry; -+ const struct rawinput_device *device = NULL; -+ struct desktop *desktop = NULL; -+ struct thread *thread = NULL, *foreground = NULL; -+ struct message *msg; -+ struct hardware_msg_data *msg_data; -+ -+ if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) -+ device = process->rawinput_mouse; -+ else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) -+ device = process->rawinput_kbd; -+ else if ((entry = find_rawinput_device( process, raw_msg->usage_page, raw_msg->usage ))) -+ device = &entry->device; -+ -+ if (!device) -+ goto done; -+ -+ if (!(desktop = get_desktop_obj( process, process->desktop, 0 )) || -+ (raw_msg->desktop && desktop != raw_msg->desktop)) -+ goto done; -+ -+ if (!(thread = get_window_thread( device->target ? device->target : desktop->foreground_input->active )) || -+ process != thread->process) -+ goto done; -+ -+ /* FIXME: Implement RIDEV_INPUTSINK */ -+ if (!(foreground = get_window_thread( desktop->foreground_input->active )) || -+ thread->process != foreground->process) -+ goto done; -+ -+ if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time, raw_msg->extra_len ))) -+ goto done; -+ msg_data = msg->data; -+ -+ msg->win = device->target; -+ msg->msg = WM_INPUT; -+ msg->wparam = RIM_INPUT; -+ msg->lparam = 0; -+ -+ memcpy( msg_data, &raw_msg->data, sizeof(*msg_data) ); -+ if (raw_msg->extra_len && raw_msg->extra) -+ memcpy( msg_data + 1, raw_msg->extra, raw_msg->extra_len ); -+ -+ queue_hardware_message( desktop, msg, 0 ); -+ -+done: -+ if (foreground) release_object( foreground ); -+ if (thread) release_object( thread ); -+ if (desktop) release_object( desktop ); -+ return 0; -+} -+ - /* queue a hardware message for a mouse event */ - static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, -- unsigned int origin, struct msg_queue *sender ) -+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) - { -- const struct rawinput_device *device; - struct hardware_msg_data *msg_data; -+ struct rawinput_message raw_msg; - struct message *msg; - unsigned int i, time, flags; - struct hw_msg_source source = { IMDT_MOUSE, origin }; -@@ -1813,32 +1880,38 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - y = desktop->cursor.y; - } - -- if ((device = current->process->rawinput_mouse)) -+ if (req_flags & SEND_HWMSG_RAWINPUT) - { -- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; -- msg_data = msg->data; -- -- msg->win = device->target; -- msg->msg = WM_INPUT; -- msg->wparam = RIM_INPUT; -- msg->lparam = 0; -+ raw_msg.desktop = desktop; -+ raw_msg.source = source; -+ raw_msg.time = time; -+ raw_msg.extra = NULL; -+ raw_msg.extra_len = 0; - -+ msg_data = &raw_msg.data; -+ msg_data->info = input->mouse.info; - msg_data->flags = flags; - msg_data->rawinput.type = RIM_TYPEMOUSE; - msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; - msg_data->rawinput.mouse.data = input->mouse.data; - -- queue_hardware_message( desktop, msg, 0 ); -+ if (req_flags == SEND_HWMSG_RAWINPUT) -+ enum_processes( queue_rawinput_message, &raw_msg ); -+ else -+ queue_rawinput_message( current->process, &raw_msg ); - } - -+ if (!(req_flags & SEND_HWMSG_WINDOW)) -+ return 0; -+ - for (i = 0; i < ARRAY_SIZE( messages ); i++) - { - if (!messages[i]) continue; - if (!(flags & (1 << i))) continue; - flags &= ~(1 << i); - -- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; -+ if (!(msg = alloc_hardware_message( input->mouse.info, source, time, 0 ))) return 0; - msg_data = msg->data; - - msg->win = get_user_full_handle( win ); -@@ -1863,11 +1936,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - - /* queue a hardware message for a keyboard event */ - static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, -- unsigned int origin, struct msg_queue *sender ) -+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) - { - 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; - unsigned char vkey = input->kbd.vkey; - unsigned int message_code, time; -@@ -1939,25 +2012,32 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - break; - } - -- if ((device = current->process->rawinput_kbd)) -+ if (req_flags & SEND_HWMSG_RAWINPUT) - { -- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; -- msg_data = msg->data; -- -- msg->win = device->target; -- msg->msg = WM_INPUT; -- msg->wparam = RIM_INPUT; -+ raw_msg.desktop = desktop; -+ raw_msg.source = source; -+ raw_msg.time = time; -+ raw_msg.extra = NULL; -+ raw_msg.extra_len = 0; - -+ msg_data = &raw_msg.data; -+ msg_data->info = input->kbd.info; - msg_data->flags = input->kbd.flags; - msg_data->rawinput.type = RIM_TYPEKEYBOARD; - msg_data->rawinput.kbd.message = message_code; - msg_data->rawinput.kbd.vkey = vkey; - msg_data->rawinput.kbd.scan = input->kbd.scan; - -- queue_hardware_message( desktop, msg, 0 ); -+ if (req_flags == SEND_HWMSG_RAWINPUT) -+ enum_processes( queue_rawinput_message, &raw_msg ); -+ else -+ queue_rawinput_message( current->process, &raw_msg ); - } - -- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; -+ if (!(req_flags & SEND_HWMSG_WINDOW)) -+ return 0; -+ -+ if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; - msg_data = msg->data; - - msg->win = get_user_full_handle( win ); -@@ -1995,7 +2075,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ - struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; - struct message *msg; - -- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; -+ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; - - msg->win = get_user_full_handle( win ); - msg->msg = input->hw.msg; -@@ -2007,6 +2087,38 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ - queue_hardware_message( desktop, msg, 1 ); - } - -+/* queue a hardware message for an hid event */ -+static void queue_hid_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, -+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags, -+ const void *report, data_size_t report_len ) -+{ -+ struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; -+ struct hardware_msg_data *msg_data; -+ struct rawinput_message raw_msg; -+ -+ if (!(req_flags & SEND_HWMSG_RAWINPUT)) -+ return; -+ -+ raw_msg.desktop = NULL; /* send to all desktops */ -+ raw_msg.source = source; -+ raw_msg.time = get_tick_count(); -+ raw_msg.usage_page = input->hid.usage_page; -+ raw_msg.usage = input->hid.usage; -+ raw_msg.extra = report; -+ raw_msg.extra_len = report_len; -+ -+ msg_data = &raw_msg.data; -+ msg_data->flags = 0; -+ msg_data->rawinput.type = RIM_TYPEHID; -+ msg_data->rawinput.hid.device = input->hid.device; -+ msg_data->rawinput.hid.length = report_len; -+ -+ if (req_flags == SEND_HWMSG_RAWINPUT) -+ enum_processes( queue_rawinput_message, &raw_msg ); -+ else -+ queue_rawinput_message( current->process, &raw_msg ); -+} -+ - /* check message filter for a hardware message */ - static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, - user_handle_t filter_win, unsigned int first, unsigned int last ) -@@ -2520,15 +2632,18 @@ DECL_HANDLER(send_hardware_message) - - switch (req->input.type) - { -- case INPUT_MOUSE: -- reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); -+ case HW_INPUT_MOUSE: -+ reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); - break; -- case INPUT_KEYBOARD: -- reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); -+ case HW_INPUT_KEYBOARD: -+ reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); - break; -- case INPUT_HARDWARE: -+ case HW_INPUT_HARDWARE: - queue_custom_hardware_message( desktop, req->win, origin, &req->input ); - break; -+ case HW_INPUT_HID: -+ queue_hid_message( desktop, req->win, &req->input, origin, sender, req->flags, get_req_data(), get_req_data_size() ); -+ break; - default: - set_error( STATUS_INVALID_PARAMETER ); - } -@@ -3329,9 +3444,9 @@ DECL_HANDLER(update_rawinput_devices) - update_rawinput_device(&devices[i]); - } - -- e = find_rawinput_device( 1, 2 ); -+ e = find_rawinput_device( current->process, 1, 2 ); - current->process->rawinput_mouse = e ? &e->device : NULL; -- e = find_rawinput_device( 1, 6 ); -+ e = find_rawinput_device( current->process, 1, 6 ); - current->process->rawinput_kbd = e ? &e->device : NULL; - } - -@@ -3360,3 +3475,27 @@ DECL_HANDLER(fsync_msgwait) - if (queue->fd) - set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); - } -+ -+DECL_HANDLER(get_rawinput_devices) -+{ -+ unsigned int device_count = list_count(¤t->process->rawinput_devices); -+ struct rawinput_device *devices; -+ struct rawinput_device_entry *e; -+ unsigned int i; -+ -+ reply->device_count = device_count; -+ if (get_reply_max_size() / sizeof (*devices) < device_count) -+ return; -+ -+ if (!(devices = mem_alloc( device_count * sizeof (*devices) ))) -+ { -+ set_error( STATUS_NO_MEMORY ); -+ return; -+ } -+ -+ i = 0; -+ LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) -+ devices[i++] = e->device; -+ -+ set_reply_data_ptr( devices, device_count * sizeof (*devices) ); -+} -diff --git a/server/request.h b/server/request.h -index 24fdd761e3..8cc1a9b38c 100644 ---- a/server/request.h -+++ b/server/request.h -@@ -411,6 +411,7 @@ DECL_HANDLER(alloc_user_handle); - DECL_HANDLER(free_user_handle); - DECL_HANDLER(set_cursor); - DECL_HANDLER(update_rawinput_devices); -+DECL_HANDLER(get_rawinput_devices); - DECL_HANDLER(get_suspend_context); - DECL_HANDLER(set_suspend_context); - DECL_HANDLER(create_job); -@@ -737,6 +738,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = - (req_handler)req_free_user_handle, - (req_handler)req_set_cursor, - (req_handler)req_update_rawinput_devices, -+ (req_handler)req_get_rawinput_devices, - (req_handler)req_get_suspend_context, - (req_handler)req_set_suspend_context, - (req_handler)req_create_job, -@@ -2507,6 +2509,9 @@ C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, new_clip) == 32 ); - C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, last_change) == 48 ); - C_ASSERT( sizeof(struct set_cursor_reply) == 56 ); - C_ASSERT( sizeof(struct update_rawinput_devices_request) == 16 ); -+C_ASSERT( sizeof(struct get_rawinput_devices_request) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct get_rawinput_devices_reply, device_count) == 8 ); -+C_ASSERT( sizeof(struct get_rawinput_devices_reply) == 16 ); - C_ASSERT( sizeof(struct get_suspend_context_request) == 16 ); - C_ASSERT( sizeof(struct get_suspend_context_reply) == 8 ); - C_ASSERT( sizeof(struct set_suspend_context_request) == 16 ); -diff --git a/server/trace.c b/server/trace.c -index 524a989401..f3150b607a 100644 ---- a/server/trace.c -+++ b/server/trace.c -@@ -381,24 +381,28 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) - { - switch (input->type) - { -- case INPUT_MOUSE: -+ case HW_INPUT_MOUSE: - fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,time=%u", - prefix, input->mouse.x, input->mouse.y, input->mouse.data, input->mouse.flags, - input->mouse.time ); - dump_uint64( ",info=", &input->mouse.info ); - fputc( '}', stderr ); - break; -- case INPUT_KEYBOARD: -+ case HW_INPUT_KEYBOARD: - fprintf( stderr, "%s{type=KEYBOARD,vkey=%04hx,scan=%04hx,flags=%08x,time=%u", - prefix, input->kbd.vkey, input->kbd.scan, input->kbd.flags, input->kbd.time ); - dump_uint64( ",info=", &input->kbd.info ); - fputc( '}', stderr ); - break; -- case INPUT_HARDWARE: -+ case HW_INPUT_HARDWARE: - fprintf( stderr, "%s{type=HARDWARE,msg=%04x", prefix, input->hw.msg ); - dump_uint64( ",lparam=", &input->hw.lparam ); - fputc( '}', stderr ); - break; -+ case HW_INPUT_HID: -+ fprintf( stderr, "%s{type=HID,device=%04x,usage_page=%02x,usage=%02x,length=%04x}", -+ prefix, input->hid.device, input->hid.usage_page, input->hid.usage, input->hid.length ); -+ break; - default: - fprintf( stderr, "%s{type=%04x}", prefix, input->type ); - break; -@@ -2876,6 +2880,7 @@ static void dump_send_hardware_message_request( const struct send_hardware_messa - fprintf( stderr, " win=%08x", req->win ); - dump_hw_input( ", input=", &req->input ); - fprintf( stderr, ", flags=%08x", req->flags ); -+ dump_varargs_bytes( ", data=", cur_size ); - } - - static void dump_send_hardware_message_reply( const struct send_hardware_message_reply *req ) -@@ -4636,6 +4641,16 @@ static void dump_update_rawinput_devices_request( const struct update_rawinput_d - dump_varargs_rawinput_devices( " devices=", cur_size ); - } - -+static void dump_get_rawinput_devices_request( const struct get_rawinput_devices_request *req ) -+{ -+} -+ -+static void dump_get_rawinput_devices_reply( const struct get_rawinput_devices_reply *req ) -+{ -+ fprintf( stderr, " device_count=%08x", req->device_count ); -+ dump_varargs_rawinput_devices( ", devices=", cur_size ); -+} -+ - static void dump_get_suspend_context_request( const struct get_suspend_context_request *req ) - { - } -@@ -5134,6 +5149,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { - (dump_func)dump_free_user_handle_request, - (dump_func)dump_set_cursor_request, - (dump_func)dump_update_rawinput_devices_request, -+ (dump_func)dump_get_rawinput_devices_request, - (dump_func)dump_get_suspend_context_request, - (dump_func)dump_set_suspend_context_request, - (dump_func)dump_create_job_request, -@@ -5457,6 +5473,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { - NULL, - (dump_func)dump_set_cursor_reply, - NULL, -+ (dump_func)dump_get_rawinput_devices_reply, - (dump_func)dump_get_suspend_context_reply, - NULL, - (dump_func)dump_create_job_reply, -@@ -5780,6 +5797,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { - "free_user_handle", - "set_cursor", - "update_rawinput_devices", -+ "get_rawinput_devices", - "get_suspend_context", - "set_suspend_context", - "create_job", -From e356bcaf352618618e15d1ded10183852a59c7bf Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 17 Dec 2019 08:19:04 -0600 -Subject: [PATCH] winex11: Apply X pointer mapping to RawButton events - ---- - dlls/winex11.drv/keyboard.c | 23 +++++++++++++++++------ - dlls/winex11.drv/mouse.c | 34 +++++++++++++++++++++++++++++++++- - dlls/winex11.drv/x11drv.h | 1 + - dlls/winex11.drv/x11drv_main.c | 1 + - 4 files changed, 52 insertions(+), 7 deletions(-) - -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index 73670adbe32..cfffad03ed6 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1977,13 +1977,24 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) - { - HWND hwnd; - -- XRefreshKeyboardMapping(&event->xmapping); -- X11DRV_InitKeyboard( event->xmapping.display ); -+ switch (event->xmapping.request) -+ { -+ case MappingModifier: -+ case MappingKeyboard: -+ XRefreshKeyboardMapping( &event->xmapping ); -+ X11DRV_InitKeyboard( event->xmapping.display ); -+ -+ hwnd = GetFocus(); -+ if (!hwnd) hwnd = GetActiveWindow(); -+ PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST, -+ 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0)); -+ break; -+ -+ case MappingPointer: -+ X11DRV_InitMouse( event->xmapping.display ); -+ break; -+ } - -- hwnd = GetFocus(); -- if (!hwnd) hwnd = GetActiveWindow(); -- PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST, -- 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0)); - return TRUE; - } - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index cb3cd4b4fd0..b8282532855 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -120,6 +120,8 @@ static const UINT button_up_data[NB_BUTTONS] = - XBUTTON2 - }; - -+static unsigned char *x_pointer_map; -+ - XContext cursor_context = 0; - - static HWND cursor_window; -@@ -140,6 +142,26 @@ MAKE_FUNCPTR(XISelectEvents); - #undef MAKE_FUNCPTR - #endif - -+void X11DRV_InitMouse( Display *display ) -+{ -+ int i, n_buttons; -+ unsigned char *new_map, *old_map; -+ -+ n_buttons = XGetPointerMapping(display, NULL, 0); -+ -+ new_map = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_map) * n_buttons); -+ -+ /* default mapping */ -+ for (i = 0; i < n_buttons; ++i) -+ new_map[i] = i + 1; -+ -+ XGetPointerMapping(display, new_map, n_buttons); -+ -+ old_map = InterlockedExchangePointer((void**)&x_pointer_map, new_map); -+ -+ HeapFree(GetProcessHeap(), 0, old_map); -+} -+ - /*********************************************************************** - * X11DRV_Xcursor_Init - * -@@ -1886,6 +1908,16 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - return TRUE; - } - -+/* apply current X pointer map to raw button event */ -+static unsigned char translate_raw_button(int from) -+{ -+ unsigned char *cur_map = x_pointer_map; -+ -+ if (!cur_map) return from; -+ -+ return cur_map[from - 1]; -+} -+ - /*********************************************************************** - * X11DRV_RawButtonEvent - */ -@@ -1893,7 +1925,7 @@ static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) - { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - XIRawEvent *event = cookie->data; -- int button = event->detail - 1; -+ int button = translate_raw_button(event->detail) - 1; - INPUT input; - - if (button >= NB_BUTTONS) return FALSE; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 08a424740ce..7a6c8596d9a 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -661,6 +661,7 @@ extern void reset_clipping_window(void) DECLSPEC_HIDDEN; - extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; - extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; - extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; -+extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; - extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, - DWORD mask, DWORD flags ) DECLSPEC_HIDDEN; - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index c031a5639aa..c8b3fdeeed8 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -601,6 +601,7 @@ static BOOL process_attach(void) - if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL ); - #endif - X11DRV_InitKeyboard( gdi_display ); -+ X11DRV_InitMouse( gdi_display ); - if (use_xim) use_xim = X11DRV_InitXIM( input_style ); - - X11DRV_DisplayDevices_Init(FALSE); -From 08cdf3ab0a650876f1e326f2d66b3f1e4acb4208 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 17 Dec 2019 12:27:44 -0600 -Subject: [PATCH] winex11: Apply device mapping to RawButton events - ---- - dlls/winex11.drv/mouse.c | 71 ++++++++++++++++++++++++++++++++++++---- - 1 file changed, 64 insertions(+), 7 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index b8282532855..110edc8ce75 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -25,6 +25,9 @@ - #include - #include - #include -+#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -+#include -+#endif - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - #include - #endif -@@ -139,6 +142,9 @@ MAKE_FUNCPTR(XIFreeDeviceInfo); - MAKE_FUNCPTR(XIQueryDevice); - MAKE_FUNCPTR(XIQueryVersion); - MAKE_FUNCPTR(XISelectEvents); -+MAKE_FUNCPTR(XOpenDevice); -+MAKE_FUNCPTR(XCloseDevice); -+MAKE_FUNCPTR(XGetDeviceButtonMapping); - #undef MAKE_FUNCPTR - #endif - -@@ -1908,14 +1914,62 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - return TRUE; - } - --/* apply current X pointer map to raw button event */ --static unsigned char translate_raw_button(int from) -+struct device_map { -+ int id, btn_count; -+ unsigned char map[256]; -+ -+ struct list entry; -+}; -+ -+static const unsigned char *get_device_map(Display *display, int device_id) -+{ -+ static struct list cache = LIST_INIT(cache); -+ -+ struct device_map *device_map; -+ XDevice *device; -+ -+ /* TODO: We should ask for DeviceMappingNotify events and update the cache. */ -+ -+ LIST_FOR_EACH_ENTRY(device_map, &cache, struct device_map, entry) -+ { -+ if (device_map->id == device_id) -+ return device_map->map; -+ } -+ -+ device = pXOpenDevice(display, device_id); -+ if (!device) -+ { -+ WARN("unable to open cursor source device? %u\n", device_id); -+ return NULL; -+ } -+ -+ device_map = HeapAlloc(GetProcessHeap(), 0, sizeof(*device_map)); -+ device_map->id = device_id; -+ -+ device_map->btn_count = pXGetDeviceButtonMapping(display, device, -+ device_map->map, ARRAY_SIZE(device_map->map)); -+ -+ pXCloseDevice(display, device); -+ -+ list_add_tail(&cache, &device_map->entry); -+ -+ return device_map->map; -+} -+ -+/* apply button maps to raw button event */ -+static unsigned char translate_raw_button(XIRawEvent *event) - { -- unsigned char *cur_map = x_pointer_map; -+ const unsigned char *device_map = get_device_map(event->display, event->sourceid); -+ const unsigned char *pointer_map = x_pointer_map; -+ int from = event->detail; -+ -+ if (device_map) -+ from = device_map[from - 1]; - -- if (!cur_map) return from; -+ if (pointer_map) -+ from = pointer_map[from - 1]; - -- return cur_map[from - 1]; -+ return from; - } - - /*********************************************************************** -@@ -1925,14 +1979,14 @@ static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) - { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - XIRawEvent *event = cookie->data; -- int button = translate_raw_button(event->detail) - 1; -+ int button = translate_raw_button(event) - 1; - INPUT input; - - if (button >= NB_BUTTONS) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; - if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; - -- TRACE( "raw button %u %s\n", button, event->evtype == XI_RawButtonRelease ? "up" : "down" ); -+ TRACE( "raw button %u (was: %u) %s\n", button, event->detail, event->evtype == XI_RawButtonRelease ? "up" : "down" ); - - input.type = INPUT_MOUSE; - input.u.mi.dx = 0; -@@ -1975,6 +2029,9 @@ void X11DRV_XInput2_Init(void) - LOAD_FUNCPTR(XIQueryDevice); - LOAD_FUNCPTR(XIQueryVersion); - LOAD_FUNCPTR(XISelectEvents); -+ LOAD_FUNCPTR(XOpenDevice); -+ LOAD_FUNCPTR(XCloseDevice); -+ LOAD_FUNCPTR(XGetDeviceButtonMapping); - #undef LOAD_FUNCPTR - - xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error ); - -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index b6adddc99b..ce0fd78d75 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2318,7 +2318,12 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * - rawinput->header.hDevice = WINE_MOUSE_HANDLE; - rawinput->header.wParam = 0; - -- rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ if (msg_data->flags & MOUSEEVENTF_ABSOLUTE) -+ rawinput->data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE; -+ else -+ rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; -+ if (msg_data->flags & MOUSEEVENTF_VIRTUALDESK) -+ rawinput->data.mouse.usFlags |= MOUSE_VIRTUAL_DESKTOP; - rawinput->data.mouse.u.s.usButtonFlags = 0; - rawinput->data.mouse.u.s.usButtonData = 0; - for (i = 1; i < ARRAY_SIZE(button_flags); ++i) -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index c6af2faa2a..850028ed2b 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -345,7 +345,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U - TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", - i, devices[i].usUsagePage, devices[i].usUsage, - devices[i].dwFlags, devices[i].hwndTarget); -- if (devices[i].dwFlags & ~RIDEV_REMOVE) -+ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) - FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i); - - d[i].usage_page = devices[i].usUsagePage; -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 110edc8ce7..aea6cc8b92 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -283,34 +283,43 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - int i; - -- thread_data->x_rel_valuator.number = -1; -- thread_data->y_rel_valuator.number = -1; -- thread_data->x_rel_valuator.accum = 0; -- thread_data->y_rel_valuator.accum = 0; -+ thread_data->x_pos_valuator.number = -1; -+ thread_data->y_pos_valuator.number = -1; - - for (i = 0; i < n_valuators; i++) - { - XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; -- struct x11drv_valuator_data *valuator_data = NULL; - -- if (valuators[i]->type != XIValuatorClass) continue; -- if (class->label == x11drv_atom( Rel_X ) || -- (!class->label && class->number == 0 && class->mode == XIModeRelative)) -- { -- valuator_data = &thread_data->x_rel_valuator; -- } -+ if (valuators[i]->type != XIValuatorClass) -+ continue; -+ else if (class->label == x11drv_atom( Rel_X ) || -+ class->label == x11drv_atom( Abs_X ) || -+ (!class->label && class->number == 0)) -+ thread_data->x_pos_valuator = *class; - else if (class->label == x11drv_atom( Rel_Y ) || -- (!class->label && class->number == 1 && class->mode == XIModeRelative)) -- { -- valuator_data = &thread_data->y_rel_valuator; -- } -+ class->label == x11drv_atom( Abs_Y ) || -+ (!class->label && class->number == 1)) -+ thread_data->y_pos_valuator = *class; -+ } - -- if (valuator_data) { -- valuator_data->number = class->number; -- valuator_data->min = class->min; -- valuator_data->max = class->max; -- } -+ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) -+ { -+ WARN("Only one X/Y axis found, ignoring RawMotion events\n"); - } -+ else if (thread_data->x_pos_valuator.mode != thread_data->y_pos_valuator.mode) -+ { -+ WARN("Relative/Absolute mismatch between X/Y axis, ignoring RawMotion events\n"); -+ thread_data->y_pos_valuator.number = -1; -+ thread_data->y_pos_valuator.number = -1; -+ } -+ -+ if (thread_data->x_pos_valuator.min >= thread_data->x_pos_valuator.max) -+ thread_data->x_pos_valuator.min = thread_data->x_pos_valuator.max = 0; -+ if (thread_data->y_pos_valuator.min >= thread_data->y_pos_valuator.max) -+ thread_data->y_pos_valuator.min = thread_data->y_pos_valuator.max = 0; -+ -+ thread_data->x_pos_valuator.value = 0; -+ thread_data->y_pos_valuator.value = 0; - } - #endif - -@@ -395,10 +404,8 @@ void X11DRV_XInput2_Disable(void) - mask.deviceid = XIAllMasterDevices; - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); -- data->x_rel_valuator.number = -1; -- data->y_rel_valuator.number = -1; -- data->x_rel_valuator.accum = 0; -- data->y_rel_valuator.accum = 0; -+ data->x_pos_valuator.number = -1; -+ data->y_pos_valuator.number = -1; - data->xi2_core_pointer = 0; - #endif - } -@@ -1827,21 +1834,28 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - { - XIRawEvent *event = xev->data; - const double *values = event->valuators.values; -+ const double *raw_values = event->raw_values; - RECT virtual_rect; - INPUT input; - POINT pt; - int i; - double dx = 0, dy = 0, val; -+ double raw_dx = 0, raw_dy = 0, raw_val; -+ double x_scale = 1, y_scale = 1; -+ double x_accum = 0, y_accum = 0; - struct x11drv_thread_data *thread_data = x11drv_thread_data(); -- struct x11drv_valuator_data *x_rel, *y_rel; -+ XIValuatorClassInfo *x_pos, *y_pos; - -- if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE; -+ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) return FALSE; - if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; - if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; - -- x_rel = &thread_data->x_rel_valuator; -- y_rel = &thread_data->y_rel_valuator; -+ x_pos = &thread_data->x_pos_valuator; -+ y_pos = &thread_data->y_pos_valuator; -+ -+ x_accum = x_pos->value; -+ y_accum = y_pos->value; - - input.type = INPUT_MOUSE; - input.u.mi.mouseData = 0; -@@ -1852,42 +1866,48 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.u.mi.dy = 0; - - virtual_rect = get_virtual_screen_rect(); -+ if (x_pos->min < x_pos->max) -+ x_scale = (virtual_rect.right - virtual_rect.left) / (x_pos->max - x_pos->min); -+ if (y_pos->min < y_pos->max) -+ y_scale = (virtual_rect.bottom - virtual_rect.top) / (y_pos->max - y_pos->min); - -- for (i = 0; i <= max ( x_rel->number, y_rel->number ); i++) -+ for (i = 0; i <= max( x_pos->number, y_pos->number ); i++) - { -- if (!XIMaskIsSet( event->valuators.mask, i )) -- continue; -+ if (!XIMaskIsSet( event->valuators.mask, i )) continue; - val = *values++; -- if (i == x_rel->number) -+ raw_val = *raw_values++; -+ if (i == x_pos->number) - { - dx = val; -- if (x_rel->min < x_rel->max) -- dx = val * (virtual_rect.right - virtual_rect.left) -- / (x_rel->max - x_rel->min); -+ raw_dx = raw_val; -+ input.u.mi.dwFlags |= (x_pos->min < x_pos->max ? MOUSEEVENTF_VIRTUALDESK : 0) | -+ (x_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); -+ if (x_pos->mode == XIModeAbsolute) -+ x_accum = virtual_rect.left + (dx - x_pos->min) * x_scale; -+ else -+ x_accum += dx * x_scale; - } -- if (i == y_rel->number) -+ if (i == y_pos->number) - { - dy = val; -- if (y_rel->min < y_rel->max) -- dy = val * (virtual_rect.bottom - virtual_rect.top) -- / (y_rel->max - y_rel->min); -+ raw_dy = raw_val; -+ input.u.mi.dwFlags |= (y_pos->min < y_pos->max ? MOUSEEVENTF_VIRTUALDESK : 0) | -+ (y_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0); -+ if (y_pos->mode == XIModeAbsolute) -+ y_accum = virtual_rect.top + (dy - y_pos->min) * y_scale; -+ else -+ y_accum += dy * y_scale; - } - } - -- /* Accumulate the *double* dx/dy motions so sub-pixel motions wont be lost -- * when sent/cast to *LONG* input.u.mi.dx/dy. -+ /* Accumulate the fractional parts so they aren't lost after casting -+ * successive motion values to integral fields. -+ * -+ * Note: It looks like raw_dx, raw_dy are already -+ * integral values but that may be wrong. - */ -- x_rel->accum += dx; -- y_rel->accum += dy; -- if (fabs(x_rel->accum) < 1.0 && fabs(y_rel->accum) < 1.0) -- { -- TRACE( "accumulating raw motion (event %f,%f, accum %f,%f)\n", dx, dy, x_rel->accum, y_rel->accum ); -- return TRUE; -- } -- input.u.mi.dx = x_rel->accum; -- input.u.mi.dy = y_rel->accum; -- x_rel->accum -= input.u.mi.dx; -- y_rel->accum -= input.u.mi.dy; -+ input.u.mi.dx = (LONG)x_accum; -+ input.u.mi.dy = (LONG)y_accum; - - if (broken_rawevents && is_old_motion_event( xev->serial )) - { -@@ -1901,14 +1921,31 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.u.mi.dx = pt.x; - input.u.mi.dy = pt.y; - -- if (!thread_data->xi2_rawinput_only) -+ x_pos->value = x_accum - input.u.mi.dx; -+ y_pos->value = y_accum - input.u.mi.dy; -+ -+ if (x_pos->mode == XIModeAbsolute) -+ { -+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); -+ } -+ else if (!thread_data->xi2_rawinput_only) - { -- TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum ); -- __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); -+ if ((dy || dy) && !(input.u.mi.dx || input.u.mi.dy)) -+ { -+ TRACE( "accumulating raw motion (event %f,%f accum %f,%f)\n", dx, dy, x_pos->value, y_pos->value ); -+ } -+ else -+ { -+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy ); -+ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW ); -+ } - } - else - { -- TRACE( "raw pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum ); -+ input.u.mi.dx = raw_dx; -+ input.u.mi.dy = raw_dy; -+ TRACE( "raw pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, raw_dx, raw_dy ); - __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT ); - } - return TRUE; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index f1ce5696df..d2412ed4a4 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -32,6 +32,9 @@ - #include - #include - #include -+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H -+#include -+#endif - - #define BOOL X_BOOL - #define BYTE X_BYTE -@@ -322,14 +325,6 @@ struct x11drv_escape_flush_gl_drawable - * X11 USER driver - */ - --struct x11drv_valuator_data --{ -- double min; -- double max; -- int number; -- double accum; --}; -- - struct x11drv_thread_data - { - Display *display; -@@ -345,11 +340,13 @@ struct x11drv_thread_data - HWND clip_hwnd; /* message window stored in desktop while clipping is active */ - DWORD clip_reset; /* time when clipping was last reset */ - HKL kbd_layout; /* active keyboard layout */ -+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ -- struct x11drv_valuator_data x_rel_valuator; -- struct x11drv_valuator_data y_rel_valuator; -+ XIValuatorClassInfo x_pos_valuator; -+ XIValuatorClassInfo y_pos_valuator; - int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_rawinput_only; -+#endif - }; - - extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; -@@ -434,6 +431,8 @@ enum x11drv_atoms - XATOM_RAW_CAP_HEIGHT, - XATOM_Rel_X, - XATOM_Rel_Y, -+ XATOM_Abs_X, -+ XATOM_Abs_Y, - XATOM_WM_PROTOCOLS, - XATOM_WM_DELETE_WINDOW, - XATOM_WM_STATE, -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 8908e84458..1e2f7f2d36 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -144,6 +144,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "RAW_CAP_HEIGHT", - "Rel X", - "Rel Y", -+ "Abs X", -+ "Abs Y", - "WM_PROTOCOLS", - "WM_DELETE_WINDOW", - "WM_STATE", -diff --git a/server/queue.c b/server/queue.c -index 848089dca7..c0094379da 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -438,6 +438,9 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) - static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - struct message *msg; - -+ if (current->process->rawinput_mouse && -+ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return; -+ - if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; - - msg->msg = WM_MOUSEMOVE; -@@ -1829,6 +1832,7 @@ done: - static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) - { -+ const struct rawinput_device *device; - struct hardware_msg_data *msg_data; - struct rawinput_message raw_msg; - struct message *msg; -@@ -1892,8 +1896,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - msg_data->info = input->mouse.info; - msg_data->flags = flags; - msg_data->rawinput.type = RIM_TYPEMOUSE; -- msg_data->rawinput.mouse.x = x - desktop->cursor.x; -- msg_data->rawinput.mouse.y = y - desktop->cursor.y; -+ msg_data->rawinput.mouse.x = input->mouse.x; -+ msg_data->rawinput.mouse.y = input->mouse.y; - msg_data->rawinput.mouse.data = input->mouse.data; - - if (req_flags == SEND_HWMSG_RAWINPUT) -@@ -1904,6 +1908,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - - if (!(req_flags & SEND_HWMSG_WINDOW)) - return 0; -+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) -+ return 0; - - for (i = 0; i < ARRAY_SIZE( messages ); i++) - { -@@ -1939,6 +1945,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) - { - 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; -@@ -2036,6 +2043,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - - if (!(req_flags & SEND_HWMSG_WINDOW)) - return 0; -+ if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) -+ return 0; - - if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; - msg_data = msg->data; -diff --git a/server/queue.c b/server/queue.c -index f5dc06100d1..4b2fef8a20a 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -421,6 +421,20 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour - return msg; - } - -+static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) -+{ -+ int updated; -+ -+ x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); -+ y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); -+ updated = (desktop->cursor.x != x || desktop->cursor.y != y); -+ desktop->cursor.x = x; -+ desktop->cursor.y = y; -+ desktop->cursor.last_change = get_tick_count(); -+ -+ return updated; -+} -+ - /* set the cursor position and queue the corresponding mouse message */ - static void set_cursor_pos( struct desktop *desktop, int x, int y ) - { -@@ -428,7 +442,11 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) - struct message *msg; - - if (current->process->rawinput_mouse && -- current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return; -+ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) -+ { -+ update_desktop_cursor_pos( desktop, x, y ); -+ return; -+ } - - if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; - -@@ -1634,12 +1652,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg - { - if (msg->msg == WM_MOUSEMOVE) - { -- int x = max( min( msg->x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); -- int y = max( min( msg->y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); -- if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1; -- desktop->cursor.x = x; -- desktop->cursor.y = y; -- desktop->cursor.last_change = get_tick_count(); -+ if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; - } - if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; - if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; -@@ -1871,7 +1884,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - if (!(req_flags & SEND_HWMSG_WINDOW)) - return 0; - if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) -+ { -+ if (flags & MOUSEEVENTF_MOVE) update_desktop_cursor_pos( desktop, x, y ); - return 0; -+ } - - for (i = 0; i < ARRAY_SIZE( messages ); i++) - { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PKGBUILDS/proton-rawinput.patch at 88b95b9bae724c9db807af1978ad0e9091a79689 · Tk-Glitch/PKGBUILDS · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + + +
+ +
+ + +
+ +
+ + + +
+
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + + Permalink + + + + + +
+ + +
+ + Tree: + 88b95b9bae + + + + + + + +
+ +
+ + Find file + + + Copy path + +
+
+ + +
+ + Find file + + + Copy path + +
+
+ + + + + + +
+ + +
+
+ + 1 contributor + + +
+ +

+ Users who have contributed to this file +

+
+ +
+
+
+
+ + + + + +
+ +
+
+ + 3232 lines (3001 sloc) + + 121 KB +
+ +
+ +
+ Raw + Blame + History +
+ + +
+ + + +
+
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From b6642329b98b06102fee55c3c696056803e6e35e Mon Sep 17 00:00:00 2001
From: Tk-Glitch <ti3nou@gmail.com>
Date: Wed, 18 Dec 2019 21:17:37 +0100
Subject: proton rawinput
+
+
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 114e3971ed..9116aaeab6 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -70,6 +70,9 @@ struct IDirectInputDeviceImpl
int acquired;
DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */
+ BOOL use_raw_input; /* use raw input instead of low-level messages */
+ RAWINPUTDEVICE raw_device; /* raw device to (un)register */
+
LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */
int queue_len; /* size of the queue - set in 'SetProperty' */
int queue_head; /* position to write new event into queue */
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index 4d2d4afe10..9e3b9f4825 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -98,6 +98,10 @@ static const struct dinput_device *dinput_devices[] =
HINSTANCE DINPUT_instance;
+static ATOM di_em_win_class;
+static const WCHAR di_em_winW[] = {'D','I','E','m','W','i','n',0};
+static HWND di_em_win;
+
static BOOL check_hook_thread(void);
static CRITICAL_SECTION dinput_hook_crit;
static struct list direct_input_list = LIST_INIT( direct_input_list );
@@ -626,6 +630,59 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE
return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
}
+static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ IDirectInputImpl *dinput;
+
+ TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam );
+
+ if (msg == WM_INPUT)
+ {
+ EnterCriticalSection( &dinput_hook_crit );
+ LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
+ {
+ IDirectInputDeviceImpl *dev;
+
+ EnterCriticalSection( &dinput->crit );
+ LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
+ {
+ if (dev->acquired && dev->event_proc && dev->use_raw_input)
+ {
+ TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
+ dev->event_proc( &dev->IDirectInputDevice8A_iface, GET_RAWINPUT_CODE_WPARAM(wparam), lparam );
+ }
+ }
+ LeaveCriticalSection( &dinput->crit );
+ }
+ LeaveCriticalSection( &dinput_hook_crit );
+ }
+
+ return DefWindowProcW(hwnd, msg, wparam, lparam);
+}
+
+static void register_di_em_win_class(void)
+{
+ static WNDCLASSEXW class;
+
+ ZeroMemory(&class, sizeof(class));
+ class.cbSize = sizeof(class);
+ class.lpfnWndProc = di_em_win_wndproc;
+ class.hInstance = DINPUT_instance;
+ class.lpszClassName = di_em_winW;
+
+ if (!(di_em_win_class = RegisterClassExW( &class )))
+ WARN( "Unable to register message window class\n" );
+}
+
+static void unregister_di_em_win_class(void)
+{
+ if (!di_em_win_class)
+ return;
+
+ if (!UnregisterClassW( MAKEINTRESOURCEW( di_em_win_class ), DINPUT_instance ))
+ WARN( "Unable to unregister message window class\n" );
+}
+
static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
{
if (!This->initialized)
@@ -1695,7 +1752,7 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam )
EnterCriticalSection( &dinput->crit );
LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
- if (dev->acquired && dev->event_proc)
+ if (dev->acquired && dev->event_proc && !dev->use_raw_input)
{
TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam );
@@ -1748,6 +1805,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
static HHOOK kbd_hook, mouse_hook;
MSG msg;
+ di_em_win = CreateWindowW( MAKEINTRESOURCEW(di_em_win_class), di_em_winW,
+ 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL );
+
/* Force creation of the message queue */
PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
SetEvent(param);
@@ -1812,6 +1872,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
DispatchMessageW(&msg);
}
+ DestroyWindow( di_em_win );
+ di_em_win = NULL;
+
FreeLibraryAndExitThread(DINPUT_instance, 0);
}
@@ -1893,6 +1956,23 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired)
hook_thread_event = NULL;
}
+ if (dev->use_raw_input)
+ {
+ if (acquired)
+ {
+ dev->raw_device.dwFlags = RIDEV_INPUTSINK;
+ dev->raw_device.hwndTarget = di_em_win;
+ }
+ else
+ {
+ dev->raw_device.dwFlags = RIDEV_REMOVE;
+ dev->raw_device.hwndTarget = NULL;
+ }
+
+ if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) ))
+ WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage );
+ }
+
PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
LeaveCriticalSection(&dinput_hook_crit);
@@ -1919,9 +1999,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(inst);
DINPUT_instance = inst;
+ register_di_em_win_class();
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
+ unregister_di_em_win_class();
DeleteCriticalSection(&dinput_hook_crit);
break;
}
diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c
index 2e0101face..b8b88f38c1 100644
--- a/dlls/dinput/mouse.c
+++ b/dlls/dinput/mouse.c
@@ -246,6 +246,13 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
list_add_tail(&dinput->devices_list, &newDevice->base.entry);
LeaveCriticalSection(&dinput->crit);
+ if (dinput->dwVersion >= 0x0800)
+ {
+ newDevice->base.use_raw_input = TRUE;
+ newDevice->base.raw_device.usUsagePage = 1; /* HID generic device page */
+ newDevice->base.raw_device.usUsage = 2; /* HID generic mouse */
+ }
+
return newDevice;
failed:
@@ -318,7 +325,115 @@ static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM
{
MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface);
- int wdata = 0, inst_id = -1, ret = 0;
+ int wdata = 0, inst_id = -1, ret = 0, i;
+
+ if (wparam == RIM_INPUT || wparam == RIM_INPUTSINK)
+ {
+ RAWINPUTHEADER raw_header;
+ RAWINPUT raw_input;
+ UINT size;
+ POINT rel, pt;
+
+ static const USHORT mouse_button_flags[] =
+ {
+ RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP,
+ RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP,
+ RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP,
+ RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP,
+ RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP
+ };
+
+ TRACE("(%p) wp %08lx, lp %08lx\n", iface, wparam, lparam);
+
+ size = sizeof(raw_header);
+ if (GetRawInputData( (HRAWINPUT)lparam, RID_HEADER, &raw_header, &size, sizeof(RAWINPUTHEADER) ) != sizeof(raw_header))
+ {
+ WARN( "Unable to read raw input data header\n" );
+ return 0;
+ }
+
+ if (raw_header.dwType != RIM_TYPEMOUSE)
+ return 0;
+
+ if (raw_header.dwSize > sizeof(raw_input))
+ {
+ WARN( "Unexpected size for mouse raw input data\n" );
+ return 0;
+ }
+
+ size = raw_header.dwSize;
+ if (GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &raw_input, &size, sizeof(RAWINPUTHEADER) ) != raw_header.dwSize )
+ {
+ WARN( "Unable to read raw input data\n" );
+ return 0;
+ }
+
+ if (raw_input.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)
+ FIXME( "Unimplemented MOUSE_VIRTUAL_DESKTOP flag\n" );
+ if (raw_input.data.mouse.usFlags & MOUSE_ATTRIBUTES_CHANGED)
+ FIXME( "Unimplemented MOUSE_ATTRIBUTES_CHANGED flag\n" );
+
+ EnterCriticalSection(&This->base.crit);
+
+ rel.x = raw_input.data.mouse.lLastX;
+ rel.y = raw_input.data.mouse.lLastY;
+ if (raw_input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
+ {
+ GetCursorPos(&pt);
+ rel.x -= pt.x;
+ rel.y -= pt.y;
+ }
+
+ This->m_state.lX += rel.x;
+ This->m_state.lY += rel.y;
+
+ if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
+ {
+ pt.x = This->m_state.lX;
+ pt.y = This->m_state.lY;
+ }
+ else
+ {
+ pt = rel;
+ }
+
+ if (rel.x)
+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS,
+ pt.x, GetCurrentTime(), This->base.dinput->evsequence);
+
+ if (rel.y)
+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS,
+ pt.y, GetCurrentTime(), This->base.dinput->evsequence);
+
+ if (rel.x || rel.y)
+ {
+ if ((This->warp_override == WARP_FORCE_ON) ||
+ (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE)))
+ This->need_warp = TRUE;
+ }
+
+ if (raw_input.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
+ {
+ This->m_state.lZ += (wdata = (SHORT)raw_input.data.mouse.usButtonData);
+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS,
+ wdata, GetCurrentTime(), This->base.dinput->evsequence);
+ ret = This->clipped;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mouse_button_flags); ++i)
+ {
+ if (raw_input.data.mouse.usButtonFlags & mouse_button_flags[i])
+ {
+ This->m_state.rgbButtons[i / 2] = 0x80 - (i % 2) * 0x80;
+ queue_event(iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + (i / 2)) | DIDFT_PSHBUTTON,
+ This->m_state.rgbButtons[i / 2], GetCurrentTime(), This->base.dinput->evsequence);
+ }
+ }
+
+ LeaveCriticalSection(&This->base.crit);
+
+ return ret;
+ }
TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y);
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c
index 0e905c8322..6a3271055c 100644
--- a/dlls/hidclass.sys/device.c
+++ b/dlls/hidclass.sys/device.c
@@ -26,9 +26,11 @@
#include "winuser.h"
#include "setupapi.h"
+#include "wine/server.h"
#include "wine/debug.h"
#include "ddk/hidsdi.h"
#include "ddk/hidtypes.h"
+#include "ddk/ntifs.h"
#include "ddk/wdm.h"
#include "initguid.h"
@@ -131,6 +133,8 @@ NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device)
ext->is_mouse = TRUE;
}
+ ext->link_handle = INVALID_HANDLE_VALUE;
+
return STATUS_SUCCESS;
error:
@@ -207,6 +211,8 @@ void HID_DeleteDevice(DEVICE_OBJECT *device)
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
+ CloseHandle(ext->link_handle);
+
TRACE("Delete device(%p) %s\n", device, debugstr_w(ext->device_name));
HeapFree(GetProcessHeap(), 0, ext->device_name);
RtlFreeUnicodeString(&ext->link_name);
@@ -241,6 +247,28 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U
return STATUS_BUFFER_OVERFLOW;
}
+static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet)
+{
+ BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
+
+ if (ext->link_handle == INVALID_HANDLE_VALUE)
+ return;
+
+ SERVER_START_REQ(send_hardware_message)
+ {
+ req->win = 0;
+ req->flags = SEND_HWMSG_RAWINPUT;
+ req->input.type = HW_INPUT_HID;
+ req->input.hid.device = wine_server_obj_handle(ext->link_handle);
+ req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
+ req->input.hid.usage = ext->preparseData->caps.Usage;
+ req->input.hid.length = packet->reportBufferLen;
+ wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
+ wine_server_call(req);
+ }
+ SERVER_END_REQ;
+}
+
static void HID_Device_processQueue(DEVICE_OBJECT *device)
{
IRP *irp;
@@ -324,6 +352,7 @@ static DWORD CALLBACK hid_device_thread(void *args)
if (irp->IoStatus.u.Status == STATUS_SUCCESS)
{
RingBuffer_Write(ext->ring_buffer, packet);
+ HID_Device_sendRawInput(device, packet);
HID_Device_processQueue(device);
}
@@ -370,6 +399,7 @@ static DWORD CALLBACK hid_device_thread(void *args)
else
packet->reportId = 0;
RingBuffer_Write(ext->ring_buffer, packet);
+ HID_Device_sendRawInput(device, packet);
HID_Device_processQueue(device);
}
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h
index 36d13c009d..f12e04d789 100644
--- a/dlls/hidclass.sys/hid.h
+++ b/dlls/hidclass.sys/hid.h
@@ -46,6 +46,7 @@ typedef struct _BASE_DEVICE_EXTENSION {
ULONG poll_interval;
WCHAR *device_name;
UNICODE_STRING link_name;
+ HANDLE link_handle;
WCHAR device_id[MAX_DEVICE_ID_LEN];
WCHAR instance_id[MAX_DEVICE_ID_LEN];
struct ReportRingBuffer *ring_buffer;
diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c
index 1c130e8dd8..b84a358dba 100644
--- a/dlls/hidclass.sys/pnp.c
+++ b/dlls/hidclass.sys/pnp.c
@@ -299,12 +299,28 @@ NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp)
case IRP_MN_START_DEVICE:
{
BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
+ OBJECT_ATTRIBUTES attr;
rc = minidriver->PNPDispatch(device, irp);
IoSetDeviceInterfaceState(&ext->link_name, TRUE);
if (ext->is_mouse)
IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE);
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = &ext->link_name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ NtOpenSymbolicLinkObject(&ext->link_handle, SYMBOLIC_LINK_QUERY, &attr);
+ ext->link_handle = ConvertToGlobalHandle(ext->link_handle);
+
+ if (ext->link_handle == INVALID_HANDLE_VALUE)
+ ERR("Failed to open link %s, error %u.\n", debugstr_w(ext->link_name.Buffer), GetLastError());
+ else
+ TRACE("Opened link handle: %p for %s\n", ext->link_handle, debugstr_w(ext->link_name.Buffer));
+
return rc;
}
case IRP_MN_REMOVE_DEVICE:
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c
index 25d4040da0..9b8f8a4828 100644
--- a/dlls/setupapi/devinst.c
+++ b/dlls/setupapi/devinst.c
@@ -101,6 +101,7 @@ static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
static const WCHAR backslashW[] = {'\\',0};
+static const WCHAR hashW[] = {'#',0};
static const WCHAR emptyW[] = {0};
struct driver
@@ -312,7 +313,6 @@ static WCHAR *get_iface_key_path(struct device_iface *iface)
static WCHAR *get_refstr_key_path(struct device_iface *iface)
{
- static const WCHAR hashW[] = {'#',0};
static const WCHAR slashW[] = {'\\',0};
WCHAR *path, *ptr;
size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1;
@@ -2288,6 +2288,80 @@ static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
}
}
+
+/* iterate over all interfaces supported by this device instance. if any of
+ * them are "linked", return TRUE */
+static BOOL is_device_instance_linked(HKEY interfacesKey, const WCHAR *deviceInstance)
+{
+ LONG l;
+ DWORD class_idx = 0, device_idx, len, type;
+ HKEY class_key, device_key, link_key;
+ WCHAR class_keyname[40], device_keyname[MAX_DEVICE_ID_LEN];
+ WCHAR interface_devinstance[MAX_DEVICE_ID_LEN];
+
+ while (1)
+ {
+ len = ARRAY_SIZE(class_keyname);
+ l = RegEnumKeyExW(interfacesKey, class_idx++, class_keyname, &len, NULL, NULL, NULL, NULL);
+ if (l)
+ break;
+
+ l = RegOpenKeyExW(interfacesKey, class_keyname, 0, KEY_READ, &class_key);
+ if (l)
+ continue;
+
+ device_idx = 0;
+ while (1)
+ {
+ len = ARRAY_SIZE(device_keyname);
+ l = RegEnumKeyExW(class_key, device_idx++, device_keyname, &len, NULL, NULL, NULL, NULL);
+ if (l)
+ break;
+
+ l = RegOpenKeyExW(class_key, device_keyname, 0, KEY_READ, &device_key);
+ if (l)
+ continue;
+
+ len = ARRAY_SIZE(interface_devinstance);
+ l = RegQueryValueExW(device_key, DeviceInstance, NULL, &type, (BYTE *)interface_devinstance, &len);
+ if (l || type != REG_SZ)
+ {
+ RegCloseKey(device_key);
+ continue;
+ }
+
+ if (lstrcmpiW(interface_devinstance, deviceInstance))
+ {
+ /* not our device instance */
+ RegCloseKey(device_key);
+ continue;
+ }
+
+ l = RegOpenKeyExW(device_key, hashW, 0, KEY_READ, &link_key);
+ if (l)
+ {
+ RegCloseKey(device_key);
+ continue;
+ }
+
+ if (is_linked(link_key))
+ {
+ RegCloseKey(link_key);
+ RegCloseKey(device_key);
+ RegCloseKey(class_key);
+ return TRUE;
+ }
+
+ RegCloseKey(link_key);
+ RegCloseKey(device_key);
+ }
+
+ RegCloseKey(class_key);
+ }
+
+ return FALSE;
+}
+
static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
const GUID *class, DWORD flags)
@@ -2296,6 +2370,7 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
DWORD i, len;
WCHAR deviceInstance[MAX_PATH];
LONG l = ERROR_SUCCESS;
+ HKEY interfacesKey = SetupDiOpenClassRegKeyExW(NULL, KEY_READ, DIOCR_INTERFACE, NULL, NULL);
TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
@@ -2332,7 +2407,9 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
{'%','s','\\','%','s','\\','%','s',0};
if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator,
- deviceName, deviceInstance) != -1)
+ deviceName, deviceInstance) != -1 &&
+ (!(flags & DIGCF_PRESENT) ||
+ is_device_instance_linked(interfacesKey, id)))
{
create_device(set, &deviceClass, id, FALSE);
}
@@ -2345,6 +2422,8 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
l = ERROR_SUCCESS;
}
}
+
+ RegCloseKey(interfacesKey);
}
static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 340d20e58f..97a5ada922 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -122,9 +122,9 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
*
* Internal SendInput function to allow the graphics driver to inject real events.
*/
-BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input )
+BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags )
{
- NTSTATUS status = send_hardware_message( hwnd, input, 0 );
+ NTSTATUS status = send_hardware_message( hwnd, input, flags );
if (status) SetLastError( RtlNtStatusToDosError(status) );
return !status;
}
@@ -192,9 +192,9 @@ UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
/* we need to update the coordinates to what the server expects */
INPUT input = inputs[i];
update_mouse_coords( &input );
- status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED );
+ status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
}
- else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED );
+ else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED|SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
if (status)
{
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index cc25d2f6c2..b6adddc99b 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -2285,10 +2285,17 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data *
{
struct user_thread_info *thread_info = get_user_thread_info();
RAWINPUT *rawinput = thread_info->rawinput;
+ SIZE_T data_len = 0;
+
+ if (msg_data->rawinput.type == RIM_TYPEHID)
+ {
+ data_len = msg_data->rawinput.hid.length;
+ rawinput = thread_info->rawinput = HeapReAlloc( GetProcessHeap(), 0, rawinput, sizeof(*rawinput) + data_len );
+ }
if (!rawinput)
{
- thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) );
+ thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) + data_len );
if (!(rawinput = thread_info->rawinput)) return FALSE;
}
@@ -2383,6 +2390,16 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data *
rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message;
rawinput->data.keyboard.ExtraInformation = msg_data->info;
}
+ else if (msg_data->rawinput.type == RIM_TYPEHID)
+ {
+ rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + data_len;
+ rawinput->header.hDevice = rawinput_handle_from_device_handle(wine_server_ptr_handle(msg_data->rawinput.hid.device), TRUE);
+ rawinput->header.wParam = 0;
+
+ rawinput->data.hid.dwSizeHid = data_len;
+ rawinput->data.hid.dwCount = 1;
+ memcpy(rawinput->data.hid.bRawData, msg_data + 1, data_len);
+ }
else
{
FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type);
@@ -3354,10 +3371,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags )
{
req->win = wine_server_user_handle( hwnd );
req->flags = flags;
- req->input.type = input->type;
switch (input->type)
{
case INPUT_MOUSE:
+ req->input.type = HW_INPUT_MOUSE;
req->input.mouse.x = input->u.mi.dx;
req->input.mouse.y = input->u.mi.dy;
req->input.mouse.data = input->u.mi.mouseData;
@@ -3366,6 +3383,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags )
req->input.mouse.info = input->u.mi.dwExtraInfo;
break;
case INPUT_KEYBOARD:
+ req->input.type = HW_INPUT_KEYBOARD;
req->input.kbd.vkey = input->u.ki.wVk;
req->input.kbd.scan = input->u.ki.wScan;
req->input.kbd.flags = input->u.ki.dwFlags;
@@ -3373,6 +3391,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags )
req->input.kbd.info = input->u.ki.dwExtraInfo;
break;
case INPUT_HARDWARE:
+ req->input.type = HW_INPUT_HARDWARE;
req->input.hw.msg = input->u.hi.uMsg;
req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH );
break;
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c
index 85ff0c5e80..c6af2faa2a 100644
--- a/dlls/user32/rawinput.c
+++ b/dlls/user32/rawinput.c
@@ -43,6 +43,7 @@ struct hid_device
{
WCHAR *path;
HANDLE file;
+ HANDLE handle;
RID_DEVICE_INFO_HID info;
PHIDP_PREPARSED_DATA data;
};
@@ -138,41 +139,63 @@ static struct hid_device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *ifa
device = &hid_devices[hid_devices_count++];
device->path = path;
device->file = file;
+ device->handle = INVALID_HANDLE_VALUE;
return device;
}
-static void find_hid_devices(void)
+extern DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags);
+static void find_hid_devices(BOOL);
+
+HANDLE rawinput_handle_from_device_handle(HANDLE device, BOOL rescan)
{
- static ULONGLONG last_check;
+ WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1];
+ OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer;
+ ULONG dummy;
+ unsigned int i;
+ for (i = 0; i < hid_devices_count; ++i)
+ {
+ if (hid_devices[i].handle == device)
+ return &hid_devices[i];
+ }
+
+ if (NtQueryObject( device, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy ) || !info->Name.Buffer)
+ return NULL;
+
+ /* replace \??\ with \\?\ to match hid_devices paths */
+ if (info->Name.Length > 1 && info->Name.Buffer[0] == '\\' && info->Name.Buffer[1] == '?')
+ info->Name.Buffer[1] = '\\';
+
+ for (i = 0; i < hid_devices_count; ++i)
+ {
+ if (strcmpW(hid_devices[i].path, info->Name.Buffer) == 0)
+ {
+ hid_devices[i].handle = device;
+ return &hid_devices[i];
+ }
+ }
+
+ if (!rescan)
+ return NULL;
+
+ find_hid_devices(TRUE);
+
+ return rawinput_handle_from_device_handle(device, FALSE);
+}
+
+static void find_hid_devices_by_guid(const GUID *guid)
+{
SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) };
struct hid_device *device;
HIDD_ATTRIBUTES attr;
HIDP_CAPS caps;
- GUID hid_guid;
HDEVINFO set;
DWORD idx;
- if (GetTickCount64() - last_check < 2000)
- return;
- last_check = GetTickCount64();
+ set = SetupDiGetClassDevsW(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
- HidD_GetHidGuid(&hid_guid);
-
- set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
-
- EnterCriticalSection(&hid_devices_cs);
-
- /* destroy previous list */
- for (idx = 0; idx < hid_devices_count; ++idx)
- {
- CloseHandle(hid_devices[idx].file);
- heap_free(hid_devices[idx].path);
- }
-
- hid_devices_count = 0;
- for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, &hid_guid, idx, &iface); ++idx)
+ for (idx = 0; SetupDiEnumDeviceInterfaces(set, NULL, guid, idx, &iface); ++idx)
{
if (!(device = add_device(set, &iface)))
continue;
@@ -194,10 +217,49 @@ static void find_hid_devices(void)
device->info.usUsage = caps.Usage;
}
- LeaveCriticalSection(&hid_devices_cs);
SetupDiDestroyDeviceInfoList(set);
}
+static void find_hid_devices(BOOL force)
+{
+ static ULONGLONG last_check;
+
+ DWORD idx;
+ GUID hid_guid;
+
+ if (!force && GetTickCount64() - last_check < 2000)
+ return;
+
+ HidD_GetHidGuid(&hid_guid);
+
+ EnterCriticalSection(&hid_devices_cs);
+
+ if (!force && GetTickCount64() - last_check < 2000)
+ {
+ LeaveCriticalSection(&hid_devices_cs);
+ return;
+ }
+
+ last_check = GetTickCount64();
+
+ /* destroy previous list */
+ for (idx = 0; idx < hid_devices_count; ++idx)
+ {
+ CloseHandle(hid_devices[idx].file);
+ heap_free(hid_devices[idx].path);
+ }
+
+ hid_devices_count = 0;
+
+ find_hid_devices_by_guid(&hid_guid);
+
+ /* HACK: also look up the xinput-specific devices */
+ hid_guid.Data4[7]++;
+ find_hid_devices_by_guid(&hid_guid);
+
+ LeaveCriticalSection(&hid_devices_cs);
+}
+
/***********************************************************************
* GetRawInputDeviceList (USER32.@)
*/
@@ -219,7 +281,7 @@ UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_coun
return ~0U;
}
- find_hid_devices();
+ find_hid_devices(FALSE);
if (!devices)
{
@@ -415,6 +477,7 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT
device, command, data, data_size);
if (!data_size) return ~0U;
+ if (!device) return ~0U;
/* each case below must set:
* *data_size: length (meaning defined by command) of data we want to copy
@@ -501,14 +564,65 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT
return *data_size;
}
+static int compare_raw_input_devices(const void *ap, const void *bp)
+{
+ const RAWINPUTDEVICE a = *(const RAWINPUTDEVICE *)ap;
+ const RAWINPUTDEVICE b = *(const RAWINPUTDEVICE *)bp;
+
+ if (a.usUsagePage != b.usUsagePage) return a.usUsagePage - b.usUsagePage;
+ if (a.usUsage != b.usUsage) return a.usUsage - b.usUsage;
+ return 0;
+}
+
/***********************************************************************
* GetRegisteredRawInputDevices (USER32.@)
*/
UINT WINAPI DECLSPEC_HOTPATCH GetRegisteredRawInputDevices(RAWINPUTDEVICE *devices, UINT *device_count, UINT size)
{
- FIXME("devices %p, device_count %p, size %u stub!\n", devices, device_count, size);
+ struct rawinput_device *d = NULL;
+ unsigned int count = ~0U;
- return 0;
+ TRACE("devices %p, device_count %p, size %u\n", devices, device_count, size);
+
+ if (!device_count)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return ~0U;
+ }
+
+ if (devices && !(d = HeapAlloc( GetProcessHeap(), 0, *device_count * sizeof(*d) )))
+ return ~0U;
+
+ SERVER_START_REQ( get_rawinput_devices )
+ {
+ if (d)
+ wine_server_set_reply( req, d, *device_count * sizeof(*d) );
+
+ if (wine_server_call( req ))
+ goto done;
+
+ if (!d || reply->device_count > *device_count)
+ {
+ *device_count = reply->device_count;
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ goto done;
+ }
+
+ for (count = 0; count < reply->device_count; ++count)
+ {
+ devices[count].usUsagePage = d[count].usage_page;
+ devices[count].usUsage = d[count].usage;
+ devices[count].dwFlags = d[count].flags;
+ devices[count].hwndTarget = wine_server_ptr_handle(d[count].target);
+ }
+ }
+ SERVER_END_REQ;
+
+ qsort(devices, count, sizeof(*devices), compare_raw_input_devices);
+
+done:
+ if (d) HeapFree( GetProcessHeap(), 0, d );
+ return count;
}
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index c08ad5ff4f..b59ba38133 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -833,5 +833,5 @@
# All functions must be prefixed with '__wine_' (for internal functions)
# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
#
-@ cdecl __wine_send_input(long ptr)
+@ cdecl __wine_send_input(long ptr long)
@ cdecl __wine_set_pixel_format(long long)
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 17d09dd2c1..372cb130c5 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -377,4 +377,6 @@ static inline WCHAR *heap_strdupW(const WCHAR *src)
return dst;
}
+extern HANDLE rawinput_handle_from_device_handle(HANDLE device, BOOL rescan);
+
#endif /* __WINE_USER_PRIVATE_H */
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index fbd53a76bd..6a676ff33e 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -2091,6 +2091,7 @@ HWND WINAPI GetDesktopWindow(void)
WCHAR app[MAX_PATH + ARRAY_SIZE( explorer )];
WCHAR cmdline[MAX_PATH + ARRAY_SIZE( explorer ) + ARRAY_SIZE( args )];
WCHAR desktop[MAX_PATH];
+ char *ld_preload;
HANDLE token;
void *redir;
@@ -2127,6 +2128,12 @@ HWND WINAPI GetDesktopWindow(void)
if (!(token = __wine_create_default_token( FALSE )))
ERR( "Failed to create limited token\n" );
+ /* HACK: Unset LD_PRELOAD before executing explorer.exe to disable buggy gameoverlayrenderer.so
+ * It's not going to work through the CreateProcessW env parameter, as it will not be used for the loader execv.
+ */
+ if ((ld_preload = getenv("LD_PRELOAD")))
+ unsetenv("LD_PRELOAD");
+
Wow64DisableWow64FsRedirection( &redir );
if (CreateProcessAsUserW( token, app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
NULL, windir, &si, &pi ))
@@ -2141,6 +2148,9 @@ HWND WINAPI GetDesktopWindow(void)
if (token) CloseHandle( token );
+ /* HACK: Restore the previous value, just in case */
+ if (ld_preload) setenv("LD_PRELOAD", ld_preload, 1);
+
SERVER_START_REQ( get_desktop_window )
{
req->force = 1;
diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c
index a0f3257f74..1af8a98f1f 100644
--- a/dlls/wineandroid.drv/keyboard.c
+++ b/dlls/wineandroid.drv/keyboard.c
@@ -680,7 +680,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags )
input.u.ki.time = 0;
input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input );
+ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
}
/***********************************************************************
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c
index 2fc258dfd9..d96f001432 100644
--- a/dlls/wineandroid.drv/window.c
+++ b/dlls/wineandroid.drv/window.c
@@ -524,7 +524,7 @@ static int process_events( DWORD mask )
}
SERVER_END_REQ;
}
- __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input );
+ __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
}
break;
@@ -538,7 +538,7 @@ static int process_events( DWORD mask )
event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk,
event->data.kbd.input.u.ki.wScan );
update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state );
- __wine_send_input( 0, &event->data.kbd.input );
+ __wine_send_input( 0, &event->data.kbd.input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
break;
default:
diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c
index dabe6654f9..2ed6e6f66a 100644
--- a/dlls/winemac.drv/ime.c
+++ b/dlls/winemac.drv/ime.c
@@ -1427,10 +1427,10 @@ void macdrv_im_set_text(const macdrv_event *event)
{
input.ki.wScan = chars[i];
input.ki.dwFlags = KEYEVENTF_UNICODE;
- __wine_send_input(hwnd, &input);
+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW);
input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
- __wine_send_input(hwnd, &input);
+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW);
}
}
diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c
index bb408cb20c..41919baafc 100644
--- a/dlls/winemac.drv/keyboard.c
+++ b/dlls/winemac.drv/keyboard.c
@@ -929,7 +929,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD fl
input.ki.time = time;
input.ki.dwExtraInfo = 0;
- __wine_send_input(hwnd, &input);
+ __wine_send_input(hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW);
}
diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c
index dd6443fe1b..91cafdf136 100644
--- a/dlls/winemac.drv/mouse.c
+++ b/dlls/winemac.drv/mouse.c
@@ -165,7 +165,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags,
input.mi.time = time;
input.mi.dwExtraInfo = 0;
- __wine_send_input(top_level_hwnd, &input);
+ __wine_send_input(top_level_hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW);
}
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index dd1d0847ae..4c2bf3ada7 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -155,9 +155,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] =
"SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
};
-/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
-BOOL keyboard_grabbed = FALSE;
-
int xinput2_opcode = 0;
/* return the name of an X event */
@@ -314,6 +311,24 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE
}
#endif
+static int try_grab_pointer( Display *display )
+{
+ if (!grab_pointer)
+ return 1;
+
+ /* if we are already clipping the cursor in the current thread, we should not
+ * call XGrabPointer here or it would change the confine-to window. */
+ if (clipping_cursor && x11drv_thread_data()->clip_hwnd)
+ return 1;
+
+ if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync,
+ None, None, CurrentTime ) != GrabSuccess)
+ return 0;
+
+ XUngrabPointer( display, CurrentTime );
+ return 1;
+}
+
/***********************************************************************
* merge_events
*
@@ -321,6 +336,10 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE
*/
static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
{
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+ struct x11drv_thread_data *thread_data = x11drv_thread_data();
+#endif
+
switch (prev->type)
{
case ConfigureNotify:
@@ -352,19 +371,21 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
case GenericEvent:
if (next->xcookie.extension != xinput2_opcode) break;
if (next->xcookie.evtype != XI_RawMotion) break;
- if (x11drv_thread_data()->warp_serial) break;
+ if (thread_data->xi2_rawinput_only) break;
+ if (thread_data->warp_serial) break;
return MERGE_KEEP;
}
break;
case GenericEvent:
if (prev->xcookie.extension != xinput2_opcode) break;
if (prev->xcookie.evtype != XI_RawMotion) break;
+ if (thread_data->xi2_rawinput_only) break;
switch (next->type)
{
case GenericEvent:
if (next->xcookie.extension != xinput2_opcode) break;
if (next->xcookie.evtype != XI_RawMotion) break;
- if (x11drv_thread_data()->warp_serial) break;
+ if (thread_data->warp_serial) break;
return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
#endif
}
@@ -594,12 +615,20 @@ static void set_input_focus( struct x11drv_win_data *data )
/**********************************************************************
* set_focus
*/
-static void set_focus( Display *display, HWND hwnd, Time time )
+static void set_focus( XEvent *event, HWND hwnd, Time time )
{
HWND focus;
Window win;
GUITHREADINFO threadinfo;
+ if (!try_grab_pointer( event->xany.display ))
+ {
+ /* ask the foreground window to release its grab before trying to get ours */
+ SendMessageW( GetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 );
+ XSendEvent( event->xany.display, event->xany.window, False, 0, event );
+ return;
+ }
+
TRACE( "setting foreground window to %p\n", hwnd );
SetForegroundWindow( hwnd );
@@ -613,7 +642,7 @@ static void set_focus( Display *display, HWND hwnd, Time time )
if (win)
{
TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
- XSetInputFocus( display, win, RevertToParent, time );
+ XSetInputFocus( event->xany.display, win, RevertToParent, time );
}
}
@@ -621,8 +650,10 @@ static void set_focus( Display *display, HWND hwnd, Time time )
/**********************************************************************
* handle_manager_message
*/
-static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
+static void handle_manager_message( HWND hwnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
+
if (hwnd != GetDesktopWindow()) return;
if (systray_atom && event->data.l[1] == systray_atom)
change_systray_owner( event->display, event->data.l[2] );
@@ -632,8 +663,9 @@ static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
/**********************************************************************
* handle_wm_protocols
*/
-static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
+static void handle_wm_protocols( HWND hwnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
Atom protocol = (Atom)event->data.l[0];
Time event_time = (Time)event->data.l[1];
@@ -709,7 +741,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
{
- set_focus( event->display, hwnd, event_time );
+ set_focus( xev, hwnd, event_time );
return;
}
}
@@ -718,7 +750,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
hwnd = GetForegroundWindow();
if (!hwnd) hwnd = last_focus;
if (!hwnd) hwnd = GetDesktopWindow();
- set_focus( event->display, hwnd, event_time );
+ set_focus( xev, hwnd, event_time );
return;
}
/* try to find some other window to give the focus to */
@@ -726,7 +758,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
if (!hwnd) hwnd = GetActiveWindow();
if (!hwnd) hwnd = last_focus;
- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time );
}
else if (protocol == x11drv_atom(_NET_WM_PING))
{
@@ -775,30 +807,19 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
if (event->detail == NotifyPointer) return FALSE;
if (hwnd == GetDesktopWindow()) return FALSE;
- switch (event->mode)
- {
- case NotifyGrab:
- WARN( "unexpected FocusIn event with NotifyGrab mode\n" );
- break;
- case NotifyWhileGrabbed:
- keyboard_grabbed = TRUE;
- break;
- case NotifyNormal:
- keyboard_grabbed = FALSE;
- break;
- case NotifyUngrab:
- /* Focus was just restored but it can be right after super was
- * pressed and gnome-shell needs a bit of time to respond and
- * toggle the activity view. If we grab the cursor right away
- * it will cancel it and super key will do nothing.
- */
- if (wm_is_mutter(event->display))
- Sleep(100);
+ /* Focus was just restored but it can be right after super was
+ * pressed and gnome-shell needs a bit of time to respond and
+ * toggle the activity view. If we grab the cursor right away
+ * it will cancel it and super key will do nothing.
+ */
+ if (event->mode == NotifyUngrab && wm_is_mutter(event->display))
+ Sleep(100);
- keyboard_grabbed = FALSE;
- retry_grab_clipping_window();
- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
- }
+ /* ask the foreground window to re-apply the current ClipCursor rect */
+ SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR, 0, 0 );
+
+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
if (use_take_focus)
@@ -813,9 +834,17 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
if (!hwnd) hwnd = GetActiveWindow();
if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime );
+ return TRUE;
+ }
+
+ if (!try_grab_pointer( event->display ))
+ {
+ XSendEvent( event->display, event->window, False, 0, xev );
+ return FALSE;
}
- else SetForegroundWindow( hwnd );
+
+ SetForegroundWindow( hwnd );
return TRUE;
}
@@ -902,28 +931,10 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
}
if (!hwnd) return FALSE;
- switch (event->mode)
- {
- case NotifyUngrab:
- WARN( "unexpected FocusOut event with NotifyUngrab mode\n" );
- break;
- case NotifyNormal:
- keyboard_grabbed = FALSE;
- break;
- case NotifyWhileGrabbed:
- keyboard_grabbed = TRUE;
- break;
- case NotifyGrab:
- keyboard_grabbed = TRUE;
-
- /* This will do nothing due to keyboard_grabbed == TRUE, but it
- * will save the current clipping rect so we can restore it on
- * FocusIn with NotifyUngrab mode.
- */
- retry_grab_clipping_window();
+ if (hwnd == GetForegroundWindow()) ungrab_clipping_window();
- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
- }
+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
focus_out( event->display, hwnd );
return TRUE;
@@ -1790,8 +1801,10 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
/**********************************************************************
* handle_xembed_protocol
*/
-static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
+static void handle_xembed_protocol( HWND hwnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
+
switch (event->data.l[1])
{
case XEMBED_EMBEDDED_NOTIFY:
@@ -1846,8 +1859,9 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
/**********************************************************************
* handle_dnd_protocol
*/
-static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
+static void handle_dnd_protocol( HWND hwnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
Window root, child;
int root_x, root_y, child_x, child_y;
unsigned int u;
@@ -1866,8 +1880,8 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
struct client_message_handler
{
- int atom; /* protocol atom */
- void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
+ int atom; /* protocol atom */
+ void (*handler)(HWND, XEvent *); /* corresponding handler function */
};
static const struct client_message_handler client_messages[] =
@@ -1903,7 +1917,7 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
{
if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
{
- client_messages[i].handler( hwnd, event );
+ client_messages[i].handler( hwnd, xev );
return TRUE;
}
}
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 3c38784ebf..7856b04c8f 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1149,7 +1149,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD f
input.u.ki.time = time;
input.u.ki.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input );
+ __wine_send_input( hwnd, &input, SEND_HWMSG_RAWINPUT|SEND_HWMSG_WINDOW );
}
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 68aecdf90c..cb3cd4b4fd 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -125,9 +125,6 @@ XContext cursor_context = 0;
static HWND cursor_window;
static HCURSOR last_cursor;
static DWORD last_cursor_change;
-static RECT last_clip_rect;
-static HWND last_clip_foreground_window;
-static BOOL last_clip_refused;
static RECT clip_rect;
static Cursor create_cursor( HANDLE handle );
@@ -291,9 +288,9 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator
/***********************************************************************
- * enable_xinput2
+ * X11DRV_XInput2_Enable
*/
-static void enable_xinput2(void)
+void X11DRV_XInput2_Enable(void)
{
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
struct x11drv_thread_data *data = x11drv_thread_data();
@@ -306,12 +303,16 @@ static void enable_xinput2(void)
if (data->xi2_state == xi_unknown)
{
- int major = 2, minor = 0;
- if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled;
+ int major = 2, minor = 1;
+ if (!pXIQueryVersion( data->display, &major, &minor ) && major == 2 && minor > 0)
+ {
+ TRACE( "XInput2 v%d.%d available\n", major, minor );
+ data->xi2_state = xi_disabled;
+ }
else
{
data->xi2_state = xi_unavailable;
- WARN( "X Input 2 not available\n" );
+ WARN( "XInput v2.1 not available\n" );
}
}
if (data->xi2_state == xi_unavailable) return;
@@ -319,11 +320,23 @@ static void enable_xinput2(void)
mask.mask = mask_bits;
mask.mask_len = sizeof(mask_bits);
- mask.deviceid = XIAllDevices;
+ mask.deviceid = XIAllMasterDevices;
memset( mask_bits, 0, sizeof(mask_bits) );
+
XISetMask( mask_bits, XI_DeviceChanged );
XISetMask( mask_bits, XI_RawMotion );
- XISetMask( mask_bits, XI_ButtonPress );
+
+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
+ {
+ XISetMask( mask_bits, XI_RawButtonPress );
+ XISetMask( mask_bits, XI_RawButtonRelease );
+ data->xi2_rawinput_only = TRUE;
+ }
+ else
+ {
+ XISetMask( mask_bits, XI_ButtonPress );
+ data->xi2_rawinput_only = FALSE;
+ }
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
@@ -331,24 +344,14 @@ static void enable_xinput2(void)
update_relative_valuators( pointer_info->classes, pointer_info->num_classes );
pXIFreeDeviceInfo( pointer_info );
- /* This device info list is only used to find the initial current slave if
- * no XI_DeviceChanged events happened. If any hierarchy change occurred that
- * might be relevant here (eg. user switching mice after (un)plugging), a
- * XI_DeviceChanged event will point us to the right slave. So this list is
- * safe to be obtained statically at enable_xinput2() time.
- */
- if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices );
- data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count );
- data->xi2_current_slave = 0;
-
data->xi2_state = xi_enabled;
#endif
}
/***********************************************************************
- * disable_xinput2
+ * X11DRV_XInput2_Disable
*/
-static void disable_xinput2(void)
+void X11DRV_XInput2_Disable(void)
{
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
struct x11drv_thread_data *data = x11drv_thread_data();
@@ -361,17 +364,14 @@ static void disable_xinput2(void)
mask.mask = NULL;
mask.mask_len = 0;
- mask.deviceid = XIAllDevices;
+ mask.deviceid = XIAllMasterDevices;
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
- pXIFreeDeviceInfo( data->xi2_devices );
data->x_rel_valuator.number = -1;
data->y_rel_valuator.number = -1;
data->x_rel_valuator.accum = 0;
data->y_rel_valuator.accum = 0;
- data->xi2_devices = NULL;
data->xi2_core_pointer = 0;
- data->xi2_current_slave = 0;
#endif
}
@@ -385,14 +385,10 @@ static BOOL grab_clipping_window( const RECT *clip )
{
static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
struct x11drv_thread_data *data = x11drv_thread_data();
- static DWORD timeout = 5000;
- static DWORD step = 100;
- DWORD time = 0;
Window clip_window;
HWND msg_hwnd = 0;
POINT pos;
RECT real_clip;
- INT ret;
if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
return TRUE; /* don't clip in the desktop process */
@@ -404,21 +400,8 @@ static BOOL grab_clipping_window( const RECT *clip )
GetModuleHandleW(0), NULL )))
return TRUE;
- if (keyboard_grabbed)
- {
- WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) );
- last_clip_refused = TRUE;
- last_clip_foreground_window = GetForegroundWindow();
- last_clip_rect = *clip;
- return FALSE;
- }
- else
- {
- last_clip_refused = FALSE;
- }
-
/* enable XInput2 unless we are already clipping */
- if (!data->clip_hwnd) enable_xinput2();
+ if (!data->clip_hwnd) X11DRV_XInput2_Enable();
if (data->xi2_state != xi_enabled)
{
@@ -460,25 +443,14 @@ static BOOL grab_clipping_window( const RECT *clip )
clip->right < clip_rect.right || clip->bottom < clip_rect.bottom)
data->warp_serial = NextRequest( data->display );
- /* Some windows managers temporarily grab the pointer during window transition. Retry grabbing. */
- do
- {
- ret = XGrabPointer( data->display, clip_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
- GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime );
- if (ret == AlreadyGrabbed || ret == GrabFrozen)
- {
- time += step;
- Sleep(step);
- }
- } while ((ret == AlreadyGrabbed || ret == GrabFrozen) && time < timeout);
-
- if (ret == GrabSuccess)
+ if (!XGrabPointer( data->display, clip_window, False,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime ))
clipping_cursor = TRUE;
if (!clipping_cursor)
{
- ERR("Failed to grab pointer\n");
- disable_xinput2();
+ X11DRV_XInput2_Disable();
DestroyWindow( msg_hwnd );
return FALSE;
}
@@ -521,20 +493,6 @@ void reset_clipping_window(void)
ClipCursor( NULL ); /* make sure the clip rectangle is reset too */
}
-/***********************************************************************
- * retry_grab_clipping_window
- *
- * Restore the current clip rectangle or retry the last one if it has
- * been refused because of an active keyboard grab.
- */
-void retry_grab_clipping_window(void)
-{
- if (clipping_cursor)
- ClipCursor( &clip_rect );
- else if (last_clip_refused && GetForegroundWindow() == last_clip_foreground_window)
- ClipCursor( &last_clip_rect );
-}
-
BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
/***********************************************************************
@@ -560,7 +518,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd )
TRACE( "clip hwnd reset from %p\n", hwnd );
data->clip_hwnd = 0;
data->clip_reset = GetTickCount();
- disable_xinput2();
+ X11DRV_XInput2_Disable();
DestroyWindow( hwnd );
}
else if (hwnd == GetForegroundWindow()) /* request to clip */
@@ -672,7 +630,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
input->u.mi.dx = pt.x;
input->u.mi.dy = pt.y;
- __wine_send_input( hwnd, input );
+ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW );
return;
}
@@ -739,7 +697,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
input->u.mi.dx = pt.x;
input->u.mi.dy = pt.y;
- __wine_send_input( hwnd, input );
+ __wine_send_input( hwnd, input, SEND_HWMSG_WINDOW );
}
#ifdef SONAME_LIBXCURSOR
@@ -1533,12 +1491,6 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y )
TRACE("real setting to %u, %u\n",
pos.x, pos.y);
- if (keyboard_grabbed)
- {
- WARN( "refusing to warp to %u, %u\n", pos.x, pos.y );
- return FALSE;
- }
-
if (!clipping_cursor &&
XGrabPointer( data->display, root_window, False,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
@@ -1693,7 +1645,7 @@ void move_resize_window( HWND hwnd, int dir )
input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input.u.mi.time = GetTickCount();
input.u.mi.dwExtraInfo = 0;
- __wine_send_input( hwnd, &input );
+ __wine_send_input( hwnd, &input, SEND_HWMSG_WINDOW );
}
while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
@@ -1837,7 +1789,6 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev )
if (event->reason != XISlaveSwitch) return FALSE;
update_relative_valuators( event->classes, event->num_classes );
- data->xi2_current_slave = event->sourceid;
return TRUE;
}
@@ -1859,30 +1810,12 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE;
if (!event->valuators.mask_len) return FALSE;
if (thread_data->xi2_state != xi_enabled) return FALSE;
-
- /* If there is no slave currently detected, no previous motion nor device
- * change events were received. Look it up now on the device list in this
- * case.
- */
- if (!thread_data->xi2_current_slave)
- {
- XIDeviceInfo *devices = thread_data->xi2_devices;
-
- for (i = 0; i < thread_data->xi2_device_count; i++)
- {
- if (devices[i].use != XISlavePointer) continue;
- if (devices[i].deviceid != event->deviceid) continue;
- if (devices[i].attachment != thread_data->xi2_core_pointer) continue;
- thread_data->xi2_current_slave = event->deviceid;
- break;
- }
- }
-
- if (event->deviceid != thread_data->xi2_current_slave) return FALSE;
+ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE;
x_rel = &thread_data->x_rel_valuator;
y_rel = &thread_data->y_rel_valuator;
+ input.type = INPUT_MOUSE;
input.u.mi.mouseData = 0;
input.u.mi.dwFlags = MOUSEEVENTF_MOVE;
input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
@@ -1940,10 +1873,44 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
input.u.mi.dx = pt.x;
input.u.mi.dy = pt.y;
- TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum );
+ if (!thread_data->xi2_rawinput_only)
+ {
+ TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum );
+ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW );
+ }
+ else
+ {
+ TRACE( "raw pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum );
+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT );
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ * X11DRV_RawButtonEvent
+ */
+static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie )
+{
+ struct x11drv_thread_data *thread_data = x11drv_thread_data();
+ XIRawEvent *event = cookie->data;
+ int button = event->detail - 1;
+ INPUT input;
- input.type = INPUT_MOUSE;
- __wine_send_input( 0, &input );
+ if (button >= NB_BUTTONS) return FALSE;
+ if (thread_data->xi2_state != xi_enabled) return FALSE;
+ if (event->deviceid != thread_data->xi2_core_pointer) return FALSE;
+
+ TRACE( "raw button %u %s\n", button, event->evtype == XI_RawButtonRelease ? "up" : "down" );
+
+ input.type = INPUT_MOUSE;
+ input.u.mi.dx = 0;
+ input.u.mi.dy = 0;
+ input.u.mi.mouseData = event->evtype == XI_RawButtonRelease ? button_up_data[button] : button_down_data[button];
+ input.u.mi.dwFlags = event->evtype == XI_RawButtonRelease ? button_up_flags[button] : button_down_flags[button];
+ input.u.mi.time = EVENT_x11_time_to_win32_time(event->time);
+ input.u.mi.dwExtraInfo = 0;
+
+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT );
return TRUE;
}
@@ -2011,6 +1978,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
case XI_RawMotion:
ret = X11DRV_RawMotion( event );
break;
+ case XI_RawButtonPress:
+ case XI_RawButtonRelease:
+ ret = X11DRV_RawButtonEvent( event );
+ break;
default:
TRACE( "Unhandled event %#x\n", event->evtype );
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index 115b287422..d7422a8c63 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -2996,6 +2996,9 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
return 0;
case WM_X11DRV_CLIP_CURSOR:
return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp );
+ case WM_X11DRV_RELEASE_CURSOR:
+ ungrab_clipping_window();
+ return 0;
default:
FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
return 0;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index b9bdda88cd..adfbe9700f 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -198,6 +198,8 @@ extern BOOL CDECL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN;
extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN;
extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN;
+extern void X11DRV_XInput2_Enable(void) DECLSPEC_HIDDEN;
+extern void X11DRV_XInput2_Disable(void) DECLSPEC_HIDDEN;
extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
@@ -242,10 +244,10 @@ extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp,
DWORD dwReadLen) DECLSPEC_HIDDEN;
extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN;
+extern void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN;
+extern void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN;
+extern void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN;
+extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN;
extern void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection,
Atom *targets, UINT count,
void (*callback)( Atom, UINT, HANDLE )) DECLSPEC_HIDDEN;
@@ -343,12 +345,10 @@ struct x11drv_thread_data
DWORD clip_reset; /* time when clipping was last reset */
HKL kbd_layout; /* active keyboard layout */
enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */
- void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */
- int xi2_device_count;
struct x11drv_valuator_data x_rel_valuator;
struct x11drv_valuator_data y_rel_valuator;
int xi2_core_pointer; /* XInput2 core pointer id */
- int xi2_current_slave; /* Current slave driving the Core pointer */
+ int xi2_rawinput_only;
};
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN;
@@ -389,7 +389,6 @@ extern Colormap default_colormap DECLSPEC_HIDDEN;
extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN;
extern Window root_window DECLSPEC_HIDDEN;
extern BOOL clipping_cursor DECLSPEC_HIDDEN;
-extern BOOL keyboard_grabbed DECLSPEC_HIDDEN;
extern unsigned int screen_bpp DECLSPEC_HIDDEN;
extern BOOL use_xkb DECLSPEC_HIDDEN;
extern BOOL usexrandr DECLSPEC_HIDDEN;
@@ -545,7 +544,8 @@ enum x11drv_window_messages
WM_X11DRV_SET_WIN_REGION,
WM_X11DRV_RESIZE_DESKTOP,
WM_X11DRV_SET_CURSOR,
- WM_X11DRV_CLIP_CURSOR
+ WM_X11DRV_CLIP_CURSOR,
+ WM_X11DRV_RELEASE_CURSOR
};
/* _NET_WM_STATE properties that we keep track of */
@@ -662,7 +662,6 @@ extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN;
extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN;
extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
-extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN;
extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN;
extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 820668b045..90e907b8c8 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -645,6 +645,8 @@ void CDECL X11DRV_ThreadDetach(void)
if (data)
{
+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
+ X11DRV_XInput2_Disable();
if (data->xim) XCloseIM( data->xim );
if (data->font_set) XFreeFontSet( data->display, data->font_set );
XCloseDisplay( data->display );
@@ -719,6 +721,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
TlsSetValue( thread_data_tls_index, data );
if (use_xim) X11DRV_SetupXIM();
+ if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
+ X11DRV_XInput2_Enable();
return data;
}
diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c
index 1f7f0d932b..960c9f75a3 100644
--- a/dlls/winex11.drv/xdnd.c
+++ b/dlls/winex11.drv/xdnd.c
@@ -192,8 +192,9 @@ static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect)
*
* Handle an XdndEnter event.
*/
-void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event )
+void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
int version;
Atom *xdndtypes;
unsigned long count = 0;
@@ -291,8 +292,9 @@ static HWND window_accepting_files(HWND hwnd)
*
* Handle an XdndPosition event.
*/
-void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
+void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
XClientMessageEvent e;
int accept = 0; /* Assume we're not accepting */
IDropTarget *dropTarget = NULL;
@@ -405,8 +407,9 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
*
* Handle an XdndDrop event.
*/
-void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
+void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev )
{
+ XClientMessageEvent *event = &xev->xclient;
XClientMessageEvent e;
IDropTarget *dropTarget;
DWORD effect = XDNDDropEffect;
@@ -499,7 +502,7 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
*
* Handle an XdndLeave event.
*/
-void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event )
+void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev )
{
IDropTarget *dropTarget;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index f0c8f88732..1df698df4c 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -305,6 +305,13 @@ struct hardware_msg_data
int y;
unsigned int data;
} mouse;
+ struct
+ {
+ int type;
+ obj_handle_t device;
+ unsigned int length;
+
+ } hid;
} rawinput;
};
@@ -351,7 +358,19 @@ typedef union
unsigned int msg;
lparam_t lparam;
} hw;
+ struct
+ {
+ int type;
+ obj_handle_t device;
+ unsigned char usage_page;
+ unsigned char usage;
+ unsigned int length;
+ } hid;
} hw_input_t;
+#define HW_INPUT_MOUSE 0
+#define HW_INPUT_KEYBOARD 1
+#define HW_INPUT_HARDWARE 2
+#define HW_INPUT_HID 3
typedef union
{
@@ -3233,6 +3252,7 @@ struct send_hardware_message_request
user_handle_t win;
hw_input_t input;
unsigned int flags;
+ /* VARARG(data,bytes); */
char __pad_52[4];
};
struct send_hardware_message_reply
@@ -3247,6 +3267,8 @@ struct send_hardware_message_reply
char __pad_28[4];
};
#define SEND_HWMSG_INJECTED 0x01
+#define SEND_HWMSG_RAWINPUT 0x02
+#define SEND_HWMSG_WINDOW 0x04
@@ -5825,6 +5847,19 @@ struct update_rawinput_devices_reply
};
+struct get_rawinput_devices_request
+{
+ struct request_header __header;
+ char __pad_12[4];
+};
+struct get_rawinput_devices_reply
+{
+ struct reply_header __header;
+ unsigned int device_count;
+ /* VARARG(devices,rawinput_devices); */
+ char __pad_12[4];
+};
+
struct get_suspend_context_request
{
@@ -6465,6 +6500,7 @@ enum request
REQ_free_user_handle,
REQ_set_cursor,
REQ_update_rawinput_devices,
+ REQ_get_rawinput_devices,
REQ_get_suspend_context,
REQ_set_suspend_context,
REQ_create_job,
@@ -6792,6 +6828,7 @@ union generic_request
struct free_user_handle_request free_user_handle_request;
struct set_cursor_request set_cursor_request;
struct update_rawinput_devices_request update_rawinput_devices_request;
+ struct get_rawinput_devices_request get_rawinput_devices_request;
struct get_suspend_context_request get_suspend_context_request;
struct set_suspend_context_request set_suspend_context_request;
struct create_job_request create_job_request;
@@ -7117,6 +7154,7 @@ union generic_reply
struct free_user_handle_reply free_user_handle_reply;
struct set_cursor_reply set_cursor_reply;
struct update_rawinput_devices_reply update_rawinput_devices_reply;
+ struct get_rawinput_devices_reply get_rawinput_devices_reply;
struct get_suspend_context_reply get_suspend_context_reply;
struct set_suspend_context_reply set_suspend_context_reply;
struct create_job_reply create_job_reply;
diff --git a/include/winuser.h b/include/winuser.h
index 51c73d25c2..10cebfa97d 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -4389,7 +4389,7 @@ static inline BOOL WINAPI SetRectEmpty(LPRECT rect)
WORD WINAPI SYSTEM_KillSystemTimer( WORD );
#ifdef __WINESRC__
-WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input );
+WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, UINT flags );
#endif
#ifdef __cplusplus
diff --git a/server/protocol.def b/server/protocol.def
index ccbb57e8ad..610efa8cb8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -321,6 +321,13 @@ struct hardware_msg_data
int y; /* y coordinate */
unsigned int data; /* mouse data */
} mouse;
+ struct
+ {
+ int type; /* RIM_TYPEHID */
+ obj_handle_t device;
+ unsigned int length; /* HID report length */
+ /* followed by length bytes of HID report data */
+ } hid;
} rawinput;
};
@@ -344,7 +351,7 @@ typedef union
int type;
struct
{
- int type; /* INPUT_KEYBOARD */
+ int type; /* HW_INPUT_KEYBOARD */
unsigned short vkey; /* virtual key code */
unsigned short scan; /* scan code */
unsigned int flags; /* event flags */
@@ -353,7 +360,7 @@ typedef union
} kbd;
struct
{
- int type; /* INPUT_MOUSE */
+ int type; /* HW_INPUT_MOUSE */
int x; /* coordinates */
int y;
unsigned int data; /* mouse data */
@@ -363,11 +370,23 @@ typedef union
} mouse;
struct
{
- int type; /* INPUT_HARDWARE */
+ int type; /* HW_INPUT_HARDWARE */
unsigned int msg; /* message code */
lparam_t lparam; /* message param */
} hw;
+ struct
+ {
+ int type; /* HW_INPUT_HID */
+ obj_handle_t device;
+ unsigned char usage_page;
+ unsigned char usage;
+ unsigned int length;
+ } hid;
} hw_input_t;
+#define HW_INPUT_MOUSE 0
+#define HW_INPUT_KEYBOARD 1
+#define HW_INPUT_HARDWARE 2
+#define HW_INPUT_HID 3
typedef union
{
@@ -2361,6 +2380,7 @@ enum message_type
user_handle_t win; /* window handle */
hw_input_t input; /* input data */
unsigned int flags; /* flags (see below) */
+ VARARG(data,bytes); /* hid report data */
@REPLY
int wait; /* do we need to wait for a reply? */
int prev_x; /* previous cursor position */
@@ -2370,6 +2390,8 @@ enum message_type
VARARG(keystate,bytes); /* global state array for all the keys */
@END
#define SEND_HWMSG_INJECTED 0x01
+#define SEND_HWMSG_RAWINPUT 0x02
+#define SEND_HWMSG_WINDOW 0x04
/* Get a message from the current queue */
@@ -3985,6 +4007,12 @@ struct handle_info
VARARG(devices,rawinput_devices);
@END
+/* Retrieve the list of registered rawinput devices */
+@REQ(get_rawinput_devices)
+@REPLY
+ unsigned int device_count;
+ VARARG(devices,rawinput_devices);
+@END
/* Retrieve the suspended context of a thread */
@REQ(get_suspend_context)
diff --git a/server/queue.c b/server/queue.c
index 2bc11789b2..848089dca7 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -409,13 +409,13 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_
/* allocate a hardware message and its data */
static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_source source,
- unsigned int time )
+ unsigned int time, data_size_t extra_len )
{
struct hardware_msg_data *msg_data;
struct message *msg;
if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL;
- if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
+ if (!(msg_data = mem_alloc( sizeof(*msg_data) + extra_len )))
{
free( msg );
return NULL;
@@ -424,9 +424,9 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour
msg->type = MSG_HARDWARE;
msg->time = time;
msg->data = msg_data;
- msg->data_size = sizeof(*msg_data);
+ msg->data_size = sizeof(*msg_data) + extra_len;
- memset( msg_data, 0, sizeof(*msg_data) );
+ memset( msg_data, 0, sizeof(*msg_data) + extra_len );
msg_data->info = info;
msg_data->source = source;
return msg;
@@ -438,7 +438,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y )
static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
struct message *msg;
- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
+ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->msg = WM_MOUSEMOVE;
msg->x = x;
@@ -1597,11 +1597,11 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru
return win;
}
-static struct rawinput_device_entry *find_rawinput_device( unsigned short usage_page, unsigned short usage )
+static struct rawinput_device_entry *find_rawinput_device( struct process *process, unsigned short usage_page, unsigned short usage )
{
struct rawinput_device_entry *e;
- LIST_FOR_EACH_ENTRY( e, &current->process->rawinput_devices, struct rawinput_device_entry, entry )
+ LIST_FOR_EACH_ENTRY( e, &process->rawinput_devices, struct rawinput_device_entry, entry )
{
if (e->device.usage_page != usage_page || e->device.usage != usage) continue;
return e;
@@ -1614,7 +1614,7 @@ static void update_rawinput_device(const struct rawinput_device *device)
{
struct rawinput_device_entry *e;
- if (!(e = find_rawinput_device( device->usage_page, device->usage )))
+ if (!(e = find_rawinput_device( current->process, device->usage_page, device->usage )))
{
if (!(e = mem_alloc( sizeof(*e) ))) return;
list_add_tail( &current->process->rawinput_devices, &e->entry );
@@ -1719,7 +1719,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
struct msg_queue *queue;
struct message *msg;
timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */
- int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL;
+ int id = (input->type == HW_INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL;
if (!(hook_thread = get_first_global_hook( id ))) return 0;
if (!(queue = hook_thread->queue)) return 0;
@@ -1737,7 +1737,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
msg->data_size = hardware_msg->data_size;
msg->result = NULL;
- if (input->type == INPUT_KEYBOARD)
+ if (input->type == HW_INPUT_KEYBOARD)
{
unsigned short vkey = input->kbd.vkey;
if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET;
@@ -1758,12 +1758,79 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
return 1;
}
+struct rawinput_message
+{
+ struct desktop *desktop;
+ struct hw_msg_source source;
+ unsigned int time;
+ unsigned char usage_page;
+ unsigned char usage;
+ struct hardware_msg_data data;
+ const void *extra;
+ data_size_t extra_len;
+};
+
+static int queue_rawinput_message( struct process* process, void* user )
+{
+ const struct rawinput_message* raw_msg = user;
+ const struct rawinput_device_entry *entry;
+ const struct rawinput_device *device = NULL;
+ struct desktop *desktop = NULL;
+ struct thread *thread = NULL, *foreground = NULL;
+ struct message *msg;
+ struct hardware_msg_data *msg_data;
+
+ if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE)
+ device = process->rawinput_mouse;
+ else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD)
+ device = process->rawinput_kbd;
+ else if ((entry = find_rawinput_device( process, raw_msg->usage_page, raw_msg->usage )))
+ device = &entry->device;
+
+ if (!device)
+ goto done;
+
+ if (!(desktop = get_desktop_obj( process, process->desktop, 0 )) ||
+ (raw_msg->desktop && desktop != raw_msg->desktop))
+ goto done;
+
+ if (!(thread = get_window_thread( device->target ? device->target : desktop->foreground_input->active )) ||
+ process != thread->process)
+ goto done;
+
+ /* FIXME: Implement RIDEV_INPUTSINK */
+ if (!(foreground = get_window_thread( desktop->foreground_input->active )) ||
+ thread->process != foreground->process)
+ goto done;
+
+ if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time, raw_msg->extra_len )))
+ goto done;
+ msg_data = msg->data;
+
+ msg->win = device->target;
+ msg->msg = WM_INPUT;
+ msg->wparam = RIM_INPUT;
+ msg->lparam = 0;
+
+ memcpy( msg_data, &raw_msg->data, sizeof(*msg_data) );
+ if (raw_msg->extra_len && raw_msg->extra)
+ memcpy( msg_data + 1, raw_msg->extra, raw_msg->extra_len );
+
+ queue_hardware_message( desktop, msg, 0 );
+
+done:
+ if (foreground) release_object( foreground );
+ if (thread) release_object( thread );
+ if (desktop) release_object( desktop );
+ return 0;
+}
+
/* queue a hardware message for a mouse event */
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
- unsigned int origin, struct msg_queue *sender )
+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags )
{
- const struct rawinput_device *device;
struct hardware_msg_data *msg_data;
+ struct rawinput_message raw_msg;
struct message *msg;
unsigned int i, time, flags;
struct hw_msg_source source = { IMDT_MOUSE, origin };
@@ -1813,32 +1880,38 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
y = desktop->cursor.y;
}
- if ((device = current->process->rawinput_mouse))
+ if (req_flags & SEND_HWMSG_RAWINPUT)
{
- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0;
- msg_data = msg->data;
-
- msg->win = device->target;
- msg->msg = WM_INPUT;
- msg->wparam = RIM_INPUT;
- msg->lparam = 0;
+ raw_msg.desktop = desktop;
+ raw_msg.source = source;
+ raw_msg.time = time;
+ raw_msg.extra = NULL;
+ raw_msg.extra_len = 0;
+ msg_data = &raw_msg.data;
+ msg_data->info = input->mouse.info;
msg_data->flags = flags;
msg_data->rawinput.type = RIM_TYPEMOUSE;
msg_data->rawinput.mouse.x = x - desktop->cursor.x;
msg_data->rawinput.mouse.y = y - desktop->cursor.y;
msg_data->rawinput.mouse.data = input->mouse.data;
- queue_hardware_message( desktop, msg, 0 );
+ if (req_flags == SEND_HWMSG_RAWINPUT)
+ enum_processes( queue_rawinput_message, &raw_msg );
+ else
+ queue_rawinput_message( current->process, &raw_msg );
}
+ if (!(req_flags & SEND_HWMSG_WINDOW))
+ return 0;
+
for (i = 0; i < ARRAY_SIZE( messages ); i++)
{
if (!messages[i]) continue;
if (!(flags & (1 << i))) continue;
flags &= ~(1 << i);
- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0;
+ if (!(msg = alloc_hardware_message( input->mouse.info, source, time, 0 ))) return 0;
msg_data = msg->data;
msg->win = get_user_full_handle( win );
@@ -1863,11 +1936,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
/* queue a hardware message for a keyboard event */
static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
- unsigned int origin, struct msg_queue *sender )
+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags )
{
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;
unsigned char vkey = input->kbd.vkey;
unsigned int message_code, time;
@@ -1939,25 +2012,32 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
break;
}
- if ((device = current->process->rawinput_kbd))
+ if (req_flags & SEND_HWMSG_RAWINPUT)
{
- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
- msg_data = msg->data;
-
- msg->win = device->target;
- msg->msg = WM_INPUT;
- msg->wparam = RIM_INPUT;
+ raw_msg.desktop = desktop;
+ raw_msg.source = source;
+ raw_msg.time = time;
+ raw_msg.extra = NULL;
+ raw_msg.extra_len = 0;
+ msg_data = &raw_msg.data;
+ msg_data->info = input->kbd.info;
msg_data->flags = input->kbd.flags;
msg_data->rawinput.type = RIM_TYPEKEYBOARD;
msg_data->rawinput.kbd.message = message_code;
msg_data->rawinput.kbd.vkey = vkey;
msg_data->rawinput.kbd.scan = input->kbd.scan;
- queue_hardware_message( desktop, msg, 0 );
+ if (req_flags == SEND_HWMSG_RAWINPUT)
+ enum_processes( queue_rawinput_message, &raw_msg );
+ else
+ queue_rawinput_message( current->process, &raw_msg );
}
- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
+ if (!(req_flags & SEND_HWMSG_WINDOW))
+ return 0;
+
+ if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0;
msg_data = msg->data;
msg->win = get_user_full_handle( win );
@@ -1995,7 +2075,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_
struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };
struct message *msg;
- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
+ if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->win = get_user_full_handle( win );
msg->msg = input->hw.msg;
@@ -2007,6 +2087,38 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_
queue_hardware_message( desktop, msg, 1 );
}
+/* queue a hardware message for an hid event */
+static void queue_hid_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
+ unsigned int origin, struct msg_queue *sender, unsigned int req_flags,
+ const void *report, data_size_t report_len )
+{
+ struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };
+ struct hardware_msg_data *msg_data;
+ struct rawinput_message raw_msg;
+
+ if (!(req_flags & SEND_HWMSG_RAWINPUT))
+ return;
+
+ raw_msg.desktop = NULL; /* send to all desktops */
+ raw_msg.source = source;
+ raw_msg.time = get_tick_count();
+ raw_msg.usage_page = input->hid.usage_page;
+ raw_msg.usage = input->hid.usage;
+ raw_msg.extra = report;
+ raw_msg.extra_len = report_len;
+
+ msg_data = &raw_msg.data;
+ msg_data->flags = 0;
+ msg_data->rawinput.type = RIM_TYPEHID;
+ msg_data->rawinput.hid.device = input->hid.device;
+ msg_data->rawinput.hid.length = report_len;
+
+ if (req_flags == SEND_HWMSG_RAWINPUT)
+ enum_processes( queue_rawinput_message, &raw_msg );
+ else
+ queue_rawinput_message( current->process, &raw_msg );
+}
+
/* check message filter for a hardware message */
static int check_hw_message_filter( user_handle_t win, unsigned int msg_code,
user_handle_t filter_win, unsigned int first, unsigned int last )
@@ -2520,15 +2632,18 @@ DECL_HANDLER(send_hardware_message)
switch (req->input.type)
{
- case INPUT_MOUSE:
- reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender );
+ case HW_INPUT_MOUSE:
+ reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags );
break;
- case INPUT_KEYBOARD:
- reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender );
+ case HW_INPUT_KEYBOARD:
+ reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags );
break;
- case INPUT_HARDWARE:
+ case HW_INPUT_HARDWARE:
queue_custom_hardware_message( desktop, req->win, origin, &req->input );
break;
+ case HW_INPUT_HID:
+ queue_hid_message( desktop, req->win, &req->input, origin, sender, req->flags, get_req_data(), get_req_data_size() );
+ break;
default:
set_error( STATUS_INVALID_PARAMETER );
}
@@ -3329,9 +3444,9 @@ DECL_HANDLER(update_rawinput_devices)
update_rawinput_device(&devices[i]);
}
- e = find_rawinput_device( 1, 2 );
+ e = find_rawinput_device( current->process, 1, 2 );
current->process->rawinput_mouse = e ? &e->device : NULL;
- e = find_rawinput_device( 1, 6 );
+ e = find_rawinput_device( current->process, 1, 6 );
current->process->rawinput_kbd = e ? &e->device : NULL;
}
@@ -3360,3 +3475,27 @@ DECL_HANDLER(fsync_msgwait)
if (queue->fd)
set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 );
}
+
+DECL_HANDLER(get_rawinput_devices)
+{
+ unsigned int device_count = list_count(&current->process->rawinput_devices);
+ struct rawinput_device *devices;
+ struct rawinput_device_entry *e;
+ unsigned int i;
+
+ reply->device_count = device_count;
+ if (get_reply_max_size() / sizeof (*devices) < device_count)
+ return;
+
+ if (!(devices = mem_alloc( device_count * sizeof (*devices) )))
+ {
+ set_error( STATUS_NO_MEMORY );
+ return;
+ }
+
+ i = 0;
+ LIST_FOR_EACH_ENTRY( e, &current->process->rawinput_devices, struct rawinput_device_entry, entry )
+ devices[i++] = e->device;
+
+ set_reply_data_ptr( devices, device_count * sizeof (*devices) );
+}
diff --git a/server/request.h b/server/request.h
index 24fdd761e3..8cc1a9b38c 100644
--- a/server/request.h
+++ b/server/request.h
@@ -411,6 +411,7 @@ DECL_HANDLER(alloc_user_handle);
DECL_HANDLER(free_user_handle);
DECL_HANDLER(set_cursor);
DECL_HANDLER(update_rawinput_devices);
+DECL_HANDLER(get_rawinput_devices);
DECL_HANDLER(get_suspend_context);
DECL_HANDLER(set_suspend_context);
DECL_HANDLER(create_job);
@@ -737,6 +738,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_free_user_handle,
(req_handler)req_set_cursor,
(req_handler)req_update_rawinput_devices,
+ (req_handler)req_get_rawinput_devices,
(req_handler)req_get_suspend_context,
(req_handler)req_set_suspend_context,
(req_handler)req_create_job,
@@ -2507,6 +2509,9 @@ C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, new_clip) == 32 );
C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, last_change) == 48 );
C_ASSERT( sizeof(struct set_cursor_reply) == 56 );
C_ASSERT( sizeof(struct update_rawinput_devices_request) == 16 );
+C_ASSERT( sizeof(struct get_rawinput_devices_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_rawinput_devices_reply, device_count) == 8 );
+C_ASSERT( sizeof(struct get_rawinput_devices_reply) == 16 );
C_ASSERT( sizeof(struct get_suspend_context_request) == 16 );
C_ASSERT( sizeof(struct get_suspend_context_reply) == 8 );
C_ASSERT( sizeof(struct set_suspend_context_request) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 524a989401..f3150b607a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -381,24 +381,28 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input )
{
switch (input->type)
{
- case INPUT_MOUSE:
+ case HW_INPUT_MOUSE:
fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,time=%u",
prefix, input->mouse.x, input->mouse.y, input->mouse.data, input->mouse.flags,
input->mouse.time );
dump_uint64( ",info=", &input->mouse.info );
fputc( '}', stderr );
break;
- case INPUT_KEYBOARD:
+ case HW_INPUT_KEYBOARD:
fprintf( stderr, "%s{type=KEYBOARD,vkey=%04hx,scan=%04hx,flags=%08x,time=%u",
prefix, input->kbd.vkey, input->kbd.scan, input->kbd.flags, input->kbd.time );
dump_uint64( ",info=", &input->kbd.info );
fputc( '}', stderr );
break;
- case INPUT_HARDWARE:
+ case HW_INPUT_HARDWARE:
fprintf( stderr, "%s{type=HARDWARE,msg=%04x", prefix, input->hw.msg );
dump_uint64( ",lparam=", &input->hw.lparam );
fputc( '}', stderr );
break;
+ case HW_INPUT_HID:
+ fprintf( stderr, "%s{type=HID,device=%04x,usage_page=%02x,usage=%02x,length=%04x}",
+ prefix, input->hid.device, input->hid.usage_page, input->hid.usage, input->hid.length );
+ break;
default:
fprintf( stderr, "%s{type=%04x}", prefix, input->type );
break;
@@ -2876,6 +2880,7 @@ static void dump_send_hardware_message_request( const struct send_hardware_messa
fprintf( stderr, " win=%08x", req->win );
dump_hw_input( ", input=", &req->input );
fprintf( stderr, ", flags=%08x", req->flags );
+ dump_varargs_bytes( ", data=", cur_size );
}
static void dump_send_hardware_message_reply( const struct send_hardware_message_reply *req )
@@ -4636,6 +4641,16 @@ static void dump_update_rawinput_devices_request( const struct update_rawinput_d
dump_varargs_rawinput_devices( " devices=", cur_size );
}
+static void dump_get_rawinput_devices_request( const struct get_rawinput_devices_request *req )
+{
+}
+
+static void dump_get_rawinput_devices_reply( const struct get_rawinput_devices_reply *req )
+{
+ fprintf( stderr, " device_count=%08x", req->device_count );
+ dump_varargs_rawinput_devices( ", devices=", cur_size );
+}
+
static void dump_get_suspend_context_request( const struct get_suspend_context_request *req )
{
}
@@ -5134,6 +5149,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_free_user_handle_request,
(dump_func)dump_set_cursor_request,
(dump_func)dump_update_rawinput_devices_request,
+ (dump_func)dump_get_rawinput_devices_request,
(dump_func)dump_get_suspend_context_request,
(dump_func)dump_set_suspend_context_request,
(dump_func)dump_create_job_request,
@@ -5457,6 +5473,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
NULL,
(dump_func)dump_set_cursor_reply,
NULL,
+ (dump_func)dump_get_rawinput_devices_reply,
(dump_func)dump_get_suspend_context_reply,
NULL,
(dump_func)dump_create_job_reply,
@@ -5780,6 +5797,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"free_user_handle",
"set_cursor",
"update_rawinput_devices",
+ "get_rawinput_devices",
"get_suspend_context",
"set_suspend_context",
"create_job",
From e356bcaf352618618e15d1ded10183852a59c7bf Mon Sep 17 00:00:00 2001
From: Andrew Eikum <aeikum@codeweavers.com>
Date: Tue, 17 Dec 2019 08:19:04 -0600
Subject: [PATCH] winex11: Apply X pointer mapping to RawButton events
+
---
dlls/winex11.drv/keyboard.c | 23 +++++++++++++++++------
dlls/winex11.drv/mouse.c | 34 +++++++++++++++++++++++++++++++++-
dlls/winex11.drv/x11drv.h | 1 +
dlls/winex11.drv/x11drv_main.c | 1 +
4 files changed, 52 insertions(+), 7 deletions(-)
+
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 73670adbe32..cfffad03ed6 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1977,13 +1977,24 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
{
HWND hwnd;
- XRefreshKeyboardMapping(&event->xmapping);
- X11DRV_InitKeyboard( event->xmapping.display );
+ switch (event->xmapping.request)
+ {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping( &event->xmapping );
+ X11DRV_InitKeyboard( event->xmapping.display );
+
+ hwnd = GetFocus();
+ if (!hwnd) hwnd = GetActiveWindow();
+ PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
+ 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
+ break;
+
+ case MappingPointer:
+ X11DRV_InitMouse( event->xmapping.display );
+ break;
+ }
- hwnd = GetFocus();
- if (!hwnd) hwnd = GetActiveWindow();
- PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
- 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
return TRUE;
}
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index cb3cd4b4fd0..b8282532855 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -120,6 +120,8 @@ static const UINT button_up_data[NB_BUTTONS] =
XBUTTON2
};
+static unsigned char *x_pointer_map;
+
XContext cursor_context = 0;
static HWND cursor_window;
@@ -140,6 +142,26 @@ MAKE_FUNCPTR(XISelectEvents);
#undef MAKE_FUNCPTR
#endif
+void X11DRV_InitMouse( Display *display )
+{
+ int i, n_buttons;
+ unsigned char *new_map, *old_map;
+
+ n_buttons = XGetPointerMapping(display, NULL, 0);
+
+ new_map = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_map) * n_buttons);
+
+ /* default mapping */
+ for (i = 0; i < n_buttons; ++i)
+ new_map[i] = i + 1;
+
+ XGetPointerMapping(display, new_map, n_buttons);
+
+ old_map = InterlockedExchangePointer((void**)&x_pointer_map, new_map);
+
+ HeapFree(GetProcessHeap(), 0, old_map);
+}
+
/***********************************************************************
* X11DRV_Xcursor_Init
*
@@ -1886,6 +1908,16 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
return TRUE;
}
+/* apply current X pointer map to raw button event */
+static unsigned char translate_raw_button(int from)
+{
+ unsigned char *cur_map = x_pointer_map;
+
+ if (!cur_map) return from;
+
+ return cur_map[from - 1];
+}
+
/***********************************************************************
* X11DRV_RawButtonEvent
*/
@@ -1893,7 +1925,7 @@ static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie )
{
struct x11drv_thread_data *thread_data = x11drv_thread_data();
XIRawEvent *event = cookie->data;
- int button = event->detail - 1;
+ int button = translate_raw_button(event->detail) - 1;
INPUT input;
if (button >= NB_BUTTONS) return FALSE;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 08a424740ce..7a6c8596d9a 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -661,6 +661,7 @@ extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN;
extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
+extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN;
extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout,
DWORD mask, DWORD flags ) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index c031a5639aa..c8b3fdeeed8 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -601,6 +601,7 @@ static BOOL process_attach(void)
if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
#endif
X11DRV_InitKeyboard( gdi_display );
+ X11DRV_InitMouse( gdi_display );
if (use_xim) use_xim = X11DRV_InitXIM( input_style );
X11DRV_DisplayDevices_Init(FALSE);
From 08cdf3ab0a650876f1e326f2d66b3f1e4acb4208 Mon Sep 17 00:00:00 2001
From: Andrew Eikum <aeikum@codeweavers.com>
Date: Tue, 17 Dec 2019 12:27:44 -0600
Subject: [PATCH] winex11: Apply device mapping to RawButton events
+
---
dlls/winex11.drv/mouse.c | 71 ++++++++++++++++++++++++++++++++++++----
1 file changed, 64 insertions(+), 7 deletions(-)
+
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index b8282532855..110edc8ce75 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -25,6 +25,9 @@
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <stdarg.h>
+#ifdef HAVE_X11_EXTENSIONS_XINPUT_H
+#include <X11/extensions/XInput.h>
+#endif
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
#include <X11/extensions/XInput2.h>
#endif
@@ -139,6 +142,9 @@ MAKE_FUNCPTR(XIFreeDeviceInfo);
MAKE_FUNCPTR(XIQueryDevice);
MAKE_FUNCPTR(XIQueryVersion);
MAKE_FUNCPTR(XISelectEvents);
+MAKE_FUNCPTR(XOpenDevice);
+MAKE_FUNCPTR(XCloseDevice);
+MAKE_FUNCPTR(XGetDeviceButtonMapping);
#undef MAKE_FUNCPTR
#endif
@@ -1908,14 +1914,62 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
return TRUE;
}
-/* apply current X pointer map to raw button event */
-static unsigned char translate_raw_button(int from)
+struct device_map {
+ int id, btn_count;
+ unsigned char map[256];
+
+ struct list entry;
+};
+
+static const unsigned char *get_device_map(Display *display, int device_id)
+{
+ static struct list cache = LIST_INIT(cache);
+
+ struct device_map *device_map;
+ XDevice *device;
+
+ /* TODO: We should ask for DeviceMappingNotify events and update the cache. */
+
+ LIST_FOR_EACH_ENTRY(device_map, &cache, struct device_map, entry)
+ {
+ if (device_map->id == device_id)
+ return device_map->map;
+ }
+
+ device = pXOpenDevice(display, device_id);
+ if (!device)
+ {
+ WARN("unable to open cursor source device? %u\n", device_id);
+ return NULL;
+ }
+
+ device_map = HeapAlloc(GetProcessHeap(), 0, sizeof(*device_map));
+ device_map->id = device_id;
+
+ device_map->btn_count = pXGetDeviceButtonMapping(display, device,
+ device_map->map, ARRAY_SIZE(device_map->map));
+
+ pXCloseDevice(display, device);
+
+ list_add_tail(&cache, &device_map->entry);
+
+ return device_map->map;
+}
+
+/* apply button maps to raw button event */
+static unsigned char translate_raw_button(XIRawEvent *event)
{
- unsigned char *cur_map = x_pointer_map;
+ const unsigned char *device_map = get_device_map(event->display, event->sourceid);
+ const unsigned char *pointer_map = x_pointer_map;
+ int from = event->detail;
+
+ if (device_map)
+ from = device_map[from - 1];
- if (!cur_map) return from;
+ if (pointer_map)
+ from = pointer_map[from - 1];
- return cur_map[from - 1];
+ return from;
}
/***********************************************************************
@@ -1925,14 +1979,14 @@ static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie )
{
struct x11drv_thread_data *thread_data = x11drv_thread_data();
XIRawEvent *event = cookie->data;
- int button = translate_raw_button(event->detail) - 1;
+ int button = translate_raw_button(event) - 1;
INPUT input;
if (button >= NB_BUTTONS) return FALSE;
if (thread_data->xi2_state != xi_enabled) return FALSE;
if (event->deviceid != thread_data->xi2_core_pointer) return FALSE;
- TRACE( "raw button %u %s\n", button, event->evtype == XI_RawButtonRelease ? "up" : "down" );
+ TRACE( "raw button %u (was: %u) %s\n", button, event->detail, event->evtype == XI_RawButtonRelease ? "up" : "down" );
input.type = INPUT_MOUSE;
input.u.mi.dx = 0;
@@ -1975,6 +2029,9 @@ void X11DRV_XInput2_Init(void)
LOAD_FUNCPTR(XIQueryDevice);
LOAD_FUNCPTR(XIQueryVersion);
LOAD_FUNCPTR(XISelectEvents);
+ LOAD_FUNCPTR(XOpenDevice);
+ LOAD_FUNCPTR(XCloseDevice);
+ LOAD_FUNCPTR(XGetDeviceButtonMapping);
#undef LOAD_FUNCPTR
xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error );
+
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index b6adddc99b..ce0fd78d75 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -2318,7 +2318,12 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data *
rawinput->header.hDevice = WINE_MOUSE_HANDLE;
rawinput->header.wParam = 0;
- rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
+ if (msg_data->flags & MOUSEEVENTF_ABSOLUTE)
+ rawinput->data.mouse.usFlags = MOUSE_MOVE_ABSOLUTE;
+ else
+ rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
+ if (msg_data->flags & MOUSEEVENTF_VIRTUALDESK)
+ rawinput->data.mouse.usFlags |= MOUSE_VIRTUAL_DESKTOP;
rawinput->data.mouse.u.s.usButtonFlags = 0;
rawinput->data.mouse.u.s.usButtonData = 0;
for (i = 1; i < ARRAY_SIZE(button_flags); ++i)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c
index c6af2faa2a..850028ed2b 100644
--- a/dlls/user32/rawinput.c
+++ b/dlls/user32/rawinput.c
@@ -345,7 +345,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U
TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
i, devices[i].usUsagePage, devices[i].usUsage,
devices[i].dwFlags, devices[i].hwndTarget);
- if (devices[i].dwFlags & ~RIDEV_REMOVE)
+ if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY))
FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
d[i].usage_page = devices[i].usUsagePage;
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 110edc8ce7..aea6cc8b92 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -283,34 +283,43 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator
struct x11drv_thread_data *thread_data = x11drv_thread_data();
int i;
- thread_data->x_rel_valuator.number = -1;
- thread_data->y_rel_valuator.number = -1;
- thread_data->x_rel_valuator.accum = 0;
- thread_data->y_rel_valuator.accum = 0;
+ thread_data->x_pos_valuator.number = -1;
+ thread_data->y_pos_valuator.number = -1;
for (i = 0; i < n_valuators; i++)
{
XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i];
- struct x11drv_valuator_data *valuator_data = NULL;
- if (valuators[i]->type != XIValuatorClass) continue;
- if (class->label == x11drv_atom( Rel_X ) ||
- (!class->label && class->number == 0 && class->mode == XIModeRelative))
- {
- valuator_data = &thread_data->x_rel_valuator;
- }
+ if (valuators[i]->type != XIValuatorClass)
+ continue;
+ else if (class->label == x11drv_atom( Rel_X ) ||
+ class->label == x11drv_atom( Abs_X ) ||
+ (!class->label && class->number == 0))
+ thread_data->x_pos_valuator = *class;
else if (class->label == x11drv_atom( Rel_Y ) ||
- (!class->label && class->number == 1 && class->mode == XIModeRelative))
- {
- valuator_data = &thread_data->y_rel_valuator;
- }
+ class->label == x11drv_atom( Abs_Y ) ||
+ (!class->label && class->number == 1))
+ thread_data->y_pos_valuator = *class;
+ }
- if (valuator_data) {
- valuator_data->number = class->number;
- valuator_data->min = class->min;
- valuator_data->max = class->max;
- }
+ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0)
+ {
+ WARN("Only one X/Y axis found, ignoring RawMotion events\n");
}
+ else if (thread_data->x_pos_valuator.mode != thread_data->y_pos_valuator.mode)
+ {
+ WARN("Relative/Absolute mismatch between X/Y axis, ignoring RawMotion events\n");
+ thread_data->y_pos_valuator.number = -1;
+ thread_data->y_pos_valuator.number = -1;
+ }
+
+ if (thread_data->x_pos_valuator.min >= thread_data->x_pos_valuator.max)
+ thread_data->x_pos_valuator.min = thread_data->x_pos_valuator.max = 0;
+ if (thread_data->y_pos_valuator.min >= thread_data->y_pos_valuator.max)
+ thread_data->y_pos_valuator.min = thread_data->y_pos_valuator.max = 0;
+
+ thread_data->x_pos_valuator.value = 0;
+ thread_data->y_pos_valuator.value = 0;
}
#endif
@@ -395,10 +404,8 @@ void X11DRV_XInput2_Disable(void)
mask.deviceid = XIAllMasterDevices;
pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
- data->x_rel_valuator.number = -1;
- data->y_rel_valuator.number = -1;
- data->x_rel_valuator.accum = 0;
- data->y_rel_valuator.accum = 0;
+ data->x_pos_valuator.number = -1;
+ data->y_pos_valuator.number = -1;
data->xi2_core_pointer = 0;
#endif
}
@@ -1827,21 +1834,28 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
{
XIRawEvent *event = xev->data;
const double *values = event->valuators.values;
+ const double *raw_values = event->raw_values;
RECT virtual_rect;
INPUT input;
POINT pt;
int i;
double dx = 0, dy = 0, val;
+ double raw_dx = 0, raw_dy = 0, raw_val;
+ double x_scale = 1, y_scale = 1;
+ double x_accum = 0, y_accum = 0;
struct x11drv_thread_data *thread_data = x11drv_thread_data();
- struct x11drv_valuator_data *x_rel, *y_rel;
+ XIValuatorClassInfo *x_pos, *y_pos;
- if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE;
+ if (thread_data->x_pos_valuator.number < 0 || thread_data->y_pos_valuator.number < 0) return FALSE;
if (!event->valuators.mask_len) return FALSE;
if (thread_data->xi2_state != xi_enabled) return FALSE;
if (event->deviceid != thread_data->xi2_core_pointer) return FALSE;
- x_rel = &thread_data->x_rel_valuator;
- y_rel = &thread_data->y_rel_valuator;
+ x_pos = &thread_data->x_pos_valuator;
+ y_pos = &thread_data->y_pos_valuator;
+
+ x_accum = x_pos->value;
+ y_accum = y_pos->value;
input.type = INPUT_MOUSE;
input.u.mi.mouseData = 0;
@@ -1852,42 +1866,48 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
input.u.mi.dy = 0;
virtual_rect = get_virtual_screen_rect();
+ if (x_pos->min < x_pos->max)
+ x_scale = (virtual_rect.right - virtual_rect.left) / (x_pos->max - x_pos->min);
+ if (y_pos->min < y_pos->max)
+ y_scale = (virtual_rect.bottom - virtual_rect.top) / (y_pos->max - y_pos->min);
- for (i = 0; i <= max ( x_rel->number, y_rel->number ); i++)
+ for (i = 0; i <= max( x_pos->number, y_pos->number ); i++)
{
- if (!XIMaskIsSet( event->valuators.mask, i ))
- continue;
+ if (!XIMaskIsSet( event->valuators.mask, i )) continue;
val = *values++;
- if (i == x_rel->number)
+ raw_val = *raw_values++;
+ if (i == x_pos->number)
{
dx = val;
- if (x_rel->min < x_rel->max)
- dx = val * (virtual_rect.right - virtual_rect.left)
- / (x_rel->max - x_rel->min);
+ raw_dx = raw_val;
+ input.u.mi.dwFlags |= (x_pos->min < x_pos->max ? MOUSEEVENTF_VIRTUALDESK : 0) |
+ (x_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0);
+ if (x_pos->mode == XIModeAbsolute)
+ x_accum = virtual_rect.left + (dx - x_pos->min) * x_scale;
+ else
+ x_accum += dx * x_scale;
}
- if (i == y_rel->number)
+ if (i == y_pos->number)
{
dy = val;
- if (y_rel->min < y_rel->max)
- dy = val * (virtual_rect.bottom - virtual_rect.top)
- / (y_rel->max - y_rel->min);
+ raw_dy = raw_val;
+ input.u.mi.dwFlags |= (y_pos->min < y_pos->max ? MOUSEEVENTF_VIRTUALDESK : 0) |
+ (y_pos->mode == XIModeAbsolute ? MOUSEEVENTF_ABSOLUTE : 0);
+ if (y_pos->mode == XIModeAbsolute)
+ y_accum = virtual_rect.top + (dy - y_pos->min) * y_scale;
+ else
+ y_accum += dy * y_scale;
}
}
- /* Accumulate the *double* dx/dy motions so sub-pixel motions wont be lost
- * when sent/cast to *LONG* input.u.mi.dx/dy.
+ /* Accumulate the fractional parts so they aren't lost after casting
+ * successive motion values to integral fields.
+ *
+ * Note: It looks like raw_dx, raw_dy are already
+ * integral values but that may be wrong.
*/
- x_rel->accum += dx;
- y_rel->accum += dy;
- if (fabs(x_rel->accum) < 1.0 && fabs(y_rel->accum) < 1.0)
- {
- TRACE( "accumulating raw motion (event %f,%f, accum %f,%f)\n", dx, dy, x_rel->accum, y_rel->accum );
- return TRUE;
- }
- input.u.mi.dx = x_rel->accum;
- input.u.mi.dy = y_rel->accum;
- x_rel->accum -= input.u.mi.dx;
- y_rel->accum -= input.u.mi.dy;
+ input.u.mi.dx = (LONG)x_accum;
+ input.u.mi.dy = (LONG)y_accum;
if (broken_rawevents && is_old_motion_event( xev->serial ))
{
@@ -1901,14 +1921,31 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
input.u.mi.dx = pt.x;
input.u.mi.dy = pt.y;
- if (!thread_data->xi2_rawinput_only)
+ x_pos->value = x_accum - input.u.mi.dx;
+ y_pos->value = y_accum - input.u.mi.dy;
+
+ if (x_pos->mode == XIModeAbsolute)
+ {
+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
+ __wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT );
+ }
+ else if (!thread_data->xi2_rawinput_only)
{
- TRACE( "pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum );
- __wine_send_input( 0, &input, SEND_HWMSG_WINDOW );
+ if ((dy || dy) && !(input.u.mi.dx || input.u.mi.dy))
+ {
+ TRACE( "accumulating raw motion (event %f,%f accum %f,%f)\n", dx, dy, x_pos->value, y_pos->value );
+ }
+ else
+ {
+ TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
+ __wine_send_input( 0, &input, SEND_HWMSG_WINDOW );
+ }
}
else
{
- TRACE( "raw pos %d,%d (event %f,%f, accum %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy, x_rel->accum, y_rel->accum );
+ input.u.mi.dx = raw_dx;
+ input.u.mi.dy = raw_dy;
+ TRACE( "raw pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, raw_dx, raw_dy );
__wine_send_input( 0, &input, SEND_HWMSG_RAWINPUT );
}
return TRUE;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index f1ce5696df..d2412ed4a4 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -32,6 +32,9 @@
#include <X11/Xresource.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+#include <X11/extensions/XInput2.h>
+#endif
#define BOOL X_BOOL
#define BYTE X_BYTE
@@ -322,14 +325,6 @@ struct x11drv_escape_flush_gl_drawable
* X11 USER driver
*/
-struct x11drv_valuator_data
-{
- double min;
- double max;
- int number;
- double accum;
-};
-
struct x11drv_thread_data
{
Display *display;
@@ -345,11 +340,13 @@ struct x11drv_thread_data
HWND clip_hwnd; /* message window stored in desktop while clipping is active */
DWORD clip_reset; /* time when clipping was last reset */
HKL kbd_layout; /* active keyboard layout */
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */
- struct x11drv_valuator_data x_rel_valuator;
- struct x11drv_valuator_data y_rel_valuator;
+ XIValuatorClassInfo x_pos_valuator;
+ XIValuatorClassInfo y_pos_valuator;
int xi2_core_pointer; /* XInput2 core pointer id */
int xi2_rawinput_only;
+#endif
};
extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN;
@@ -434,6 +431,8 @@ enum x11drv_atoms
XATOM_RAW_CAP_HEIGHT,
XATOM_Rel_X,
XATOM_Rel_Y,
+ XATOM_Abs_X,
+ XATOM_Abs_Y,
XATOM_WM_PROTOCOLS,
XATOM_WM_DELETE_WINDOW,
XATOM_WM_STATE,
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 8908e84458..1e2f7f2d36 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -144,6 +144,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
"RAW_CAP_HEIGHT",
"Rel X",
"Rel Y",
+ "Abs X",
+ "Abs Y",
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"WM_STATE",
diff --git a/server/queue.c b/server/queue.c
index 848089dca7..c0094379da 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -438,6 +438,9 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y )
static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
struct message *msg;
+ if (current->process->rawinput_mouse &&
+ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return;
+
if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->msg = WM_MOUSEMOVE;
@@ -1829,6 +1832,7 @@ done:
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
unsigned int origin, struct msg_queue *sender, unsigned int req_flags )
{
+ const struct rawinput_device *device;
struct hardware_msg_data *msg_data;
struct rawinput_message raw_msg;
struct message *msg;
@@ -1892,8 +1896,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
msg_data->info = input->mouse.info;
msg_data->flags = flags;
msg_data->rawinput.type = RIM_TYPEMOUSE;
- msg_data->rawinput.mouse.x = x - desktop->cursor.x;
- msg_data->rawinput.mouse.y = y - desktop->cursor.y;
+ msg_data->rawinput.mouse.x = input->mouse.x;
+ msg_data->rawinput.mouse.y = input->mouse.y;
msg_data->rawinput.mouse.data = input->mouse.data;
if (req_flags == SEND_HWMSG_RAWINPUT)
@@ -1904,6 +1908,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if (!(req_flags & SEND_HWMSG_WINDOW))
return 0;
+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY))
+ return 0;
for (i = 0; i < ARRAY_SIZE( messages ); i++)
{
@@ -1939,6 +1945,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
unsigned int origin, struct msg_queue *sender, unsigned int req_flags )
{
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;
@@ -2036,6 +2043,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
if (!(req_flags & SEND_HWMSG_WINDOW))
return 0;
+ if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY))
+ return 0;
if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0;
msg_data = msg->data;
diff --git a/server/queue.c b/server/queue.c
index f5dc06100d1..4b2fef8a20a 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -421,6 +421,20 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour
return msg;
}
+static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y )
+{
+ int updated;
+
+ x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
+ y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
+ updated = (desktop->cursor.x != x || desktop->cursor.y != y);
+ desktop->cursor.x = x;
+ desktop->cursor.y = y;
+ desktop->cursor.last_change = get_tick_count();
+
+ return updated;
+}
+
/* set the cursor position and queue the corresponding mouse message */
static void set_cursor_pos( struct desktop *desktop, int x, int y )
{
@@ -428,7 +442,11 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y )
struct message *msg;
if (current->process->rawinput_mouse &&
- current->process->rawinput_mouse->flags & RIDEV_NOLEGACY) return;
+ current->process->rawinput_mouse->flags & RIDEV_NOLEGACY)
+ {
+ update_desktop_cursor_pos( desktop, x, y );
+ return;
+ }
if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
@@ -1634,12 +1652,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg
{
if (msg->msg == WM_MOUSEMOVE)
{
- int x = max( min( msg->x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
- int y = max( min( msg->y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
- if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1;
- desktop->cursor.x = x;
- desktop->cursor.y = y;
- desktop->cursor.last_change = get_tick_count();
+ if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1;
}
if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON;
if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON;
@@ -1871,7 +1884,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if (!(req_flags & SEND_HWMSG_WINDOW))
return 0;
if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY))
+ {
+ if (flags & MOUSEEVENTF_MOVE) update_desktop_cursor_pos( desktop, x, y );
return 0;
+ }
for (i = 0; i < ARRAY_SIZE( messages ); i++)
{
+ + + +
+ +
+ + + +
+ + +
+ + +
+
+ + + +
+
+ +
+
+ + +
+ + + + + + +
+ + + You can’t perform that action at this time. +
+ + + + + + + + + + + + + + + + + +
+ + + + diff --git a/game-patches-testing/wine-patches/0001-dinput-Support-default-DIPROP_BUFFERSIZE-buffer-size.patch b/game-patches-testing/wine-patches/0001-dinput-Support-default-DIPROP_BUFFERSIZE-buffer-size.patch deleted file mode 100644 index 4cd308e98..000000000 --- a/game-patches-testing/wine-patches/0001-dinput-Support-default-DIPROP_BUFFERSIZE-buffer-size.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 095e3e2646bc5ba024c166a2ac6829a894c0d1f7 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 10 Jan 2020 09:28:50 +1100 -Subject: [PATCH] dinput: Support default DIPROP_BUFFERSIZE buffer size - -When a program calls SetProperty with DIPROP_BUFFERSIZE, dinput records -this value for GetProperty but only uses it when the device can support -that number of buffers otherwise a max value. - -In the case of game "Far Cry 5", it passes through (DWORD)-1 which -cause HeapAlloc to fail ((DWORD)-1 * sizeof(DIDEVICEOBJECTDATA)). - -Since there is no real way of working out the max value, I've capped it at 100 as -the default value is 20. - -MSDN reference. -https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee417908(v=vs.85) - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45732 - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/dinput/device.c | 14 ++++++++++---- - dlls/dinput/device_private.h | 3 ++- - dlls/dinput/joystick_linux.c | 4 ++++ - dlls/dinput/joystick_linuxinput.c | 4 ++++ - dlls/dinput/joystick_osx.c | 4 ++++ - dlls/dinput/keyboard.c | 3 +++ - dlls/dinput/mouse.c | 3 +++ - dlls/dinput/tests/device.c | 14 ++++++++++++++ - 8 files changed, 44 insertions(+), 5 deletions(-) - -diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c -index 28329d03b5..1604075f84 100644 ---- a/dlls/dinput/device.c -+++ b/dlls/dinput/device.c -@@ -1307,7 +1307,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, - - if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM; - -- pd->dwData = This->queue_len; -+ pd->dwData = This->buffersize; - TRACE("buffersize = %d\n", pd->dwData); - break; - } -@@ -1396,12 +1396,18 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty( - TRACE("buffersize = %d\n", pd->dwData); - - EnterCriticalSection(&This->crit); -+ -+ This->buffersize = pd->dwData; -+ -+ This->queue_len = This->buffersize > 100 ? 100 : This->buffersize; -+ if (This->buffersize > 100) -+ WARN("Trying to set large buffer size %d\n", pd->dwData); -+ - HeapFree(GetProcessHeap(), 0, This->data_queue); - -- This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0, -- pd->dwData * sizeof(DIDEVICEOBJECTDATA)); -+ This->data_queue = !This->queue_len ? NULL : HeapAlloc(GetProcessHeap(), 0, -+ This->queue_len * sizeof(DIDEVICEOBJECTDATA)); - This->queue_head = This->queue_tail = This->overflow = 0; -- This->queue_len = pd->dwData; - - LeaveCriticalSection(&This->crit); - break; -diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h -index 27e9c26286..23d9e2eebc 100644 ---- a/dlls/dinput/device_private.h -+++ b/dlls/dinput/device_private.h -@@ -71,10 +71,11 @@ struct IDirectInputDeviceImpl - DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */ - - LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ -- int queue_len; /* size of the queue - set in 'SetProperty' */ -+ int queue_len; /* valid size of the queue */ - int queue_head; /* position to write new event into queue */ - int queue_tail; /* next event to read from queue */ - BOOL overflow; /* return DI_BUFFEROVERFLOW in 'GetDeviceData' */ -+ DWORD buffersize; /* size of the queue - set in 'SetProperty' */ - - DataFormat data_format; /* user data format and wine to user format converter */ - -diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c -index afdf659b4a..1e7bf72936 100644 ---- a/dlls/dinput/joystick_linux.c -+++ b/dlls/dinput/joystick_linux.c -@@ -501,6 +501,10 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput, - newDevice->generic.base.ref = 1; - newDevice->generic.base.dinput = dinput; - newDevice->generic.base.guid = *rguid; -+ newDevice->generic.base.buffersize = 20; -+ newDevice->generic.base.queue_len = 20; -+ newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, -+ newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); - InitializeCriticalSection(&newDevice->generic.base.crit); - newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit"); - -diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c -index b5418d805c..98283a1eed 100644 ---- a/dlls/dinput/joystick_linuxinput.c -+++ b/dlls/dinput/joystick_linuxinput.c -@@ -471,6 +471,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig - newDevice->generic.base.ref = 1; - newDevice->generic.base.guid = *rguid; - newDevice->generic.base.dinput = dinput; -+ newDevice->generic.base.buffersize = 20; -+ newDevice->generic.base.queue_len = 20; -+ newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, -+ newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); - newDevice->generic.joy_polldev = joy_polldev; - newDevice->joyfd = -1; - newDevice->joydev = &joydevs[index]; -diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c -index 990f5d1f07..c48cad1f5a 100644 ---- a/dlls/dinput/joystick_osx.c -+++ b/dlls/dinput/joystick_osx.c -@@ -1168,6 +1168,10 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput, - newDevice->generic.base.ref = 1; - newDevice->generic.base.dinput = dinput; - newDevice->generic.base.guid = *rguid; -+ newDevice->generic.base.buffersize = 20; -+ newDevice->generic.base.queue_len = 20; -+ newDevice->generic.base.data_queue = HeapAlloc(GetProcessHeap(), 0, -+ newDevice->generic.base.queue_len * sizeof(DIDEVICEOBJECTDATA)); - InitializeCriticalSection(&newDevice->generic.base.crit); - newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit"); - -diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c -index 47f28cac52..15a6be4dee 100644 ---- a/dlls/dinput/keyboard.c -+++ b/dlls/dinput/keyboard.c -@@ -268,6 +268,9 @@ static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) - InitializeCriticalSection(&newDevice->base.crit); - newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit"); - newDevice->subtype = get_keyboard_subtype(); -+ newDevice->base.buffersize = 20; -+ newDevice->base.queue_len = 20; -+ newDevice->base.data_queue = HeapAlloc(GetProcessHeap(), 0, newDevice->base.queue_len * sizeof(DIDEVICEOBJECTDATA)); - - /* Create copy of default data format */ - if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed; -diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c -index 08ace2f4e9..59c8c9dad8 100644 ---- a/dlls/dinput/mouse.c -+++ b/dlls/dinput/mouse.c -@@ -214,6 +214,9 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) - newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit"); - newDevice->base.dinput = dinput; - newDevice->base.event_proc = dinput_mouse_hook; -+ newDevice->base.buffersize = 20; -+ newDevice->base.queue_len = 20; -+ newDevice->base.data_queue = HeapAlloc(GetProcessHeap(), 0, newDevice->base.queue_len * sizeof(DIDEVICEOBJECTDATA)); - - get_app_key(&hkey, &appkey); - if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) -diff --git a/dlls/dinput/tests/device.c b/dlls/dinput/tests/device.c -index a2a5a65686..4dd16c70d2 100644 ---- a/dlls/dinput/tests/device.c -+++ b/dlls/dinput/tests/device.c -@@ -106,8 +106,22 @@ static void test_object_info(IDirectInputDeviceA *device, HWND hwnd) - dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dp.diph.dwHow = DIPH_DEVICE; - dp.diph.dwObj = 0; -+ dp.dwData = -1; -+ -+ hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph); -+ ok(hr == DI_OK, "Failed: %08x\n", hr); -+ ok(dp.dwData == 20, "got %d\n", dp.dwData); -+ -+ dp.dwData = -1; -+ hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); -+ ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); -+ - dp.dwData = 0; -+ hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph); -+ ok(hr == DI_OK, "Failed: %08x\n", hr); -+ ok(dp.dwData == -1, "got %d\n", dp.dwData); - -+ dp.dwData = 0; - hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); - ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); - cnt = 5; --- -2.17.1 - diff --git a/game-patches-testing/wine-patches/0001-dsound-Use-an-SRW-lock-for-buffer_list_lock.patch b/game-patches-testing/wine-patches/0001-dsound-Use-an-SRW-lock-for-buffer_list_lock.patch deleted file mode 100644 index 7728a56bf..000000000 --- a/game-patches-testing/wine-patches/0001-dsound-Use-an-SRW-lock-for-buffer_list_lock.patch +++ /dev/null @@ -1,166 +0,0 @@ -From 410d340084e24732e3d7423f74dbe8aa92dddd09 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Thu, 9 Jan 2020 14:51:36 -0600 -Subject: [PATCH] dsound: Use an SRW lock for buffer_list_lock. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48408 - -Signed-off-by: Zebediah Figura ---- - dlls/dsound/buffer.c | 4 ++-- - dlls/dsound/dsound.c | 15 +++++++-------- - dlls/dsound/dsound_private.h | 2 +- - dlls/dsound/mixer.c | 4 ++-- - dlls/dsound/primary.c | 4 ++-- - 5 files changed, 14 insertions(+), 15 deletions(-) - -diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c -index c61868a7820..82a23eb8907 100644 ---- a/dlls/dsound/buffer.c -+++ b/dlls/dsound/buffer.c -@@ -644,7 +644,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, - - if (x1 || x2) - { -- RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE); -+ AcquireSRWLockShared(&This->device->buffer_list_lock); - LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry ) - { - RtlAcquireResourceShared(&iter->lock, TRUE); -@@ -665,7 +665,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, - } - RtlReleaseResource(&iter->lock); - } -- RtlReleaseResource(&This->device->buffer_list_lock); -+ ReleaseSRWLockShared(&This->device->buffer_list_lock); - } - - return hres; -diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c -index 4dcea9e29e9..e991210621f 100644 ---- a/dlls/dsound/dsound.c -+++ b/dlls/dsound/dsound.c -@@ -181,7 +181,7 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) - InitializeCriticalSection(&(device->mixlock)); - device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock"); - -- RtlInitializeResource(&(device->buffer_list_lock)); -+ InitializeSRWLock(&device->buffer_list_lock); - - init_eax_device(device); - -@@ -242,7 +242,6 @@ static ULONG DirectSoundDevice_Release(DirectSoundDevice * device) - HeapFree(GetProcessHeap(), 0, device->tmp_buffer); - HeapFree(GetProcessHeap(), 0, device->cp_buffer); - HeapFree(GetProcessHeap(), 0, device->buffer); -- RtlDeleteResource(&device->buffer_list_lock); - device->mixlock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&device->mixlock); - HeapFree(GetProcessHeap(),0,device); -@@ -616,7 +615,7 @@ HRESULT DirectSoundDevice_AddBuffer( - - TRACE("(%p, %p)\n", device, pDSB); - -- RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); -+ AcquireSRWLockExclusive(&device->buffer_list_lock); - - if (device->buffers) - newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1)); -@@ -633,7 +632,7 @@ HRESULT DirectSoundDevice_AddBuffer( - hr = DSERR_OUTOFMEMORY; - } - -- RtlReleaseResource(&(device->buffer_list_lock)); -+ ReleaseSRWLockExclusive(&device->buffer_list_lock); - - return hr; - } -@@ -648,7 +647,7 @@ void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBuff - - TRACE("(%p, %p)\n", device, pDSB); - -- RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); -+ AcquireSRWLockExclusive(&device->buffer_list_lock); - - if (device->nrofbuffers == 1) { - assert(device->buffers[0] == pDSB); -@@ -666,7 +665,7 @@ void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBuff - device->nrofbuffers--; - TRACE("buffer count is now %d\n", device->nrofbuffers); - -- RtlReleaseResource(&(device->buffer_list_lock)); -+ ReleaseSRWLockExclusive(&device->buffer_list_lock); - } - - /******************************************************************************* -@@ -873,14 +872,14 @@ static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface - level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE"); - } - -- RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE); -+ AcquireSRWLockExclusive(&device->buffer_list_lock); - EnterCriticalSection(&device->mixlock); - if ((level == DSSCL_WRITEPRIMARY) != (device->priolevel == DSSCL_WRITEPRIMARY)) - hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY); - if (SUCCEEDED(hr)) - device->priolevel = level; - LeaveCriticalSection(&device->mixlock); -- RtlReleaseResource(&device->buffer_list_lock); -+ ReleaseSRWLockExclusive(&device->buffer_list_lock); - return hr; - } - -diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h -index dcb67d56948..87786c6b11b 100644 ---- a/dlls/dsound/dsound_private.h -+++ b/dlls/dsound/dsound_private.h -@@ -83,7 +83,7 @@ struct DirectSoundDevice - DWORD writelead, buflen, ac_frames, frag_frames, playpos, pad, stopped; - int nrofbuffers; - IDirectSoundBufferImpl** buffers; -- RTL_RWLOCK buffer_list_lock; -+ RTL_SRWLOCK buffer_list_lock; - CRITICAL_SECTION mixlock; - IDirectSoundBufferImpl *primary; - DWORD speaker_config; -diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c -index 023622a9f98..3006d249d43 100644 ---- a/dlls/dsound/mixer.c -+++ b/dlls/dsound/mixer.c -@@ -856,9 +856,9 @@ DWORD CALLBACK DSOUND_mixthread(void *p) - if (!dev->ref) - break; - -- RtlAcquireResourceShared(&(dev->buffer_list_lock), TRUE); -+ AcquireSRWLockShared(&dev->buffer_list_lock); - DSOUND_PerformMix(dev); -- RtlReleaseResource(&(dev->buffer_list_lock)); -+ ReleaseSRWLockShared(&dev->buffer_list_lock); - } - return 0; - } -diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c -index 852ec51b7ff..8d42fe0ed90 100644 ---- a/dlls/dsound/primary.c -+++ b/dlls/dsound/primary.c -@@ -472,7 +472,7 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe - } - - /* **** */ -- RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); -+ AcquireSRWLockExclusive(&device->buffer_list_lock); - EnterCriticalSection(&(device->mixlock)); - - if (device->priolevel == DSSCL_WRITEPRIMARY) { -@@ -508,7 +508,7 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe - - out: - LeaveCriticalSection(&(device->mixlock)); -- RtlReleaseResource(&(device->buffer_list_lock)); -+ ReleaseSRWLockExclusive(&device->buffer_list_lock); - /* **** */ - - return err; --- -2.24.1 - diff --git a/wine b/wine index 28ab23db5..da816802e 160000 --- a/wine +++ b/wine @@ -1 +1 @@ -Subproject commit 28ab23db56347f4e5c6c617ae35fbb6269f6e16a +Subproject commit da816802e022e8aa8eb197de94e18305a92766c1 diff --git a/wine-staging b/wine-staging index 329005baa..9a2a33ee2 160000 --- a/wine-staging +++ b/wine-staging @@ -1 +1 @@ -Subproject commit 329005baaf5cb49fea7cc11db8427d1cf181b9fb +Subproject commit 9a2a33ee2b43fe87be1d8879703399688655e668