add keyboard monitor hotkey

This commit is contained in:
huiyadanli 2024-02-03 23:04:14 +08:00
parent 7ac890e43f
commit 54ee6e2ad1
8 changed files with 267 additions and 60 deletions

View File

@ -9,28 +9,42 @@ using System.Windows.Input;
namespace BetterGenshinImpact.Core.Config;
/// <summary>
/// 格式必须是 快捷键 与 快捷键Type
/// </summary>
[Serializable]
public partial class HotKeyConfig : ObservableObject
{
[ObservableProperty] private string _bgiEnabledHotkey = "F11";
[ObservableProperty] private string _bgiEnabledHotkeyType = HotKeyTypeEnum.GlobalRegister.ToString();
[ObservableProperty] private string _autoPickEnabledHotkey = "F1";
[ObservableProperty] private string _autoPickEnabledHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoSkipEnabledHotkey = "F2";
[ObservableProperty] private string _autoSkipEnabledHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoFishingEnabledHotkey = "";
[ObservableProperty] private string _autoFishingEnabledHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _turnAroundHotkey = "F3";
[ObservableProperty] private string _turnAroundHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _enhanceArtifactHotkey = "F4";
[ObservableProperty] private string _enhanceArtifactHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _quickBuyHotkey = "";
[ObservableProperty] private string _quickBuyHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoGeniusInvokation = "";
[ObservableProperty] private string _autoGeniusInvokationHotkey = "";
[ObservableProperty] private string _autoGeniusInvokationHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoWoodHotkey = "";
[ObservableProperty] private string _autoWoodHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoFightHotkey = "";
[ObservableProperty] private string _autoFightHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
[ObservableProperty] private string _autoDomainHotkey = "";
[ObservableProperty] private string _autoDomainHotkeyType = HotKeyTypeEnum.KeyboardMonitor.ToString();
}

View File

@ -43,7 +43,8 @@ public class MouseKeyMonitor
_globalHook.KeyDown += GlobalHookKeyDown;
_globalHook.KeyUp += GlobalHookKeyUp;
//_globalHook.MouseDownExt += GlobalHookMouseDownExt;
_globalHook.MouseDownExt += GlobalHookMouseDownExt;
_globalHook.MouseUpExt += GlobalHookMouseUpExt;
//_globalHook.KeyPress += GlobalHookKeyPress;
_firstSpaceKeyDownTime = DateTime.MaxValue;
@ -128,15 +129,21 @@ public class MouseKeyMonitor
// Debug.WriteLine("KeyPress: \t{0}", e.KeyChar);
//}
//private void GlobalHookMouseDownExt(object? sender, MouseEventExtArgs e)
//{
// Debug.WriteLine("MouseDown: {0}; \t Location: {1};\t System Timestamp: {2}", e.Button, e.Location, e.Timestamp);
private void GlobalHookMouseDownExt(object? sender, MouseEventExtArgs e)
{
Debug.WriteLine("MouseDown: {0}; \t Location: {1};\t System Timestamp: {2}", e.Button, e.Location, e.Timestamp);
// // uncommenting the following line will suppress the middle mouse button click
// if (e.Button == MouseButtons.Left)
// {
// }
//}
// uncommenting the following line will suppress the middle mouse button click
if (e.Button == MouseButtons.Left)
{
}
}
private void GlobalHookMouseUpExt(object? sender, MouseEventExtArgs e)
{
Debug.WriteLine("MouseUp: {0}; \t Location: {1};\t System Timestamp: {2}", e.Button, e.Location, e.Timestamp);
}
public void Unsubscribe()
{

View File

@ -1,15 +1,23 @@
using System;
using System.Text;
using System.Windows.Input;
using System.Xml.Linq;
namespace BetterGenshinImpact.Model;
public readonly partial record struct HotKey(Key Key, ModifierKeys Modifiers = ModifierKeys.None)
public readonly partial record struct HotKey(Key Key, ModifierKeys Modifiers = ModifierKeys.None, MouseButton MouseButton = MouseButton.Left)
{
public override string ToString()
{
if (Key == Key.None && Modifiers == ModifierKeys.None)
if (Key == Key.None && Modifiers == ModifierKeys.None && MouseButton == MouseButton.Left)
{
return "< None >";
}
if (MouseButton != MouseButton.Left)
{
return MouseButton.ToString();
}
var buffer = new StringBuilder();
@ -27,15 +35,26 @@ public readonly partial record struct HotKey(Key Key, ModifierKeys Modifiers = M
return buffer.ToString();
}
public bool IsEmpty => Key == Key.None && Modifiers == ModifierKeys.None;
public bool IsEmpty => Key == Key.None && Modifiers == ModifierKeys.None && MouseButton == MouseButton.Left;
public static HotKey FromString(string str)
{
var key = Key.None;
var modifiers = ModifierKeys.None;
var mouseButton = MouseButton.Left;
if (string.IsNullOrWhiteSpace(str) || string.Equals(str, "< None >"))
{
return new HotKey(key, modifiers);
return new HotKey(key, modifiers, mouseButton);
}
if (str == MouseButton.XButton1.ToString())
{
return new HotKey(key, modifiers, MouseButton.XButton1);
}
if (str == MouseButton.XButton2.ToString())
{
return new HotKey(key, modifiers, MouseButton.XButton2);
}
var parts = str.Split('+');
@ -50,11 +69,20 @@ public readonly partial record struct HotKey(Key Key, ModifierKeys Modifiers = M
modifiers |= ModifierKeys.Alt;
else if (trimmed == "Win")
modifiers |= ModifierKeys.Windows;
else if (trimmed == "XButton1")
mouseButton = MouseButton.XButton1;
else if (trimmed == "XButton2")
mouseButton = MouseButton.XButton2;
else
key = (Key)Enum.Parse(typeof(Key), trimmed);
}
return new HotKey(key, modifiers);
return new HotKey(key, modifiers, mouseButton);
}
public static bool IsMouseButton(string name)
{
return name == MouseButton.XButton1.ToString() || name == MouseButton.XButton2.ToString();
}
}

View File

@ -1,11 +1,8 @@
using System;
using System.Diagnostics;
using System.Text.Json.Serialization;
using System.Windows;
using BetterGenshinImpact.Helpers;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Fischless.HotkeyCapture;
using Gma.System.MouseKeyHook.HotKeys;
using System;
using System.Diagnostics;
namespace BetterGenshinImpact.Model;
@ -16,19 +13,33 @@ public partial class HotKeySettingModel : ObservableObject
{
[ObservableProperty] private HotKey _hotKey;
/// <summary>
/// 键盘监听、全局热键
/// </summary>
[ObservableProperty] private HotKeyTypeEnum _hotKeyType;
[ObservableProperty]
private string _hotKeyTypeName;
public string FunctionName { get; set; }
public string ConfigPropertyName { get; set; }
public Action<object?, KeyPressedEventArgs> OnKeyAction { get; set; }
/// <summary>
/// 全局热键配置
/// </summary>
public HotkeyHook? KeyBindInfo { get; set; }
public HotKeySettingModel(string functionName, string configPropertyName, string hotkey, Action<object?, KeyPressedEventArgs> onKeyAction)
public HotKeySettingModel(string functionName, string configPropertyName, string hotkey, string hotKeyTypeCode, Action<object?, KeyPressedEventArgs> onKeyAction)
{
FunctionName = functionName;
ConfigPropertyName = configPropertyName;
HotKey = HotKey.FromString(hotkey);
HotKeyType = (HotKeyTypeEnum)Enum.Parse(typeof(HotKeyTypeEnum), hotKeyTypeCode);
HotKeyTypeName = HotKeyType.ToChineseName();
OnKeyAction = onKeyAction;
}
@ -39,32 +50,53 @@ public partial class HotKeySettingModel : ObservableObject
return;
}
try
if (HotKeyType == HotKeyTypeEnum.GlobalRegister)
{
Fischless.HotkeyCapture.Hotkey hotkey = new(HotKey.ToString());
KeyBindInfo?.Dispose();
KeyBindInfo = new HotkeyHook();
KeyBindInfo.KeyPressed -= OnKeyPressed;
KeyBindInfo.KeyPressed += OnKeyPressed;
KeyBindInfo.RegisterHotKey(hotkey.ModifierKey, hotkey.Key);
try
{
Hotkey hotkey = new(HotKey.ToString());
KeyBindInfo?.Dispose();
KeyBindInfo = new HotkeyHook();
KeyBindInfo.KeyPressed -= OnKeyPressed;
KeyBindInfo.KeyPressed += OnKeyPressed;
KeyBindInfo.RegisterHotKey(hotkey.ModifierKey, hotkey.Key);
}
catch (Exception e)
{
Debug.WriteLine(e);
HotKey = HotKey.None;
}
}
catch (Exception e)
else
{
Debug.WriteLine(e);
HotKey = HotKey.None;
}
}
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
{
OnKeyAction.Invoke(sender, e);
}
public void UnRegisterHotKey()
{
KeyBindInfo?.Dispose();
if (HotKeyType == HotKeyTypeEnum.GlobalRegister)
{
KeyBindInfo?.Dispose();
}
else
{
}
}
[RelayCommand]
public void OnSwitchHotKeyType()
{
HotKeyType = HotKeyType == HotKeyTypeEnum.GlobalRegister ? HotKeyTypeEnum.KeyboardMonitor : HotKeyTypeEnum.GlobalRegister;
HotKeyTypeName = HotKeyType.ToChineseName();
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace BetterGenshinImpact.Model;
public enum HotKeyTypeEnum
{
GlobalRegister, // 全局热键
KeyboardMonitor, // 键盘监听
}
public static class HotKeyTypeEnumExtension
{
public static string ToChineseName(this HotKeyTypeEnum type)
{
return type switch
{
HotKeyTypeEnum.GlobalRegister => "全局热键",
HotKeyTypeEnum.KeyboardMonitor => "键盘监听",
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
};
}
}

View File

@ -1,12 +1,33 @@
using System.Windows;
using BetterGenshinImpact.Model;
using System.Windows;
using System.Windows.Input;
using BetterGenshinImpact.Model;
using Wpf.Ui.Controls;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using TextBox = Wpf.Ui.Controls.TextBox;
namespace BetterGenshinImpact.View.Controls;
public class HotKeyTextBox : TextBox
{
public static readonly DependencyProperty HotkeyTypeNameProperty = DependencyProperty.Register(
nameof(HotKeyTypeName),
typeof(string),
typeof(HotKeyTextBox),
new FrameworkPropertyMetadata(
default(string),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
)
);
/// <summary>
/// 热键类型 (中文)
/// </summary>
public string HotKeyTypeName
{
get => (string)GetValue(HotkeyTypeNameProperty);
set => SetValue(HotkeyTypeNameProperty, value);
}
public static readonly DependencyProperty HotkeyProperty = DependencyProperty.Register(
nameof(Hotkey),
typeof(HotKey),
@ -120,10 +141,30 @@ public class HotKeyTextBox : TextBox
return;
// If key has a character and pressed without modifiers or only with Shift - return
if (HasKeyChar(key) && modifiers is ModifierKeys.None or ModifierKeys.Shift)
if (HotKeyTypeName == HotKeyTypeEnum.GlobalRegister.ToChineseName() && HasKeyChar(key) && modifiers is ModifierKeys.None or ModifierKeys.Shift)
return;
// Set value
Hotkey = new HotKey(key, modifiers);
}
/// <summary>
/// 支持鼠标侧键配置
/// </summary>
/// <param name="args"></param>
protected override void OnPreviewMouseDown(MouseButtonEventArgs args)
{
if (args.ChangedButton is MouseButton.XButton1 or MouseButton.XButton2)
{
if (HotKeyTypeName == HotKeyTypeEnum.GlobalRegister.ToChineseName())
{
Hotkey = new HotKey(Key.None);
}
else
{
Hotkey = new HotKey(Key.None, ModifierKeys.None, args.ChangedButton);
}
}
}
}

View File

@ -20,23 +20,36 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Margin="0,0,0,8"
FontTypography="BodyStrong"
Text="快捷键设置" />
<ItemsControl Grid.Row="1" ItemsSource="{Binding HotKeySettingModels}">
<ui:TextBlock Grid.Row="1"
Margin="0,0,0,8"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
TextWrapping="Wrap"
Text="全局热键:只支持组合键和功能键。键盘监听:只支持任意单键(推荐)。点击类型按钮可以切换快捷键类型" />
<ItemsControl Grid.Row="2" ItemsSource="{Binding HotKeySettingModels}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type model:HotKeySettingModel}">
<Grid Margin="0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="180" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{Binding FunctionName}" />
<controls:HotKeyTextBox Grid.Column="1"
<ui:Button Grid.Column="1"
HorizontalAlignment="Right"
Margin="0,0,8,0"
Content="{Binding HotKeyTypeName, Mode=OneWay}"
Command="{Binding SwitchHotKeyTypeCommand}"/>
<controls:HotKeyTextBox Grid.Column="2"
HotKeyTypeName="{Binding HotKeyTypeName, Mode=OneWay}"
Hotkey="{Binding HotKey}"
Style="{StaticResource DefaultTextBoxStyle}"
TextAlignment="Center" />

View File

@ -12,6 +12,7 @@ using HotKeySettingModel = BetterGenshinImpact.Model.HotKeySettingModel;
using CommunityToolkit.Mvvm.Messaging.Messages;
using CommunityToolkit.Mvvm.Messaging;
using BetterGenshinImpact.GameTask.QucikBuy;
using BetterGenshinImpact.Model;
namespace BetterGenshinImpact.ViewModel.Pages;
@ -40,21 +41,38 @@ public partial class HotKeyPageViewModel : ObservableObject
{
if (sender is HotKeySettingModel model)
{
Debug.WriteLine($"{model.FunctionName} 快捷键变更为 {model.HotKey}");
// 反射更新配置
var pi = Config.HotKeyConfig.GetType().GetProperty(model.ConfigPropertyName, BindingFlags.Public | BindingFlags.Instance);
if (null != pi && pi.CanWrite)
{
var str = model.HotKey.ToString();
if (str == "< None >")
{
str = "";
}
pi.SetValue(Config.HotKeyConfig, str, null);
// 更新快捷键
if (e.PropertyName == "HotKey")
{
Debug.WriteLine($"{model.FunctionName} 快捷键变更为 {model.HotKey}");
var pi = Config.HotKeyConfig.GetType().GetProperty(model.ConfigPropertyName, BindingFlags.Public | BindingFlags.Instance);
if (null != pi && pi.CanWrite)
{
var str = model.HotKey.ToString();
if (str == "< None >")
{
str = "";
}
pi.SetValue(Config.HotKeyConfig, str, null);
}
}
// 更新快捷键类型
if (e.PropertyName == "HotKeyType")
{
Debug.WriteLine($"{model.FunctionName} 快捷键类型变更为 {model.HotKeyType.ToChineseName()}");
model.HotKey = HotKey.None;
var pi = Config.HotKeyConfig.GetType().GetProperty(model.ConfigPropertyName + "Type", BindingFlags.Public | BindingFlags.Instance);
if (null != pi && pi.CanWrite)
{
pi.SetValue(Config.HotKeyConfig, model.HotKeyType.ToString(), null);
}
}
RemoveDuplicateHotKey(model);
model.UnRegisterHotKey();
model.RegisterHotKey();
}
@ -62,17 +80,39 @@ public partial class HotKeyPageViewModel : ObservableObject
}
}
/// <summary>
/// 移除重复的快捷键配置
/// </summary>
/// <param name="current"></param>
private void RemoveDuplicateHotKey(HotKeySettingModel current)
{
if (current.HotKey.IsEmpty)
{
return;
}
foreach (var hotKeySettingModel in HotKeySettingModels)
{
if (hotKeySettingModel.HotKey.IsEmpty)
{
continue;
}
if (hotKeySettingModel.ConfigPropertyName != current.ConfigPropertyName && hotKeySettingModel.HotKey == current.HotKey)
{
hotKeySettingModel.HotKey = HotKey.None;
}
}
}
private void BuildHotKeySettingModelList()
{
var bgiEnabledHotKeySettingModel = new HotKeySettingModel(
"启动停止 BetterGI",
nameof(Config.HotKeyConfig.BgiEnabledHotkey),
Config.HotKeyConfig.BgiEnabledHotkey,
(_, _) =>
{
WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "SwitchTriggerStatus", "", ""));
}
Config.HotKeyConfig.BgiEnabledHotkeyType,
(_, _) => { WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "SwitchTriggerStatus", "", "")); }
);
HotKeySettingModels.Add(bgiEnabledHotKeySettingModel);
@ -80,6 +120,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"自动拾取开关",
nameof(Config.HotKeyConfig.AutoPickEnabledHotkey),
Config.HotKeyConfig.AutoPickEnabledHotkey,
Config.HotKeyConfig.AutoPickEnabledHotkeyType,
(_, _) =>
{
TaskContext.Instance().Config.AutoPickConfig.Enabled = !TaskContext.Instance().Config.AutoPickConfig.Enabled;
@ -92,6 +133,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"自动剧情开关",
nameof(Config.HotKeyConfig.AutoSkipEnabledHotkey),
Config.HotKeyConfig.AutoSkipEnabledHotkey,
Config.HotKeyConfig.AutoSkipEnabledHotkeyType,
(_, _) =>
{
TaskContext.Instance().Config.AutoSkipConfig.Enabled = !TaskContext.Instance().Config.AutoSkipConfig.Enabled;
@ -104,6 +146,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"自动钓鱼开关",
nameof(Config.HotKeyConfig.AutoFishingEnabledHotkey),
Config.HotKeyConfig.AutoFishingEnabledHotkey,
Config.HotKeyConfig.AutoFishingEnabledHotkeyType,
(_, _) =>
{
TaskContext.Instance().Config.AutoFishingConfig.Enabled = !TaskContext.Instance().Config.AutoFishingConfig.Enabled;
@ -116,6 +159,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"长按旋转视角 - 那维莱特转圈",
nameof(Config.HotKeyConfig.TurnAroundHotkey),
Config.HotKeyConfig.TurnAroundHotkey,
Config.HotKeyConfig.TurnAroundHotkeyType,
(_, _) => { TurnAroundMacro.Done(); }
);
HotKeySettingModels.Add(turnAroundHotKeySettingModel);
@ -124,6 +168,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"按下快速强化圣遗物",
nameof(Config.HotKeyConfig.EnhanceArtifactHotkey),
Config.HotKeyConfig.EnhanceArtifactHotkey,
Config.HotKeyConfig.EnhanceArtifactHotkeyType,
(_, _) => { QuickEnhanceArtifactMacro.Done(); }
);
HotKeySettingModels.Add(enhanceArtifactHotKeySettingModel);
@ -132,14 +177,16 @@ public partial class HotKeyPageViewModel : ObservableObject
"按下快速购买商店物品",
nameof(Config.HotKeyConfig.QuickBuyHotkey),
Config.HotKeyConfig.QuickBuyHotkey,
Config.HotKeyConfig.QuickBuyHotkeyType,
(_, _) => { QuickBuyTask.Done(); }
));
HotKeySettingModels.Add(new HotKeySettingModel(
"启动/停止自动七圣召唤",
nameof(Config.HotKeyConfig.AutoGeniusInvokation),
Config.HotKeyConfig.AutoGeniusInvokation,
nameof(Config.HotKeyConfig.AutoGeniusInvokationHotkey),
Config.HotKeyConfig.AutoGeniusInvokationHotkey,
Config.HotKeyConfig.AutoGeniusInvokationHotkeyType,
(_, _) => { _taskSettingsPageViewModel.OnSwitchAutoGeniusInvokation(); }
));
@ -147,6 +194,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"启动/停止自动伐木",
nameof(Config.HotKeyConfig.AutoWoodHotkey),
Config.HotKeyConfig.AutoWoodHotkey,
Config.HotKeyConfig.AutoWoodHotkeyType,
(_, _) => { _taskSettingsPageViewModel.OnSwitchAutoWood(); }
));
@ -154,6 +202,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"启动/停止自动战斗",
nameof(Config.HotKeyConfig.AutoFightHotkey),
Config.HotKeyConfig.AutoFightHotkey,
Config.HotKeyConfig.AutoFightHotkeyType,
(_, _) => { _taskSettingsPageViewModel.OnSwitchAutoFight(); }
));
@ -161,6 +210,7 @@ public partial class HotKeyPageViewModel : ObservableObject
"启动/停止自动秘境",
nameof(Config.HotKeyConfig.AutoDomainHotkey),
Config.HotKeyConfig.AutoDomainHotkey,
Config.HotKeyConfig.AutoDomainHotkeyType,
(_, _) => { _taskSettingsPageViewModel.OnSwitchAutoDomain(); }
));
}