diff --git a/BetterGenshinImpact/Core/Simulator/PostMessageSimulator.cs b/BetterGenshinImpact/Core/Simulator/PostMessageSimulator.cs
index 881d3aea..1089fde2 100644
--- a/BetterGenshinImpact/Core/Simulator/PostMessageSimulator.cs
+++ b/BetterGenshinImpact/Core/Simulator/PostMessageSimulator.cs
@@ -65,6 +65,16 @@ public class PostMessageSimulator
return this;
}
+ public PostMessageSimulator LeftButtonClickBackground()
+ {
+ User32.PostMessage(_hWnd, User32.WindowMessage.WM_ACTIVATE, 1, 0);
+ IntPtr p = (16 << 16) | 16;
+ User32.PostMessage(_hWnd, WM_LBUTTONDOWN, IntPtr.Zero, p);
+ Thread.Sleep(100);
+ User32.PostMessage(_hWnd, WM_LBUTTONUP, IntPtr.Zero, p);
+ return this;
+ }
+
///
/// 默认位置左键按下
///
diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs
index 73aaefbe..0580ebf7 100644
--- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs
+++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs
@@ -1,78 +1,82 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
-namespace BetterGenshinImpact.GameTask.AutoSkip
+namespace BetterGenshinImpact.GameTask.AutoSkip;
+
+///
+/// 自动跳过剧情配置
+///
+[Serializable]
+public partial class AutoSkipConfig : ObservableObject
{
///
- /// 自动跳过剧情配置
+ /// 触发器是否启用
+ /// 启用后:
+ /// 1. 快速跳过对话
+ /// 2. 自动点击一个识别到的选项
+ /// 3. 黑屏过长自动点击跳过
///
- [Serializable]
- public partial class AutoSkipConfig : ObservableObject
+ [ObservableProperty] private bool _enabled = true;
+
+ ///
+ /// 快速跳过对话
+ ///
+ [ObservableProperty] private bool _quicklySkipConversationsEnabled = true;
+
+ public int ChatOptionTextWidth { get; set; } = 280;
+
+ public int ExpeditionOptionTextWidth { get; set; } = 130;
+
+ ///
+ /// 选择选项前的延迟(毫秒)
+ ///
+ [ObservableProperty] private int _afterChooseOptionSleepDelay = 0;
+
+ ///
+ /// 自动领取每日委托奖励
+ ///
+ [ObservableProperty] private bool _autoGetDailyRewardsEnabled = true;
+
+ ///
+ /// 自动重新派遣
+ ///
+ [ObservableProperty] private bool _autoReExploreEnabled = true;
+
+ ///
+ /// 自动重新派遣使用角色配置,逗号分割
+ ///
+ [Obsolete]
+ [ObservableProperty] private string _autoReExploreCharacter = "";
+
+ ///
+ /// 优先选择第一个选项
+ /// 优先选择最后一个选项
+ /// 不选择选项
+ ///
+ [ObservableProperty] private string _clickChatOption = "优先选择最后一个选项";
+
+ ///
+ /// 自动邀约启用
+ ///
+ [ObservableProperty] private bool _autoHangoutEventEnabled = false;
+
+ ///
+ /// 自动邀约启用
+ ///
+ [ObservableProperty] private string _autoHangoutEndChoose = string.Empty;
+
+ public bool IsClickFirstChatOption()
{
- ///
- /// 触发器是否启用
- /// 启用后:
- /// 1. 快速跳过对话
- /// 2. 自动点击一个识别到的选项
- /// 3. 黑屏过长自动点击跳过
- ///
- [ObservableProperty] private bool _enabled = true;
-
- ///
- /// 快速跳过对话
- ///
- [ObservableProperty] private bool _quicklySkipConversationsEnabled = true;
-
- public int ChatOptionTextWidth { get; set; } = 280;
-
- public int ExpeditionOptionTextWidth { get; set; } = 130;
-
- ///
- /// 选择选项前的延迟(毫秒)
- ///
- [ObservableProperty] private int _afterChooseOptionSleepDelay = 0;
-
- ///
- /// 自动领取每日委托奖励
- ///
- [ObservableProperty] private bool _autoGetDailyRewardsEnabled = true;
-
- ///
- /// 自动重新派遣
- ///
- [ObservableProperty] private bool _autoReExploreEnabled = true;
-
- ///
- /// 自动重新派遣使用角色配置,逗号分割
- ///
- [Obsolete]
- [ObservableProperty] private string _autoReExploreCharacter = "";
-
- ///
- /// 优先选择第一个选项
- /// 优先选择最后一个选项
- /// 不选择选项
- ///
- [ObservableProperty] private string _clickChatOption = "优先选择最后一个选项";
-
- ///
- /// 自动邀约启用
- ///
- [ObservableProperty] private bool _autoHangoutEventEnabled = false;
-
- ///
- /// 自动邀约启用
- ///
- [ObservableProperty] private string _autoHangoutEndChoose = string.Empty;
-
- public bool IsClickFirstChatOption()
- {
- return ClickChatOption == "优先选择第一个选项";
- }
-
- public bool IsClickNoneChatOption()
- {
- return ClickChatOption == "不选择选项";
- }
+ return ClickChatOption == "优先选择第一个选项";
}
+
+ public bool IsClickNoneChatOption()
+ {
+ return ClickChatOption == "不选择选项";
+ }
+
+ ///
+ /// 后台运行
+ ///
+ [ObservableProperty] private bool _runBackgroundEnabled = false;
}
diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs
index 814178e9..c099c9c9 100644
--- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs
+++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs
@@ -1,4 +1,5 @@
using BetterGenshinImpact.Core.Config;
+using BetterGenshinImpact.Core.Recognition;
using BetterGenshinImpact.Core.Recognition.OCR;
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.Core.Simulator;
@@ -6,12 +7,12 @@ using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.AutoSkip.Model;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.GameTask.Common.Element.Assets;
+using BetterGenshinImpact.GameTask.Model.Area;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Service;
using BetterGenshinImpact.View.Drawable;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
-using Sdcb.PaddleOCR;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -20,8 +21,6 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
-using BetterGenshinImpact.Core.Recognition;
-using BetterGenshinImpact.GameTask.Model.Area;
using Vanara.PInvoke;
namespace BetterGenshinImpact.GameTask.AutoSkip;
@@ -38,6 +37,8 @@ public class AutoSkipTrigger : ITaskTrigger
public int Priority => 20;
public bool IsExclusive => false;
+ public bool IsBackgroundRunning { get; set; }
+
private readonly AutoSkipAssets _autoSkipAssets;
private readonly AutoSkipConfig _config;
@@ -57,6 +58,8 @@ public class AutoSkipTrigger : ITaskTrigger
///
private List _selectList = new();
+ private PostMessageSimulator? _postMessageSimulator;
+
public AutoSkipTrigger()
{
_autoSkipAssets = AutoSkipAssets.Instance;
@@ -65,7 +68,9 @@ public class AutoSkipTrigger : ITaskTrigger
public void Init()
{
- IsEnabled = TaskContext.Instance().Config.AutoSkipConfig.Enabled;
+ IsEnabled = _config.Enabled;
+ IsBackgroundRunning = _config.RunBackgroundEnabled;
+ _postMessageSimulator = TaskContext.Instance().PostMessageSimulator;
try
{
@@ -182,7 +187,14 @@ public class AutoSkipTrigger : ITaskTrigger
_prevPlayingTime = DateTime.Now;
if (TaskContext.Instance().Config.AutoSkipConfig.QuicklySkipConversationsEnabled)
{
- Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
+ if (IsBackgroundRunning)
+ {
+ _postMessageSimulator?.KeyPressBackground(User32.VK.VK_SPACE);
+ }
+ else
+ {
+ Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
+ }
}
// 对话选项选择
@@ -392,7 +404,7 @@ public class AutoSkipTrigger : ITaskTrigger
using var exclamationIconRa = region.Find(_autoSkipAssets.ExclamationIconRo);
if (!exclamationIconRa.IsEmpty())
{
- TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
+ Thread.Sleep(_config.AfterChooseOptionSleepDelay);
exclamationIconRa.Click();
AutoSkipLog("点击感叹号选项");
return true;
@@ -515,7 +527,7 @@ public class AutoSkipTrigger : ITaskTrigger
}
// 没OCR到文字,直接选择气泡选项
- TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
+ Thread.Sleep(_config.AfterChooseOptionSleepDelay);
clickRect.Click();
var msg = _config.IsClickFirstChatOption() ? "第一个" : "最后一个";
AutoSkipLog($"点击{msg}气泡选项");
@@ -531,9 +543,20 @@ public class AutoSkipTrigger : ITaskTrigger
{
if (string.IsNullOrEmpty(optionType))
{
- TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
+ Thread.Sleep(_config.AfterChooseOptionSleepDelay);
+ }
+ if (IsBackgroundRunning && !SystemControl.IsGenshinImpactActive())
+ {
+ User32.GetCursorPos(out var p);
+ region.Move(); // 必须移动实际鼠标
+ _postMessageSimulator?.LeftButtonClickBackground();
+ Thread.Sleep(10);
+ DesktopRegion.DesktopRegionMove(p.X, p.Y); // 鼠标移动回原来位置
+ }
+ else
+ {
+ region.Click();
}
- region.Click();
AutoSkipLog(region.Text);
}
diff --git a/BetterGenshinImpact/GameTask/ITaskTrigger.cs b/BetterGenshinImpact/GameTask/ITaskTrigger.cs
index 2dc1bc44..4a816fd7 100644
--- a/BetterGenshinImpact/GameTask/ITaskTrigger.cs
+++ b/BetterGenshinImpact/GameTask/ITaskTrigger.cs
@@ -6,7 +6,7 @@
/// * 也可以是任务的本身
///
/// 需要短时间内持续循环获取游戏图像的,使用触发器;
-/// 需要休眠等待且有一定流程的,应该使用
+/// 需要休眠等待且有一定流程的,应自行实现Task
///
public interface ITaskTrigger
{
@@ -14,6 +14,7 @@ public interface ITaskTrigger
/// 触发器名称
///
string Name { get; }
+
///
/// 是否处于启用状态
///
@@ -29,6 +30,11 @@ public interface ITaskTrigger
///
bool IsExclusive { get; }
+ ///
+ /// 处于可以后台运行的状态(原神窗口不处于激活状态)
+ ///
+ bool IsBackgroundRunning => false;
+
///
/// 初始化
///
@@ -39,4 +45,4 @@ public interface ITaskTrigger
///
/// 捕获的图片等内容
void OnCapture(CaptureContent content);
-}
\ No newline at end of file
+}
diff --git a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs
index 1501dff9..75521d17 100644
--- a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs
+++ b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs
@@ -18,6 +18,12 @@ public class DesktopRegion() : Region(0, 0, PrimaryScreen.WorkingArea.Width, Pri
(y + (h * 1d / 2)) * 65535 / Height).LeftButtonClick().Sleep(50).LeftButtonUp();
}
+ public void DesktopRegionMove(int x, int y, int w, int h)
+ {
+ Simulation.SendInput.Mouse.MoveMouseTo((x + (w * 1d / 2)) * 65535 / Width,
+ (y + (h * 1d / 2)) * 65535 / Height);
+ }
+
///
/// 静态方法,每次都会重新计算屏幕大小
///
diff --git a/BetterGenshinImpact/GameTask/Model/Area/Region.cs b/BetterGenshinImpact/GameTask/Model/Area/Region.cs
index 3c026dd5..a7bbce27 100644
--- a/BetterGenshinImpact/GameTask/Model/Area/Region.cs
+++ b/BetterGenshinImpact/GameTask/Model/Area/Region.cs
@@ -111,6 +111,41 @@ public class Region : IDisposable
res.TargetRegion.DesktopRegionClick(res.X, res.Y, res.Width, res.Height);
}
+ ///
+ /// 移动到【自己】的中心
+ /// region.Derive(x,y).Move() 等效于 region.MoveTo(x,y)
+ ///
+ public void Move()
+ {
+ // 相对自己是 0, 0 坐标
+ MoveTo(0, 0, Width, Height);
+ }
+
+ ///
+ /// 移动到区域内【指定位置】
+ /// region.Derive(x,y).Move() 等效于 region.MoveTo(x,y)
+ ///
+ ///
+ ///
+ public void MoveTo(int x, int y)
+ {
+ MoveTo(x, y, 0, 0);
+ }
+
+ ///
+ /// 移动到区域内【指定矩形区域】的中心
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void MoveTo(int x, int y, int w, int h)
+ {
+ var res = ConvertRes.ConvertPositionToTargetRegion(x, y, w, h, this);
+ res.TargetRegion.DesktopRegionMove(res.X, res.Y, res.Width, res.Height);
+ }
+
///
/// 直接在遮罩窗口绘制【自己】
///
diff --git a/BetterGenshinImpact/GameTask/TaskContext.cs b/BetterGenshinImpact/GameTask/TaskContext.cs
index 603cc4af..de302237 100644
--- a/BetterGenshinImpact/GameTask/TaskContext.cs
+++ b/BetterGenshinImpact/GameTask/TaskContext.cs
@@ -5,6 +5,7 @@ using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Service;
using System;
using System.Threading;
+using BetterGenshinImpact.Core.Simulator;
namespace BetterGenshinImpact.GameTask
{
@@ -32,6 +33,7 @@ namespace BetterGenshinImpact.GameTask
public void Init(IntPtr hWnd)
{
GameHandle = hWnd;
+ PostMessageSimulator = Simulation.PostMessage(GameHandle);
SystemInfo = new SystemInfo(hWnd);
DpiScale = DpiHelper.ScaleY;
//MaskWindowHandle = new WindowInteropHelper(MaskWindow.Instance()).Handle;
@@ -42,6 +44,8 @@ namespace BetterGenshinImpact.GameTask
public IntPtr GameHandle { get; set; }
+ public PostMessageSimulator PostMessageSimulator { get; private set; }
+
//public IntPtr MaskWindowHandle { get; set; }
public float DpiScale { get; set; }
diff --git a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs
index 11ff0975..f32cd2e7 100644
--- a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs
+++ b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs
@@ -268,6 +268,7 @@ namespace BetterGenshinImpact.GameTask
}
// 检查游戏是否在前台
+ var hasBackgroundTriggerToRun = false;
var active = SystemControl.IsGenshinImpactActive();
if (!active)
{
@@ -291,7 +292,24 @@ namespace BetterGenshinImpact.GameTask
}
_prevGameActive = active;
- return;
+
+ if (_triggers != null)
+ {
+ var exclusive = _triggers.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
+ if (exclusive != null)
+ {
+ hasBackgroundTriggerToRun = exclusive.IsBackgroundRunning;
+ }
+ else
+ {
+ hasBackgroundTriggerToRun = _triggers.Any(t => t is { IsEnabled: true, IsBackgroundRunning: true });
+ }
+ }
+ if (!hasBackgroundTriggerToRun)
+ {
+ // 没有后台运行的触发器,这次不再进行截图
+ return;
+ }
}
else
{
@@ -342,7 +360,7 @@ namespace BetterGenshinImpact.GameTask
// 循环执行所有触发器 有独占状态的触发器的时候只执行独占触发器
var content = new CaptureContent(bitmap, _frameIndex, _timer.Interval);
- var exclusiveTrigger = _triggers.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
+ var exclusiveTrigger = _triggers!.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
if (exclusiveTrigger != null)
{
exclusiveTrigger.OnCapture(content);
@@ -350,7 +368,13 @@ namespace BetterGenshinImpact.GameTask
}
else
{
- foreach (var trigger in _triggers.Where(trigger => trigger.IsEnabled))
+ var runningTriggers = _triggers.Where(t => t.IsEnabled);
+ if (hasBackgroundTriggerToRun)
+ {
+ runningTriggers = runningTriggers.Where(t => t.IsBackgroundRunning);
+ }
+
+ foreach (var trigger in runningTriggers)
{
trigger.OnCapture(content);
speedTimer.Record(trigger.Name);
diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml
index 2c9948d3..34da33aa 100644
--- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml
+++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml
@@ -222,6 +222,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs
index a01a5fdd..b0f86908 100644
--- a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs
+++ b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs
@@ -12,6 +12,7 @@ using BetterGenshinImpact.GameTask.AutoFight;
using BetterGenshinImpact.GameTask.AutoTrackPath;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.GameTask.Common.BgiVision;
+using BetterGenshinImpact.GameTask.Model.Area;
using BetterGenshinImpact.Helpers.Extensions;
using Microsoft.Extensions.Logging;
using HotKeySettingModel = BetterGenshinImpact.Model.HotKeySettingModel;
@@ -385,8 +386,13 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel
{
postMessageSimulator = Simulation.PostMessage(TaskContext.Instance().GameHandle);
}
+ User32.GetCursorPos(out var p);
+ Debug.WriteLine($"鼠标位置:{p.X},{p.Y}");
// postMessageSimulator.KeyPressBackground(User32.VK.VK_W);
+ GameCaptureRegion.GameRegion1080PPosMove(1340, 655);
postMessageSimulator.LeftButtonClickBackground(1340, 655);
+ Thread.Sleep(5);
+ DesktopRegion.DesktopRegionMove(p.X, p.Y);
}
));
}