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

@ -27,12 +27,15 @@ namespace Flow.Launcher.Infrastructure.Hotkey
static GlobalHotkey() static GlobalHotkey()
{ {
// Set the hook // Set the hook
hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc); hookId = InterceptKeys.SetHook(&LowLevelKeyboardProc);
} }
public static SpecialKeyState CheckModifiers() public static SpecialKeyState CheckModifiers()
{ {
SpecialKeyState state = new SpecialKeyState(); SpecialKeyState state = new SpecialKeyState();
if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0) if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0)
{ {
//SHIFT is pressed //SHIFT is pressed

View file

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

View file

@ -34,5 +34,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode); 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" Margin="0,0,18,0"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
input:InputMethod.IsInputMethodEnabled="False" input:InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
TabIndex="100" TabIndex="100"
LostFocus="tbHotkey_LostFocus"/> LostFocus="tbHotkey_LostFocus"/>
</Grid> </Grid>

View file

@ -9,6 +9,8 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using System.Threading; using System.Threading;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher namespace Flow.Launcher
{ {
@ -25,41 +27,93 @@ namespace Flow.Launcher
protected virtual void OnHotkeyChanged() => HotkeyChanged?.Invoke(this, EventArgs.Empty); protected virtual void OnHotkeyChanged() => HotkeyChanged?.Invoke(this, EventArgs.Empty);
private Func<int, int, SpecialKeyState, bool> callback { get; set; }
public HotkeyControl() public HotkeyControl()
{ {
InitializeComponent(); InitializeComponent();
tbMsgTextOriginal = tbMsg.Text; tbMsgTextOriginal = tbMsg.Text;
tbMsgForegroundColorOriginal = tbMsg.Foreground; tbMsgForegroundColorOriginal = tbMsg.Foreground;
callback = TbHotkey_OnPreviewKeyDown;
GotFocus += (_, _) =>
{
PluginManager.API.RegisterGlobalKeyboardCallback(callback);
};
LostFocus += (_, _) =>
{
PluginManager.API.RemoveGlobalKeyboardCallback(callback);
};
} }
private CancellationTokenSource hotkeyUpdateSource; 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?.Cancel();
hotkeyUpdateSource?.Dispose(); hotkeyUpdateSource?.Dispose();
hotkeyUpdateSource = new(); hotkeyUpdateSource = new();
var token = hotkeyUpdateSource.Token; 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( var hotkeyModel = new HotkeyModel(
specialKeyState.AltPressed, state.AltPressed,
specialKeyState.ShiftPressed, state.ShiftPressed,
specialKeyState.WinPressed, state.WinPressed,
specialKeyState.CtrlPressed, state.CtrlPressed,
key); key);
var hotkeyString = hotkeyModel.ToString(); var hotkeyString = hotkeyModel.ToString();
if (hotkeyString == tbHotkey.Text) if (hotkeyString == tbHotkey.Text)
{ {
return; return false;
} }
Log.Debug("test hotkey" + hotkeyString);
_ = Dispatcher.InvokeAsync(async () => _ = Dispatcher.InvokeAsync(async () =>
{ {
@ -67,6 +121,8 @@ namespace Flow.Launcher
if (!token.IsCancellationRequested) if (!token.IsCancellationRequested)
await SetHotkey(hotkeyModel); await SetHotkey(hotkeyModel);
}); });
return false;
} }
public async Task SetHotkey(HotkeyModel keyModel, bool triggerValidate = true) 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) private void OnHotkeyControlFocused(object sender, RoutedEventArgs e)
{ {
HotKeyMapper.RemoveHotkey(settings.Hotkey); //HotKeyMapper.RemoveHotkey(settings.Hotkey);
} }
private void OnHotkeyControlFocusLost(object sender, RoutedEventArgs e) private void OnHotkeyControlFocusLost(object sender, RoutedEventArgs e)