mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-12-24 02:00:55 +08:00
Fix #23: KeyDown/KeyUp firing sequence; Prevent duplicate launch when pressing Enter key
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Threading;
|
||||
using QuickLook.Helpers;
|
||||
|
||||
namespace QuickLook
|
||||
{
|
||||
@@ -9,10 +10,11 @@ namespace QuickLook
|
||||
private static BackgroundListener _instance;
|
||||
|
||||
private GlobalKeyboardHook _hook;
|
||||
private bool _isKeyDownInDesktopOrShell;
|
||||
|
||||
protected BackgroundListener()
|
||||
{
|
||||
InstallKeyHook(HotkeyEventHandler);
|
||||
InstallKeyHook(KeyDownEventHandler, KeyUpEventHandler);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -21,29 +23,55 @@ namespace QuickLook
|
||||
_hook = null;
|
||||
}
|
||||
|
||||
private void HotkeyEventHandler(object sender, KeyEventArgs e)
|
||||
private void KeyDownEventHandler(object sender, KeyEventArgs e)
|
||||
{
|
||||
CallViewWindowManagerInvokeRoutine(e, true);
|
||||
}
|
||||
|
||||
private void KeyUpEventHandler(object sender, KeyEventArgs e)
|
||||
{
|
||||
CallViewWindowManagerInvokeRoutine(e, false);
|
||||
}
|
||||
|
||||
private void CallViewWindowManagerInvokeRoutine(KeyEventArgs e, bool isKeyDown)
|
||||
{
|
||||
if (e.Modifiers != Keys.None)
|
||||
return;
|
||||
|
||||
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ViewWindowManager.GetInstance().InvokeRoutine(e)),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
// set variable only when KeyDown
|
||||
if (isKeyDown)
|
||||
{
|
||||
_isKeyDownInDesktopOrShell = NativeMethods.QuickLook.GetFocusedWindowType() !=
|
||||
NativeMethods.QuickLook.FocusedWindowType.Invalid;
|
||||
_isKeyDownInDesktopOrShell |= WindowHelper.IsForegroundWindowBelongToSelf();
|
||||
}
|
||||
|
||||
// call InvokeRoutine only when the KeyDown is valid
|
||||
if (_isKeyDownInDesktopOrShell)
|
||||
Dispatcher.CurrentDispatcher.BeginInvoke(
|
||||
new Action<bool>(down =>
|
||||
ViewWindowManager.GetInstance().InvokeRoutine(e, down)),
|
||||
DispatcherPriority.ApplicationIdle,
|
||||
isKeyDown);
|
||||
|
||||
// reset variable only when KeyUp
|
||||
if (!isKeyDown)
|
||||
_isKeyDownInDesktopOrShell = false;
|
||||
}
|
||||
|
||||
private void InstallKeyHook(KeyEventHandler handler)
|
||||
private void InstallKeyHook(KeyEventHandler downHandler, KeyEventHandler upHandler)
|
||||
{
|
||||
_hook = GlobalKeyboardHook.GetInstance();
|
||||
|
||||
_hook.HookedDownKeys.Add(Keys.Enter);
|
||||
_hook.KeyDown += handler;
|
||||
|
||||
_hook.HookedUpKeys.Add(Keys.Space);
|
||||
_hook.HookedUpKeys.Add(Keys.Escape);
|
||||
_hook.HookedUpKeys.Add(Keys.Up);
|
||||
_hook.HookedUpKeys.Add(Keys.Down);
|
||||
_hook.HookedUpKeys.Add(Keys.Left);
|
||||
_hook.HookedUpKeys.Add(Keys.Right);
|
||||
_hook.KeyUp += handler;
|
||||
_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()
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace QuickLook
|
||||
|
||||
private User32.KeyboardHookProc _callback;
|
||||
private IntPtr _hhook = IntPtr.Zero;
|
||||
internal List<Keys> HookedDownKeys = new List<Keys>();
|
||||
internal List<Keys> HookedUpKeys = new List<Keys>();
|
||||
internal List<Keys> HookedKeys = new List<Keys>();
|
||||
|
||||
protected GlobalKeyboardHook()
|
||||
{
|
||||
@@ -64,21 +63,13 @@ namespace QuickLook
|
||||
if (code >= 0)
|
||||
{
|
||||
var key = (Keys) lParam.vkCode;
|
||||
if (HookedDownKeys.Contains(key))
|
||||
if (HookedKeys.Contains(key))
|
||||
{
|
||||
key = AddModifiers(key);
|
||||
|
||||
var kea = new KeyEventArgs(key);
|
||||
if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN)
|
||||
KeyDown?.Invoke(this, kea);
|
||||
if (kea.Handled)
|
||||
return 1;
|
||||
}
|
||||
else if (HookedUpKeys.Contains(key))
|
||||
{
|
||||
key = AddModifiers(key);
|
||||
|
||||
var kea = new KeyEventArgs(key);
|
||||
if (wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP)
|
||||
KeyUp?.Invoke(this, kea);
|
||||
if (kea.Handled)
|
||||
|
||||
@@ -8,19 +8,19 @@ namespace QuickLook.NativeMethods
|
||||
{
|
||||
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetFocusedWindowType",
|
||||
CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern FocusedWindowType GetFocusedWindowTypeNative_32();
|
||||
private static extern FocusedWindowType GetFocusedWindowTypeNative_32();
|
||||
|
||||
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetCurrentSelection",
|
||||
CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void GetCurrentSelectionNative_32([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
|
||||
private static extern void GetCurrentSelectionNative_32([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
|
||||
|
||||
[DllImport("QuickLook.Native.Shell32.x64.dll", EntryPoint = "GetFocusedWindowType",
|
||||
CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern FocusedWindowType GetFocusedWindowTypeNative_64();
|
||||
private static extern FocusedWindowType GetFocusedWindowTypeNative_64();
|
||||
|
||||
[DllImport("QuickLook.Native.Shell32.x64.dll", EntryPoint = "GetCurrentSelection",
|
||||
CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void GetCurrentSelectionNative_64([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
|
||||
private static extern void GetCurrentSelectionNative_64([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
|
||||
|
||||
internal static FocusedWindowType GetFocusedWindowType()
|
||||
{
|
||||
|
||||
@@ -34,51 +34,62 @@ namespace QuickLook
|
||||
StopFocusMonitor();
|
||||
}
|
||||
|
||||
internal void InvokeRoutine(KeyEventArgs kea)
|
||||
internal void InvokeRoutine(KeyEventArgs kea, bool isKeyDown)
|
||||
{
|
||||
switch (kea.KeyCode)
|
||||
{
|
||||
case Keys.Up:
|
||||
case Keys.Down:
|
||||
case Keys.Left:
|
||||
case Keys.Right:
|
||||
SwitchPreview();
|
||||
break;
|
||||
case Keys.Space:
|
||||
TogglePreview();
|
||||
break;
|
||||
case Keys.Escape:
|
||||
ClosePreview();
|
||||
break;
|
||||
case Keys.Enter:
|
||||
RunAndClosePreview();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Debug.WriteLine($"InvokeRoutine: key={kea.KeyCode},down={isKeyDown}");
|
||||
|
||||
|
||||
if (isKeyDown)
|
||||
switch (kea.KeyCode)
|
||||
{
|
||||
case Keys.Enter:
|
||||
RunAndClosePreview();
|
||||
break;
|
||||
}
|
||||
else
|
||||
switch (kea.KeyCode)
|
||||
{
|
||||
case Keys.Up:
|
||||
case Keys.Down:
|
||||
case Keys.Left:
|
||||
case Keys.Right:
|
||||
SwitchPreview();
|
||||
break;
|
||||
case Keys.Space:
|
||||
TogglePreview();
|
||||
break;
|
||||
case Keys.Escape:
|
||||
ClosePreview();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void RunAndClosePreview()
|
||||
{
|
||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
||||
return;
|
||||
|
||||
if (_currentMainWindow.Visibility != Visibility.Visible)
|
||||
return;
|
||||
|
||||
// if the current focus is in Desktop or explorer windows, just close the preview window and leave the task to System.
|
||||
var focus = NativeMethods.QuickLook.GetFocusedWindowType();
|
||||
if (focus == NativeMethods.QuickLook.FocusedWindowType.Desktop ||
|
||||
focus == NativeMethods.QuickLook.FocusedWindowType.Explorer)
|
||||
if (_path == NativeMethods.QuickLook.GetCurrentSelection())
|
||||
{
|
||||
StopFocusMonitor();
|
||||
_currentMainWindow.BeginHide();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the focus is in the preview window, run it
|
||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
||||
return;
|
||||
|
||||
StopFocusMonitor();
|
||||
_currentMainWindow.RunAndHide();
|
||||
}
|
||||
|
||||
internal void ClosePreview()
|
||||
{
|
||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
||||
return;
|
||||
|
||||
if (_currentMainWindow.Visibility != Visibility.Visible)
|
||||
return;
|
||||
|
||||
@@ -90,11 +101,6 @@ namespace QuickLook
|
||||
{
|
||||
_lastSwitchTick = DateTime.Now.Ticks;
|
||||
|
||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
||||
return;
|
||||
|
||||
if (_currentMainWindow.Visibility == Visibility.Visible)
|
||||
{
|
||||
ClosePreview();
|
||||
@@ -113,10 +119,6 @@ namespace QuickLook
|
||||
|
||||
_lastSwitchTick = DateTime.Now.Ticks;
|
||||
|
||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
||||
return;
|
||||
|
||||
_path = NativeMethods.QuickLook.GetCurrentSelection();
|
||||
|
||||
InvokeViewer();
|
||||
|
||||
Reference in New Issue
Block a user