Fix #715: add 1s timeout before any previewing request

This commit is contained in:
Paddy Xu
2020-08-23 15:12:41 +02:00
parent 80d95dbe20
commit dd025757d4
4 changed files with 57 additions and 42 deletions

View File

@@ -16,8 +16,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
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();
}

View File

@@ -16,14 +16,13 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
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<Keys> HookedKeys = new List<Keys>();
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()

View File

@@ -16,22 +16,35 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
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<Keys> _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<Keys>(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());
}
}
}

View File

@@ -180,8 +180,8 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="BackgroundListener.cs" />
<Compile Include="GlobalKeyboardHook.cs" />
<Compile Include="KeystrokeDispatcher.cs" />
<Compile Include="Helpers\GlobalKeyboardHook.cs" />
<Compile Include="ViewerWindow.xaml.cs">
<DependentUpon>ViewerWindow.xaml</DependentUpon>
<SubType>Code</SubType>