Use Global Hook for Hotkey Control

This commit is contained in:
Hongtao Zhang 2021-12-24 15:06:59 -06:00
parent add175730b
commit 05dbe94f53
6 changed files with 81 additions and 20 deletions

View file

@ -12,9 +12,9 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public unsafe class GlobalHotkey : IDisposable
{
private static readonly IntPtr hookId;
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
internal static Func<KeyEvent, int, SpecialKeyState, bool> hookedKeyboardCallback;
@ -27,12 +27,15 @@ namespace Flow.Launcher.Infrastructure.Hotkey
static GlobalHotkey()
{
// Set the hook
hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc);
hookId = InterceptKeys.SetHook(&LowLevelKeyboardProc);
}
public static SpecialKeyState CheckModifiers()
{
SpecialKeyState state = new SpecialKeyState();
if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0)
{
//SHIFT is pressed

View file

@ -31,15 +31,15 @@ namespace Flow.Launcher.Infrastructure.Hotkey
}
if (Shift)
{
modifierKeys = modifierKeys | ModifierKeys.Shift;
modifierKeys |= ModifierKeys.Shift;
}
if (Win)
{
modifierKeys = modifierKeys | ModifierKeys.Windows;
modifierKeys |= ModifierKeys.Windows;
}
if (Ctrl)
{
modifierKeys = modifierKeys | ModifierKeys.Control;
modifierKeys |= ModifierKeys.Control;
}
return modifierKeys;
}

View file

@ -34,5 +34,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetAsyncKeyState(int keyCode);
}
}

View file

@ -49,7 +49,6 @@
Margin="0,0,18,0"
VerticalContentAlignment="Center"
input:InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
TabIndex="100"
LostFocus="tbHotkey_LostFocus"/>
</Grid>

View file

@ -9,6 +9,8 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin;
using System.Threading;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher
{
@ -25,41 +27,93 @@ namespace Flow.Launcher
protected virtual void OnHotkeyChanged() => HotkeyChanged?.Invoke(this, EventArgs.Empty);
private Func<int, int, SpecialKeyState, bool> callback { get; set; }
public HotkeyControl()
{
InitializeComponent();
tbMsgTextOriginal = tbMsg.Text;
tbMsgForegroundColorOriginal = tbMsg.Foreground;
callback = TbHotkey_OnPreviewKeyDown;
GotFocus += (_, _) =>
{
PluginManager.API.RegisterGlobalKeyboardCallback(callback);
};
LostFocus += (_, _) =>
{
PluginManager.API.RemoveGlobalKeyboardCallback(callback);
};
}
private CancellationTokenSource hotkeyUpdateSource;
private void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e)
private SpecialKeyState state = new SpecialKeyState();
private bool TbHotkey_OnPreviewKeyDown(int keyevent, int vkcode, SpecialKeyState dummy)
{
var key = KeyInterop.KeyFromVirtualKey(vkcode);
if ((KeyEvent)keyevent is not (KeyEvent.WM_KEYDOWN or KeyEvent.WM_SYSKEYDOWN))
{
switch (key)
{
case Key.LeftAlt or Key.RightAlt:
state.AltPressed = false;
break;
case Key.LeftCtrl or Key.RightCtrl:
state.CtrlPressed = false;
break;
case Key.LeftShift or Key.RightShift:
state.ShiftPressed = false;
break;
case Key.LWin or Key.LWin:
state.WinPressed = false;
break;
default:
break;
}
return true;
}
switch (key)
{
case Key.LeftAlt or Key.RightAlt:
state.AltPressed = true;
break;
case Key.LeftCtrl or Key.RightCtrl:
state.CtrlPressed = true;
break;
case Key.LeftShift or Key.RightShift:
state.ShiftPressed = true;
break;
case Key.LWin or Key.LWin:
state.WinPressed = true;
break;
}
hotkeyUpdateSource?.Cancel();
hotkeyUpdateSource?.Dispose();
hotkeyUpdateSource = new();
var token = hotkeyUpdateSource.Token;
e.Handled = true;
//when alt is pressed, the real key should be e.SystemKey
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
var hotkeyModel = new HotkeyModel(
specialKeyState.AltPressed,
specialKeyState.ShiftPressed,
specialKeyState.WinPressed,
specialKeyState.CtrlPressed,
state.AltPressed,
state.ShiftPressed,
state.WinPressed,
state.CtrlPressed,
key);
var hotkeyString = hotkeyModel.ToString();
if (hotkeyString == tbHotkey.Text)
{
return;
return false;
}
Log.Debug("test hotkey" + hotkeyString);
_ = Dispatcher.InvokeAsync(async () =>
{
@ -67,6 +121,8 @@ namespace Flow.Launcher
if (!token.IsCancellationRequested)
await SetHotkey(hotkeyModel);
});
return false;
}
public async Task SetHotkey(HotkeyModel keyModel, bool triggerValidate = true)

View file

@ -137,7 +137,7 @@ namespace Flow.Launcher
private void OnHotkeyControlFocused(object sender, RoutedEventArgs e)
{
HotKeyMapper.RemoveHotkey(settings.Hotkey);
//HotKeyMapper.RemoveHotkey(settings.Hotkey);
}
private void OnHotkeyControlFocusLost(object sender, RoutedEventArgs e)