mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-08 11:57:53 +08:00
Merge branch 'main' into main
This commit is contained in:
commit
9f46fb00be
@ -101,6 +101,7 @@ public partial class App : Application
|
||||
services.AddView<OneDragonFlowPage, OneDragonFlowViewModel>();
|
||||
services.AddSingleton<PathingConfigViewModel>();
|
||||
// services.AddView<PathingConfigView, PathingConfigViewModel>();
|
||||
services.AddView<KeyBindingsSettingsPage, KeyBindingsSettingsPageViewModel>();
|
||||
|
||||
// 一条龙 ViewModels
|
||||
// services.AddSingleton<CraftViewModel>();
|
||||
|
@ -165,6 +165,11 @@ public partial class AllConfig : ObservableObject
|
||||
/// </summary>
|
||||
public NotificationConfig NotificationConfig { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 原神按键绑定配置
|
||||
/// </summary>
|
||||
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;
|
||||
|
964
BetterGenshinImpact/Core/Config/KeyBindingsConfig.cs
Normal file
964
BetterGenshinImpact/Core/Config/KeyBindingsConfig.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 原神按键绑定配置
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class KeyBindingsConfig:ObservableObject
|
||||
{
|
||||
|
||||
#region Actions(操作)
|
||||
|
||||
/// <summary>
|
||||
/// 向前移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _moveForward = KeyId.W;
|
||||
|
||||
/// <summary>
|
||||
/// 向后移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _moveBackward = KeyId.S;
|
||||
|
||||
/// <summary>
|
||||
/// 向左移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _moveLeft = KeyId.A;
|
||||
|
||||
/// <summary>
|
||||
/// 向右移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _moveRight = KeyId.D;
|
||||
|
||||
/// <summary>
|
||||
/// 切换走/跑;特定操作模式下向下移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchToWalkOrRun = KeyId.LeftCtrl;
|
||||
|
||||
/// <summary>
|
||||
/// 普通攻击
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _normalAttack = KeyId.MouseLeftButton;
|
||||
|
||||
/// <summary>
|
||||
/// 元素战技
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _elementalSkill = KeyId.E;
|
||||
|
||||
/// <summary>
|
||||
/// 元素爆发
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _elementalBurst = KeyId.Q;
|
||||
|
||||
/// <summary>
|
||||
/// 冲刺(键盘)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _sprintKeyboard = KeyId.LeftShift;
|
||||
|
||||
/// <summary>
|
||||
/// 冲刺(鼠标)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _sprintMouse = KeyId.MouseRightButton;
|
||||
|
||||
/// <summary>
|
||||
/// 切换瞄准模式
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchAimingMode = KeyId.R;
|
||||
|
||||
/// <summary>
|
||||
/// 跳跃;特定操作模式下向上移动
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _jump = KeyId.Space;
|
||||
|
||||
/// <summary>
|
||||
/// 落下
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _drop = KeyId.X;
|
||||
|
||||
/// <summary>
|
||||
/// 拾取/交互(自动拾取由AutoPick模块管理)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _pickUpOrInteract = KeyId.F;
|
||||
|
||||
/// <summary>
|
||||
/// 快捷使用小道具
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _quickUseGadget = KeyId.Z;
|
||||
|
||||
/// <summary>
|
||||
/// 特定玩法内交互操作
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _interactionInSomeMode = KeyId.T;
|
||||
|
||||
/// <summary>
|
||||
/// 开启任务追踪
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _questNavigation = KeyId.V;
|
||||
|
||||
/// <summary>
|
||||
/// 中断挑战
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _abandonChallenge = KeyId.P;
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色1
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchMember1 = KeyId.D1;
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色2
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchMember2 = KeyId.D2;
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色3
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchMember3 = KeyId.D3;
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色4
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchMember4 = KeyId.D4;
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色5
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _switchMember5 = KeyId.D5;
|
||||
|
||||
/// <summary>
|
||||
/// 呼出快捷轮盘
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _shortcutWheel = KeyId.Tab;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Menus(菜单)
|
||||
|
||||
/// <summary>
|
||||
/// 打开背包
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openInventory = KeyId.B;
|
||||
|
||||
/// <summary>
|
||||
/// 打开角色界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openCharacterScreen = KeyId.C;
|
||||
|
||||
/// <summary>
|
||||
/// 打开地图
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openMap = KeyId.M;
|
||||
|
||||
/// <summary>
|
||||
/// 打开派蒙界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openPaimonMenu = KeyId.Escape;
|
||||
|
||||
/// <summary>
|
||||
/// 打开冒险之证界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openAdventurerHandbook = KeyId.F1;
|
||||
|
||||
/// <summary>
|
||||
/// 打开多人游戏界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openCoOpScreen = KeyId.F2;
|
||||
|
||||
/// <summary>
|
||||
/// 打开祈愿界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openWishScreen = KeyId.F3;
|
||||
|
||||
/// <summary>
|
||||
/// 打开纪行界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openBattlePassScreen = KeyId.F4;
|
||||
|
||||
/// <summary>
|
||||
/// 打开活动面板
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openTheEventsMenu = KeyId.F5;
|
||||
|
||||
/// <summary>
|
||||
/// 打开玩法系统界面(尘歌壶内猫尾酒馆内)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openTheSettingsMenu = KeyId.F6;
|
||||
|
||||
/// <summary>
|
||||
/// 打开摆设界面(尘歌壶内)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openTheFurnishingScreen = KeyId.F7;
|
||||
|
||||
/// <summary>
|
||||
/// 打开星之归还(条件符合期间生效)
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openStellarReunion = KeyId.F8;
|
||||
|
||||
/// <summary>
|
||||
/// 开关任务菜单
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openQuestMenu = KeyId.J;
|
||||
|
||||
/// <summary>
|
||||
/// 打开通知详情
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openNotificationDetails = KeyId.Y;
|
||||
|
||||
/// <summary>
|
||||
/// 打开聊天界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openChatScreen = KeyId.Enter;
|
||||
|
||||
/// <summary>
|
||||
/// 打开特殊环境说明
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openSpecialEnvironmentInformation = KeyId.U;
|
||||
|
||||
/// <summary>
|
||||
/// 查看教程详情
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _checkTutorialDetails = KeyId.G;
|
||||
|
||||
/// <summary>
|
||||
/// 长按打开元素视野
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _elementalSight = KeyId.MouseMiddleButton;
|
||||
|
||||
/// <summary>
|
||||
/// 呼出鼠标
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _showCursor = KeyId.LeftAlt;
|
||||
|
||||
/// <summary>
|
||||
/// 打开队伍配置界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openPartySetupScreen = KeyId.L;
|
||||
|
||||
/// <summary>
|
||||
/// 打开好友界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _openFriendsScreen = KeyId.O;
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏主界面
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _hideUI = KeyId.Slash;
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
public static class KeyIdConverter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 将KeyId转换为字符串(可在后续支持多语言),按键名称的显示尽量与原神UI一致
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
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 => "<None>",
|
||||
KeyId.Unknown => "<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(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将KeyId转换为VK
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将KeyId转换为System.Windows.Input.Key
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static Key ToInputKey(this KeyId value)
|
||||
{
|
||||
// 部分按键名称相同,使用名称转换
|
||||
try
|
||||
{
|
||||
return Enum.Parse<Key>(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)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将KeyId转换为MouseButton
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
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方法"),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [实验] 将KeyId转换为WinForm中的Keys(用于兼容按键连发功能)
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static Keys ToWinFormKeys(this KeyId value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Enum.Parse<Keys>(value.ToInputKey().ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将VK转换为KeyId
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static KeyId FromVK(VK value)
|
||||
{
|
||||
// 尝试通过VK的值获取KeyId的枚举名。若成功,表示对应的VK在KeyId支持的范围内,直接转换;否则返回Unknown
|
||||
return string.IsNullOrEmpty(Enum.GetName(typeof(KeyId), value)) ? KeyId.Unknown : (KeyId)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将System.Windows.Input.Key转换为KeyId
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static KeyId FromInputKey(Key value)
|
||||
{
|
||||
// 部分按键名称相同,使用名称转换
|
||||
try
|
||||
{
|
||||
return Enum.Parse<KeyId>(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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将MouseButton转换为KeyId
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用于与VK/Windows.Input.Key解耦,值与VK对应,但是仅包含美式键盘(104键,不包括媒体控制等)和鼠标中的按键
|
||||
/// </summary>
|
||||
public enum KeyId
|
||||
{
|
||||
/// <summary>无</summary>
|
||||
None = 0x00,
|
||||
|
||||
/// <summary>未知按键</summary>
|
||||
Unknown = 0xFF,
|
||||
|
||||
#region 鼠标按键
|
||||
|
||||
/// <summary>鼠标左键</summary>
|
||||
MouseLeftButton = 0x01,
|
||||
|
||||
/// <summary>鼠标右键</summary>
|
||||
MouseRightButton = 0x02,
|
||||
|
||||
/// <summary>鼠标中键(滚轮)</summary>
|
||||
MouseMiddleButton = 0x04,
|
||||
|
||||
/// <summary>鼠标侧键1(后退)</summary>
|
||||
MouseSideButton1 = 0x05,
|
||||
|
||||
/// <summary>鼠标侧键2(前进)</summary>
|
||||
MouseSideButton2 = 0x06,
|
||||
|
||||
#endregion
|
||||
|
||||
#region F键区
|
||||
|
||||
/// <summary>F1</summary>
|
||||
F1 = 0x70,
|
||||
|
||||
/// <summary>F2</summary>
|
||||
F2 = 0x71,
|
||||
|
||||
/// <summary>F3</summary>
|
||||
F3 = 0x72,
|
||||
|
||||
/// <summary>F4</summary>
|
||||
F4 = 0x73,
|
||||
|
||||
/// <summary>F5</summary>
|
||||
F5 = 0x74,
|
||||
|
||||
/// <summary>F6</summary>
|
||||
F6 = 0x75,
|
||||
|
||||
/// <summary>F7</summary>
|
||||
F7 = 0x76,
|
||||
|
||||
/// <summary>F8</summary>
|
||||
F8 = 0x77,
|
||||
|
||||
/// <summary>F9</summary>
|
||||
F9 = 0x78,
|
||||
|
||||
/// <summary>F10</summary>
|
||||
F10 = 0x79,
|
||||
|
||||
/// <summary>F11</summary>
|
||||
F11 = 0x7A,
|
||||
|
||||
/// <summary>F12</summary>
|
||||
F12 = 0x7B,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 控制&功能键
|
||||
|
||||
/// <summary>Esc</summary>
|
||||
Escape = 0x1B,
|
||||
|
||||
/// <summary>PrintScreen</summary>
|
||||
PrintScreen = 0x2C,
|
||||
|
||||
/// <summary>ScrollLock</summary>
|
||||
ScrollLock = 0x91,
|
||||
|
||||
/// <summary>Pause</summary>
|
||||
Pause = 0x13,
|
||||
|
||||
/// <summary>Insert</summary>
|
||||
Insert = 0x2D,
|
||||
|
||||
/// <summary>Delete</summary>
|
||||
Delete = 0x2E,
|
||||
|
||||
/// <summary>Home</summary>
|
||||
Home = 0x24,
|
||||
|
||||
/// <summary>End</summary>
|
||||
End = 0x23,
|
||||
|
||||
/// <summary>Page Up</summary>
|
||||
PageUp = 0x21,
|
||||
|
||||
/// <summary>Page Down</summary>
|
||||
PageDown = 0x22,
|
||||
|
||||
/// <summary>Backspace退格</summary>
|
||||
Backspace = 0x08,
|
||||
|
||||
/// <summary>Tab</summary>
|
||||
Tab = 0x09,
|
||||
|
||||
/// <summary>Caps Lock大写锁定</summary>
|
||||
CapsLock = 0x14,
|
||||
|
||||
/// <summary>Enter回车</summary>
|
||||
Enter = 0x0D,
|
||||
|
||||
///// <summary>Shift</summary>
|
||||
//Shift = 0x10,
|
||||
|
||||
/// <summary>左Shift</summary>
|
||||
LeftShift = 0xA0,
|
||||
|
||||
/// <summary>右Shift</summary>
|
||||
RightShift = 0xA1,
|
||||
|
||||
///// <summary>Ctrl</summary>
|
||||
//Ctrl = 0x11,
|
||||
|
||||
/// <summary>左Ctrl</summary>
|
||||
LeftCtrl = 0xA2,
|
||||
|
||||
/// <summary>右Ctrl</summary>
|
||||
RightCtrl = 0xA3,
|
||||
|
||||
///// <summary>Alt</summary>
|
||||
//Alt = 0x12,
|
||||
|
||||
/// <summary>左Alt</summary>
|
||||
LeftAlt = 0xA4,
|
||||
|
||||
/// <summary>右Alt</summary>
|
||||
RightAlt = 0xA5,
|
||||
|
||||
/// <summary>左Win键 (Microsoft Natural Keyboard)</summary>
|
||||
LeftWin = 0x5B,
|
||||
|
||||
/// <summary>右Win键 (Microsoft Natural Keyboard)</summary>
|
||||
RightWin = 0x5C,
|
||||
|
||||
/// <summary>菜单键 (Microsoft Natural Keyboard)</summary>
|
||||
Apps = 0x5D,
|
||||
|
||||
/// <summary>Space空格键</summary>
|
||||
Space = 0x20,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方向键
|
||||
|
||||
/// <summary>方向键 ←</summary>
|
||||
Left = 0x25,
|
||||
|
||||
/// <summary>方向键 ↑</summary>
|
||||
Up = 0x26,
|
||||
|
||||
/// <summary>方向键 →</summary>
|
||||
Right = 0x27,
|
||||
|
||||
/// <summary>方向键 ↓</summary>
|
||||
Down = 0x28,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字母区 - 字母
|
||||
|
||||
/// <summary>A</summary>
|
||||
A = 0x41,
|
||||
|
||||
/// <summary>B</summary>
|
||||
B = 0x42,
|
||||
|
||||
/// <summary>C</summary>
|
||||
C = 0x43,
|
||||
|
||||
/// <summary>D</summary>
|
||||
D = 0x44,
|
||||
|
||||
/// <summary>E</summary>
|
||||
E = 0x45,
|
||||
|
||||
/// <summary>F</summary>
|
||||
F = 0x46,
|
||||
|
||||
/// <summary>G</summary>
|
||||
G = 0x47,
|
||||
|
||||
/// <summary>H</summary>
|
||||
H = 0x48,
|
||||
|
||||
/// <summary>I</summary>
|
||||
I = 0x49,
|
||||
|
||||
/// <summary>J</summary>
|
||||
J = 0x4A,
|
||||
|
||||
/// <summary>K</summary>
|
||||
K = 0x4B,
|
||||
|
||||
/// <summary>L</summary>
|
||||
L = 0x4C,
|
||||
|
||||
/// <summary>M</summary>
|
||||
M = 0x4D,
|
||||
|
||||
/// <summary>N</summary>
|
||||
N = 0x4E,
|
||||
|
||||
/// <summary>O</summary>
|
||||
O = 0x4F,
|
||||
|
||||
/// <summary>P</summary>
|
||||
P = 0x50,
|
||||
|
||||
/// <summary>Q</summary>
|
||||
Q = 0x51,
|
||||
|
||||
/// <summary>R</summary>
|
||||
R = 0x52,
|
||||
|
||||
/// <summary>S</summary>
|
||||
S = 0x53,
|
||||
|
||||
/// <summary>T</summary>
|
||||
T = 0x54,
|
||||
|
||||
/// <summary>U</summary>
|
||||
U = 0x55,
|
||||
|
||||
/// <summary>V</summary>
|
||||
V = 0x56,
|
||||
|
||||
/// <summary>W</summary>
|
||||
W = 0x57,
|
||||
|
||||
/// <summary>X</summary>
|
||||
X = 0x58,
|
||||
|
||||
/// <summary>Y</summary>
|
||||
Y = 0x59,
|
||||
|
||||
/// <summary>Z</summary>
|
||||
Z = 0x5A,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字母区 - 数字
|
||||
|
||||
/// <summary>0</summary>
|
||||
D0 = 0x30,
|
||||
|
||||
/// <summary>1</summary>
|
||||
D1 = 0x31,
|
||||
|
||||
/// <summary>2</summary>
|
||||
D2 = 0x32,
|
||||
|
||||
/// <summary>3</summary>
|
||||
D3 = 0x33,
|
||||
|
||||
/// <summary>4</summary>
|
||||
D4 = 0x34,
|
||||
|
||||
/// <summary>5</summary>
|
||||
D5 = 0x35,
|
||||
|
||||
/// <summary>6</summary>
|
||||
D6 = 0x36,
|
||||
|
||||
/// <summary>7</summary>
|
||||
D7 = 0x37,
|
||||
|
||||
/// <summary>8</summary>
|
||||
D8 = 0x38,
|
||||
|
||||
/// <summary>9</summary>
|
||||
D9 = 0x39,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字母区 - 符号
|
||||
|
||||
/// <summary>引号 '</summary>
|
||||
Apostrophe = 0xDE,
|
||||
|
||||
/// <summary>逗号 ,</summary>
|
||||
Comma = 0xBC,
|
||||
|
||||
/// <summary>连接符 -</summary>
|
||||
Minus = 0xBD,
|
||||
|
||||
/// <summary>等于号 =</summary>
|
||||
Equal = 0xBB,
|
||||
|
||||
/// <summary>句号 .</summary>
|
||||
Period = 0xBE,
|
||||
|
||||
/// <summary>斜杠 /</summary>
|
||||
Slash = 0xBF,
|
||||
|
||||
/// <summary>反斜杠 \</summary>
|
||||
Backslash = 0xE2,
|
||||
|
||||
/// <summary>分号 ;</summary>
|
||||
Semicolon = 0xBA,
|
||||
|
||||
/// <summary>左方括号 [</summary>
|
||||
LeftSquareBracket = 0xDB,
|
||||
|
||||
/// <summary>右方括号 ]</summary>
|
||||
RightSquareBracket = 0xDD,
|
||||
|
||||
/// <summary>波浪号 `</summary>
|
||||
Tilde = 0xC0,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 小键盘区
|
||||
|
||||
/// <summary>Num Lock</summary>
|
||||
NumLock = 0x90,
|
||||
|
||||
/// <summary>Num 0</summary>
|
||||
NumPad0 = 0x60,
|
||||
|
||||
/// <summary>Num 1</summary>
|
||||
NumPad1 = 0x61,
|
||||
|
||||
/// <summary>Num 2</summary>
|
||||
NumPad2 = 0x62,
|
||||
|
||||
/// <summary>Num 3</summary>
|
||||
NumPad3 = 0x63,
|
||||
|
||||
/// <summary>Num 4</summary>
|
||||
NumPad4 = 0x64,
|
||||
|
||||
/// <summary>Num 5</summary>
|
||||
NumPad5 = 0x65,
|
||||
|
||||
/// <summary>Num 6</summary>
|
||||
NumPad6 = 0x66,
|
||||
|
||||
/// <summary>Num 7</summary>
|
||||
NumPad7 = 0x67,
|
||||
|
||||
/// <summary>Num 8</summary>
|
||||
NumPad8 = 0x68,
|
||||
|
||||
/// <summary>Num 9</summary>
|
||||
NumPad9 = 0x69,
|
||||
|
||||
/// <summary>Num .</summary>
|
||||
Decimal = 0x6E,
|
||||
|
||||
/// <summary>Num /</summary>
|
||||
Divide = 0x6F,
|
||||
|
||||
/// <summary>Num *</summary>
|
||||
Multiply = 0x6A,
|
||||
|
||||
/// <summary>Num -</summary>
|
||||
Subtract = 0x6D,
|
||||
|
||||
/// <summary>Num +</summary>
|
||||
Add = 0x6B,
|
||||
|
||||
/// <summary>Num Enter</summary>
|
||||
NumEnter = 0x0E,
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
@ -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
|
||||
/// </summary>
|
||||
private readonly Timer _fTimer = new();
|
||||
|
||||
private Keys _pickUpKey = Keys.F;
|
||||
|
||||
private User32.VK _pickUpKeyCode = User32.VK.VK_F;
|
||||
|
||||
//private readonly Random _random = new();
|
||||
|
||||
/// <summary>
|
||||
@ -25,6 +30,10 @@ public class MouseKeyMonitor
|
||||
/// </summary>
|
||||
private readonly Timer _spaceTimer = new();
|
||||
|
||||
private Keys _releaseControlKey = Keys.Space;
|
||||
|
||||
private User32.VK _releaseControlKeyCode = User32.VK.VK_SPACE;
|
||||
|
||||
private DateTime _firstFKeyDownTime = DateTime.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
@ -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)
|
||||
{
|
||||
|
270
BetterGenshinImpact/Core/Simulator/Extensions/Enums.cs
Normal file
270
BetterGenshinImpact/Core/Simulator/Extensions/Enums.cs
Normal file
@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterGenshinImpact.Core.Simulator.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 模拟按键类型
|
||||
/// </summary>
|
||||
public enum KeyType
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 单击按键(KeyPress)
|
||||
/// </summary>
|
||||
KeyPress,
|
||||
|
||||
/// <summary>
|
||||
/// 按住按键(KeyDown)
|
||||
/// </summary>
|
||||
KeyDown,
|
||||
|
||||
/// <summary>
|
||||
/// 释放按键(KeyUp)
|
||||
/// </summary>
|
||||
KeyUp,
|
||||
|
||||
/// <summary>
|
||||
/// 长按1s
|
||||
/// </summary>
|
||||
Hold,
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原神按键动作
|
||||
/// </summary>
|
||||
public enum GIActions
|
||||
{
|
||||
/// <summary>
|
||||
/// 向前移动
|
||||
/// </summary>
|
||||
MoveForward,
|
||||
|
||||
/// <summary>
|
||||
/// 向后移动
|
||||
/// </summary>
|
||||
MoveBackward,
|
||||
|
||||
/// <summary>
|
||||
/// 向左移动
|
||||
/// </summary>
|
||||
MoveLeft,
|
||||
|
||||
/// <summary>
|
||||
/// 向右移动
|
||||
/// </summary>
|
||||
MoveRight,
|
||||
|
||||
/// <summary>
|
||||
/// 切换走/跑;特定操作模式下向下移动
|
||||
/// </summary>
|
||||
SwitchToWalkOrRun,
|
||||
|
||||
/// <summary>
|
||||
/// 普通攻击
|
||||
/// </summary>
|
||||
NormalAttack,
|
||||
|
||||
/// <summary>
|
||||
/// 元素战技
|
||||
/// </summary>
|
||||
ElementalSkill,
|
||||
|
||||
/// <summary>
|
||||
/// 元素爆发
|
||||
/// </summary>
|
||||
ElementalBurst,
|
||||
|
||||
/// <summary>
|
||||
/// 冲刺(键盘)
|
||||
/// </summary>
|
||||
SprintKeyboard,
|
||||
|
||||
/// <summary>
|
||||
/// 冲刺(鼠标)
|
||||
/// </summary>
|
||||
SprintMouse,
|
||||
|
||||
/// <summary>
|
||||
/// 切换瞄准模式
|
||||
/// </summary>
|
||||
SwitchAimingMode,
|
||||
|
||||
/// <summary>
|
||||
/// 跳跃;特定操作模式下向上移动
|
||||
/// </summary>
|
||||
Jump,
|
||||
|
||||
/// <summary>
|
||||
/// 落下
|
||||
/// </summary>
|
||||
Drop,
|
||||
|
||||
/// <summary>
|
||||
/// 拾取/交互(自动拾取由AutoPick模块管理)
|
||||
/// </summary>
|
||||
PickUpOrInteract,
|
||||
|
||||
/// <summary>
|
||||
/// 快捷使用小道具
|
||||
/// </summary>
|
||||
QuickUseGadget,
|
||||
|
||||
/// <summary>
|
||||
/// 特定玩法内交互操作
|
||||
/// </summary>
|
||||
InteractionInSomeMode,
|
||||
|
||||
/// <summary>
|
||||
/// 开启任务追踪
|
||||
/// </summary>
|
||||
QuestNavigation,
|
||||
|
||||
/// <summary>
|
||||
/// 中断挑战
|
||||
/// </summary>
|
||||
AbandonChallenge,
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色1
|
||||
/// </summary>
|
||||
SwitchMember1,
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色2
|
||||
/// </summary>
|
||||
SwitchMember2,
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色3
|
||||
/// </summary>
|
||||
SwitchMember3,
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色4
|
||||
/// </summary>
|
||||
SwitchMember4,
|
||||
|
||||
/// <summary>
|
||||
/// 切换小队角色5
|
||||
/// </summary>
|
||||
SwitchMember5,
|
||||
|
||||
/// <summary>
|
||||
/// 呼出快捷轮盘
|
||||
/// </summary>
|
||||
ShortcutWheel,
|
||||
|
||||
/// <summary>
|
||||
/// 打开背包
|
||||
/// </summary>
|
||||
OpenInventory,
|
||||
|
||||
/// <summary>
|
||||
/// 打开角色界面
|
||||
/// </summary>
|
||||
OpenCharacterScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开地图
|
||||
/// </summary>
|
||||
OpenMap,
|
||||
|
||||
/// <summary>
|
||||
/// 打开派蒙界面
|
||||
/// </summary>
|
||||
OpenPaimonMenu,
|
||||
|
||||
/// <summary>
|
||||
/// 打开冒险之证界面
|
||||
/// </summary>
|
||||
OpenAdventurerHandbook,
|
||||
|
||||
/// <summary>
|
||||
/// 打开多人游戏界面
|
||||
/// </summary>
|
||||
OpenCoOpScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开祈愿界面
|
||||
/// </summary>
|
||||
OpenWishScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开纪行界面
|
||||
/// </summary>
|
||||
OpenBattlePassScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开活动面板
|
||||
/// </summary>
|
||||
OpenTheEventsMenu,
|
||||
|
||||
/// <summary>
|
||||
/// 打开玩法系统界面(尘歌壶内猫尾酒馆内)
|
||||
/// </summary>
|
||||
OpenTheSettingsMenu,
|
||||
|
||||
/// <summary>
|
||||
/// 打开摆设界面(尘歌壶内)
|
||||
/// </summary>
|
||||
OpenTheFurnishingScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开星之归还(条件符合期间生效)
|
||||
/// </summary>
|
||||
OpenStellarReunion,
|
||||
|
||||
/// <summary>
|
||||
/// 开关任务菜单
|
||||
/// </summary>
|
||||
OpenQuestMenu,
|
||||
|
||||
/// <summary>
|
||||
/// 打开通知详情
|
||||
/// </summary>
|
||||
OpenNotificationDetails,
|
||||
|
||||
/// <summary>
|
||||
/// 打开聊天界面
|
||||
/// </summary>
|
||||
OpenChatScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开特殊环境说明
|
||||
/// </summary>
|
||||
OpenSpecialEnvironmentInformation,
|
||||
|
||||
/// <summary>
|
||||
/// 查看教程详情
|
||||
/// </summary>
|
||||
CheckTutorialDetails,
|
||||
|
||||
/// <summary>
|
||||
/// 长按打开元素视野
|
||||
/// </summary>
|
||||
ElementalSight,
|
||||
|
||||
/// <summary>
|
||||
/// 呼出鼠标
|
||||
/// </summary>
|
||||
ShowCursor,
|
||||
|
||||
/// <summary>
|
||||
/// 打开队伍配置界面
|
||||
/// </summary>
|
||||
OpenPartySetupScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 打开好友界面
|
||||
/// </summary>
|
||||
OpenFriendsScreen,
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏主界面
|
||||
/// </summary>
|
||||
HideUI,
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 用于扩展<seealso cref="Fischless.WindowsInput.InputSimulator"/>的功能
|
||||
/// </summary>
|
||||
public static class InputSimulatorExtension
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 模拟玩家操作
|
||||
/// </summary>
|
||||
/// <param name="action">动作</param>
|
||||
/// <param name="type">按键类型</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 为<seealso cref="PostMessageSimulator"/>提供扩展功能
|
||||
/// </summary>
|
||||
public static class PostMessageSimulatorExtension
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 模拟玩家操作
|
||||
/// </summary>
|
||||
/// <param name="action">动作</param>
|
||||
/// <param name="type">按键类型</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模拟玩家操作(后台)
|
||||
/// </summary>
|
||||
/// <param name="action">动作</param>
|
||||
/// <param name="type">按键类型</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过ActionId取得实际的键盘绑定
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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<Vec3b>(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;
|
||||
|
@ -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
|
||||
/// </summary>
|
||||
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
|
||||
/// </summary>
|
||||
public void Jump()
|
||||
{
|
||||
AutoFightContext.Instance.Simulator.KeyPress(User32.VK.VK_SPACE);
|
||||
AutoFightContext.Instance.Simulator.SimulateAction(GIActions.Jump);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
// 识别距离
|
||||
|
@ -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;
|
||||
|
@ -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<MovementControl>
|
||||
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<MovementControl>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
// 点击进入尘歌壶
|
||||
|
50
BetterGenshinImpact/Model/KeyBindingSettingModel.cs
Normal file
50
BetterGenshinImpact/Model/KeyBindingSettingModel.cs
Normal file
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 按键绑定值
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private KeyId _keyValue;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<KeyBindingSettingModel> _children = [];
|
||||
|
||||
public string ActionName { get; set; }
|
||||
|
||||
public bool IsExpanded => true;
|
||||
|
||||
/// <summary>
|
||||
/// 界面上显示是文件夹而不是按键绑定
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 按键绑定
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
@ -141,6 +141,13 @@
|
||||
<ui:SymbolIcon Symbol="Flash24" />
|
||||
</ui:NavigationViewItem.Icon>
|
||||
</ui:NavigationViewItem>
|
||||
<ui:NavigationViewItem Content="按键绑定"
|
||||
NavigationCacheMode="Enabled"
|
||||
TargetPageType="{x:Type pages:KeyBindingsSettingsPage}" Cursor="Hand">
|
||||
<ui:NavigationViewItem.Icon>
|
||||
<ui:SymbolIcon Symbol="KeyboardMouse16" />
|
||||
</ui:NavigationViewItem.Icon>
|
||||
</ui:NavigationViewItem>
|
||||
<!--<ui:NavigationViewItem Content="通知"
|
||||
NavigationCacheMode="Enabled"
|
||||
TargetPageType="{x:Type pages:NotificationSettingsPage}">
|
||||
@ -171,9 +178,17 @@
|
||||
<ui:ImageIcon Source="pack://application:,,,/Assets/Images/logo.png" />
|
||||
</ui:TitleBar.Icon>
|
||||
<ui:TitleBar.Header>
|
||||
<StackPanel>
|
||||
<ui:Button Width="44"
|
||||
Height="30"
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
|
||||
<ui:Button Width="46"
|
||||
Height="32"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Command="{Binding SwitchBackdropCommand}"
|
||||
CornerRadius="0"
|
||||
Icon="{ui:SymbolIcon Blur24}"
|
||||
ToolTip="{Binding CurrentBackdropType}" />
|
||||
<ui:Button Width="46"
|
||||
Height="32"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Command="{Binding HideCommand}"
|
||||
|
@ -71,18 +71,18 @@ public partial class MainWindow : FluentWindow, INavigationWindow
|
||||
|
||||
private void TryApplySystemBackdrop()
|
||||
{
|
||||
if (WindowBackdrop.IsSupported(WindowBackdropType.Acrylic)) // 改用Acrylic效果
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(100, 0, 0, 0));
|
||||
WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Acrylic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WindowBackdrop.IsSupported(WindowBackdropType.Mica))
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.Transparent);
|
||||
WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Mica);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WindowBackdrop.IsSupported(WindowBackdropType.Tabbed))
|
||||
{
|
||||
Background = new SolidColorBrush(Colors.Transparent);
|
||||
WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Tabbed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
84
BetterGenshinImpact/View/Pages/KeyBindingsSettingsPage.xaml
Normal file
84
BetterGenshinImpact/View/Pages/KeyBindingsSettingsPage.xaml
Normal file
@ -0,0 +1,84 @@
|
||||
<UserControl x:Class="BetterGenshinImpact.View.Pages.KeyBindingsSettingsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:controls="clr-namespace:BetterGenshinImpact.View.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:kb="clr-namespace:BetterGenshinImpact.View.Controls.KeyBindings"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="clr-namespace:BetterGenshinImpact.Model"
|
||||
xmlns:pages="clr-namespace:BetterGenshinImpact.ViewModel.Pages"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
d:DataContext="{d:DesignInstance Type=pages:KeyBindingsSettingsPageViewModel}"
|
||||
d:DesignHeight="850"
|
||||
d:DesignWidth="600"
|
||||
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
|
||||
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
FontFamily="{StaticResource TextThemeFontFamily}"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Margin="42,16,42,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ui:TextBlock Grid.Row="0"
|
||||
Margin="0,0,0,8"
|
||||
FontTypography="BodyStrong"
|
||||
Text="按键绑定设置" />
|
||||
<ui:TextBlock Grid.Row="1"
|
||||
Margin="0,0,0,8"
|
||||
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
|
||||
Text="此处的按键绑定设置对除自动拾取、钓鱼、音游、伐木外的功能有效。请手动设置拾取按键、星之归还按键、隐藏主界面按键。"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<ui:Button Command="{Binding FetchFromRegistryCommand}"
|
||||
Content="从注册表读取"
|
||||
Icon="{ui:SymbolIcon Notepad32}" />
|
||||
</StackPanel>
|
||||
|
||||
<ui:Border Grid.Row="3"
|
||||
Background="{DynamicResource CardBackground}"
|
||||
BorderBrush="{DynamicResource CardBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource ControlCornerRadius}">
|
||||
<Grid Margin="4">
|
||||
<ui:Grid ColumnDefinitions="*,135" Visibility="Hidden">
|
||||
<Grid x:Name="TreeColumnStar" Grid.Column="0" />
|
||||
</ui:Grid>
|
||||
<ui:TreeListView BorderThickness="0" ItemsSource="{Binding KeyBindingSettingModels}">
|
||||
<ui:TreeListView.Columns>
|
||||
<GridViewColumnCollection>
|
||||
<ui:GridViewColumn Width="{Binding ActualWidth, ElementName=TreeColumnStar}" Header="动作">
|
||||
<ui:GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ui:TreeRowExpander Content="{Binding ActionName}" />
|
||||
</DataTemplate>
|
||||
</ui:GridViewColumn.CellTemplate>
|
||||
</ui:GridViewColumn>
|
||||
<ui:GridViewColumn Width="120" Header="按键绑定">
|
||||
<ui:GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<kb:KeyBindingTextBox Padding="16,6,16,6"
|
||||
VerticalAlignment="Center"
|
||||
KeyBinding="{Binding KeyValue}"
|
||||
Style="{StaticResource DefaultTextBoxStyle}"
|
||||
TextAlignment="Center"
|
||||
Visibility="{Binding IsDirectory, Converter={StaticResource BooleanToVisibilityRevertConverter}, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</ui:GridViewColumn.CellTemplate>
|
||||
</ui:GridViewColumn>
|
||||
</GridViewColumnCollection>
|
||||
</ui:TreeListView.Columns>
|
||||
<ui:TreeListView.ItemTemplate>
|
||||
<HierarchicalDataTemplate ItemsSource="{Binding Children}" />
|
||||
</ui:TreeListView.ItemTemplate>
|
||||
</ui:TreeListView>
|
||||
</Grid>
|
||||
</ui:Border>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -0,0 +1,30 @@
|
||||
using BetterGenshinImpact.ViewModel.Pages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BetterGenshinImpact.View.Pages;
|
||||
|
||||
/// <summary>
|
||||
/// KeyBindingsSettingsPage.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class KeyBindingsSettingsPage : UserControl
|
||||
{
|
||||
|
||||
private KeyBindingsSettingsPageViewModel ViewModel { get; }
|
||||
|
||||
public KeyBindingsSettingsPage(KeyBindingsSettingsPageViewModel viewModel)
|
||||
{
|
||||
DataContext = ViewModel = viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
@ -1,37 +1,183 @@
|
||||
<Window x:Class="BetterGenshinImpact.View.PickerWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="选择捕获窗口"
|
||||
Width="800"
|
||||
Height="450"
|
||||
FontFamily="{DynamicResource TextThemeFontFamily}"
|
||||
mc:Ignorable="d">
|
||||
<Grid Background="Black">
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#FF1E1E1E">
|
||||
|
||||
<Window.Resources>
|
||||
<!-- ListBoxItem Fluent UI 样式 -->
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Margin" Value="8,4" />
|
||||
<Setter Property="Padding" Value="12" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListBoxItem">
|
||||
<Border x:Name="Border"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="8"
|
||||
BorderThickness="1"
|
||||
BorderBrush="Transparent">
|
||||
<Grid>
|
||||
<Border x:Name="SelectionBackground"
|
||||
Background="#30FFFFFF"
|
||||
CornerRadius="8"
|
||||
Opacity="0"/>
|
||||
<ContentPresenter />
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="SelectionBackground" Property="Opacity" Value="0.1" />
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="#20FFFFFF" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="SelectionBackground" Property="Opacity" Value="0.2" />
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="#40FFFFFF" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0"
|
||||
Margin="5,0"
|
||||
Background="White"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock FontSize="20" Text="双击选中要捕获的窗口" />
|
||||
</StackPanel>
|
||||
<!-- 标题区域 -->
|
||||
<Border Grid.Row="0"
|
||||
Background="#FF252525"
|
||||
Padding="24,20">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ListBox x:Name="WindowList"
|
||||
Grid.Row="1"
|
||||
Padding="0,10"
|
||||
BorderThickness="0">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl MouseDoubleClick="WindowsOnMouseDoubleClick">
|
||||
<TextBlock FontSize="14" Text="{Binding Name}" />
|
||||
</ContentControl>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<TextBlock Text="选择捕获窗口"
|
||||
FontSize="24"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FFFFFF"/>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Text="双击选中要捕获的窗口"
|
||||
Margin="0,8,0,0"
|
||||
Foreground="#99FFFFFF"
|
||||
FontSize="14"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ScrollViewer Grid.Row="1"
|
||||
PanningMode="VerticalOnly"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox x:Name="WindowList"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
MouseDoubleClick="WindowsOnMouseDoubleClick"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling"
|
||||
ScrollViewer.CanContentScroll="False">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Margin" Value="4"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListBoxItem">
|
||||
<Border x:Name="Border"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="8"
|
||||
BorderThickness="1"
|
||||
BorderBrush="Transparent">
|
||||
<ContentPresenter/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetName="Border"
|
||||
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
|
||||
To="#22FFFFFF"
|
||||
Duration="0:0:0.2">
|
||||
<ColorAnimation.EasingFunction>
|
||||
<ExponentialEase EasingMode="EaseOut"/>
|
||||
</ColorAnimation.EasingFunction>
|
||||
</ColorAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetName="Border"
|
||||
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
|
||||
To="#00000000"
|
||||
Duration="0:0:0.2">
|
||||
<ColorAnimation.EasingFunction>
|
||||
<ExponentialEase EasingMode="EaseOut"/>
|
||||
</ColorAnimation.EasingFunction>
|
||||
</ColorAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="Border" Property="Background" Value="#33FFFFFF"/>
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="#44FFFFFF"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="12,8" Height="48">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 内容层 -->
|
||||
<Border Grid.Column="0"
|
||||
Width="40"
|
||||
Height="40"
|
||||
Background="#22FFFFFF"
|
||||
CornerRadius="4"
|
||||
Margin="0,0,12,0">
|
||||
<Image Width="24"
|
||||
Height="24"
|
||||
Source="{Binding Icon}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality"/>
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FFFFFF"/>
|
||||
<TextBlock Text="{Binding ProcessName}"
|
||||
FontSize="12"
|
||||
Foreground="#99FFFFFF"
|
||||
Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
</Window>
|
@ -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<CapturableWindow>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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<KeyBindingsSettingsPageViewModel> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// 配置文件
|
||||
/// </summary>
|
||||
private readonly KeyBindingsConfig _config;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<KeyBindingSettingModel> _keyBindingSettingModels = [];
|
||||
|
||||
public void OnNavigatedFrom()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnNavigatedTo()
|
||||
{
|
||||
}
|
||||
|
||||
public KeyBindingsSettingsPageViewModel(IConfigService configService, ILogger<KeyBindingsSettingsPageViewModel> 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<KeyBindingSettingModel> GetAllNonDirectoryKeyBinding(IEnumerable<KeyBindingSettingModel> modelList)
|
||||
{
|
||||
var list = new List<KeyBindingSettingModel>();
|
||||
foreach (var keyBindingSettingModel in modelList)
|
||||
{
|
||||
if (!keyBindingSettingModel.IsDirectory)
|
||||
{
|
||||
list.Add(keyBindingSettingModel);
|
||||
}
|
||||
|
||||
list.AddRange(GetAllNonDirectoryChildren(keyBindingSettingModel));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<KeyBindingSettingModel> GetAllNonDirectoryChildren(KeyBindingSettingModel model)
|
||||
{
|
||||
var result = new List<KeyBindingSettingModel>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造按键绑定列表
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从注册表中读取按键
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1
View/PickerWindow.xaml
Normal file
1
View/PickerWindow.xaml
Normal file
@ -0,0 +1 @@
|
||||
|
Loading…
Reference in New Issue
Block a user