diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index e01bc1efd..40c2cb956 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -11,6 +11,7 @@
false
false
false
+ true
@@ -21,7 +22,6 @@
DEBUG;TRACE
prompt
4
- true
false
@@ -32,7 +32,6 @@
TRACE
prompt
4
- false
false
diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs
index e92a93c12..a09185696 100644
--- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs
+++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs
@@ -9,13 +9,14 @@ namespace Flow.Launcher.Infrastructure.Hotkey
/// Listens keyboard globally.
/// Uses WH_KEYBOARD_LL.
///
- public class GlobalHotkey : IDisposable
+ public unsafe class GlobalHotkey : IDisposable
{
- private static GlobalHotkey instance;
- private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
- private IntPtr hookId = IntPtr.Zero;
+ private static readonly IntPtr hookId;
+
+
+
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
- public event KeyboardCallback hookedKeyboardCallback;
+ internal static Func hookedKeyboardCallback;
//Modifier key constants
private const int VK_SHIFT = 0x10;
@@ -23,27 +24,13 @@ namespace Flow.Launcher.Infrastructure.Hotkey
private const int VK_ALT = 0x12;
private const int VK_WIN = 91;
- public static GlobalHotkey Instance
+ static GlobalHotkey()
{
- get
- {
- if (instance == null)
- {
- instance = new GlobalHotkey();
- }
- return instance;
- }
- }
-
- private GlobalHotkey()
- {
- // We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime
- hookedLowLevelKeyboardProc = LowLevelKeyboardProc;
// Set the hook
- hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
+ hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc);
}
- public SpecialKeyState CheckModifiers()
+ public static SpecialKeyState CheckModifiers()
{
SpecialKeyState state = new SpecialKeyState();
if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0)
@@ -70,8 +57,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey
return state;
}
- [MethodImpl(MethodImplOptions.NoInlining)]
- private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
+ [UnmanagedCallersOnly]
+ private static IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
{
bool continues = true;
@@ -91,17 +78,17 @@ namespace Flow.Launcher.Infrastructure.Hotkey
{
return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
}
- return (IntPtr)1;
- }
-
- ~GlobalHotkey()
- {
- Dispose();
+ return (IntPtr)(-1);
}
public void Dispose()
{
InterceptKeys.UnhookWindowsHookEx(hookId);
}
+
+ ~GlobalHotkey()
+ {
+ Dispose();
+ }
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs
index c45e685f3..d33bac34c 100644
--- a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs
+++ b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs
@@ -4,13 +4,13 @@ using System.Runtime.InteropServices;
namespace Flow.Launcher.Infrastructure.Hotkey
{
- internal static class InterceptKeys
+ internal static unsafe class InterceptKeys
{
public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
private const int WH_KEYBOARD_LL = 13;
- public static IntPtr SetHook(LowLevelKeyboardProc proc)
+ public static IntPtr SetHook(delegate* unmanaged proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
@@ -20,7 +20,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
+ public static extern IntPtr SetWindowsHookEx(int idHook, delegate* unmanaged lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
index 0b59371f8..d1444d5db 100644
--- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
@@ -119,7 +119,21 @@ namespace Flow.Launcher.Plugin
/// Fired after global keyboard events
/// if you want to hook something like Ctrl+R, you should use this event
///
+ [Obsolete("Unable to Retrieve correct return value")]
event FlowLauncherGlobalKeyboardEventHandler GlobalKeyboardEvent;
+
+ ///
+ /// Register a callback for Global Keyboard Event
+ ///
+ ///
+ public void RegisterGlobalKeyboardCallback(Func callback);
+
+ ///
+ /// Remove a callback for Global Keyboard Event
+ ///
+ ///
+ public void RemoveGlobalKeyboardCallback(Func callback);
+
///
/// Fuzzy Search the string with the given query. This is the core search mechanism Flow uses
diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs
index 9ba7c4368..bc437d862 100644
--- a/Flow.Launcher/HotkeyControl.xaml.cs
+++ b/Flow.Launcher/HotkeyControl.xaml.cs
@@ -45,7 +45,7 @@ namespace Flow.Launcher
//when alt is pressed, the real key should be e.SystemKey
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
- SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers();
+ SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
var hotkeyModel = new HotkeyModel(
specialKeyState.AltPressed,
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index eb62733b7..6713929d6 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -41,7 +41,7 @@ namespace Flow.Launcher
_settingsVM = settingsVM;
_mainVM = mainVM;
_alphabet = alphabet;
- GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback;
+ GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
}
@@ -204,25 +204,35 @@ namespace Flow.Launcher
Arguments = FileName is null ?
explorerInfo.DirectoryArgument.Replace("%d", DirectoryPath) :
explorerInfo.FileArgument.Replace("%d", DirectoryPath).Replace("%f",
- Path.IsPathRooted(FileName) ? FileName : Path.Combine(DirectoryPath, FileName))
+ Path.IsPathRooted(FileName) ? FileName : Path.Combine(DirectoryPath, FileName))
};
explorer.Start();
}
public event FlowLauncherGlobalKeyboardEventHandler GlobalKeyboardEvent;
+ private readonly List> _globalKeyboardHandlers = new();
+
+ public void RegisterGlobalKeyboardCallback(Func callback) => _globalKeyboardHandlers.Add(callback);
+ public void RemoveGlobalKeyboardCallback(Func callback) => _globalKeyboardHandlers.Remove(callback);
+
#endregion
#region Private Methods
private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state)
{
+ var continueHook = true;
if (GlobalKeyboardEvent != null)
{
- return GlobalKeyboardEvent((int)keyevent, vkcode, state);
+ continueHook = GlobalKeyboardEvent((int)keyevent, vkcode, state);
+ }
+ foreach (var x in _globalKeyboardHandlers)
+ {
+ continueHook &= x((int)keyevent, vkcode, state);
}
- return true;
+ return continueHook;
}
#endregion
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index 187ba63ec..37052cca6 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -208,7 +208,7 @@ namespace Flow.Launcher.ViewModel
{
bool hideWindow = result.Action != null && result.Action(new ActionContext
{
- SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
+ SpecialKeyState = GlobalHotkey.CheckModifiers()
});
if (hideWindow)
@@ -244,8 +244,8 @@ namespace Flow.Launcher.ViewModel
autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText;
}
- var SpecialKeyState = GlobalHotkey.Instance.CheckModifiers();
- if (SpecialKeyState.ShiftPressed)
+ var specialKeyState = GlobalHotkey.CheckModifiers();
+ if (specialKeyState.ShiftPressed)
{
autoCompleteText = result.SubTitle;
}
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
index 5bf82cb10..0c539015e 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
@@ -312,7 +312,7 @@ namespace Flow.Launcher.Plugin.Shell
{
this.context = context;
_settings = context.API.LoadSettingJsonStorage();
- context.API.GlobalKeyboardEvent += API_GlobalKeyboardEvent;
+ context.API.RegisterGlobalKeyboardCallback(API_GlobalKeyboardEvent);
}
bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state)
@@ -337,12 +337,9 @@ namespace Flow.Launcher.Plugin.Shell
private void OnWinRPressed()
{
- context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
-
// show the main window and set focus to the query box
- Window mainWindow = Application.Current.MainWindow;
- mainWindow.Show();
- mainWindow.Focus();
+ context.API.ShowMainWindow();
+ context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
}
public Control CreateSettingPanel()
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
index b71dba2da..2cfcbca2e 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
@@ -4,7 +4,7 @@
"Name": "Shell",
"Description": "Provide executing commands from Flow Launcher",
"Author": "qianlifeng",
- "Version": "1.4.6",
+ "Version": "1.4.7",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll",