Merge pull request #1770 from VictoriousRaptor/FixPreviewHotkey

Validate hotkey when setting it
This commit is contained in:
Jeremy Wu 2023-01-19 08:08:04 +11:00 committed by GitHub
commit d2cc5760ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 50 deletions

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using System.Windows.Navigation;
namespace Flow.Launcher.Infrastructure.Hotkey
{
@ -11,10 +12,10 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public bool Shift { get; set; }
public bool Win { get; set; }
public bool Ctrl { get; set; }
public Key CharKey { get; set; }
public Key CharKey { get; set; } = Key.None;
Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
private static readonly Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
{
{Key.Space, "Space"},
{Key.Oem3, "~"}
@ -27,19 +28,19 @@ namespace Flow.Launcher.Infrastructure.Hotkey
ModifierKeys modifierKeys = ModifierKeys.None;
if (Alt)
{
modifierKeys = ModifierKeys.Alt;
modifierKeys |= ModifierKeys.Alt;
}
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;
}
@ -86,7 +87,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
Ctrl = true;
keys.Remove("Ctrl");
}
if (keys.Count > 0)
if (keys.Count == 1)
{
string charKey = keys[0];
KeyValuePair<Key, string>? specialSymbolPair = specialSymbolDictionary.FirstOrDefault(pair => pair.Value == charKey);
@ -110,36 +111,75 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public override string ToString()
{
string text = string.Empty;
List<string> keys = new List<string>();
if (Ctrl)
{
text += "Ctrl + ";
keys.Add("Ctrl");
}
if (Alt)
{
text += "Alt + ";
keys.Add("Alt");
}
if (Shift)
{
text += "Shift + ";
keys.Add("Shift");
}
if (Win)
{
text += "Win + ";
keys.Add("Win");
}
if (CharKey != Key.None)
{
text += specialSymbolDictionary.ContainsKey(CharKey)
keys.Add(specialSymbolDictionary.ContainsKey(CharKey)
? specialSymbolDictionary[CharKey]
: CharKey.ToString();
}
else if (!string.IsNullOrEmpty(text))
{
text = text.Remove(text.Length - 3);
: CharKey.ToString());
}
return string.Join(" + ", keys);
}
return text;
public bool Validate()
{
switch (CharKey)
{
case Key.LeftAlt:
case Key.RightAlt:
case Key.LeftCtrl:
case Key.RightCtrl:
case Key.LeftShift:
case Key.RightShift:
case Key.LWin:
case Key.RWin:
return false;
default:
if (ModifierKeys == ModifierKeys.None)
{
return !((CharKey >= Key.A && CharKey <= Key.Z) ||
(CharKey >= Key.D0 && CharKey <= Key.D9) ||
(CharKey >= Key.NumPad0 && CharKey <= Key.NumPad9));
}
else
{
return CharKey != Key.None;
}
}
}
public override bool Equals(object obj)
{
if (obj is HotkeyModel other)
{
return ModifierKeys == other.ModifierKeys && CharKey == other.CharKey;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return HashCode.Combine(ModifierKeys, CharKey);
}
}
}

View file

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

View file

@ -9,16 +9,11 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin;
using System.Threading;
using System.Windows.Interop;
namespace Flow.Launcher
{
public partial class HotkeyControl : UserControl
{
private Brush tbMsgForegroundColorOriginal;
private string tbMsgTextOriginal;
public HotkeyModel CurrentHotkey { get; private set; }
public bool CurrentHotkeyAvailable { get; private set; }
@ -29,8 +24,6 @@ namespace Flow.Launcher
public HotkeyControl()
{
InitializeComponent();
tbMsgTextOriginal = tbMsg.Text;
tbMsgForegroundColorOriginal = tbMsg.Foreground;
}
private CancellationTokenSource hotkeyUpdateSource;
@ -55,9 +48,7 @@ namespace Flow.Launcher
specialKeyState.CtrlPressed,
key);
var hotkeyString = hotkeyModel.ToString();
if (hotkeyString == tbHotkey.Text)
if (hotkeyModel.Equals(CurrentHotkey))
{
return;
}
@ -72,33 +63,32 @@ namespace Flow.Launcher
public async Task SetHotkeyAsync(HotkeyModel keyModel, bool triggerValidate = true)
{
CurrentHotkey = keyModel;
tbHotkey.Text = CurrentHotkey.ToString();
tbHotkey.Text = keyModel.ToString();
tbHotkey.Select(tbHotkey.Text.Length, 0);
if (triggerValidate)
{
CurrentHotkeyAvailable = CheckHotkeyAvailability();
if (!CurrentHotkeyAvailable)
{
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
}
else
{
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
}
tbMsg.Visibility = Visibility.Visible;
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel);
CurrentHotkeyAvailable = hotkeyAvailable;
SetMessage(hotkeyAvailable);
OnHotkeyChanged();
var token = hotkeyUpdateSource.Token;
await Task.Delay(500, token);
if (token.IsCancellationRequested)
return;
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
Keyboard.ClearFocus();
if (CurrentHotkeyAvailable)
{
CurrentHotkey = keyModel;
// To trigger LostFocus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
Keyboard.ClearFocus();
}
}
else
{
CurrentHotkey = keyModel;
}
}
@ -107,14 +97,40 @@ namespace Flow.Launcher
return SetHotkeyAsync(new HotkeyModel(keyStr), triggerValidate);
}
private bool CheckHotkeyAvailability() => HotKeyMapper.CheckAvailability(CurrentHotkey);
private static bool CheckHotkeyAvailability(HotkeyModel hotkey) => hotkey.Validate() && HotKeyMapper.CheckAvailability(hotkey);
public new bool IsFocused => tbHotkey.IsFocused;
private void tbHotkey_LostFocus(object sender, RoutedEventArgs e)
{
tbMsg.Text = tbMsgTextOriginal;
tbHotkey.Text = CurrentHotkey.ToString();
tbHotkey.Select(tbHotkey.Text.Length, 0);
}
private void tbHotkey_GotFocus(object sender, RoutedEventArgs e)
{
ResetMessage();
}
private void ResetMessage()
{
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey");
tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B");
}
private void SetMessage(bool hotkeyAvailable)
{
if (!hotkeyAvailable)
{
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
}
else
{
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
}
tbMsg.Visibility = Visibility.Visible;
}
}
}

View file

@ -27,7 +27,7 @@ namespace Flow.Launcher.Resources.Pages
tbMsgTextOriginal = HotkeyControl.tbMsg.Text;
tbMsgForegroundColorOriginal = HotkeyControl.tbMsg.Foreground;
HotkeyControl.SetHotkeyAsync(new Infrastructure.Hotkey.HotkeyModel(Settings.Hotkey), false);
HotkeyControl.SetHotkeyAsync(Settings.Hotkey, false);
}
private void HotkeyControl_OnGotFocus(object sender, RoutedEventArgs args)
{
@ -49,4 +49,4 @@ namespace Flow.Launcher.Resources.Pages
HotkeyControl.tbMsg.Foreground = tbMsgForegroundColorOriginal;
}
}
}
}