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@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;