[gtk+/gtk-3-22] GDK W32: Use keyboard hook to detect AeroSnap combinations better
- From: Руслан Ижбулатов <ruslanizhb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-3-22] GDK W32: Use keyboard hook to detect AeroSnap combinations better
- Date: Tue, 10 Jan 2017 12:55:13 +0000 (UTC)
commit eece8a7dd2405f76829031f3d6dd5e39fb5dc542
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date: Sat Dec 24 21:01:23 2016 +0000
GDK W32: Use keyboard hook to detect AeroSnap combinations better
Windows WM handles AeroSnap for normal windows on keydown. We did this
on keyup only because we do not get a keydown message, even if Windows WM
does nothing with a combination. However, in some specific cases it DOES
do something - and we have no way to detect that. Specifically, winkey+downarrow
causes maximized window to be restored by WM, and GDK fails to detect that. Then
GDK gets a keyup message, figures that winkey+downarrow was pressed and released,
and handles the combination - by minimizing the window.
To overcome this, install a low-level keyboard hook (high-level ones have
the same problem as normal message loop - they don't get messages when
Windows WM handles combinations) and use it to detect interesting key combinations
before Windows WM has a chance to block them from being processed.
Once an interesting combination is detected, post a message to the window, which
will be handled in due order.
It should be noted that this code handles key repetitions in a very crude manner.
The downside is that AeroSnap will not work if hook installation function call fails.
Also, this is a global hook, and if the hook procedure does something wrong, bad things
can happen.
https://bugzilla.gnome.org/show_bug.cgi?id=776031
gdk/win32/gdkevents-win32.c | 170 ++++++++++++++++++++++++++++++++-----------
1 files changed, 128 insertions(+), 42 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 8d88631..611cb07 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -147,6 +147,10 @@ static int debug_indent = 0;
static int both_shift_pressed[2]; /* to store keycodes for shift keys */
+/* low-level keyboard hook handle */
+static HHOOK keyboard_hook = NULL;
+static UINT aerosnap_message;
+
static void
track_mouse_event (DWORD dwFlags,
HWND hwnd)
@@ -295,6 +299,124 @@ _gdk_win32_window_procedure (HWND hwnd,
return retval;
}
+static LRESULT
+low_level_keystroke_handler (WPARAM message,
+ KBDLLHOOKSTRUCT *kbdhook,
+ GdkWindow *window)
+{
+ GdkWindow *toplevel = gdk_window_get_toplevel (window);
+ static DWORD last_keydown = 0;
+
+ if (message == WM_KEYDOWN &&
+ !GDK_WINDOW_DESTROYED (toplevel) &&
+ _gdk_win32_window_lacks_wm_decorations (toplevel) && /* For CSD only */
+ last_keydown != kbdhook->vkCode &&
+ ((GetKeyState (VK_LWIN) & 0x8000) ||
+ (GetKeyState (VK_RWIN) & 0x8000)))
+ {
+ GdkWin32AeroSnapCombo combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
+ gboolean lshiftdown = GetKeyState (VK_LSHIFT) & 0x8000;
+ gboolean rshiftdown = GetKeyState (VK_RSHIFT) & 0x8000;
+ gboolean oneshiftdown = (lshiftdown || rshiftdown) && !(lshiftdown && rshiftdown);
+ gboolean maximized = gdk_window_get_state (toplevel) & GDK_WINDOW_STATE_MAXIMIZED;
+
+ switch (kbdhook->vkCode)
+ {
+ case VK_UP:
+ combo = GDK_WIN32_AEROSNAP_COMBO_UP;
+ break;
+ case VK_DOWN:
+ combo = GDK_WIN32_AEROSNAP_COMBO_DOWN;
+ break;
+ case VK_LEFT:
+ combo = GDK_WIN32_AEROSNAP_COMBO_LEFT;
+ break;
+ case VK_RIGHT:
+ combo = GDK_WIN32_AEROSNAP_COMBO_RIGHT;
+ break;
+ }
+
+ if (oneshiftdown && combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
+ combo += 4;
+
+ /* These are the only combos that Windows WM does handle for us */
+ if (combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT ||
+ combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT)
+ combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
+
+ /* On Windows 10 the WM will handle this specific combo */
+ if (combo == GDK_WIN32_AEROSNAP_COMBO_DOWN && maximized &&
+ g_win32_check_windows_version (6, 4, 0, G_WIN32_OS_ANY))
+ combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
+
+ if (combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
+ PostMessage (GDK_WINDOW_HWND (toplevel), aerosnap_message, (WPARAM) combo, 0);
+ }
+
+ if (message == WM_KEYDOWN)
+ last_keydown = kbdhook->vkCode;
+ else if (message = WM_KEYUP && last_keydown == kbdhook->vkCode)
+ last_keydown = 0;
+
+ return 0;
+}
+
+static LRESULT CALLBACK
+low_level_keyboard_proc (int code,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ KBDLLHOOKSTRUCT *kbdhook;
+ HWND kbd_focus_owner;
+ GdkWindow *gdk_kbd_focus_owner;
+ LRESULT chain;
+
+ do
+ {
+ if (code < 0)
+ break;
+
+ kbd_focus_owner = GetFocus ();
+
+ if (kbd_focus_owner == NULL)
+ break;
+
+ gdk_kbd_focus_owner = gdk_win32_handle_table_lookup (kbd_focus_owner);
+
+ if (gdk_kbd_focus_owner == NULL)
+ break;
+
+ kbdhook = (KBDLLHOOKSTRUCT *) lParam;
+ chain = low_level_keystroke_handler (wParam, kbdhook, gdk_kbd_focus_owner);
+
+ if (chain != 0)
+ return chain;
+ } while (FALSE);
+
+ return CallNextHookEx (0, code, wParam, lParam);
+}
+
+static void
+set_up_low_level_keyboard_hook (void)
+{
+ HHOOK hook_handle;
+
+ if (keyboard_hook != NULL)
+ return;
+
+ hook_handle = SetWindowsHookEx (WH_KEYBOARD_LL,
+ (HOOKPROC) low_level_keyboard_proc,
+ _gdk_dll_hinstance,
+ 0);
+
+ if (hook_handle != NULL)
+ keyboard_hook = hook_handle;
+ else
+ WIN32_API_FAILED ("SetWindowsHookEx");
+
+ aerosnap_message = RegisterWindowMessage ("GDK_WIN32_AEROSNAP_MESSAGE");
+}
+
void
_gdk_events_init (GdkDisplay *display)
{
@@ -405,6 +527,8 @@ _gdk_events_init (GdkDisplay *display)
g_source_add_poll (source, &event_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
+
+ set_up_low_level_keyboard_hook ();
}
gboolean
@@ -2283,6 +2407,10 @@ gdk_event_translate (MSG *msg,
}
}
+ if (msg->message == aerosnap_message)
+ _gdk_win32_window_handle_aerosnap (gdk_window_get_toplevel (window),
+ (GdkWin32AeroSnapCombo) msg->wParam);
+
switch (msg->message)
{
case WM_INPUTLANGCHANGE:
@@ -2362,48 +2490,6 @@ gdk_event_translate (MSG *msg,
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
- if (msg->message == WM_KEYUP &&
- !GDK_WINDOW_DESTROYED (gdk_window_get_toplevel (window)) &&
- _gdk_win32_window_lacks_wm_decorations (gdk_window_get_toplevel (window)) && /* For CSD only */
- ((GetKeyState (VK_LWIN) & 0x8000) ||
- (GetKeyState (VK_RWIN) & 0x8000)))
- {
- GdkWin32AeroSnapCombo combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
- gboolean lshiftdown = GetKeyState (VK_LSHIFT) & 0x8000;
- gboolean rshiftdown = GetKeyState (VK_RSHIFT) & 0x8000;
- gboolean oneshiftdown = (lshiftdown || rshiftdown) && !(lshiftdown && rshiftdown);
-
- switch (msg->wParam)
- {
- case VK_UP:
- combo = GDK_WIN32_AEROSNAP_COMBO_UP;
- break;
- case VK_DOWN:
- combo = GDK_WIN32_AEROSNAP_COMBO_DOWN;
- break;
- case VK_LEFT:
- combo = GDK_WIN32_AEROSNAP_COMBO_LEFT;
- break;
- case VK_RIGHT:
- combo = GDK_WIN32_AEROSNAP_COMBO_RIGHT;
- break;
- }
-
- if (oneshiftdown && combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
- combo += 4;
-
- /* These are the only combos that Windows WM does handle for us */
- if (combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT ||
- combo == GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT)
- combo = GDK_WIN32_AEROSNAP_COMBO_NOTHING;
-
- if (combo != GDK_WIN32_AEROSNAP_COMBO_NOTHING)
- {
- _gdk_win32_window_handle_aerosnap (gdk_window_get_toplevel (window), combo);
- break;
- }
- }
-
API_CALL (GetKeyboardState, (key_state));
ccount = 0;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]