From dd025757d476ee7107dec00ea5fcd92c10a46697 Mon Sep 17 00:00:00 2001 From: Paddy Xu Date: Sun, 23 Aug 2020 15:12:41 +0200 Subject: [PATCH] Fix #715: add 1s timeout before any previewing request --- QuickLook/App.xaml.cs | 8 ++- QuickLook/{ => Helpers}/GlobalKeyboardHook.cs | 36 ++++++------- ...oundListener.cs => KeystrokeDispatcher.cs} | 51 +++++++++++++------ QuickLook/QuickLook.csproj | 4 +- 4 files changed, 57 insertions(+), 42 deletions(-) rename QuickLook/{ => Helpers}/GlobalKeyboardHook.cs (74%) rename QuickLook/{BackgroundListener.cs => KeystrokeDispatcher.cs} (70%) diff --git a/QuickLook/App.xaml.cs b/QuickLook/App.xaml.cs index 4f5a9a6..ea739b9 100644 --- a/QuickLook/App.xaml.cs +++ b/QuickLook/App.xaml.cs @@ -16,8 +16,6 @@ // along with this program. If not, see . using System; -using System.Configuration; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -80,7 +78,7 @@ namespace QuickLook Shutdown(); return; } - + CheckUpdate(); RunListener(e); @@ -115,7 +113,7 @@ namespace QuickLook PluginManager.GetInstance(); ViewWindowManager.GetInstance(); - BackgroundListener.GetInstance(); + KeystrokeDispatcher.GetInstance(); PipeServerManager.GetInstance(); } @@ -128,7 +126,7 @@ namespace QuickLook PipeServerManager.GetInstance().Dispose(); TrayIconManager.GetInstance().Dispose(); - BackgroundListener.GetInstance().Dispose(); + KeystrokeDispatcher.GetInstance().Dispose(); ViewWindowManager.GetInstance().Dispose(); } diff --git a/QuickLook/GlobalKeyboardHook.cs b/QuickLook/Helpers/GlobalKeyboardHook.cs similarity index 74% rename from QuickLook/GlobalKeyboardHook.cs rename to QuickLook/Helpers/GlobalKeyboardHook.cs index aceda57..e1b1327 100644 --- a/QuickLook/GlobalKeyboardHook.cs +++ b/QuickLook/Helpers/GlobalKeyboardHook.cs @@ -16,14 +16,13 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using System.Windows.Forms; using System.Windows.Input; using QuickLook.Common.NativeMethods; using KeyEventArgs = System.Windows.Forms.KeyEventArgs; using KeyEventHandler = System.Windows.Forms.KeyEventHandler; -namespace QuickLook +namespace QuickLook.Helpers { internal class GlobalKeyboardHook : IDisposable { @@ -31,7 +30,6 @@ namespace QuickLook private User32.KeyboardHookProc _callback; private IntPtr _hhook = IntPtr.Zero; - internal List HookedKeys = new List(); protected GlobalKeyboardHook() { @@ -72,25 +70,23 @@ namespace QuickLook private int HookProc(int code, int wParam, ref User32.KeyboardHookStruct lParam) { - if (code >= 0) - if (!IsWindowsKeyPressed()) - { - var key = (Keys) lParam.vkCode; - if (HookedKeys.Contains(key)) - { - key = AddModifiers(key); + if (code < 0) + return User32.CallNextHookEx(_hhook, code, wParam, ref lParam); - var kea = new KeyEventArgs(key); - if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN) - KeyDown?.Invoke(this, kea); - if (wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP) - KeyUp?.Invoke(this, kea); - if (kea.Handled) - return 1; - } - } + if (IsWindowsKeyPressed()) + return User32.CallNextHookEx(_hhook, code, wParam, ref lParam); - return User32.CallNextHookEx(_hhook, code, wParam, ref lParam); + var key = (Keys) lParam.vkCode; + key = AddModifiers(key); + + var kea = new KeyEventArgs(key); + + if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN) + KeyDown?.Invoke(this, kea); + else if (wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP) + KeyUp?.Invoke(this, kea); + + return kea.Handled ? 1 : User32.CallNextHookEx(_hhook, code, wParam, ref lParam); } private bool IsWindowsKeyPressed() diff --git a/QuickLook/BackgroundListener.cs b/QuickLook/KeystrokeDispatcher.cs similarity index 70% rename from QuickLook/BackgroundListener.cs rename to QuickLook/KeystrokeDispatcher.cs index 6a2b644..3b9d6da 100644 --- a/QuickLook/BackgroundListener.cs +++ b/QuickLook/KeystrokeDispatcher.cs @@ -16,22 +16,35 @@ // along with this program. If not, see . using System; +using System.Collections.Generic; using System.Diagnostics; using System.Windows.Forms; using QuickLook.Common.Helpers; +using QuickLook.Helpers; namespace QuickLook { - internal class BackgroundListener : IDisposable + internal class KeystrokeDispatcher : IDisposable { - private static BackgroundListener _instance; + private static KeystrokeDispatcher _instance; + + private static HashSet _validKeys; private GlobalKeyboardHook _hook; private bool _isKeyDownInDesktopOrShell; + private long _lastInvalidKeyPressTick; - protected BackgroundListener() + private const long VALID_KEY_PRESS_DELAY = TimeSpan.TicksPerSecond * 1; + + protected KeystrokeDispatcher() { InstallKeyHook(KeyDownEventHandler, KeyUpEventHandler); + + _validKeys = new HashSet(new[] + { + Keys.Up, Keys.Down, Keys.Left, Keys.Right, + Keys.Enter, Keys.Space, Keys.Escape + }); } public void Dispose() @@ -55,7 +68,7 @@ namespace QuickLook if (e.Modifiers != Keys.None) return; - // set variable only when KeyDown + // check if the window is valid at the time of pressing a key, used for case 1 if (isKeyDown) { _isKeyDownInDesktopOrShell = NativeMethods.QuickLook.GetFocusedWindowType() != @@ -64,17 +77,32 @@ namespace QuickLook _isKeyDownInDesktopOrShell |= WindowHelper.IsForegroundWindowBelongToSelf(); } - // call InvokeRoutine only when the KeyDown is valid + // call InvokeRoutine only when: + // (1) user released a key which was pressed in a valid window, or + // (2) user pressed a key in a valid window if (_isKeyDownInDesktopOrShell) InvokeRoutine(e.KeyCode, isKeyDown); - // reset variable only when KeyUp + // in case 2, reset the variable if (!isKeyDown) _isKeyDownInDesktopOrShell = false; } private void InvokeRoutine(Keys key, bool isKeyDown) { + if (!_validKeys.Contains(key)) + { + Debug.WriteLine($"Invalid keypress: key={key},down={isKeyDown}, time={_lastInvalidKeyPressTick}"); + + _lastInvalidKeyPressTick = DateTime.Now.Ticks; + return; + } + + if (DateTime.Now.Ticks - _lastInvalidKeyPressTick < VALID_KEY_PRESS_DELAY) + return; + + _lastInvalidKeyPressTick = 0L; + Debug.WriteLine($"InvokeRoutine: key={key},down={isKeyDown}"); if (isKeyDown) @@ -110,20 +138,13 @@ namespace QuickLook { _hook = GlobalKeyboardHook.GetInstance(); - _hook.HookedKeys.Add(Keys.Enter); - _hook.HookedKeys.Add(Keys.Space); - _hook.HookedKeys.Add(Keys.Escape); - _hook.HookedKeys.Add(Keys.Up); - _hook.HookedKeys.Add(Keys.Down); - _hook.HookedKeys.Add(Keys.Left); - _hook.HookedKeys.Add(Keys.Right); _hook.KeyDown += downHandler; _hook.KeyUp += upHandler; } - internal static BackgroundListener GetInstance() + internal static KeystrokeDispatcher GetInstance() { - return _instance ?? (_instance = new BackgroundListener()); + return _instance ?? (_instance = new KeystrokeDispatcher()); } } } \ No newline at end of file diff --git a/QuickLook/QuickLook.csproj b/QuickLook/QuickLook.csproj index 7b3ea3c..36aaeff 100644 --- a/QuickLook/QuickLook.csproj +++ b/QuickLook/QuickLook.csproj @@ -180,8 +180,8 @@ App.xaml Code - - + + ViewerWindow.xaml Code