diff --git a/BetterGenshinImpact/App.xaml.cs b/BetterGenshinImpact/App.xaml.cs index 9985f237..efad91de 100644 --- a/BetterGenshinImpact/App.xaml.cs +++ b/BetterGenshinImpact/App.xaml.cs @@ -101,6 +101,7 @@ public partial class App : Application services.AddView(); services.AddSingleton(); // services.AddView(); + services.AddView(); // 一条龙 ViewModels // services.AddSingleton(); diff --git a/BetterGenshinImpact/Core/Config/AllConfig.cs b/BetterGenshinImpact/Core/Config/AllConfig.cs index 3dcee4ee..4c637853 100644 --- a/BetterGenshinImpact/Core/Config/AllConfig.cs +++ b/BetterGenshinImpact/Core/Config/AllConfig.cs @@ -165,6 +165,11 @@ public partial class AllConfig : ObservableObject /// public NotificationConfig NotificationConfig { get; set; } = new(); + /// + /// 原神按键绑定配置 + /// + public KeyBindingsConfig KeyBindingsConfig { get; set; } = new(); + [JsonIgnore] public Action? OnAnyChangedAction { get; set; } @@ -176,6 +181,7 @@ public partial class AllConfig : ObservableObject GenshinStartConfig.PropertyChanged += OnAnyPropertyChanged; NotificationConfig.PropertyChanged += OnAnyPropertyChanged; NotificationConfig.PropertyChanged += OnNotificationPropertyChanged; + KeyBindingsConfig.PropertyChanged += OnAnyPropertyChanged; AutoPickConfig.PropertyChanged += OnAnyPropertyChanged; AutoSkipConfig.PropertyChanged += OnAnyPropertyChanged; diff --git a/BetterGenshinImpact/Core/Config/KeyBindingsConfig.cs b/BetterGenshinImpact/Core/Config/KeyBindingsConfig.cs new file mode 100644 index 00000000..9c022f6c --- /dev/null +++ b/BetterGenshinImpact/Core/Config/KeyBindingsConfig.cs @@ -0,0 +1,964 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using System; +using System.Windows.Forms; +using System.Windows.Input; +using Windows.Networking.PushNotifications; +using static Vanara.PInvoke.User32; + +namespace BetterGenshinImpact.Core.Config; + +/// +/// 原神按键绑定配置 +/// +[Serializable] +public partial class KeyBindingsConfig:ObservableObject +{ + + #region Actions(操作) + + /// + /// 向前移动 + /// + [ObservableProperty] + private KeyId _moveForward = KeyId.W; + + /// + /// 向后移动 + /// + [ObservableProperty] + private KeyId _moveBackward = KeyId.S; + + /// + /// 向左移动 + /// + [ObservableProperty] + private KeyId _moveLeft = KeyId.A; + + /// + /// 向右移动 + /// + [ObservableProperty] + private KeyId _moveRight = KeyId.D; + + /// + /// 切换走/跑;特定操作模式下向下移动 + /// + [ObservableProperty] + private KeyId _switchToWalkOrRun = KeyId.LeftCtrl; + + /// + /// 普通攻击 + /// + [ObservableProperty] + private KeyId _normalAttack = KeyId.MouseLeftButton; + + /// + /// 元素战技 + /// + [ObservableProperty] + private KeyId _elementalSkill = KeyId.E; + + /// + /// 元素爆发 + /// + [ObservableProperty] + private KeyId _elementalBurst = KeyId.Q; + + /// + /// 冲刺(键盘) + /// + [ObservableProperty] + private KeyId _sprintKeyboard = KeyId.LeftShift; + + /// + /// 冲刺(鼠标) + /// + [ObservableProperty] + private KeyId _sprintMouse = KeyId.MouseRightButton; + + /// + /// 切换瞄准模式 + /// + [ObservableProperty] + private KeyId _switchAimingMode = KeyId.R; + + /// + /// 跳跃;特定操作模式下向上移动 + /// + [ObservableProperty] + private KeyId _jump = KeyId.Space; + + /// + /// 落下 + /// + [ObservableProperty] + private KeyId _drop = KeyId.X; + + /// + /// 拾取/交互(自动拾取由AutoPick模块管理) + /// + [ObservableProperty] + private KeyId _pickUpOrInteract = KeyId.F; + + /// + /// 快捷使用小道具 + /// + [ObservableProperty] + private KeyId _quickUseGadget = KeyId.Z; + + /// + /// 特定玩法内交互操作 + /// + [ObservableProperty] + private KeyId _interactionInSomeMode = KeyId.T; + + /// + /// 开启任务追踪 + /// + [ObservableProperty] + private KeyId _questNavigation = KeyId.V; + + /// + /// 中断挑战 + /// + [ObservableProperty] + private KeyId _abandonChallenge = KeyId.P; + + /// + /// 切换小队角色1 + /// + [ObservableProperty] + private KeyId _switchMember1 = KeyId.D1; + + /// + /// 切换小队角色2 + /// + [ObservableProperty] + private KeyId _switchMember2 = KeyId.D2; + + /// + /// 切换小队角色3 + /// + [ObservableProperty] + private KeyId _switchMember3 = KeyId.D3; + + /// + /// 切换小队角色4 + /// + [ObservableProperty] + private KeyId _switchMember4 = KeyId.D4; + + /// + /// 切换小队角色5 + /// + [ObservableProperty] + private KeyId _switchMember5 = KeyId.D5; + + /// + /// 呼出快捷轮盘 + /// + [ObservableProperty] + private KeyId _shortcutWheel = KeyId.Tab; + + #endregion + + #region Menus(菜单) + + /// + /// 打开背包 + /// + [ObservableProperty] + private KeyId _openInventory = KeyId.B; + + /// + /// 打开角色界面 + /// + [ObservableProperty] + private KeyId _openCharacterScreen = KeyId.C; + + /// + /// 打开地图 + /// + [ObservableProperty] + private KeyId _openMap = KeyId.M; + + /// + /// 打开派蒙界面 + /// + [ObservableProperty] + private KeyId _openPaimonMenu = KeyId.Escape; + + /// + /// 打开冒险之证界面 + /// + [ObservableProperty] + private KeyId _openAdventurerHandbook = KeyId.F1; + + /// + /// 打开多人游戏界面 + /// + [ObservableProperty] + private KeyId _openCoOpScreen = KeyId.F2; + + /// + /// 打开祈愿界面 + /// + [ObservableProperty] + private KeyId _openWishScreen = KeyId.F3; + + /// + /// 打开纪行界面 + /// + [ObservableProperty] + private KeyId _openBattlePassScreen = KeyId.F4; + + /// + /// 打开活动面板 + /// + [ObservableProperty] + private KeyId _openTheEventsMenu = KeyId.F5; + + /// + /// 打开玩法系统界面(尘歌壶内猫尾酒馆内) + /// + [ObservableProperty] + private KeyId _openTheSettingsMenu = KeyId.F6; + + /// + /// 打开摆设界面(尘歌壶内) + /// + [ObservableProperty] + private KeyId _openTheFurnishingScreen = KeyId.F7; + + /// + /// 打开星之归还(条件符合期间生效) + /// + [ObservableProperty] + private KeyId _openStellarReunion = KeyId.F8; + + /// + /// 开关任务菜单 + /// + [ObservableProperty] + private KeyId _openQuestMenu = KeyId.J; + + /// + /// 打开通知详情 + /// + [ObservableProperty] + private KeyId _openNotificationDetails = KeyId.Y; + + /// + /// 打开聊天界面 + /// + [ObservableProperty] + private KeyId _openChatScreen = KeyId.Enter; + + /// + /// 打开特殊环境说明 + /// + [ObservableProperty] + private KeyId _openSpecialEnvironmentInformation = KeyId.U; + + /// + /// 查看教程详情 + /// + [ObservableProperty] + private KeyId _checkTutorialDetails = KeyId.G; + + /// + /// 长按打开元素视野 + /// + [ObservableProperty] + private KeyId _elementalSight = KeyId.MouseMiddleButton; + + /// + /// 呼出鼠标 + /// + [ObservableProperty] + private KeyId _showCursor = KeyId.LeftAlt; + + /// + /// 打开队伍配置界面 + /// + [ObservableProperty] + private KeyId _openPartySetupScreen = KeyId.L; + + /// + /// 打开好友界面 + /// + [ObservableProperty] + private KeyId _openFriendsScreen = KeyId.O; + + /// + /// 隐藏主界面 + /// + [ObservableProperty] + private KeyId _hideUI = KeyId.Slash; + + #endregion + +} + +public static class KeyIdConverter +{ + + /// + /// 将KeyId转换为字符串(可在后续支持多语言),按键名称的显示尽量与原神UI一致 + /// + /// + /// + public static string ToName(this KeyId value) + { + return ToChineseName(value); + } + + private static string ToChineseName(KeyId value) + { + return value switch + { + // 需要单独翻译的按键 + KeyId.None => "<未指定>", + KeyId.Unknown => "<未知>", + KeyId.MouseLeftButton => "鼠标左键", + KeyId.MouseRightButton => "鼠标右键", + KeyId.MouseMiddleButton => "鼠标中键", + KeyId.MouseSideButton1 => "鼠标侧键1", + KeyId.MouseSideButton2 => "鼠标侧键2", + KeyId.Apps => "菜单键", + // 无需单独翻译的部分 + _ => EnglishKeyNameToChinese(value), + }; + } + + private static string EnglishKeyNameToChinese(KeyId value) + { + var engName = ToEnglishName(value); + if (engName.StartsWith("Left ") || engName.StartsWith("Right ")) + { + return engName.Replace("Left ", "左").Replace("Right ", "右"); + } + return engName; + } + + private static string ToEnglishName(KeyId value) + { + return value switch + { + // 需要转换的部分 + KeyId.None => "", + KeyId.Unknown => "", + KeyId.MouseLeftButton => "Mouse LButton", + KeyId.MouseRightButton => "Mouse RButton", + KeyId.MouseMiddleButton => "Mouse MButton", + KeyId.MouseSideButton1 => "Mouse XButton1", + KeyId.MouseSideButton2 => "Mouse XButton2", + KeyId.Escape => "Esc", + KeyId.PageUp => "Page Up", + KeyId.PageDown => "Page Down", + KeyId.CapsLock => "Caps Lock", + KeyId.ScrollLock => "Scroll Lock", + KeyId.LeftShift => "Left Shift", + KeyId.RightShift => "Right Shift", + KeyId.LeftCtrl => "Left Crtl", + KeyId.RightCtrl => "Right Ctrl", + KeyId.LeftAlt => "Left Alt", + KeyId.RightAlt => "Right Alt", + KeyId.LeftWin => "Left Win", + KeyId.RightWin => "Right Win", + KeyId.Apps => "Menu", + KeyId.Left => "←", + KeyId.Up => "↑", + KeyId.Right => "→", + KeyId.Down => "↓", + KeyId.D0 => "0", + KeyId.D1 => "1", + KeyId.D2 => "2", + KeyId.D3 => "3", + KeyId.D4 => "4", + KeyId.D5 => "5", + KeyId.D6 => "6", + KeyId.D7 => "7", + KeyId.D8 => "8", + KeyId.D9 => "9", + KeyId.Apostrophe => "'", + KeyId.Comma => ",", + KeyId.Minus => "-", + KeyId.Equal => "=", + KeyId.Period => ".", + KeyId.Slash => "/", + KeyId.Backslash => @"\", + KeyId.Semicolon => ";", + KeyId.LeftSquareBracket => "[", + KeyId.RightSquareBracket => "]", + KeyId.Tilde => "`", + KeyId.NumLock => "Num Lock", + KeyId.NumPad0 => "Num 0", + KeyId.NumPad1 => "Num 1", + KeyId.NumPad2 => "Num 2", + KeyId.NumPad3 => "Num 3", + KeyId.NumPad4 => "Num 4", + KeyId.NumPad5 => "Num 5", + KeyId.NumPad6 => "Num 6", + KeyId.NumPad7 => "Num 7", + KeyId.NumPad8 => "Num 8", + KeyId.NumPad9 => "Num 9", + KeyId.Decimal => "Num .", + KeyId.Divide => "Num /", + KeyId.Multiply => "Num *", + KeyId.Subtract => "Num -", + KeyId.Add => "Num +", + KeyId.NumEnter => "Num Enter", + // 默认使用枚举名 + _ => value.ToString(), + }; + } + + /// + /// 将KeyId转换为VK + /// + /// + /// + public static VK ToVK(this KeyId value) + { + return value switch + { + // 这两个值在VK中没有,抛异常 + KeyId.None => throw new ArgumentOutOfRangeException(nameof(value), "未指定按键,无法转换为VK。"), + KeyId.Unknown => throw new ArgumentOutOfRangeException(nameof(value), "未知按键,无法转换为VK。"), + // 剩下的值相同,直接转 + _ => (VK)value, + }; + } + + /// + /// 将KeyId转换为System.Windows.Input.Key + /// + /// + /// + public static Key ToInputKey(this KeyId value) + { + // 部分按键名称相同,使用名称转换 + try + { + return Enum.Parse(value.ToString()); + } + catch + { + // 其他键使用查表法转换 + return value switch + { + KeyId.LeftWin => Key.LWin, + KeyId.RightWin => Key.RWin, + KeyId.Apostrophe => Key.Oem7, + KeyId.Comma => Key.OemComma, + KeyId.Minus => Key.OemMinus, + KeyId.Equal => Key.OemPlus, + KeyId.Period => Key.OemPeriod, + KeyId.Slash => Key.Oem2, + KeyId.Semicolon => Key.Oem1, + KeyId.LeftSquareBracket => Key.Oem4, + KeyId.Backslash => Key.Oem5, + KeyId.RightSquareBracket => Key.Oem6, + KeyId.Tilde => Key.Oem3, + KeyId.Enter => Key.Enter, + KeyId.ScrollLock => Key.Scroll, + KeyId.PageUp => Key.Prior, + KeyId.PageDown => Key.Next, + KeyId.Backspace => Key.Back, + KeyId.CapsLock => Key.Capital, + // None、Unknown和鼠标按键抛异常 + _ => throw new ArgumentOutOfRangeException(nameof(value)), + }; + } + } + + /// + /// 将KeyId转换为MouseButton + /// + /// + /// + /// + public static MouseButton ToMouseButton(this KeyId value) + { + return value switch + { + KeyId.MouseLeftButton => MouseButton.Left, + KeyId.MouseRightButton => MouseButton.Right, + KeyId.MouseMiddleButton => MouseButton.Middle, + KeyId.MouseSideButton1 => MouseButton.XButton1, + KeyId.MouseSideButton2 => MouseButton.XButton2, + _ => throw new ArgumentOutOfRangeException(nameof(value), "键盘按键请使用ToInputKey方法"), + }; + } + + /// + /// [实验] 将KeyId转换为WinForm中的Keys(用于兼容按键连发功能) + /// + /// + /// + public static Keys ToWinFormKeys(this KeyId value) + { + try + { + return Enum.Parse(value.ToInputKey().ToString()); + } + catch + { + return default; + } + } + + /// + /// 将VK转换为KeyId + /// + /// + /// + public static KeyId FromVK(VK value) + { + // 尝试通过VK的值获取KeyId的枚举名。若成功,表示对应的VK在KeyId支持的范围内,直接转换;否则返回Unknown + return string.IsNullOrEmpty(Enum.GetName(typeof(KeyId), value)) ? KeyId.Unknown : (KeyId)value; + } + + /// + /// 将System.Windows.Input.Key转换为KeyId + /// + /// + /// + public static KeyId FromInputKey(Key value) + { + // 部分按键名称相同,使用名称转换 + try + { + return Enum.Parse(value.ToString()); + } + catch + { + // 其他键使用查表法转换 + return value switch + { + Key.LWin => KeyId.LeftWin, + Key.RWin => KeyId.RightWin, + Key.Oem7 => KeyId.Apostrophe, + Key.OemComma => KeyId.Comma, + Key.OemMinus => KeyId.Minus, + Key.OemPlus => KeyId.Equal, + Key.OemPeriod => KeyId.Period, + Key.Oem2 => KeyId.Slash, + Key.Oem1 => KeyId.Semicolon, + Key.Oem4 => KeyId.LeftSquareBracket, + Key.Oem5 => KeyId.Backslash, + Key.Oem6 => KeyId.RightSquareBracket, + Key.Oem3 => KeyId.Tilde, + Key.Enter => KeyId.Enter, + Key.Scroll => KeyId.ScrollLock, + Key.Prior => KeyId.PageUp, + Key.Next => KeyId.PageDown, + Key.Back => KeyId.Backspace, + Key.Capital => KeyId.CapsLock, + // 支持列表外的值返回Unknown + _ => KeyId.Unknown, + }; + } + } + + /// + /// 将MouseButton转换为KeyId + /// + /// + /// + public static KeyId FromMouseButton(MouseButton value) + { + return value switch + { + MouseButton.Left => KeyId.MouseLeftButton, + MouseButton.Right => KeyId.MouseRightButton, + MouseButton.Middle => KeyId.MouseMiddleButton, + MouseButton.XButton1 => KeyId.MouseSideButton1, + MouseButton.XButton2 => KeyId.MouseSideButton2, + _ => KeyId.Unknown, + }; + } + +} + +/// +/// 用于与VK/Windows.Input.Key解耦,值与VK对应,但是仅包含美式键盘(104键,不包括媒体控制等)和鼠标中的按键 +/// +public enum KeyId +{ + /// + None = 0x00, + + /// 未知按键 + Unknown = 0xFF, + + #region 鼠标按键 + + /// 鼠标左键 + MouseLeftButton = 0x01, + + /// 鼠标右键 + MouseRightButton = 0x02, + + /// 鼠标中键(滚轮) + MouseMiddleButton = 0x04, + + /// 鼠标侧键1(后退) + MouseSideButton1 = 0x05, + + /// 鼠标侧键2(前进) + MouseSideButton2 = 0x06, + + #endregion + + #region F键区 + + /// F1 + F1 = 0x70, + + /// F2 + F2 = 0x71, + + /// F3 + F3 = 0x72, + + /// F4 + F4 = 0x73, + + /// F5 + F5 = 0x74, + + /// F6 + F6 = 0x75, + + /// F7 + F7 = 0x76, + + /// F8 + F8 = 0x77, + + /// F9 + F9 = 0x78, + + /// F10 + F10 = 0x79, + + /// F11 + F11 = 0x7A, + + /// F12 + F12 = 0x7B, + + #endregion + + #region 控制&功能键 + + /// Esc + Escape = 0x1B, + + /// PrintScreen + PrintScreen = 0x2C, + + /// ScrollLock + ScrollLock = 0x91, + + /// Pause + Pause = 0x13, + + /// Insert + Insert = 0x2D, + + /// Delete + Delete = 0x2E, + + /// Home + Home = 0x24, + + /// End + End = 0x23, + + /// Page Up + PageUp = 0x21, + + /// Page Down + PageDown = 0x22, + + /// Backspace退格 + Backspace = 0x08, + + /// Tab + Tab = 0x09, + + /// Caps Lock大写锁定 + CapsLock = 0x14, + + /// Enter回车 + Enter = 0x0D, + + ///// Shift + //Shift = 0x10, + + /// 左Shift + LeftShift = 0xA0, + + /// 右Shift + RightShift = 0xA1, + + ///// Ctrl + //Ctrl = 0x11, + + /// 左Ctrl + LeftCtrl = 0xA2, + + /// 右Ctrl + RightCtrl = 0xA3, + + ///// Alt + //Alt = 0x12, + + /// 左Alt + LeftAlt = 0xA4, + + /// 右Alt + RightAlt = 0xA5, + + /// 左Win键 (Microsoft Natural Keyboard) + LeftWin = 0x5B, + + /// 右Win键 (Microsoft Natural Keyboard) + RightWin = 0x5C, + + /// 菜单键 (Microsoft Natural Keyboard) + Apps = 0x5D, + + /// Space空格键 + Space = 0x20, + + #endregion + + #region 方向键 + + /// 方向键 ← + Left = 0x25, + + /// 方向键 ↑ + Up = 0x26, + + /// 方向键 → + Right = 0x27, + + /// 方向键 ↓ + Down = 0x28, + + #endregion + + #region 字母区 - 字母 + + /// A + A = 0x41, + + /// B + B = 0x42, + + /// C + C = 0x43, + + /// D + D = 0x44, + + /// E + E = 0x45, + + /// F + F = 0x46, + + /// G + G = 0x47, + + /// H + H = 0x48, + + /// I + I = 0x49, + + /// J + J = 0x4A, + + /// K + K = 0x4B, + + /// L + L = 0x4C, + + /// M + M = 0x4D, + + /// N + N = 0x4E, + + /// O + O = 0x4F, + + /// P + P = 0x50, + + /// Q + Q = 0x51, + + /// R + R = 0x52, + + /// S + S = 0x53, + + /// T + T = 0x54, + + /// U + U = 0x55, + + /// V + V = 0x56, + + /// W + W = 0x57, + + /// X + X = 0x58, + + /// Y + Y = 0x59, + + /// Z + Z = 0x5A, + + #endregion + + #region 字母区 - 数字 + + /// 0 + D0 = 0x30, + + /// 1 + D1 = 0x31, + + /// 2 + D2 = 0x32, + + /// 3 + D3 = 0x33, + + /// 4 + D4 = 0x34, + + /// 5 + D5 = 0x35, + + /// 6 + D6 = 0x36, + + /// 7 + D7 = 0x37, + + /// 8 + D8 = 0x38, + + /// 9 + D9 = 0x39, + + #endregion + + #region 字母区 - 符号 + + /// 引号 ' + Apostrophe = 0xDE, + + /// 逗号 , + Comma = 0xBC, + + /// 连接符 - + Minus = 0xBD, + + /// 等于号 = + Equal = 0xBB, + + /// 句号 . + Period = 0xBE, + + /// 斜杠 / + Slash = 0xBF, + + /// 反斜杠 \ + Backslash = 0xE2, + + /// 分号 ; + Semicolon = 0xBA, + + /// 左方括号 [ + LeftSquareBracket = 0xDB, + + /// 右方括号 ] + RightSquareBracket = 0xDD, + + /// 波浪号 ` + Tilde = 0xC0, + + #endregion + + #region 小键盘区 + + /// Num Lock + NumLock = 0x90, + + /// Num 0 + NumPad0 = 0x60, + + /// Num 1 + NumPad1 = 0x61, + + /// Num 2 + NumPad2 = 0x62, + + /// Num 3 + NumPad3 = 0x63, + + /// Num 4 + NumPad4 = 0x64, + + /// Num 5 + NumPad5 = 0x65, + + /// Num 6 + NumPad6 = 0x66, + + /// Num 7 + NumPad7 = 0x67, + + /// Num 8 + NumPad8 = 0x68, + + /// Num 9 + NumPad9 = 0x69, + + /// Num . + Decimal = 0x6E, + + /// Num / + Divide = 0x6F, + + /// Num * + Multiply = 0x6A, + + /// Num - + Subtract = 0x6D, + + /// Num + + Add = 0x6B, + + /// Num Enter + NumEnter = 0x0E, + + #endregion + +} diff --git a/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs b/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs index bce0f404..acc09573 100644 --- a/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs +++ b/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs @@ -1,4 +1,5 @@ -using BetterGenshinImpact.Core.Recorder; +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Core.Recorder; using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.GameTask; using BetterGenshinImpact.Model; @@ -18,6 +19,10 @@ public class MouseKeyMonitor /// private readonly Timer _fTimer = new(); + private Keys _pickUpKey = Keys.F; + + private User32.VK _pickUpKeyCode = User32.VK.VK_F; + //private readonly Random _random = new(); /// @@ -25,6 +30,10 @@ public class MouseKeyMonitor /// private readonly Timer _spaceTimer = new(); + private Keys _releaseControlKey = Keys.Space; + + private User32.VK _releaseControlKeyCode = User32.VK.VK_SPACE; + private DateTime _firstFKeyDownTime = DateTime.MaxValue; /// @@ -49,14 +58,19 @@ public class MouseKeyMonitor _globalHook.MouseWheelExt += GlobalHookMouseWheelExt; //_globalHook.KeyPress += GlobalHookKeyPress; + _pickUpKey = TaskContext.Instance().Config.KeyBindingsConfig.PickUpOrInteract.ToWinFormKeys(); + _pickUpKeyCode = TaskContext.Instance().Config.KeyBindingsConfig.PickUpOrInteract.ToVK(); + _releaseControlKey = TaskContext.Instance().Config.KeyBindingsConfig.Jump.ToWinFormKeys(); + _releaseControlKeyCode = TaskContext.Instance().Config.KeyBindingsConfig.Jump.ToVK(); + _firstSpaceKeyDownTime = DateTime.MaxValue; var si = TaskContext.Instance().Config.MacroConfig.SpaceFireInterval; _spaceTimer.Interval = si; - _spaceTimer.Elapsed += (sender, args) => { Simulation.PostMessage(_hWnd).KeyPress(User32.VK.VK_SPACE); }; + _spaceTimer.Elapsed += (sender, args) => { Simulation.PostMessage(_hWnd).KeyPress(_releaseControlKeyCode); }; var fi = TaskContext.Instance().Config.MacroConfig.FFireInterval; _fTimer.Interval = fi; - _fTimer.Elapsed += (sender, args) => { Simulation.PostMessage(_hWnd).KeyPress(User32.VK.VK_F); }; + _fTimer.Elapsed += (sender, args) => { Simulation.PostMessage(_hWnd).KeyPress(_pickUpKeyCode); }; } private void GlobalHookKeyDown(object? sender, KeyEventArgs e) @@ -67,7 +81,7 @@ public class MouseKeyMonitor // 热键按下事件 HotKeyDown(sender, e); - if (e.KeyCode == Keys.Space) + if (e.KeyCode == _releaseControlKey) { if (_firstSpaceKeyDownTime == DateTime.MaxValue) { @@ -81,7 +95,7 @@ public class MouseKeyMonitor _spaceTimer.Start(); } } - else if (e.KeyCode == Keys.F) + else if (e.KeyCode == _pickUpKey) { if (_firstFKeyDownTime == DateTime.MaxValue) { @@ -105,7 +119,7 @@ public class MouseKeyMonitor // 热键松开事件 HotKeyUp(sender, e); - if (e.KeyCode == Keys.Space) + if (e.KeyCode == _releaseControlKey) { if (_firstSpaceKeyDownTime != DateTime.MaxValue) { @@ -115,7 +129,7 @@ public class MouseKeyMonitor _spaceTimer.Stop(); } } - else if (e.KeyCode == Keys.F) + else if (e.KeyCode == _pickUpKey) { if (_firstFKeyDownTime != DateTime.MaxValue) { diff --git a/BetterGenshinImpact/Core/Simulator/Extensions/Enums.cs b/BetterGenshinImpact/Core/Simulator/Extensions/Enums.cs new file mode 100644 index 00000000..b19263b1 --- /dev/null +++ b/BetterGenshinImpact/Core/Simulator/Extensions/Enums.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BetterGenshinImpact.Core.Simulator.Extensions; + +/// +/// 模拟按键类型 +/// +public enum KeyType +{ + + /// + /// 单击按键(KeyPress) + /// + KeyPress, + + /// + /// 按住按键(KeyDown) + /// + KeyDown, + + /// + /// 释放按键(KeyUp) + /// + KeyUp, + + /// + /// 长按1s + /// + Hold, + +} + +/// +/// 原神按键动作 +/// +public enum GIActions +{ + /// + /// 向前移动 + /// + MoveForward, + + /// + /// 向后移动 + /// + MoveBackward, + + /// + /// 向左移动 + /// + MoveLeft, + + /// + /// 向右移动 + /// + MoveRight, + + /// + /// 切换走/跑;特定操作模式下向下移动 + /// + SwitchToWalkOrRun, + + /// + /// 普通攻击 + /// + NormalAttack, + + /// + /// 元素战技 + /// + ElementalSkill, + + /// + /// 元素爆发 + /// + ElementalBurst, + + /// + /// 冲刺(键盘) + /// + SprintKeyboard, + + /// + /// 冲刺(鼠标) + /// + SprintMouse, + + /// + /// 切换瞄准模式 + /// + SwitchAimingMode, + + /// + /// 跳跃;特定操作模式下向上移动 + /// + Jump, + + /// + /// 落下 + /// + Drop, + + /// + /// 拾取/交互(自动拾取由AutoPick模块管理) + /// + PickUpOrInteract, + + /// + /// 快捷使用小道具 + /// + QuickUseGadget, + + /// + /// 特定玩法内交互操作 + /// + InteractionInSomeMode, + + /// + /// 开启任务追踪 + /// + QuestNavigation, + + /// + /// 中断挑战 + /// + AbandonChallenge, + + /// + /// 切换小队角色1 + /// + SwitchMember1, + + /// + /// 切换小队角色2 + /// + SwitchMember2, + + /// + /// 切换小队角色3 + /// + SwitchMember3, + + /// + /// 切换小队角色4 + /// + SwitchMember4, + + /// + /// 切换小队角色5 + /// + SwitchMember5, + + /// + /// 呼出快捷轮盘 + /// + ShortcutWheel, + + /// + /// 打开背包 + /// + OpenInventory, + + /// + /// 打开角色界面 + /// + OpenCharacterScreen, + + /// + /// 打开地图 + /// + OpenMap, + + /// + /// 打开派蒙界面 + /// + OpenPaimonMenu, + + /// + /// 打开冒险之证界面 + /// + OpenAdventurerHandbook, + + /// + /// 打开多人游戏界面 + /// + OpenCoOpScreen, + + /// + /// 打开祈愿界面 + /// + OpenWishScreen, + + /// + /// 打开纪行界面 + /// + OpenBattlePassScreen, + + /// + /// 打开活动面板 + /// + OpenTheEventsMenu, + + /// + /// 打开玩法系统界面(尘歌壶内猫尾酒馆内) + /// + OpenTheSettingsMenu, + + /// + /// 打开摆设界面(尘歌壶内) + /// + OpenTheFurnishingScreen, + + /// + /// 打开星之归还(条件符合期间生效) + /// + OpenStellarReunion, + + /// + /// 开关任务菜单 + /// + OpenQuestMenu, + + /// + /// 打开通知详情 + /// + OpenNotificationDetails, + + /// + /// 打开聊天界面 + /// + OpenChatScreen, + + /// + /// 打开特殊环境说明 + /// + OpenSpecialEnvironmentInformation, + + /// + /// 查看教程详情 + /// + CheckTutorialDetails, + + /// + /// 长按打开元素视野 + /// + ElementalSight, + + /// + /// 呼出鼠标 + /// + ShowCursor, + + /// + /// 打开队伍配置界面 + /// + OpenPartySetupScreen, + + /// + /// 打开好友界面 + /// + OpenFriendsScreen, + + /// + /// 隐藏主界面 + /// + HideUI, + +} diff --git a/BetterGenshinImpact/Core/Simulator/Extensions/InputSimulatorExtension.cs b/BetterGenshinImpact/Core/Simulator/Extensions/InputSimulatorExtension.cs new file mode 100644 index 00000000..fb18baf0 --- /dev/null +++ b/BetterGenshinImpact/Core/Simulator/Extensions/InputSimulatorExtension.cs @@ -0,0 +1,135 @@ +using BetterGenshinImpact.Core.Config; +using System; +using System.Collections.Generic; +using System.Text; +using BetterGenshinImpact.Core.Simulator; +using System.Threading; +using Fischless.WindowsInput; + +namespace BetterGenshinImpact.Core.Simulator.Extensions; + +/// +/// 用于扩展的功能 +/// +public static class InputSimulatorExtension +{ + + /// + /// 模拟玩家操作 + /// + /// 动作 + /// 按键类型 + public static void SimulateAction(this InputSimulator self, GIActions action, KeyType type = KeyType.KeyPress) + { + var key = action.ToActionKey(); + switch (type) + { + case KeyType.KeyPress: + KeyPress(self, key); + break; + case KeyType.KeyDown: + KeyDown(self, key); + break; + case KeyType.KeyUp: + KeyUp(self, key); + break; + case KeyType.Hold: + HoldKeyPress(self, key); + break; + default: + break; + } + } + + private static void HoldKeyPress(InputSimulator self, KeyId key) + { + KeyDown(self, key); + Thread.Sleep(1000); + KeyUp(self, key); + } + + private static void KeyPress(InputSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.Mouse.LeftButtonClick(); + break; + case KeyId.MouseRightButton: + self.Mouse.RightButtonClick(); + break; + case KeyId.MouseMiddleButton: + self.Mouse.MiddleButtonClick(); + break; + case KeyId.MouseSideButton1: + self.Mouse.XButtonClick(0x0001); + break; + case KeyId.MouseSideButton2: + self.Mouse.XButtonClick(0x0001); + break; + default: + self.Keyboard.KeyPress(key.ToVK()); + break; + } + } + + private static void KeyDown(InputSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.Mouse.LeftButtonDown(); + break; + case KeyId.MouseRightButton: + self.Mouse.RightButtonDown(); + break; + case KeyId.MouseMiddleButton: + self.Mouse.MiddleButtonDown(); + break; + case KeyId.MouseSideButton1: + self.Mouse.XButtonDown(0x0001); + break; + case KeyId.MouseSideButton2: + self.Mouse.XButtonDown(0x0001); + break; + default: + self.Keyboard.KeyDown(key.ToVK()); + break; + } + } + + private static void KeyUp(InputSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.Mouse.LeftButtonUp(); + break; + case KeyId.MouseRightButton: + self.Mouse.RightButtonUp(); + break; + case KeyId.MouseMiddleButton: + self.Mouse.MiddleButtonUp(); + break; + case KeyId.MouseSideButton1: + self.Mouse.XButtonUp(0x0001); + break; + case KeyId.MouseSideButton2: + self.Mouse.XButtonUp(0x0001); + break; + default: + self.Keyboard.KeyUp(key.ToVK()); + break; + } + } + +} diff --git a/BetterGenshinImpact/Core/Simulator/Extensions/PostMessageSimulatorExtension.cs b/BetterGenshinImpact/Core/Simulator/Extensions/PostMessageSimulatorExtension.cs new file mode 100644 index 00000000..daa7faa9 --- /dev/null +++ b/BetterGenshinImpact/Core/Simulator/Extensions/PostMessageSimulatorExtension.cs @@ -0,0 +1,204 @@ +using BetterGenshinImpact.Core.Config; +using Fischless.WindowsInput; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace BetterGenshinImpact.Core.Simulator.Extensions; + +/// +/// 为提供扩展功能 +/// +public static class PostMessageSimulatorExtension +{ + + /// + /// 模拟玩家操作 + /// + /// 动作 + /// 按键类型 + public static PostMessageSimulator SimulateAction(this PostMessageSimulator self, GIActions action, KeyType type = KeyType.KeyPress) + { + var key = action.ToActionKey(); + switch (type) + { + case KeyType.KeyPress: + KeyPress(self, key); + break; + case KeyType.KeyDown: + KeyDown(self, key); + break; + case KeyType.KeyUp: + KeyUp(self, key); + break; + case KeyType.Hold: + HoldKeyPress(self, key); + break; + default: + break; + } + return self; + } + + private static void HoldKeyPress(PostMessageSimulator self, KeyId key) + { + self.LongKeyPress(key.ToVK()); + } + + private static void KeyPress(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.LeftButtonClick(); + break; + case KeyId.MouseRightButton: + self.RightButtonClick(); + break; + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyPress(key.ToVK()); + break; + } + } + + private static void KeyDown(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.LeftButtonDown(); + break; + case KeyId.MouseRightButton: + self.RightButtonDown(); + break; + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyDown(key.ToVK()); + break; + } + } + + private static void KeyUp(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.LeftButtonUp(); + break; + case KeyId.MouseRightButton: + self.RightButtonUp(); + break; + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyUp(key.ToVK()); + break; + } + } + + /// + /// 模拟玩家操作(后台) + /// + /// 动作 + /// 按键类型 + public static PostMessageSimulator SimulateActionBackground(this PostMessageSimulator self, GIActions action, KeyType type = KeyType.KeyPress) + { + var key = action.ToActionKey(); + switch (type) + { + case KeyType.KeyPress: + KeyPressBackground(self, key); + break; + case KeyType.KeyDown: + KeyDownBackground(self, key); + break; + case KeyType.KeyUp: + KeyUpBackground(self, key); + break; + case KeyType.Hold: + break; + default: + break; + } + return self; + } + + private static void KeyPressBackground(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + self.LeftButtonClickBackground(); + break; + case KeyId.MouseRightButton: + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyPressBackground(key.ToVK()); + break; + } + } + + private static void KeyDownBackground(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + case KeyId.MouseRightButton: + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyDownBackground(key.ToVK()); + break; + } + } + + private static void KeyUpBackground(PostMessageSimulator self, KeyId key) + { + switch (key) + { + case KeyId.None: + case KeyId.Unknown: + break; + case KeyId.MouseLeftButton: + case KeyId.MouseRightButton: + case KeyId.MouseMiddleButton: + case KeyId.MouseSideButton1: + case KeyId.MouseSideButton2: + break; + default: + self.KeyUpBackground(key.ToVK()); + break; + } + } + +} diff --git a/BetterGenshinImpact/Core/Simulator/Extensions/SimulateKeyHelper.cs b/BetterGenshinImpact/Core/Simulator/Extensions/SimulateKeyHelper.cs new file mode 100644 index 00000000..5106cfd0 --- /dev/null +++ b/BetterGenshinImpact/Core/Simulator/Extensions/SimulateKeyHelper.cs @@ -0,0 +1,79 @@ +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.GameTask; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace BetterGenshinImpact.Core.Simulator.Extensions; + +public static class SimulateKeyHelper +{ + + private static KeyBindingsConfig KeyConfig => TaskContext.Instance().Config.KeyBindingsConfig; + + public static KeyId ToActionKey(this GIActions action) + { + return GetActionKey(action); + } + + /// + /// 通过ActionId取得实际的键盘绑定 + /// + /// + /// + public static KeyId GetActionKey(GIActions action) + { + return action switch + { + GIActions.MoveForward => KeyConfig.MoveForward, + GIActions.MoveBackward => KeyConfig.MoveBackward, + GIActions.MoveLeft => KeyConfig.MoveLeft, + GIActions.MoveRight => KeyConfig.MoveRight, + GIActions.SwitchToWalkOrRun => KeyConfig.SwitchToWalkOrRun, + GIActions.NormalAttack => KeyConfig.NormalAttack, + GIActions.ElementalSkill => KeyConfig.ElementalSkill, + GIActions.ElementalBurst => KeyConfig.ElementalBurst, + GIActions.SprintKeyboard => KeyConfig.SprintKeyboard, + GIActions.SprintMouse => KeyConfig.SprintMouse, + GIActions.SwitchAimingMode => KeyConfig.SwitchAimingMode, + GIActions.Jump => KeyConfig.Jump, + GIActions.Drop => KeyConfig.Drop, + GIActions.PickUpOrInteract => KeyConfig.PickUpOrInteract, + GIActions.QuickUseGadget => KeyConfig.QuickUseGadget, + GIActions.InteractionInSomeMode => KeyConfig.InteractionInSomeMode, + GIActions.QuestNavigation => KeyConfig.QuestNavigation, + GIActions.AbandonChallenge => KeyConfig.AbandonChallenge, + GIActions.SwitchMember1 => KeyConfig.SwitchMember1, + GIActions.SwitchMember2 => KeyConfig.SwitchMember2, + GIActions.SwitchMember3 => KeyConfig.SwitchMember3, + GIActions.SwitchMember4 => KeyConfig.SwitchMember4, + GIActions.SwitchMember5 => KeyConfig.SwitchMember5, + GIActions.ShortcutWheel => KeyConfig.ShortcutWheel, + GIActions.OpenInventory => KeyConfig.OpenInventory, + GIActions.OpenCharacterScreen => KeyConfig.OpenCharacterScreen, + GIActions.OpenMap => KeyConfig.OpenMap, + GIActions.OpenPaimonMenu => KeyConfig.OpenPaimonMenu, + GIActions.OpenAdventurerHandbook => KeyConfig.OpenAdventurerHandbook, + GIActions.OpenCoOpScreen => KeyConfig.OpenCoOpScreen, + GIActions.OpenWishScreen => KeyConfig.OpenWishScreen, + GIActions.OpenBattlePassScreen => KeyConfig.OpenBattlePassScreen, + GIActions.OpenTheEventsMenu => KeyConfig.OpenTheEventsMenu, + GIActions.OpenTheSettingsMenu => KeyConfig.OpenTheSettingsMenu, + GIActions.OpenTheFurnishingScreen => KeyConfig.OpenTheFurnishingScreen, + GIActions.OpenStellarReunion => KeyConfig.OpenStellarReunion, + GIActions.OpenQuestMenu => KeyConfig.OpenQuestMenu, + GIActions.OpenNotificationDetails => KeyConfig.OpenNotificationDetails, + GIActions.OpenChatScreen => KeyConfig.OpenChatScreen, + GIActions.OpenSpecialEnvironmentInformation => KeyConfig.OpenSpecialEnvironmentInformation, + GIActions.CheckTutorialDetails => KeyConfig.CheckTutorialDetails, + GIActions.ElementalSight => KeyConfig.ElementalSight, + GIActions.ShowCursor => KeyConfig.ShowCursor, + GIActions.OpenPartySetupScreen => KeyConfig.OpenPartySetupScreen, + GIActions.OpenFriendsScreen => KeyConfig.OpenFriendsScreen, + GIActions.HideUI => KeyConfig.HideUI, + _ => default, + }; + } + +} diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index 75065796..82b4e36f 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -2,6 +2,7 @@ using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Recognition.ONNX; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoFight; using BetterGenshinImpact.GameTask.AutoFight.Assets; using BetterGenshinImpact.GameTask.AutoFight.Model; @@ -223,31 +224,31 @@ public class AutoDomainTask : ISoloTask if ("芬德尼尔之顶".Equals(_taskParam.DomainName)) { - Simulation.SendInput.Keyboard.KeyDown(VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown); Thread.Sleep(3000); - Simulation.SendInput.Keyboard.KeyUp(VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp); } else if ("无妄引咎密宫".Equals(_taskParam.DomainName)) { - Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); Thread.Sleep(500); - Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); Thread.Sleep(100); - Simulation.SendInput.Keyboard.KeyDown(VK.VK_A); + Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyDown); Thread.Sleep(1600); - Simulation.SendInput.Keyboard.KeyUp(VK.VK_A); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } else if ("苍白的遗荣".Equals(_taskParam.DomainName)) { - Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); Thread.Sleep(1000); - Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } else { - Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); Thread.Sleep(3000); - Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } await Delay(3000, _ct); // 站稳 @@ -282,10 +283,10 @@ public class AutoDomainTask : ISoloTask var fightAssets = AutoFightContext.Instance.FightAssets; // 进入秘境 - using var fRectArea = CaptureToRectArea().Find(AutoPickAssets.Instance.FRo); + using var fRectArea = CaptureToRectArea().Find(AutoPickAssets.Instance.PickRo); if (!fRectArea.IsEmpty()) { - Simulation.SendInput.Keyboard.KeyPress(VK.VK_F); + Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk); Logger.LogInformation("自动秘境:{Text}", "进入秘境"); // 秘境开门动画 5s await Delay(5000, _ct); @@ -352,19 +353,19 @@ public class AutoDomainTask : ISoloTask await Task.Run((Action)(() => { - _simulator.KeyDown(VK.VK_W); + _simulator.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); Sleep(20); // 组合键好像不能直接用 postmessage if (!_config.WalkToF) { - Simulation.SendInput.Keyboard.KeyDown(VK.VK_SHIFT); + Simulation.SendInput.SimulateAction(GIActions.SprintKeyboard, KeyType.KeyDown); } try { while (!_ct.IsCancellationRequested) { - using var fRectArea = Common.TaskControl.CaptureToRectArea().Find(AutoPickAssets.Instance.FRo); + using var fRectArea = Common.TaskControl.CaptureToRectArea().Find(AutoPickAssets.Instance.PickRo); if (fRectArea.IsEmpty()) { Sleep(100, _ct); @@ -372,18 +373,18 @@ public class AutoDomainTask : ISoloTask else { Logger.LogInformation("检测到交互键"); - Simulation.SendInput.Keyboard.KeyPress(VK.VK_F); + Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk); break; } } } finally { - _simulator.KeyUp(VK.VK_W); + _simulator.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); Sleep(50); if (!_config.WalkToF) { - Simulation.SendInput.Keyboard.KeyUp(VK.VK_SHIFT); + Simulation.SendInput.SimulateAction(GIActions.SprintKeyboard, KeyType.KeyUp); } } }), _ct); @@ -519,7 +520,7 @@ public class AutoDomainTask : ISoloTask if (Bv.CurrentAvatarIsLowHp(CaptureToRectArea())) { // 模拟按键 "Z" - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_Z); + Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); Logger.LogInformation("检测到红血,按Z吃药"); // TODO 吃饱了会一直吃 } @@ -569,12 +570,16 @@ public class AutoDomainTask : ISoloTask { return new Task(() => { + var keyConfig = TaskContext.Instance().Config.KeyBindingsConfig; + var moveLeftKey = keyConfig.MoveLeft.ToVK(); + var moveRightKey = keyConfig.MoveRight.ToVK(); + var moveForwardKey = keyConfig.MoveForward.ToVK(); var captureArea = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect; var middleX = captureArea.Width / 2; var leftKeyDown = false; var rightKeyDown = false; var noDetectCount = 0; - var prevKey = VK.VK_A; + var prevKey = moveLeftKey; var backwardsAndForwardsCount = 0; while (!_ct.IsCancellationRequested) { @@ -590,13 +595,13 @@ public class AutoDomainTask : ISoloTask if (rightKeyDown) { // 先松开D键 - _simulator.KeyUp(VK.VK_D); + _simulator.KeyUp(moveRightKey); rightKeyDown = false; } if (!leftKeyDown) { - _simulator.KeyDown(VK.VK_A); + _simulator.KeyDown(moveLeftKey); leftKeyDown = true; } } @@ -608,13 +613,13 @@ public class AutoDomainTask : ISoloTask if (leftKeyDown) { // 先松开A键 - _simulator.KeyUp(VK.VK_A); + _simulator.KeyUp(moveLeftKey); leftKeyDown = false; } if (!rightKeyDown) { - _simulator.KeyDown(VK.VK_D); + _simulator.KeyDown(moveRightKey); rightKeyDown = true; } } @@ -623,42 +628,42 @@ public class AutoDomainTask : ISoloTask // 树在中间 松开所有键 if (rightKeyDown) { - _simulator.KeyUp(VK.VK_D); - prevKey = VK.VK_D; + _simulator.KeyUp(moveRightKey); + prevKey = moveRightKey; rightKeyDown = false; } if (leftKeyDown) { - _simulator.KeyUp(VK.VK_A); - prevKey = VK.VK_A; + _simulator.KeyUp(moveLeftKey); + prevKey = moveLeftKey; leftKeyDown = false; } // 松开按键后使用小碎步移动 if (treeMiddleX < middleX) { - if (prevKey == VK.VK_D) + if (prevKey == moveRightKey) { backwardsAndForwardsCount++; } - _simulator.KeyPress(VK.VK_A, 60); - prevKey = VK.VK_A; + _simulator.KeyPress(moveLeftKey, 60); + prevKey = moveLeftKey; } else if (treeMiddleX > middleX) { - if (prevKey == VK.VK_A) + if (prevKey == moveLeftKey) { backwardsAndForwardsCount++; } - _simulator.KeyPress(VK.VK_D, 60); - prevKey = VK.VK_D; + _simulator.KeyPress(moveRightKey, 60); + prevKey = moveRightKey; } else { - _simulator.KeyPress(VK.VK_W, 60); + _simulator.KeyPress(moveForwardKey, 60); Sleep(500, _ct); treeCts.Cancel(); break; @@ -674,13 +679,13 @@ public class AutoDomainTask : ISoloTask { if (leftKeyDown) { - _simulator.KeyUp(VK.VK_A); + _simulator.KeyUp(moveLeftKey); leftKeyDown = false; } if (!rightKeyDown) { - _simulator.KeyDown(VK.VK_D); + _simulator.KeyDown(moveRightKey); rightKeyDown = true; } } @@ -688,13 +693,13 @@ public class AutoDomainTask : ISoloTask { if (rightKeyDown) { - _simulator.KeyUp(VK.VK_D); + _simulator.KeyUp(moveRightKey); rightKeyDown = false; } if (!leftKeyDown) { - _simulator.KeyDown(VK.VK_A); + _simulator.KeyDown(moveLeftKey); leftKeyDown = true; } } @@ -703,7 +708,7 @@ public class AutoDomainTask : ISoloTask if (backwardsAndForwardsCount >= _config.LeftRightMoveTimes) { // 左右移动5次说明已经在树中心了 - _simulator.KeyPress(VK.VK_W, 60); + _simulator.KeyPress(moveForwardKey, 60); Sleep(500, _ct); treeCts.Cancel(); break; diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs index 79700074..928a4a57 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs @@ -1,5 +1,6 @@ using BetterGenshinImpact.Core.Recognition.ONNX; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoFight.Model; using BetterGenshinImpact.GameTask.AutoFight.Script; using BetterGenshinImpact.GameTask.Model.Area; @@ -18,6 +19,7 @@ using BetterGenshinImpact.GameTask.Common.Job; using OpenCvSharp; using Vanara; using Vanara.PInvoke; +using BetterGenshinImpact.Core.Config; namespace BetterGenshinImpact.GameTask.AutoFight; @@ -345,7 +347,7 @@ public class AutoFightTask : ISoloTask } kazuha.UseSkill(true); await Task.Delay(100); - Simulation.SendInput.Mouse.LeftButtonClick(); + Simulation.SendInput.SimulateAction(GIActions.NormalAttack); await Delay(1500, ct); } @@ -418,9 +420,9 @@ public class AutoFightTask : ISoloTask **/ await Delay(delayTime, _ct); - Logger.LogInformation("按L检查战斗是否结束"); + Logger.LogInformation("打开编队界面检查战斗是否结束"); // 最终方案确认战斗结束 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_L); + Simulation.SendInput.SimulateAction(GIActions.OpenPartySetupScreen); await Delay(450, _ct); var ra = CaptureToRectArea(); var b3 = ra.SrcMat.At(50, 790); @@ -428,11 +430,11 @@ public class AutoFightTask : ISoloTask if (AreDifferencesWithinBounds(_finishDetectConfig.BattleEndProgressBarColor, (b3.Item0, b3.Item1, b3.Item2), _finishDetectConfig.BattleEndProgressBarColorTolerance)) { Logger.LogInformation("识别到战斗结束"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.Drop); return true; } - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.Drop); Logger.LogInformation($"未识别到战斗结束{b3.Item0},{b3.Item1},{b3.Item2}"); _lastFightFlagTime = DateTime.Now; return false; diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs index 98796e1c..efa4d470 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs @@ -2,6 +2,7 @@ using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Recognition.OpenCv; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoFight.Config; using BetterGenshinImpact.GameTask.Model.Area; using BetterGenshinImpact.Helpers; @@ -16,6 +17,7 @@ using BetterGenshinImpact.GameTask.AutoTrackPath; using BetterGenshinImpact.GameTask.Common.BgiVision; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; +using BetterGenshinImpact.Core.Config; namespace BetterGenshinImpact.GameTask.AutoFight.Model; @@ -89,6 +91,7 @@ public class Avatar /// public CombatScenes CombatScenes { get; set; } + public Avatar(CombatScenes combatScenes, string name, int index, Rect nameRect) { CombatScenes = combatScenes; @@ -116,9 +119,9 @@ public class Avatar { Logger.LogWarning("检测到复苏界面,存在角色被击败,前往七天神像复活"); // 先打开地图 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_ESCAPE); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_ESCAPE); // NOTE: 此处按下Esc是为了关闭复苏界面,无需改键 Sleep(600, Ct); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_M); + Simulation.SendInput.SimulateAction(GIActions.OpenMap); // tp 到七天神像复活 var tpTask = new TpTask(Ct); tpTask.Tp(TpTask.ReviveStatueOfTheSevenPointX, TpTask.ReviveStatueOfTheSevenPointY, true).Wait(Ct); @@ -149,7 +152,26 @@ public class Avatar return; } - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_1 + (byte)Index - 1); + switch (Index) + { + case 1: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember1); + break; + case 2: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember2); + break; + case 3: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember3); + break; + case 4: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember4); + break; + case 5: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember5); + break; + default: + break; + } // Debug.WriteLine($"切换到{Index}号位"); // Cv2.ImWrite($"log/切换.png", region.SrcMat); Sleep(250, Ct); @@ -185,7 +207,26 @@ public class Avatar return true; } - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_1 + (byte)Index - 1); + switch (Index) + { + case 1: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember1); + break; + case 2: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember2); + break; + case 3: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember3); + break; + case 4: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember4); + break; + case 5: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember5); + break; + default: + break; + } Sleep(250, Ct); } @@ -210,7 +251,26 @@ public class Avatar return; } - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_1 + (byte)Index - 1); + switch (Index) + { + case 1: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember1); + break; + case 2: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember2); + break; + case 3: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember3); + break; + case 4: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember4); + break; + case 5: + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SwitchMember5); + break; + default: + break; + } Sleep(250); } } @@ -305,7 +365,7 @@ public class Avatar return; } - AutoFightContext.Instance.Simulator.LeftButtonClick(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.NormalAttack); ms -= 200; Sleep(200, Ct); } @@ -327,7 +387,7 @@ public class Avatar { if (Name == "纳西妲") { - AutoFightContext.Instance.Simulator.KeyDown(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.KeyDown); Sleep(300, Ct); for (int j = 0; j < 10; j++) { @@ -336,22 +396,22 @@ public class Avatar } Sleep(300); // 持续操作不应该被cts取消 - AutoFightContext.Instance.Simulator.KeyUp(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.KeyUp); } else if (Name == "坎蒂丝") { - AutoFightContext.Instance.Simulator.KeyDown(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.KeyDown); Thread.Sleep(3000); - AutoFightContext.Instance.Simulator.KeyUp(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.KeyUp); } else { - AutoFightContext.Instance.Simulator.LongKeyPress(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.Hold); } } else { - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_E); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalSkill, KeyType.KeyPress); } Sleep(200, Ct); @@ -395,7 +455,7 @@ public class Avatar return; } - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_Q); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.ElementalBurst); Sleep(200, Ct); var region = CaptureToRectArea(); @@ -450,9 +510,9 @@ public class Avatar ms = 200; } - AutoFightContext.Instance.Simulator.RightButtonDown(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SprintMouse, KeyType.KeyDown); Sleep(ms); // 冲刺不能被cts取消 - AutoFightContext.Instance.Simulator.RightButtonUp(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.SprintMouse, KeyType.KeyUp); } public void Walk(string key, int ms) @@ -465,19 +525,19 @@ public class Avatar User32.VK vk = User32.VK.VK_NONAME; if (key == "w") { - vk = User32.VK.VK_W; + vk = GIActions.MoveForward.ToActionKey().ToVK(); } else if (key == "s") { - vk = User32.VK.VK_S; + vk = GIActions.MoveBackward.ToActionKey().ToVK(); } else if (key == "a") { - vk = User32.VK.VK_A; + vk = GIActions.MoveLeft.ToActionKey().ToVK(); } else if (key == "d") { - vk = User32.VK.VK_D; + vk = GIActions.MoveRight.ToActionKey().ToVK(); } if (vk == User32.VK.VK_NONAME) @@ -514,7 +574,7 @@ public class Avatar /// public void Jump() { - AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_SPACE); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.Jump); } /// @@ -530,7 +590,7 @@ public class Avatar if (Name == "那维莱特") { var dpi = TaskContext.Instance().DpiScale; - AutoFightContext.Instance.Simulator.LeftButtonDown(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.NormalAttack, KeyType.KeyDown); while (ms >= 0) { if (Ct is { IsCancellationRequested: true }) @@ -543,13 +603,13 @@ public class Avatar Sleep(50); // 持续操作不应该被cts取消 } - AutoFightContext.Instance.Simulator.LeftButtonUp(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.NormalAttack, KeyType.KeyUp); } else { - AutoFightContext.Instance.Simulator.LeftButtonDown(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.NormalAttack, KeyType.KeyDown); Sleep(ms); // 持续操作不应该被cts取消 - AutoFightContext.Instance.Simulator.LeftButtonUp(); + AutoFightContext.Instance.Simulator.SimulateAction(GIActions.NormalAttack, KeyType.KeyUp); } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs index 1afd2e2e..6e6e60fd 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs @@ -7,6 +7,7 @@ using BetterGenshinImpact.GameTask.AutoPathing.Model; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; @@ -19,7 +20,7 @@ public class ElementalSkillHandler : IActionHandler public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null, object? config = null) { Logger.LogInformation("执行 {Text}", "释放元素战技"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(1000, ct); } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs index 569e4a20..0e4f6e67 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoPathing.Model; using BetterGenshinImpact.Helpers; using Microsoft.Extensions.Logging; @@ -55,7 +56,7 @@ public class NahidaCollectHandler : IActionHandler await Delay(200, ct); // 按住E技能 无死角扫码 - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill, KeyType.KeyDown); await Delay(200, ct); // 先地面来一圈 @@ -77,7 +78,7 @@ public class NahidaCollectHandler : IActionHandler Simulation.SendInput.Mouse.MoveMouseBy(x, y); await Delay(30, ct); } - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill, KeyType.KeyUp); lastETime = DateTime.Now; diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs index c6d5a00e..cfa50582 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs @@ -1,5 +1,6 @@ using System; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using Microsoft.Extensions.Logging; using System.Threading; using System.Threading.Tasks; @@ -18,7 +19,7 @@ public class NormalAttackHandler : IActionHandler public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null, object? config = null) { Logger.LogInformation("执行 {Text}", "普通攻击"); - Simulation.SendInput.Mouse.LeftButtonClick(); + Simulation.SendInput.SimulateAction(GIActions.NormalAttack); await Delay(1000, ct); } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs index 818883eb..fb23a90e 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs @@ -9,6 +9,7 @@ using BetterGenshinImpact.Helpers; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; @@ -47,7 +48,7 @@ public class PickAroundHandler() : IActionHandler public async Task MoveCircle(double edgeT, int n) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_A); + Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyDown); await Delay(30, _ct); while (n-- > 0) { @@ -55,7 +56,7 @@ public class PickAroundHandler() : IActionHandler await Delay((int)Math.Round(edgeT), _ct); } - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_A); + Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyUp); await Delay(200, _ct); } @@ -67,9 +68,9 @@ public class PickAroundHandler() : IActionHandler await Delay(500, _ct); if (ms > 0) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); await Delay(ms, _ct); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); await Delay(200, _ct); } } @@ -80,8 +81,8 @@ public class PickAroundHandler() : IActionHandler double y = oldRadius * Math.Sin(angle); Simulation.SendInput.Mouse.MiddleButtonClick(); await Delay(500, _ct); - await MoveAfterTurn(User32.VK.VK_S, (int)Math.Round(y) + 200); - await MoveAfterTurn(User32.VK.VK_A, (int)Math.Round(x)); + await MoveAfterTurn(GIActions.MoveBackward.ToActionKey().ToVK(), (int)Math.Round(y) + 200); + await MoveAfterTurn(GIActions.MoveLeft.ToActionKey().ToVK(), (int)Math.Round(x)); } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs index 6c42cc22..f1af3ffa 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoPathing.Model; using Microsoft.Extensions.Logging; using Vanara.PInvoke; @@ -25,7 +26,7 @@ public class UpDownGrabLeaf : IActionHandler // kbPress('w'); // 飞行 while (i > 0 && !ct.IsCancellationRequested) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_T); + Simulation.SendInput.SimulateAction(GIActions.InteractionInSomeMode, KeyType.KeyDown); if (i % 10 == 0) { y = -y; diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index ee828042..0ebf2399 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -30,6 +30,7 @@ using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; using static BetterGenshinImpact.GameTask.SystemControl; using ActionEnum = BetterGenshinImpact.GameTask.AutoPathing.Model.Enum.ActionEnum; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.AutoPathing; @@ -244,6 +245,24 @@ public class PathExecutor } } + catch (RetryException retryException) + { + StartSkipOtherOperations(); + Logger.LogWarning(retryException.Message); + } + catch (RetryNoCountException retryException) + { + //特殊情况下,重试不消耗次数 + i--; + StartSkipOtherOperations(); + Logger.LogWarning(retryException.Message); + } + finally + { + // 不管咋样,松开所有按键 + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + Simulation.SendInput.SimulateAction(GIActions.SprintMouse, KeyType.KeyUp); + } } } finally @@ -528,9 +547,9 @@ public class PathExecutor if (avatar.TrySwitch()) { //1命白术能两次 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(800, ct); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(800, ct); await SwitchAvatar(PartyConfig.MainAvatarIndex); await Delay(4000, ct); @@ -543,7 +562,7 @@ public class PathExecutor { if (avatar.TrySwitch()) { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(11000, ct); await SwitchAvatar(PartyConfig.MainAvatarIndex); return true; @@ -555,10 +574,10 @@ public class PathExecutor { if (avatar.TrySwitch()) { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(500, ct); //尝试Q全队回血 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_Q); + Simulation.SendInput.SimulateAction(GIActions.ElementalBurst); //单人血只给行走位加血 await SwitchAvatar(PartyConfig.MainAvatarIndex); await Delay(5000, ct); @@ -632,7 +651,7 @@ public class PathExecutor var num = 0; // 按下w,一直走 - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); while (!ct.IsCancellationRequested) { num++; @@ -694,7 +713,7 @@ public class PathExecutor //调用脱困代码,由TrapEscaper接管移动 await _trapEscaper.RotateAndMove(); await _trapEscaper.MoveTo(waypoint); - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); Logger.LogInformation("卡死脱离结束"); continue; } @@ -714,7 +733,7 @@ public class PathExecutor if (!isFlying) { Debug.WriteLine("未进入飞行状态,按下空格"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); await Delay(200, ct); } @@ -723,7 +742,7 @@ public class PathExecutor if (waypoint.MoveMode == MoveModeEnum.Jump.Code) { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); await Delay(200, ct); continue; } @@ -735,11 +754,11 @@ public class PathExecutor { if (fastMode) { - Simulation.SendInput.Mouse.RightButtonUp(); + Simulation.SendInput.SimulateAction(GIActions.SprintMouse, KeyType.KeyUp); } else { - Simulation.SendInput.Mouse.RightButtonDown(); + Simulation.SendInput.SimulateAction(GIActions.SprintMouse, KeyType.KeyDown); } fastMode = !fastMode; @@ -777,7 +796,7 @@ public class PathExecutor if (Math.Abs((fastModeColdTime - now).TotalMilliseconds) > 2500) //冷却时间2.5s,回复体力用 { fastModeColdTime = now; - Simulation.SendInput.Mouse.RightButtonClick(); + Simulation.SendInput.SimulateAction(GIActions.SprintMouse); } } } @@ -787,7 +806,7 @@ public class PathExecutor { if ((DateTime.UtcNow - _useGadgetLastUseTime).TotalMilliseconds > PartyConfig.UseGadgetIntervalMs) { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_Z); + Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); _useGadgetLastUseTime = DateTime.UtcNow; } } @@ -796,7 +815,7 @@ public class PathExecutor } // 抬起w键 - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } private async Task UseElementalSkill() @@ -819,29 +838,29 @@ public class PathExecutor // 钟离往身后放柱子 if (avatar.Name == "钟离") { - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); await Delay(50, ct); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward); await Delay(200, ct); } if (PartyConfig.GuardianElementalSkillLongPress) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill, KeyType.KeyDown); await Task.Delay(800); // 不能取消 - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill, KeyType.KeyUp); await Delay(700, ct); } else { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.SimulateAction(GIActions.ElementalSkill); await Delay(300, ct); } // 钟离往身后放柱子 后继续走路 if (avatar.Name == "钟离") { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); } } @@ -855,7 +874,7 @@ public class PathExecutor { //下落攻击接近目的地 Logger.LogInformation("动作:下落攻击"); - Simulation.SendInput.Mouse.LeftButtonClick(); + Simulation.SendInput.SimulateAction(GIActions.NormalAttack); await Delay(1000, ct); } @@ -884,11 +903,14 @@ public class PathExecutor targetOrientation = Navigation.GetTargetOrientation(waypoint, position); await _rotateTask.WaitUntilRotatedTo(targetOrientation, 2); // 小碎步接近 - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W).Sleep(60).KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); + Thread.Sleep(60); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + // Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W).Sleep(60).KeyUp(User32.VK.VK_W); await Delay(20, ct); } - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); // 到达目的地后停顿一秒 await Delay(1000, ct); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/TrapEscaper.cs b/BetterGenshinImpact/GameTask/AutoPathing/TrapEscaper.cs index b0e24848..ef3bcc4e 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/TrapEscaper.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/TrapEscaper.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.AutoPathing; @@ -40,7 +41,7 @@ public class TrapEscaper(CancellationToken ct) await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5); // 按下w,一直走 - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); while (!ct.IsCancellationRequested) { var now = DateTime.UtcNow; @@ -70,7 +71,7 @@ public class TrapEscaper(CancellationToken ct) //执行旋转 await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5); - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); // //这里是随机角度的归零逻辑,在脱困执行一秒后将randomAngle设为0以将实际角度重置为正面向点位的角度 //其实就是在一段时间内进行角度的修改以实现自动避障 @@ -91,12 +92,12 @@ public class TrapEscaper(CancellationToken ct) waypoint.MoveMode != MoveModeEnum.Fly.Code) if (Bv.GetMotionStatus(screen) == MotionStatus.Climb) { - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + Simulation.SendInput.SimulateAction(GIActions.Drop); Sleep(75); - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown); Sleep(700); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp); LastActionTime = DateTime.UtcNow; @@ -117,17 +118,17 @@ public class TrapEscaper(CancellationToken ct) } // 抬起w键 - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } public async Task RotateAndMove() { IncreaseRandomAngle(); // 脱离攀爬状态 - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + Simulation.SendInput.SimulateAction(GIActions.Drop); await Delay(75, ct); - Simulation.SendInput.Mouse.LeftButtonClick(); + Simulation.SendInput.SimulateAction(GIActions.NormalAttack); await Delay(500, ct); TimeSpan timeSinceLastAction = DateTime.UtcNow - LastActionTime; @@ -166,30 +167,30 @@ public class TrapEscaper(CancellationToken ct) private void MoveBackward(int delay) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown); Sleep(500); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); Sleep(delay); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_S); + Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp); } private void MoveLeft(int delay) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_A); + Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyDown); Sleep(300); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); Sleep(delay); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_A); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyUp); + Simulation.SendInput.SimulateAction(GIActions.Drop); } private void MoveRight(int delay) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_D); + Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyDown); Sleep(300); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); Sleep(delay); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_D); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyUp); + Simulation.SendInput.SimulateAction(GIActions.Drop); } } diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs index f9d64cfa..309e710b 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs @@ -112,7 +112,7 @@ public partial class AutoPickTrigger : ITaskTrigger if (_externalConfig is { ForceInteraction: true }) { LogPick(content, "直接拾取"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_F); + Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk); return; } diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index 1277c948..1081caf8 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Recognition.OpenCv; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoSkip.Assets; using BetterGenshinImpact.GameTask.AutoSkip.Model; using BetterGenshinImpact.GameTask.Common; @@ -203,7 +204,7 @@ public partial class AutoSkipTrigger : ITaskTrigger { if (IsUseInteractionKey) { - _postMessageSimulator?.KeyPressBackground(User32.VK.VK_F); // 注意这里不是交互键 + _postMessageSimulator? .SimulateActionBackground(GIActions.PickUpOrInteract); // 注意这里不是交互键 NOTE By Ayu0K: 这里确实是交互键 } else { diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs index 28579f9d..913df4ae 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Recognition.OpenCv; using BetterGenshinImpact.Core.Script; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.AutoSkip.Model; using BetterGenshinImpact.GameTask.Common; @@ -113,7 +114,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask { // 距离大于150米,先传送到最近的传送点 // J 打开任务 切换追踪打开地图 中心点就是任务点 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_J); + Simulation.SendInput.SimulateAction(GIActions.OpenQuestMenu); Sleep(800, _ct); // TODO 识别是否在任务界面 // 切换追踪 @@ -179,7 +180,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask private void StartTrackPoint() { // V键直接追踪 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_V); + Simulation.SendInput.SimulateAction(GIActions.QuestNavigation); Sleep(3000, _ct); var ra = CaptureToRectArea(); @@ -216,7 +217,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask Simulation.SendInput.Mouse.MoveMouseBy(-50, 0); if (wDown) { - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); wDown = false; } Debug.WriteLine("使追踪点位于俯视角上方"); @@ -242,7 +243,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask { if (!wDown) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); wDown = true; } } @@ -251,7 +252,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask { if (wDown) { - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); wDown = false; } // 识别距离 diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs index 8b4c0c23..bf29b95a 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs @@ -1,6 +1,7 @@ using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Script; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.AutoTrackPath.Model; using BetterGenshinImpact.GameTask.Common; @@ -319,7 +320,10 @@ public class AutoTrackPathTask var angle1 = GetCharacterOrientationAngle(); Simulation.SendInput.Mouse.MoveMouseBy(CharMovingUnit, 0); Sleep(500); - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W).Sleep(100).KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); + Sleep(100); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + // Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W).Sleep(100).KeyUp(User32.VK.VK_W); Sleep(1000); var angle2 = GetCharacterOrientationAngle(); var angleOffset = angle2 - angle1; diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs index 8122cf1c..483a7b0f 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs @@ -1,4 +1,5 @@ using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.Model; using System; using Vanara.PInvoke; @@ -15,7 +16,7 @@ public class MovementControl : Singleton if (!_wDown) { _wDown = true; - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); } } @@ -24,12 +25,12 @@ public class MovementControl : Singleton if (_wDown) { _wDown = false; - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } } public void SpacePress() { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + Simulation.SendInput.SimulateAction(GIActions.Jump); } } diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs index 5ac61db3..c1a19717 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using BetterGenshinImpact.GameTask.Common.Exceptions; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.AutoTrackPath; @@ -163,7 +164,7 @@ public class TpTask(CancellationToken ct) await Delay(1000, ct); ra1 = CaptureToRectArea(); } - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_M); + Simulation.SendInput.SimulateAction(GIActions.OpenMap); await Delay(1000, ct); for (int i = 0; i < 3; i++) { diff --git a/BetterGenshinImpact/GameTask/Common/Job/ArtifactSalvageTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ArtifactSalvageTask.cs index bb88abbb..27e92271 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ArtifactSalvageTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ArtifactSalvageTask.cs @@ -10,6 +10,7 @@ using BetterGenshinImpact.Helpers.Extensions; using Microsoft.Extensions.Logging; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; +using BetterGenshinImpact.Core.Simulator.Extensions; namespace BetterGenshinImpact.GameTask.Common.Job; @@ -25,7 +26,7 @@ public class ArtifactSalvageTask await _returnMainUiTask.Start(ct); // B键打开背包 - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_B); + Simulation.SendInput.SimulateAction(GIActions.OpenInventory); await Delay(1000, ct); var openBagSuccess = await NewRetry.WaitForAction(() => @@ -51,7 +52,7 @@ public class ArtifactSalvageTask if (Bv.IsInMainUi(ra)) { Debug.WriteLine("背包打开失败,再次尝试打开背包"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_B); + Simulation.SendInput.SimulateAction(GIActions.OpenInventory); } return false; diff --git a/BetterGenshinImpact/GameTask/Common/Job/ClaimBattlePassRewardsTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ClaimBattlePassRewardsTask.cs index dfa32508..e06df9a7 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ClaimBattlePassRewardsTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ClaimBattlePassRewardsTask.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.Common.Element.Assets; using BetterGenshinImpact.GameTask.Model.Area; using BetterGenshinImpact.Helpers.Extensions; @@ -37,7 +38,7 @@ public class ClaimBattlePassRewardsTask await _returnMainUiTask.Start(ct); await Delay(200, ct); - TaskContext.Instance().PostMessageSimulator.KeyPress(User32.VK.VK_F4); // F4 开纪行 + TaskContext.Instance().PostMessageSimulator.SimulateAction(GIActions.OpenBattlePassScreen); // F4 开纪行 // 领取战令1 await Delay(500, ct); diff --git a/BetterGenshinImpact/GameTask/Common/Job/ClaimEncounterPointsRewardsTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ClaimEncounterPointsRewardsTask.cs index 7c7af7dc..e7fa4567 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ClaimEncounterPointsRewardsTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ClaimEncounterPointsRewardsTask.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.Common.Element.Assets; using Microsoft.Extensions.Logging; using Vanara.PInvoke; @@ -37,7 +38,7 @@ public class ClaimEncounterPointsRewardsTask await Delay(200, ct); - TaskContext.Instance().PostMessageSimulator.KeyPress(User32.VK.VK_F1); // F1 开书 + TaskContext.Instance().PostMessageSimulator.SimulateAction(GIActions.OpenAdventurerHandbook); // F1 开书 await Delay(1000, ct); diff --git a/BetterGenshinImpact/GameTask/Common/Job/ClaimMailRewardsTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ClaimMailRewardsTask.cs index 73d78a50..23128459 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ClaimMailRewardsTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ClaimMailRewardsTask.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.Common.Element.Assets; using Microsoft.Extensions.Logging; using Vanara.PInvoke; @@ -37,7 +38,7 @@ public class ClaimMailRewardsTask await Delay(200, ct); - TaskContext.Instance().PostMessageSimulator.KeyPress(User32.VK.VK_ESCAPE); // ESC + TaskContext.Instance().PostMessageSimulator.SimulateAction(GIActions.OpenPaimonMenu); // ESC await Delay(1300, ct); diff --git a/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs index bb58d123..1810c0e4 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Recognition.ONNX; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.Model.Area; using BetterGenshinImpact.View.Drawable; using Microsoft.Extensions.Logging; @@ -84,9 +85,9 @@ public class ScanPickTask private static async Task WalkForward(CancellationToken ct) { - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); await Delay(1000, ct); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); } private void MoveCursorTo(Rect item, ImageRegion ra) diff --git a/BetterGenshinImpact/GameTask/Common/Job/SwitchPartyTask.cs b/BetterGenshinImpact/GameTask/Common/Job/SwitchPartyTask.cs index 977ae06a..fd6821dd 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/SwitchPartyTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/SwitchPartyTask.cs @@ -1,5 +1,6 @@ using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.Common.BgiVision; using BetterGenshinImpact.GameTask.Common.Element.Assets; using BetterGenshinImpact.GameTask.Model.Area; @@ -35,7 +36,7 @@ public class SwitchPartyTask await Delay(200, ct); } - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_L); + Simulation.SendInput.SimulateAction(GIActions.OpenPartySetupScreen); await Delay(1000, ct); // 加载2s // 由于胡桃可以不等待直接进入,所以这里只等待1s } diff --git a/BetterGenshinImpact/GameTask/QuickSereniteaPot/QuickSereniteaPotTask.cs b/BetterGenshinImpact/GameTask/QuickSereniteaPot/QuickSereniteaPotTask.cs index 83f55515..2abbceed 100644 --- a/BetterGenshinImpact/GameTask/QuickSereniteaPot/QuickSereniteaPotTask.cs +++ b/BetterGenshinImpact/GameTask/QuickSereniteaPot/QuickSereniteaPotTask.cs @@ -1,4 +1,5 @@ using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.GameTask.Model.Area; @@ -61,7 +62,7 @@ public class QuickSereniteaPotTask try { // 打开背包 - Simulation.SendInput.Keyboard.KeyPress(VK.VK_B); + Simulation.SendInput.SimulateAction(GIActions.OpenInventory); TaskControl.CheckAndSleep(500); WaitForBagToOpen(); @@ -80,7 +81,7 @@ public class QuickSereniteaPotTask TaskControl.CheckAndSleep(800); // 按F进入 - Simulation.SendInput.Keyboard.KeyPress(VK.VK_F); + Simulation.SendInput.SimulateAction(GIActions.PickUpOrInteract); TaskControl.CheckAndSleep(200); // 点击进入尘歌壶 diff --git a/BetterGenshinImpact/Model/KeyBindingSettingModel.cs b/BetterGenshinImpact/Model/KeyBindingSettingModel.cs new file mode 100644 index 00000000..47951423 --- /dev/null +++ b/BetterGenshinImpact/Model/KeyBindingSettingModel.cs @@ -0,0 +1,50 @@ +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Model; +using CommunityToolkit.Mvvm.ComponentModel; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; +using static Vanara.PInvoke.User32; + +namespace BetterGenshinImpact.Model; + +public partial class KeyBindingSettingModel:ObservableObject +{ + + /// + /// 按键绑定值 + /// + [ObservableProperty] + private KeyId _keyValue; + + [ObservableProperty] + private ObservableCollection _children = []; + + public string ActionName { get; set; } + + public bool IsExpanded => true; + + /// + /// 界面上显示是文件夹而不是按键绑定 + /// + [ObservableProperty] + private bool _isDirectory; + + public string ConfigPropertyName { get; set; } + + public KeyBindingSettingModel(string name) + { + IsDirectory = true; + ActionName = name; + } + + public KeyBindingSettingModel(string actionName, string configPropertyName, KeyId keyValue) + { + ActionName = actionName; + ConfigPropertyName = configPropertyName; + KeyValue = keyValue; + IsDirectory = false; + } + +} diff --git a/BetterGenshinImpact/View/Controls/KeyBindings/KeyBindingTextBox.cs b/BetterGenshinImpact/View/Controls/KeyBindings/KeyBindingTextBox.cs new file mode 100644 index 00000000..178908a4 --- /dev/null +++ b/BetterGenshinImpact/View/Controls/KeyBindings/KeyBindingTextBox.cs @@ -0,0 +1,91 @@ +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Model; +using Fischless.WindowsInput; +using System; +using System.Windows; +using System.Windows.Input; +using static Vanara.PInvoke.User32; +using KeyEventArgs = System.Windows.Input.KeyEventArgs; +using MouseButton = System.Windows.Input.MouseButton; +using TextBox = Wpf.Ui.Controls.TextBox; + +namespace BetterGenshinImpact.View.Controls.KeyBindings; + +public class KeyBindingTextBox:TextBox +{ + + public static readonly DependencyProperty KeyBindingProperty = DependencyProperty.Register( + nameof(KeyBinding), + typeof(KeyId), + typeof(KeyBindingTextBox), + new FrameworkPropertyMetadata( + KeyId.None, + FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, + (sender, _) => + { + var control = (KeyBindingTextBox)sender; + control.Text = control.KeyBinding.ToName(); + } + ) + ); + + /// + /// 按键绑定 + /// + public KeyId KeyBinding + { + get => (KeyId)GetValue(KeyBindingProperty); + set => SetValue(KeyBindingProperty, value); + } + + public KeyBindingTextBox() + { + IsReadOnly = true; + IsReadOnlyCaretVisible = false; + IsUndoEnabled = false; + + if (ContextMenu is not null) + ContextMenu.Visibility = Visibility.Collapsed; + + Text = KeyBinding.ToName(); + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + var key = e.Key; + + if (key == Key.System) + { + key = e.SystemKey; + } + + // 将按键转换为KeyId + KeyBinding = KeyIdConverter.FromInputKey(key); + } + + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + var key = e.ChangedButton; + + // 首次点击(未获得焦点)时,忽略一次鼠标左键的输入 + if (key is MouseButton.Left && !IsFocused) + { + return; + } + + // 将鼠标按键转换为KeyId + KeyBinding = KeyIdConverter.FromMouseButton(key); + } + + protected override void OnGotFocus(RoutedEventArgs e) + { + Text = "等待按键..."; + base.OnGotFocus(e); + } + + protected override void OnLostFocus(RoutedEventArgs e) + { + Text = KeyBinding.ToName(); + base.OnLostFocus(e); + } +} diff --git a/BetterGenshinImpact/View/MainWindow.xaml b/BetterGenshinImpact/View/MainWindow.xaml index 635bd9cb..1c03fa30 100644 --- a/BetterGenshinImpact/View/MainWindow.xaml +++ b/BetterGenshinImpact/View/MainWindow.xaml @@ -141,6 +141,13 @@ + + + + + + + + + - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/BetterGenshinImpact/View/PickerWindow.xaml.cs b/BetterGenshinImpact/View/PickerWindow.xaml.cs index b7cc0448..20f33cd4 100644 --- a/BetterGenshinImpact/View/PickerWindow.xaml.cs +++ b/BetterGenshinImpact/View/PickerWindow.xaml.cs @@ -7,71 +7,160 @@ using System.Windows; using System.Windows.Input; using System.Windows.Interop; using Vanara.PInvoke; +using System.Windows.Media; +using System.Collections.Generic; +using System.Windows.Media.Imaging; +using System.Runtime.InteropServices; namespace BetterGenshinImpact.View; public partial class PickerWindow : Window { private static readonly string[] _ignoreProcesses = ["applicationframehost", "shellexperiencehost", "systemsettings", "winstore.app", "searchui"]; - + private bool _isSelected = false; public PickerWindow() { InitializeComponent(); this.InitializeDpiAwareness(); Loaded += OnLoaded; } + public class CapturableWindow + { + public string Name { get; set; } + public string ProcessName { get; set; } + + public IntPtr Handle { get; set; } + public ImageSource Icon { get; set; } + } private void OnLoaded(object sender, RoutedEventArgs e) { FindWindows(); } - public IntPtr PickCaptureTarget(IntPtr hWnd) + public bool PickCaptureTarget(IntPtr hWnd,out IntPtr PickedWindow) { new WindowInteropHelper(this).Owner = hWnd; ShowDialog(); - - return ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero; + if(!_isSelected) + { + PickedWindow = IntPtr.Zero; + return false; + } + PickedWindow = ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero; + return true; } private unsafe void FindWindows() { var wih = new WindowInteropHelper(this); + var windows = new List(); + User32.EnumWindows((hWnd, lParam) => { - // ignore invisible windows - if (!User32.IsWindowVisible(hWnd)) + if (!User32.IsWindowVisible(hWnd) || wih.Handle == hWnd) return true; - // ignore untitled windows var title = new StringBuilder(1024); _ = User32.GetWindowText(hWnd, title, title.Capacity); if (string.IsNullOrWhiteSpace(title.ToString())) return true; - // ignore me - if (wih.Handle == hWnd) - return true; - _ = User32.GetWindowThreadProcessId(hWnd, out var processId); - - // ignore by process name var process = Process.GetProcessById((int)processId); if (_ignoreProcesses.Contains(process.ProcessName.ToLower())) return true; - WindowList.Items.Add(new CapturableWindow + // 获取窗口图标 + var icon = GetWindowIcon((IntPtr)hWnd); + + windows.Add(new CapturableWindow { Handle = (IntPtr)hWnd, - Name = $"{title} ({process.ProcessName}.exe)" + Name = title.ToString(), + ProcessName = process.ProcessName, + Icon = icon }); return true; }, IntPtr.Zero); + + WindowList.ItemsSource = windows; + } + private ImageSource GetWindowIcon(IntPtr hWnd) + { + try + { + const int ICON_BIG = 1; // WM_GETICON large icon constant + const int ICON_SMALL = 0; // WM_GETICON small icon constant + const int GCL_HICON = -14; // GetClassLong index for icon + + // 尝试获取窗口大图标 + var iconHandle = User32.SendMessage(hWnd, User32.WindowMessage.WM_GETICON, (IntPtr)ICON_BIG, IntPtr.Zero); + + if (iconHandle == IntPtr.Zero) + { + // 尝试获取窗口小图标 + iconHandle = User32.SendMessage(hWnd, User32.WindowMessage.WM_GETICON, (IntPtr)ICON_SMALL, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + // 尝试获取窗口类图标 + iconHandle = User32.GetClassLong(hWnd, GCL_HICON); + } + + if (iconHandle != IntPtr.Zero) + { + return Imaging.CreateBitmapSourceFromHIcon( + iconHandle, + Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()); + } + } + catch (Exception ex) + { + Debug.WriteLine($"获取窗口图标失败: {ex.Message}"); + } + + // 如果获取失败,返回一个默认图标或null + return null; + } + private bool IsGenshinWindow(string windowName) + { + // 判断是否包含原神相关的进程名 TODO:更加健壮的判断 + return windowName == "原神"; + } + + private bool AskIsThisGenshinImpact(string windowName) + { + var res = MessageBox.Question( + $""" + 这看起来不像是原神,确定要选择这个窗口吗? + + 当前选择的窗口:{windowName} + """, + "确认选择", + MessageBoxButton.YesNo, + MessageBoxResult.No + ); + return res == MessageBoxResult.Yes; } private void WindowsOnMouseDoubleClick(object sender, MouseButtonEventArgs e) { + var selectedWindow = WindowList.SelectedItem as CapturableWindow; + if (selectedWindow == null) return; + + // 如果不是原神窗口,询问用户是否确认 + if (!IsGenshinWindow(selectedWindow.Name)) + { + if (!AskIsThisGenshinImpact(selectedWindow.Name)) + { + return; + } + } + _isSelected = true; Close(); } } diff --git a/BetterGenshinImpact/ViewModel/MainWindowViewModel.cs b/BetterGenshinImpact/ViewModel/MainWindowViewModel.cs index b0e97b37..0cb6f263 100644 --- a/BetterGenshinImpact/ViewModel/MainWindowViewModel.cs +++ b/BetterGenshinImpact/ViewModel/MainWindowViewModel.cs @@ -5,6 +5,7 @@ using BetterGenshinImpact.GameTask; using BetterGenshinImpact.Helpers; using BetterGenshinImpact.Model; using BetterGenshinImpact.Service.Interface; +using BetterGenshinImpact.View; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Fischless.GameCapture.BitBlt; @@ -18,7 +19,9 @@ using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using Wpf.Ui; +using Wpf.Ui.Controls; namespace BetterGenshinImpact.ViewModel; @@ -34,6 +37,9 @@ public partial class MainWindowViewModel : ObservableObject, IViewModel [ObservableProperty] public WindowState _windowState = WindowState.Normal; + [ObservableProperty] + public WindowBackdropType _currentBackdropType = WindowBackdropType.Auto; + public AllConfig Config { get; set; } public MainWindowViewModel(INavigationService navigationService, IConfigService configService) @@ -54,6 +60,24 @@ public partial class MainWindowViewModel : ObservableObject, IViewModel { IsVisible = false; } + [RelayCommand] + private void OnSwitchBackdrop() + { + CurrentBackdropType = CurrentBackdropType switch + { + WindowBackdropType.Auto => WindowBackdropType.Mica, + WindowBackdropType.Mica => WindowBackdropType.Acrylic, + WindowBackdropType.Acrylic => WindowBackdropType.Auto, + _ => WindowBackdropType.Auto + }; + + var mainWindow = Application.Current.MainWindow as MainWindow; + if (mainWindow != null) + { + mainWindow.Background = new SolidColorBrush(Color.FromArgb(100, 0, 0, 0)); + WindowBackdrop.ApplyBackdrop(mainWindow, CurrentBackdropType); + } + } [RelayCommand] private void OnClosing(CancelEventArgs e) diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index 604cfed6..bb7613d6 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -139,29 +139,42 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi private void OnStartCaptureTest() { var picker = new PickerWindow(); - var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle); - if (hWnd != IntPtr.Zero) + + if (picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle, out var hWnd)) { - var captureWindow = new CaptureTestWindow(); - captureWindow.StartCapture(hWnd, Config.CaptureMode.ToCaptureMode()); - captureWindow.Show(); + if (hWnd != IntPtr.Zero) + { + var captureWindow = new CaptureTestWindow(); + captureWindow.StartCapture(hWnd, Config.CaptureMode.ToCaptureMode()); + captureWindow.Show(); + } + else + { + MessageBox.Error("选择的窗体句柄为空"); + } } + + } [RelayCommand] private void OnManualPickWindow() { var picker = new PickerWindow(); - var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle); - if (hWnd != IntPtr.Zero) + if(picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle,out var hWnd)) { - _hWnd = hWnd; - Start(hWnd); - } - else - { - MessageBox.Error("选择的窗体句柄为空!"); + if (hWnd != IntPtr.Zero) + { + _hWnd = hWnd; + Start(hWnd); + } + else + { + MessageBox.Error("选择的窗体句柄为空!"); + } + } + } [RelayCommand] @@ -181,8 +194,13 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi var hWnd = SystemControl.FindGenshinImpactHandle(); if (hWnd == IntPtr.Zero) { - if (Config.GenshinStartConfig.LinkedStartEnabled && !string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath)) + if (Config.GenshinStartConfig.LinkedStartEnabled) { + if (string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath)) + { + MessageBox.Error("没有找到原神的安装路径"); + return; + } hWnd = await SystemControl.StartFromLocalAsync(Config.GenshinStartConfig.InstallPath); if (hWnd != IntPtr.Zero) { diff --git a/BetterGenshinImpact/ViewModel/Pages/KeyBindingsSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/KeyBindingsSettingsPageViewModel.cs new file mode 100644 index 00000000..a35725aa --- /dev/null +++ b/BetterGenshinImpact/ViewModel/Pages/KeyBindingsSettingsPageViewModel.cs @@ -0,0 +1,558 @@ +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Model; +using BetterGenshinImpact.Service.Interface; +using BetterGenshinImpact.ViewModel; +using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Text; +using Wpf.Ui.Controls; +using BetterGenshinImpact.Genshin.Settings; +using CommunityToolkit.Mvvm.Input; +using static Vanara.PInvoke.User32; + +namespace BetterGenshinImpact.ViewModel.Pages; + +public partial class KeyBindingsSettingsPageViewModel : ObservableObject, INavigationAware, IViewModel +{ + private readonly ILogger _logger; + + /// + /// 配置文件 + /// + private readonly KeyBindingsConfig _config; + + [ObservableProperty] + private ObservableCollection _keyBindingSettingModels = []; + + public void OnNavigatedFrom() + { + } + + public void OnNavigatedTo() + { + } + + public KeyBindingsSettingsPageViewModel(IConfigService configService, ILogger logger) + { + _logger = logger; + + // 获取本模块的配置文件 + _config = configService.Get().KeyBindingsConfig; + + BuildKeyBindingsList(); + + var list = GetAllNonDirectoryKeyBinding(KeyBindingSettingModels); + foreach (var keyConfig in list) + { + keyConfig.PropertyChanged += (sender, e) => + { + if (sender is KeyBindingSettingModel model) + { + // 使用反射更新配置文件 + if (e.PropertyName == nameof(model.KeyValue)) + { + Debug.WriteLine($"按键绑定 \"{model.ActionName}\" 变更为 {model.KeyValue}"); + + var pi = _config.GetType().GetProperty(model.ConfigPropertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (pi != null && pi.CanWrite) + { + pi.SetValue(_config, model.KeyValue, null); + } + } + } + }; + } + } + + + public static List GetAllNonDirectoryKeyBinding(IEnumerable modelList) + { + var list = new List(); + foreach (var keyBindingSettingModel in modelList) + { + if (!keyBindingSettingModel.IsDirectory) + { + list.Add(keyBindingSettingModel); + } + + list.AddRange(GetAllNonDirectoryChildren(keyBindingSettingModel)); + } + + return list; + } + + public static List GetAllNonDirectoryChildren(KeyBindingSettingModel model) + { + var result = new List(); + + if (model.Children.Count == 0) + { + return result; + } + + foreach (var child in model.Children) + { + if (!child.IsDirectory) + { + result.Add(child); + } + + // 递归调用以获取子节点中的非目录对象 + result.AddRange(GetAllNonDirectoryChildren(child)); + } + + return result; + } + + /// + /// 构造按键绑定列表 + /// + private void BuildKeyBindingsList() + { + // 动作按键 + var actionDirectory = new KeyBindingSettingModel("动作"); + + // 菜单按键 + var menuDirectory = new KeyBindingSettingModel("菜单"); + + // 添加动作按键的二级菜单 + actionDirectory.Children.Add(new KeyBindingSettingModel( + "向前移动", + nameof(_config.MoveForward), + _config.MoveForward + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "向后移动", + nameof(_config.MoveBackward), + _config.MoveBackward + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "向左移动", + nameof(_config.MoveLeft), + _config.MoveLeft + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "向右移动", + nameof(_config.MoveRight), + _config.MoveRight + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换走/跑;特定操作模式下向下移动", + nameof(_config.SwitchToWalkOrRun), + _config.SwitchToWalkOrRun + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "普通攻击", + nameof(_config.NormalAttack), + _config.NormalAttack + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "元素战技", + nameof(_config.ElementalSkill), + _config.ElementalSkill + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "元素爆发", + nameof(_config.ElementalBurst), + _config.ElementalBurst + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "冲刺(键盘)", + nameof(_config.SprintKeyboard), + _config.SprintKeyboard + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "冲刺(鼠标)", + nameof(_config.SprintMouse), + _config.SprintMouse + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换瞄准模式", + nameof(_config.SwitchAimingMode), + _config.SwitchAimingMode + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "跳跃;特定操作模式下向上移动", + nameof(_config.Jump), + _config.Jump + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "落下", + nameof(_config.Drop), + _config.Drop + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "拾取/交互(自动拾取由AutoPick模块管理)", + nameof(_config.PickUpOrInteract), + _config.PickUpOrInteract + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "快捷使用小道具", + nameof(_config.QuickUseGadget), + _config.QuickUseGadget + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "特定玩法内交互操作", + nameof(_config.InteractionInSomeMode), + _config.InteractionInSomeMode + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "开启任务追踪", + nameof(_config.QuestNavigation), + _config.QuestNavigation + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "中断挑战", + nameof(_config.AbandonChallenge), + _config.AbandonChallenge + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换小队角色1", + nameof(_config.SwitchMember1), + _config.SwitchMember1 + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换小队角色2", + nameof(_config.SwitchMember2), + _config.SwitchMember2 + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换小队角色3", + nameof(_config.SwitchMember3), + _config.SwitchMember3 + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换小队角色4", + nameof(_config.SwitchMember4), + _config.SwitchMember4 + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "切换小队角色5", + nameof(_config.SwitchMember5), + _config.SwitchMember5 + )); + actionDirectory.Children.Add(new KeyBindingSettingModel( + "呼出快捷轮盘", + nameof(_config.ShortcutWheel), + _config.ShortcutWheel + )); + + // 添加菜单按键的二级菜单 + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开背包", + nameof(_config.OpenInventory), + _config.OpenInventory + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开角色界面", + nameof(_config.OpenCharacterScreen), + _config.OpenCharacterScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开地图", + nameof(_config.OpenMap), + _config.OpenMap + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开派蒙界面", + nameof(_config.OpenPaimonMenu), + _config.OpenPaimonMenu + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开冒险之证界面", + nameof(_config.OpenAdventurerHandbook), + _config.OpenAdventurerHandbook + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开多人游戏界面", + nameof(_config.OpenCoOpScreen), + _config.OpenCoOpScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开祈愿界面", + nameof(_config.OpenWishScreen), + _config.OpenWishScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开纪行界面", + nameof(_config.OpenBattlePassScreen), + _config.OpenBattlePassScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开活动面板", + nameof(_config.OpenTheEventsMenu), + _config.OpenTheEventsMenu + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开玩法系统界面(尘歌壶内猫尾酒馆内)", + nameof(_config.OpenTheSettingsMenu), + _config.OpenTheSettingsMenu + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开摆设界面(尘歌壶内)", + nameof(_config.OpenTheFurnishingScreen), + _config.OpenTheFurnishingScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开星之归还(条件符合期间生效)", + nameof(_config.OpenStellarReunion), + _config.OpenStellarReunion + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "开关任务菜单", + nameof(_config.OpenQuestMenu), + _config.OpenQuestMenu + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开通知详情", + nameof(_config.OpenNotificationDetails), + _config.OpenNotificationDetails + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开聊天界面", + nameof(_config.OpenChatScreen), + _config.OpenChatScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开特殊环境说明", + nameof(_config.OpenSpecialEnvironmentInformation), + _config.OpenSpecialEnvironmentInformation + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "查看教程详情", + nameof(_config.CheckTutorialDetails), + _config.CheckTutorialDetails + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "长按打开元素视野", + nameof(_config.ElementalSight), + _config.ElementalSight + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "呼出鼠标", + nameof(_config.ShowCursor), + _config.ShowCursor + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开队伍配置界面", + nameof(_config.OpenPartySetupScreen), + _config.OpenPartySetupScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "打开好友界面", + nameof(_config.OpenFriendsScreen), + _config.OpenFriendsScreen + )); + menuDirectory.Children.Add(new KeyBindingSettingModel( + "隐藏主界面", + nameof(_config.HideUI), + _config.HideUI + )); + + KeyBindingSettingModels.Add(actionDirectory); + KeyBindingSettingModels.Add(menuDirectory); + } + + /// + /// 从注册表中读取按键 + /// + [RelayCommand] + private void FetchFromRegistry() + { + // 读取注册表 + SettingsContainer settings = new(); + settings.FromReg(); + + var keySetting = settings.OverrideController?.KeyboardMap?.ActionElementMap; + if (keySetting != null) + { + foreach (var item in keySetting) + { + if (item.ElementIdentifierId is ElementIdentifierId keyId) + { + // 跳过无法识别的按键 + if (keyId.ToName() == "Unknown" || keyId.ToName() == "None") + { + continue; + } + var key = KeyIdConverter.FromVK(keyId.ToVK()); + switch (item.ActionId) + { + case ActionId.MoveForwardShow: + _config.MoveForward = key; + break; + case ActionId.MoveBackShow: + _config.MoveBackward = key; + break; + case ActionId.MoveLeftShow: + _config.MoveLeft = key; + break; + case ActionId.MoveRightShow: + _config.MoveRight = key; + break; + case ActionId.WalkRun: + _config.SwitchToWalkOrRun = key; + break; + case ActionId.Attack: + _config.NormalAttack = key; + break; + case ActionId.ElementalSkill: + _config.ElementalSkill = key; + break; + case ActionId.ElementalBurst: + _config.ElementalBurst = key; + break; + case ActionId.Sprint: + if (key >= KeyId.MouseLeftButton && key <= KeyId.MouseSideButton2) + { + _config.SprintMouse = key; + } + else + { + _config.SprintKeyboard = key; + } + break; + case ActionId.AimMode: + _config.SwitchAimingMode = key; + break; + case ActionId.Jump: + _config.Jump = key; + break; + case ActionId.CancelClimb: + _config.Drop = key; + break; + // TODO: 拾取&交互可能不正确 + case ActionId.UseTalk: + _config.PickUpOrInteract = key; + break; + case ActionId.Gadget: + _config.QuickUseGadget = key; + break; + case ActionId.InteractionSomeModes: + _config.InteractionInSomeMode = key; + break; + case ActionId.Navigation: + _config.QuestNavigation = key; + break; + case ActionId.AbandonChallenge: + _config.AbandonChallenge = key; + break; + case ActionId.Char1: + _config.SwitchMember1 = key; + break; + case ActionId.Char2: + _config.SwitchMember2 = key; + break; + case ActionId.Char3: + _config.SwitchMember3 = key; + break; + case ActionId.Char4: + _config.SwitchMember4 = key; + break; + case ActionId.Char5: + _config.SwitchMember5 = key; + break; + case ActionId.QuickWheel: + _config.ShortcutWheel = key; + break; + case ActionId.Inventory: + _config.OpenInventory = key; + break; + case ActionId.CharacterList: + _config.OpenCharacterScreen = key; + break; + case ActionId.Map: + _config.OpenMap = key; + break; + // TODO: 派蒙界面可能不正确 + case ActionId.MenuGamepad: + _config.OpenPaimonMenu = key; + break; + case ActionId.AdventurerHandbook: + _config.OpenAdventurerHandbook = key; + break; + case ActionId.CoOp: + _config.OpenCoOpScreen = key; + break; + case ActionId.Wish: + _config.OpenWishScreen = key; + break; + case ActionId.BattlePass: + _config.OpenBattlePassScreen = key; + break; + case ActionId.Events: + _config.OpenTheEventsMenu = key; + break; + case ActionId.PotTasks: + _config.OpenTheSettingsMenu = key; + break; + case ActionId.PotEdit: + _config.OpenTheFurnishingScreen = key; + break; + // TODO: 星之归还未找到 + case ActionId.QuestList: + _config.OpenQuestMenu = key; + break; + case ActionId.NotificationDetails: + _config.OpenNotificationDetails = key; + break; + case ActionId.Chat: + _config.OpenChatScreen = key; + break; + case ActionId.EnvironmentInfo: + _config.OpenSpecialEnvironmentInformation = key; + break; + case ActionId.Tutorial: + _config.CheckTutorialDetails = key; + break; + case ActionId.ElementalSight: + _config.ElementalSight = key; + break; + case ActionId.ShowCursor: + _config.ShowCursor = key; + break; + case ActionId.PartySetup: + _config.OpenPartySetupScreen = key; + break; + case ActionId.Friends: + _config.OpenFriendsScreen = key; + break; + // TODO: 隐藏主界面未找到 + default: + break; + } + } + } + + // 重新加载按键绑定列表 + KeyBindingSettingModels.Clear(); + BuildKeyBindingsList(); + var list = GetAllNonDirectoryKeyBinding(KeyBindingSettingModels); + foreach (var keyConfig in list) + { + keyConfig.PropertyChanged += (sender, e) => + { + if (sender is KeyBindingSettingModel model) + { + // 使用反射更新配置文件 + if (e.PropertyName == nameof(model.KeyValue)) + { + Debug.WriteLine($"按键绑定 \"{model.ActionName}\" 变更为 {model.KeyValue}"); + + var pi = _config.GetType().GetProperty(model.ConfigPropertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + if (pi != null && pi.CanWrite) + { + pi.SetValue(_config, model.KeyValue, null); + } + } + } + }; + } + } + } + +} diff --git a/View/PickerWindow.xaml b/View/PickerWindow.xaml new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/View/PickerWindow.xaml @@ -0,0 +1 @@ + \ No newline at end of file