Support change window hotkey

This commit is contained in:
Jack251970 2025-06-26 09:28:25 +08:00
parent 53e0bc33ab
commit 724b8a72cb
3 changed files with 110 additions and 29 deletions

View file

@ -10,6 +10,7 @@ using System.Windows.Input;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
@ -40,7 +41,7 @@ namespace Flow.Launcher.Core.Plugin
private static PluginsSettings Settings;
private static List<PluginMetadata> _metadatas;
private static readonly List<string> _modifiedPlugins = new();
private static readonly Dictionary<KeyGesture, List<(PluginMetadata, SearchWindowPluginHotkey)>> _windowPluginHotkeys = new();
private static readonly Dictionary<HotkeyModel, List<(PluginMetadata, SearchWindowPluginHotkey)>> _windowPluginHotkeys = new();
/// <summary>
/// Directories that will hold Flow Launcher plugin directory
@ -461,7 +462,7 @@ namespace Flow.Launcher.Core.Plugin
return hotkeyPluginInfos;
}
public static Dictionary<KeyGesture, List<(PluginMetadata Metadata, SearchWindowPluginHotkey SearchWindowPluginHotkey)>> GetWindowPluginHotkeys()
public static Dictionary<HotkeyModel, List<(PluginMetadata Metadata, SearchWindowPluginHotkey SearchWindowPluginHotkey)>> GetWindowPluginHotkeys()
{
return _windowPluginHotkeys;
}
@ -478,22 +479,66 @@ namespace Flow.Launcher.Core.Plugin
if (hotkey.HotkeyType == HotkeyType.SearchWindow && hotkey is SearchWindowPluginHotkey searchWindowHotkey)
{
var hotkeySetting = metadata.PluginHotkeys.Find(h => h.Id == hotkey.Id)?.Hotkey ?? hotkey.DefaultHotkey;
var converter = new KeyGestureConverter();
var keyGesture = (KeyGesture)converter.ConvertFromString(hotkeySetting);
if (keyGesture != null)
var hotkeyModel = new HotkeyModel(hotkeySetting);
if (!_windowPluginHotkeys.TryGetValue(hotkeyModel, out var list))
{
if (!_windowPluginHotkeys.TryGetValue(keyGesture, out var list))
{
list = new List<(PluginMetadata, SearchWindowPluginHotkey)>();
_windowPluginHotkeys[keyGesture] = list;
}
list.Add((pluginPair.Metadata, searchWindowHotkey));
list = new List<(PluginMetadata, SearchWindowPluginHotkey)>();
_windowPluginHotkeys[hotkeyModel] = list;
}
list.Add((pluginPair.Metadata, searchWindowHotkey));
}
}
}
}
public static string ChangePluginHotkey(PluginMetadata plugin, GlobalPluginHotkey pluginHotkey, HotkeyModel newHotkey)
{
var oldHotkeyItem = plugin.PluginHotkeys.First(h => h.Id == pluginHotkey.Id);
var settingHotkeyItem = Settings.GetPluginSettings(plugin.ID).pluginHotkeys.First(h => h.Id == pluginHotkey.Id);
var oldHotkey = settingHotkeyItem.Hotkey;
var newHotkeyStr = newHotkey.ToString();
// Update hotkey in plugin metadata & setting
oldHotkeyItem.Hotkey = newHotkeyStr;
settingHotkeyItem.Hotkey = newHotkeyStr;
return oldHotkey;
}
public static (HotkeyModel Old, HotkeyModel New) ChangePluginHotkey(PluginMetadata plugin, SearchWindowPluginHotkey pluginHotkey, HotkeyModel newHotkey)
{
var oldHotkeyItem = plugin.PluginHotkeys.First(h => h.Id == pluginHotkey.Id);
var settingHotkeyItem = Settings.GetPluginSettings(plugin.ID).pluginHotkeys.First(h => h.Id == pluginHotkey.Id);
var oldHotkey = settingHotkeyItem.Hotkey;
var converter = new KeyGestureConverter();
var oldHotkeyModel = new HotkeyModel(oldHotkey);
var newHotkeyStr = newHotkey.ToString();
// Update hotkey in plugin metadata & setting
oldHotkeyItem.Hotkey = newHotkeyStr;
settingHotkeyItem.Hotkey = newHotkeyStr;
// Update window plugin hotkey dictionary
var oldHotkeyModels = _windowPluginHotkeys[oldHotkeyModel];
_windowPluginHotkeys[oldHotkeyModel] = oldHotkeyModels.Where(x => x.Item1.ID != plugin.ID || x.Item2.Id != pluginHotkey.Id).ToList();
if (_windowPluginHotkeys.TryGetValue(newHotkey, out var newHotkeyModels))
{
var newList = newHotkeyModels.ToList();
newList.Add((plugin, pluginHotkey));
_windowPluginHotkeys[newHotkey] = newList;
}
else
{
_windowPluginHotkeys[newHotkey] = new List<(PluginMetadata, SearchWindowPluginHotkey)>()
{
(plugin, pluginHotkey)
};
}
return (oldHotkeyModel, newHotkey);
}
public static bool ActionKeywordRegistered(string actionKeyword)
{
// this method is only checking for action keywords (defined as not '*') registration

View file

@ -163,20 +163,27 @@ internal static class HotKeyMapper
{
if (hotkey.HotkeyType == HotkeyType.Global && hotkey is GlobalPluginHotkey globalHotkey)
{
var hotkeySetting = metadata.PluginHotkeys.Find(h => h.Id == hotkey.Id)?.Hotkey ?? hotkey.DefaultHotkey;
SetGlobalPluginHotkey(globalHotkey, metadata, hotkeySetting);
var hotkeyStr = metadata.PluginHotkeys.Find(h => h.Id == hotkey.Id)?.Hotkey ?? hotkey.DefaultHotkey;
SetGlobalPluginHotkey(globalHotkey, metadata, hotkeyStr);
}
}
}
}
internal static void SetGlobalPluginHotkey(GlobalPluginHotkey globalHotkey, PluginMetadata metadata, string hotkeySetting)
internal static void SetGlobalPluginHotkey(GlobalPluginHotkey globalHotkey, PluginMetadata metadata, string hotkeyStr)
{
SetHotkey(hotkeySetting, (s, e) =>
var hotkey = new HotkeyModel(hotkeyStr);
SetGlobalPluginHotkey(globalHotkey, metadata, hotkey);
}
internal static void SetGlobalPluginHotkey(GlobalPluginHotkey globalHotkey, PluginMetadata metadata, HotkeyModel hotkey)
{
var hotkeyStr = hotkey.ToString();
SetHotkey(hotkeyStr, (s, e) =>
{
if (_mainViewModel.ShouldIgnoreHotkeys() || metadata.Disabled)
return;
globalHotkey.Action?.Invoke();
});
}
@ -186,12 +193,11 @@ internal static class HotKeyMapper
var windowPluginHotkeys = PluginManager.GetWindowPluginHotkeys();
foreach (var hotkey in windowPluginHotkeys)
{
var keyGesture = hotkey.Key;
SetWindowHotkey(keyGesture, hotkey.Value);
SetWindowHotkey(hotkey.Key, hotkey.Value);
}
}
internal static void SetWindowHotkey(KeyGesture keyGesture, List<(PluginMetadata Metadata, SearchWindowPluginHotkey PluginHotkey)> hotkeyModels)
internal static void SetWindowHotkey(HotkeyModel hotkey, List<(PluginMetadata Metadata, SearchWindowPluginHotkey PluginHotkey)> hotkeyModels)
{
try
{
@ -201,13 +207,17 @@ internal static class HotKeyMapper
var command = BuildCommand(hotkeyModels);
// Remove any existing key binding with the same gesture to avoid duplication
var keyGesture = hotkey.ToKeyGesture();
var existingBinding = window.InputBindings
.OfType<KeyBinding>()
.FirstOrDefault(kb => kb.Gesture == keyGesture);
.FirstOrDefault(kb =>
kb.Gesture is KeyGesture keyGesture1 &&
keyGesture.Key == keyGesture1.Key &&
keyGesture.Modifiers == keyGesture1.Modifiers);
if (existingBinding != null)
{
throw new InvalidOperationException($"Key binding with gesture {keyGesture} already exists");
throw new InvalidOperationException($"Key binding with gesture {hotkey} already exists");
}
// Create and add the new key binding
@ -221,8 +231,8 @@ internal static class HotKeyMapper
string.Format("Error registering window hotkey {2}: {0} \nStackTrace:{1}",
e.Message,
e.StackTrace,
keyGesture.DisplayString));
string errorMsg = string.Format(App.API.GetTranslation("registerWindowHotkeyFailed"), keyGesture.DisplayString);
hotkey));
string errorMsg = string.Format(App.API.GetTranslation("registerWindowHotkeyFailed"), hotkey);
string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
}
@ -245,16 +255,20 @@ internal static class HotKeyMapper
});
}
internal static void RemoveWindowHotkey(KeyGesture keyGesture)
internal static void RemoveWindowHotkey(HotkeyModel hotkey)
{
try
{
if (Application.Current?.MainWindow is MainWindow window)
{
// Find and remove the key binding with the specified gesture
var keyGesture = hotkey.ToKeyGesture();
var existingBinding = window.InputBindings
.OfType<KeyBinding>()
.FirstOrDefault(kb => kb.Gesture == keyGesture);
.FirstOrDefault(kb =>
kb.Gesture is KeyGesture keyGesture1 &&
keyGesture.Key == keyGesture1.Key &&
keyGesture.Modifiers == keyGesture1.Modifiers);
if (existingBinding != null)
{
window.InputBindings.Remove(existingBinding);
@ -267,7 +281,7 @@ internal static class HotKeyMapper
string.Format("Error removing window hotkey: {0} \nStackTrace:{1}",
e.Message,
e.StackTrace));
string errorMsg = string.Format(App.API.GetTranslation("unregisterWindowHotkeyFailed"), keyGesture.DisplayString);
string errorMsg = string.Format(App.API.GetTranslation("unregisterWindowHotkeyFailed"), hotkey);
string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
}

View file

@ -3,7 +3,11 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin;
using Flow.Launcher.Resources.Controls;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
@ -65,16 +69,15 @@ public partial class SettingsPaneHotkey
var hotkeySetting = metadata.PluginHotkeys.Find(h => h.Id == hotkey.Id)?.Hotkey ?? hotkey.DefaultHotkey;
if (hotkey.Editable)
{
// TODO: Check if this can use
var hotkeyControl = new HotkeyControl
{
Type = HotkeyControl.HotkeyType.CustomQueryHotkey,
DefaultHotkey = hotkey.DefaultHotkey,
Hotkey = hotkeySetting,
ValidateKeyGesture = true
};
hotkeyControl.SetHotkey(hotkeySetting, true);
hotkeyControl.ChangeHotkey = new RelayCommand<HotkeyModel>((m) => ChangePluginHotkey(metadata, hotkey, m));
card.Content = hotkeyControl;
// TODO: Update metadata & plugin setting hotkey
}
else
{
@ -90,4 +93,23 @@ public partial class SettingsPaneHotkey
PluginHotkeySettings.Children.Add(excard);
}
}
private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey pluginHotkey, HotkeyModel newHotkey)
{
if (pluginHotkey is GlobalPluginHotkey globalPluginHotkey)
{
var oldHotkey = PluginManager.ChangePluginHotkey(metadata, globalPluginHotkey, newHotkey);
HotKeyMapper.RemoveHotkey(oldHotkey);
HotKeyMapper.SetGlobalPluginHotkey(globalPluginHotkey, metadata, newHotkey);
}
else if (pluginHotkey is SearchWindowPluginHotkey windowPluginHotkey)
{
var (oldHotkeyModel, newHotkeyModel) = PluginManager.ChangePluginHotkey(metadata, windowPluginHotkey, newHotkey);
var windowPluginHotkeys = PluginManager.GetWindowPluginHotkeys();
HotKeyMapper.RemoveWindowHotkey(oldHotkeyModel);
HotKeyMapper.RemoveWindowHotkey(newHotkeyModel);
HotKeyMapper.SetWindowHotkey(oldHotkeyModel, windowPluginHotkeys[oldHotkeyModel]);
HotKeyMapper.SetWindowHotkey(newHotkeyModel, windowPluginHotkeys[newHotkeyModel]);
}
}
}