[PATCH] winex11.drv: Send WM_SYSKEYDOWN if the Alt+F4 shortcut was used to close the window.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu Aug 6 09:06:13 CDT 2020


Some applications (e.g. Brothers - A Tale of Two Sons) are sensitive to the
difference between Alt+F4 and a normal close of the window. Window Managers
typically have the Alt+F4 configured to send the WM_DELETE_WINDOW message,
which won't even send a F4 key press at all to the window. So we have to
distinguish between that and another source of that message (for example,
clicking the X button) while handling it.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/winex11.drv/event.c    |  2 ++
 dlls/winex11.drv/keyboard.c | 49 +++++++++++++++++++++++++++++++++++++
 dlls/winex11.drv/x11drv.h   |  1 +
 3 files changed, 52 insertions(+)

diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 07f7a1a..99077ad 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -688,6 +688,8 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
                         break;
                 }
             }
+            else if (X11DRV_HandleKeyCloseShortcut( hwnd, event->display, event_time ))
+                return;
 
             PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
         }
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 48da12c..4efee15 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1417,6 +1417,55 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
     return TRUE;
 }
 
+/***********************************************************************
+ *           X11DRV_HandleKeyCloseShortcut
+ *
+ * Handle the close shortcut (Alt+F4) on a delete window message.
+ */
+BOOL X11DRV_HandleKeyCloseShortcut(HWND hwnd, Display *display, Time event_time)
+{
+    unsigned int pressed = 0, i;
+    BYTE keystate[256];
+    char keys[32];
+    WORD scan = 0;
+
+    /* WMs handle this shortcut and not send it to the window at all,
+       so we have to query the keymap and see whether it is pressed. */
+    XQueryKeymap(display, keys);
+
+    /* The minimum keycode is always greater or equal to 8. */
+    for (i = 8; i < 256; i++)
+    {
+        switch (keyc2vkey[i])
+        {
+        case VK_MENU:
+        case VK_LMENU:
+        case VK_RMENU:
+            if (keys[i / 8] & (1 << (i % 8)))
+                pressed |= 1;
+            break;
+        case VK_F4:
+            if (keys[i / 8] & (1 << (i % 8)))
+            {
+                scan = keyc2scan[i] & 0xFF;
+                pressed |= 2;
+            }
+            break;
+        }
+    }
+    if (pressed != 3) return FALSE;
+
+    /* In this case, the Alt keystate must match, but not the VK_F4. */
+    if (!get_async_key_state(keystate)) return FALSE;
+    if (!(keystate[VK_MENU] & 0x80) || (keystate[VK_F4] & 0x80)) return FALSE;
+
+    /* Simulate the VK_F4 press, since it's eaten by the WM (the release is not). */
+    update_user_time(event_time);
+    X11DRV_send_keyboard_input(hwnd, VK_F4, scan, 0, EVENT_x11_time_to_win32_time(event_time));
+
+    return TRUE;
+}
+
 /**********************************************************************
  *		X11DRV_KEYBOARD_DetectLayout
  *
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 375fd14..f294c10 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -632,6 +632,7 @@ 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 BOOL X11DRV_HandleKeyCloseShortcut( HWND hwnd, Display *display, Time event_time ) DECLSPEC_HIDDEN;
 extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
 extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout,
                                                        DWORD mask, DWORD flags ) DECLSPEC_HIDDEN;
-- 
2.21.0




More information about the wine-devel mailing list