mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Use Global Hook for Hotkey Control
This commit is contained in:
parent
add175730b
commit
05dbe94f53
6 changed files with 81 additions and 20 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,6 @@
|
|||
Margin="0,0,18,0"
|
||||
VerticalContentAlignment="Center"
|
||||
input:InputMethod.IsInputMethodEnabled="False"
|
||||
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
|
||||
TabIndex="100"
|
||||
LostFocus="tbHotkey_LostFocus"/>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue