Fix #23: KeyDown/KeyUp firing sequence; Prevent duplicate launch when pressing Enter key

This commit is contained in:
Paddy Xu
2017-06-08 21:07:27 +03:00
parent 50081abb62
commit 00a6100166
4 changed files with 91 additions and 70 deletions

View File

@@ -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()

View File

@@ -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)

View File

@@ -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()
{

View File

@@ -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();