[PATCH v3 4/5] dxgi: Implement Alt+Enter handling.
Zhiyi Zhang
zzhang at codeweavers.com
Tue May 21 07:56:03 CDT 2019
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/dxgi/swapchain.c | 2 +
dlls/wined3d/swapchain.c | 132 +++++++++++++++++++++++++++++++++
dlls/wined3d/wined3d.spec | 2 +
dlls/wined3d/wined3d_private.h | 19 +++++
include/wine/wined3d.h | 2 +
5 files changed, 157 insertions(+)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 030bb67c22..4c90012b86 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -221,6 +221,7 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface)
}
if (swapchain->factory)
IDXGIFactory_Release(swapchain->factory);
+ wined3d_swapchain_disable_window_hook(swapchain->wined3d_swapchain);
wined3d_swapchain_decref(swapchain->wined3d_swapchain);
if (device)
IWineDXGIDevice_Release(device);
@@ -849,6 +850,7 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
}
}
wined3d_mutex_unlock();
+ wined3d_swapchain_enable_window_hook(swapchain->wined3d_swapchain);
return S_OK;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 808602cb15..be0610d087 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -28,6 +28,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
WINE_DECLARE_DEBUG_CHANNEL(fps);
+static struct list hooked_swapchains = LIST_INIT(hooked_swapchains);
+static struct list window_hooks = LIST_INIT(window_hooks);
+
static void wined3d_swapchain_destroy_object(void *object)
{
swapchain_destroy_contexts(object);
@@ -1492,3 +1495,132 @@ HRESULT CDECL wined3d_swapchain_set_fullscreen(struct wined3d_swapchain *swapcha
return WINED3D_OK;
}
+
+static LRESULT CALLBACK window_hook_proc(int code, WPARAM wparam, LPARAM lparam)
+{
+ struct wined3d_window_association *association_entry;
+ struct wined3d_hooked_swapchain *swapchain_entry;
+ struct wined3d_swapchain_desc swapchain_desc;
+ MSG *msg = (MSG *)lparam;
+ BOOL handled = FALSE;
+ BOOL skip = FALSE;
+
+ /* Handle Alt+Enter */
+ if (code == HC_ACTION && msg->message == WM_SYSKEYDOWN && msg->wParam == VK_RETURN
+ && (msg->lParam & (KF_ALTDOWN << 16)))
+ {
+ wined3d_mutex_lock();
+ LIST_FOR_EACH_ENTRY(swapchain_entry, &hooked_swapchains, struct wined3d_hooked_swapchain, entry)
+ {
+ if (swapchain_entry->swapchain->device_window != msg->hwnd)
+ continue;
+
+ LIST_FOR_EACH_ENTRY(association_entry, &window_associations, struct wined3d_window_association, entry)
+ {
+ if (association_entry->hwnd == msg->hwnd
+ && (association_entry->flags & (WINED3D_MWA_NO_WINDOW_CHANGES | WINED3D_MWA_NO_ALT_ENTER)))
+ {
+ skip = TRUE;
+ break;
+ }
+ }
+
+ if (!skip)
+ {
+ wined3d_swapchain_get_desc(swapchain_entry->swapchain, &swapchain_desc);
+ swapchain_desc.windowed = !swapchain_desc.windowed;
+ wined3d_swapchain_set_fullscreen(swapchain_entry->swapchain, &swapchain_desc, NULL);
+ }
+
+ handled = TRUE;
+ break;
+ }
+ wined3d_mutex_unlock();
+ }
+
+ return handled ? 1 : CallNextHookEx(0, code, wparam, lparam);
+}
+
+void CDECL wined3d_swapchain_enable_window_hook(struct wined3d_swapchain *swapchain)
+{
+ struct wined3d_hooked_swapchain *swapchain_entry;
+ struct wined3d_swapchain_window_hook *hook_entry;
+ BOOL has_hook = FALSE;
+
+ if (!(swapchain_entry = heap_alloc_zero(sizeof(*swapchain_entry))))
+ return;
+
+ swapchain_entry->swapchain = swapchain;
+ swapchain_entry->thread_id = GetWindowThreadProcessId(swapchain->device_window, NULL);
+ wined3d_mutex_lock();
+ list_add_head(&hooked_swapchains, &swapchain_entry->entry);
+ /* Add hook for new thread if needed */
+ LIST_FOR_EACH_ENTRY(hook_entry, &window_hooks, struct wined3d_swapchain_window_hook, entry)
+ {
+ if (hook_entry->thread_id == swapchain_entry->thread_id)
+ {
+ has_hook = TRUE;
+ break;
+ }
+ }
+
+ if (!has_hook)
+ {
+ if (!(hook_entry = heap_alloc_zero(sizeof(*hook_entry))))
+ {
+ list_remove(&swapchain_entry->entry);
+ heap_free(swapchain_entry);
+ wined3d_mutex_unlock();
+ return;
+ }
+
+ hook_entry->thread_id = swapchain_entry->thread_id;
+ hook_entry->hook = SetWindowsHookExW(WH_GETMESSAGE, window_hook_proc, 0, hook_entry->thread_id);
+ list_add_head(&window_hooks, &hook_entry->entry);
+ }
+ wined3d_mutex_unlock();
+}
+
+void CDECL wined3d_swapchain_disable_window_hook(struct wined3d_swapchain *swapchain)
+{
+ struct wined3d_hooked_swapchain *swapchain_entry, *swapchain_entry2;
+ struct wined3d_swapchain_window_hook *hook_entry, *hook_entry2;
+ BOOL hook_in_use = FALSE;
+ DWORD thread_id = 0;
+
+ wined3d_mutex_lock();
+ LIST_FOR_EACH_ENTRY_SAFE(swapchain_entry, swapchain_entry2, &hooked_swapchains, struct wined3d_hooked_swapchain, entry)
+ {
+ if (swapchain_entry->swapchain == swapchain)
+ {
+ thread_id = swapchain_entry->thread_id;
+ list_remove(&swapchain_entry->entry);
+ heap_free(swapchain_entry);
+ break;
+ }
+ }
+ /* Check if hook is still used by other swapchains */
+ LIST_FOR_EACH_ENTRY(swapchain_entry, &hooked_swapchains, struct wined3d_hooked_swapchain, entry)
+ {
+ if (swapchain_entry->thread_id == thread_id)
+ {
+ hook_in_use = TRUE;
+ break;
+ }
+ }
+ /* Remove hook if it's not longer used by any thread */
+ if (!hook_in_use)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(hook_entry, hook_entry2, &window_hooks, struct wined3d_swapchain_window_hook, entry)
+ {
+ if (hook_entry->thread_id == thread_id)
+ {
+ list_remove(&hook_entry->entry);
+ UnhookWindowsHookEx(hook_entry->hook);
+ heap_free(hook_entry);
+ break;
+ }
+ }
+ }
+ wined3d_mutex_unlock();
+}
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 733eedb485..f93c8d38fe 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -263,6 +263,8 @@
@ cdecl wined3d_swapchain_create(ptr ptr ptr ptr ptr)
@ cdecl wined3d_swapchain_decref(ptr)
+@ cdecl wined3d_swapchain_disable_window_hook(ptr)
+@ cdecl wined3d_swapchain_enable_window_hook(ptr)
@ cdecl wined3d_swapchain_get_back_buffer(ptr long)
@ cdecl wined3d_swapchain_get_device(ptr)
@ cdecl wined3d_swapchain_get_display_mode(ptr ptr ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f277d898f3..ec920536c9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4177,6 +4177,25 @@ struct wined3d_swapchain
HWND backup_wnd;
};
+struct wined3d_hooked_swapchain
+{
+ struct wined3d_swapchain *swapchain;
+ DWORD thread_id;
+ struct list entry;
+};
+
+struct wined3d_swapchain_window_hook
+{
+ HHOOK hook;
+ DWORD thread_id;
+ struct list entry;
+};
+
+/* Equivalences of DXGI_MWA_* flags */
+#define WINED3D_MWA_NO_WINDOW_CHANGES 0x1
+#define WINED3D_MWA_NO_ALT_ENTER 0x2
+#define WINED3D_MWA_NO_PRINT_SCREEN 0x4
+
void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate) DECLSPEC_HIDDEN;
struct wined3d_context *swapchain_get_context(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 8514860a79..e41a9080df 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2664,6 +2664,8 @@ ULONG __cdecl wined3d_stateblock_incref(struct wined3d_stateblock *stateblock);
HRESULT __cdecl wined3d_swapchain_create(struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_swapchain **swapchain);
ULONG __cdecl wined3d_swapchain_decref(struct wined3d_swapchain *swapchain);
+void __cdecl wined3d_swapchain_disable_window_hook(struct wined3d_swapchain *swapchain);
+void __cdecl wined3d_swapchain_enable_window_hook(struct wined3d_swapchain *swapchain);
struct wined3d_texture * __cdecl wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain,
UINT backbuffer_idx);
struct wined3d_device * __cdecl wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain);
--
2.20.1
More information about the wine-devel
mailing list