mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-02-28 01:00:17 +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;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using QuickLook.Helpers;
|
||||||
|
|
||||||
namespace QuickLook
|
namespace QuickLook
|
||||||
{
|
{
|
||||||
@@ -9,10 +10,11 @@ namespace QuickLook
|
|||||||
private static BackgroundListener _instance;
|
private static BackgroundListener _instance;
|
||||||
|
|
||||||
private GlobalKeyboardHook _hook;
|
private GlobalKeyboardHook _hook;
|
||||||
|
private bool _isKeyDownInDesktopOrShell;
|
||||||
|
|
||||||
protected BackgroundListener()
|
protected BackgroundListener()
|
||||||
{
|
{
|
||||||
InstallKeyHook(HotkeyEventHandler);
|
InstallKeyHook(KeyDownEventHandler, KeyUpEventHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -21,29 +23,55 @@ namespace QuickLook
|
|||||||
_hook = null;
|
_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)
|
if (e.Modifiers != Keys.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => ViewWindowManager.GetInstance().InvokeRoutine(e)),
|
// set variable only when KeyDown
|
||||||
DispatcherPriority.ApplicationIdle);
|
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 = GlobalKeyboardHook.GetInstance();
|
||||||
|
|
||||||
_hook.HookedDownKeys.Add(Keys.Enter);
|
_hook.HookedKeys.Add(Keys.Enter);
|
||||||
_hook.KeyDown += handler;
|
_hook.HookedKeys.Add(Keys.Space);
|
||||||
|
_hook.HookedKeys.Add(Keys.Escape);
|
||||||
_hook.HookedUpKeys.Add(Keys.Space);
|
_hook.HookedKeys.Add(Keys.Up);
|
||||||
_hook.HookedUpKeys.Add(Keys.Escape);
|
_hook.HookedKeys.Add(Keys.Down);
|
||||||
_hook.HookedUpKeys.Add(Keys.Up);
|
_hook.HookedKeys.Add(Keys.Left);
|
||||||
_hook.HookedUpKeys.Add(Keys.Down);
|
_hook.HookedKeys.Add(Keys.Right);
|
||||||
_hook.HookedUpKeys.Add(Keys.Left);
|
_hook.KeyDown += downHandler;
|
||||||
_hook.HookedUpKeys.Add(Keys.Right);
|
_hook.KeyUp += upHandler;
|
||||||
_hook.KeyUp += handler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static BackgroundListener GetInstance()
|
internal static BackgroundListener GetInstance()
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ namespace QuickLook
|
|||||||
|
|
||||||
private User32.KeyboardHookProc _callback;
|
private User32.KeyboardHookProc _callback;
|
||||||
private IntPtr _hhook = IntPtr.Zero;
|
private IntPtr _hhook = IntPtr.Zero;
|
||||||
internal List<Keys> HookedDownKeys = new List<Keys>();
|
internal List<Keys> HookedKeys = new List<Keys>();
|
||||||
internal List<Keys> HookedUpKeys = new List<Keys>();
|
|
||||||
|
|
||||||
protected GlobalKeyboardHook()
|
protected GlobalKeyboardHook()
|
||||||
{
|
{
|
||||||
@@ -64,21 +63,13 @@ namespace QuickLook
|
|||||||
if (code >= 0)
|
if (code >= 0)
|
||||||
{
|
{
|
||||||
var key = (Keys) lParam.vkCode;
|
var key = (Keys) lParam.vkCode;
|
||||||
if (HookedDownKeys.Contains(key))
|
if (HookedKeys.Contains(key))
|
||||||
{
|
{
|
||||||
key = AddModifiers(key);
|
key = AddModifiers(key);
|
||||||
|
|
||||||
var kea = new KeyEventArgs(key);
|
var kea = new KeyEventArgs(key);
|
||||||
if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN)
|
if (wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN)
|
||||||
KeyDown?.Invoke(this, kea);
|
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)
|
if (wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP)
|
||||||
KeyUp?.Invoke(this, kea);
|
KeyUp?.Invoke(this, kea);
|
||||||
if (kea.Handled)
|
if (kea.Handled)
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ namespace QuickLook.NativeMethods
|
|||||||
{
|
{
|
||||||
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetFocusedWindowType",
|
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetFocusedWindowType",
|
||||||
CallingConvention = CallingConvention.Cdecl)]
|
CallingConvention = CallingConvention.Cdecl)]
|
||||||
internal static extern FocusedWindowType GetFocusedWindowTypeNative_32();
|
private static extern FocusedWindowType GetFocusedWindowTypeNative_32();
|
||||||
|
|
||||||
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetCurrentSelection",
|
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetCurrentSelection",
|
||||||
CallingConvention = CallingConvention.Cdecl)]
|
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",
|
[DllImport("QuickLook.Native.Shell32.x64.dll", EntryPoint = "GetFocusedWindowType",
|
||||||
CallingConvention = CallingConvention.Cdecl)]
|
CallingConvention = CallingConvention.Cdecl)]
|
||||||
internal static extern FocusedWindowType GetFocusedWindowTypeNative_64();
|
private static extern FocusedWindowType GetFocusedWindowTypeNative_64();
|
||||||
|
|
||||||
[DllImport("QuickLook.Native.Shell32.x64.dll", EntryPoint = "GetCurrentSelection",
|
[DllImport("QuickLook.Native.Shell32.x64.dll", EntryPoint = "GetCurrentSelection",
|
||||||
CallingConvention = CallingConvention.Cdecl)]
|
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()
|
internal static FocusedWindowType GetFocusedWindowType()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,51 +34,62 @@ namespace QuickLook
|
|||||||
StopFocusMonitor();
|
StopFocusMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvokeRoutine(KeyEventArgs kea)
|
internal void InvokeRoutine(KeyEventArgs kea, bool isKeyDown)
|
||||||
{
|
{
|
||||||
switch (kea.KeyCode)
|
Debug.WriteLine($"InvokeRoutine: key={kea.KeyCode},down={isKeyDown}");
|
||||||
{
|
|
||||||
case Keys.Up:
|
|
||||||
case Keys.Down:
|
if (isKeyDown)
|
||||||
case Keys.Left:
|
switch (kea.KeyCode)
|
||||||
case Keys.Right:
|
{
|
||||||
SwitchPreview();
|
case Keys.Enter:
|
||||||
break;
|
RunAndClosePreview();
|
||||||
case Keys.Space:
|
break;
|
||||||
TogglePreview();
|
}
|
||||||
break;
|
else
|
||||||
case Keys.Escape:
|
switch (kea.KeyCode)
|
||||||
ClosePreview();
|
{
|
||||||
break;
|
case Keys.Up:
|
||||||
case Keys.Enter:
|
case Keys.Down:
|
||||||
RunAndClosePreview();
|
case Keys.Left:
|
||||||
break;
|
case Keys.Right:
|
||||||
default:
|
SwitchPreview();
|
||||||
break;
|
break;
|
||||||
}
|
case Keys.Space:
|
||||||
|
TogglePreview();
|
||||||
|
break;
|
||||||
|
case Keys.Escape:
|
||||||
|
ClosePreview();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RunAndClosePreview()
|
internal void RunAndClosePreview()
|
||||||
{
|
{
|
||||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
|
||||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
|
||||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_currentMainWindow.Visibility != Visibility.Visible)
|
if (_currentMainWindow.Visibility != Visibility.Visible)
|
||||||
return;
|
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();
|
StopFocusMonitor();
|
||||||
_currentMainWindow.RunAndHide();
|
_currentMainWindow.RunAndHide();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClosePreview()
|
internal void ClosePreview()
|
||||||
{
|
{
|
||||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
|
||||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
|
||||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_currentMainWindow.Visibility != Visibility.Visible)
|
if (_currentMainWindow.Visibility != Visibility.Visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -90,11 +101,6 @@ namespace QuickLook
|
|||||||
{
|
{
|
||||||
_lastSwitchTick = DateTime.Now.Ticks;
|
_lastSwitchTick = DateTime.Now.Ticks;
|
||||||
|
|
||||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
|
||||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
|
||||||
if (!WindowHelper.IsForegroundWindowBelongToSelf())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_currentMainWindow.Visibility == Visibility.Visible)
|
if (_currentMainWindow.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
ClosePreview();
|
ClosePreview();
|
||||||
@@ -113,10 +119,6 @@ namespace QuickLook
|
|||||||
|
|
||||||
_lastSwitchTick = DateTime.Now.Ticks;
|
_lastSwitchTick = DateTime.Now.Ticks;
|
||||||
|
|
||||||
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
|
|
||||||
NativeMethods.QuickLook.FocusedWindowType.Invalid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_path = NativeMethods.QuickLook.GetCurrentSelection();
|
_path = NativeMethods.QuickLook.GetCurrentSelection();
|
||||||
|
|
||||||
InvokeViewer();
|
InvokeViewer();
|
||||||
|
|||||||
Reference in New Issue
Block a user