[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