Files
better-genshin-impact/BetterGenshinImpact/GameTask/SystemControl.cs

368 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.View.Windows;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Vanara.PInvoke;
namespace BetterGenshinImpact.GameTask;
public class SystemControl
{
public static nint FindGenshinImpactHandle()
{
return FindHandleByProcessName("YuanShen", "GenshinImpact", "Genshin Impact Cloud Game", "Genshin Impact Cloud");
}
public static async Task<nint> StartFromLocalAsync(string path)
{
if (!File.Exists(path))
{
await ThemedMessageBox.ErrorAsync($"原神启动路径 {path} 不存在,请前往 启动——同时启动原神——原神安装路径 重新进行配置!");
return IntPtr.Zero;
}
var cfg = TaskContext.Instance().Config.GenshinStartConfig;
var workdir = Path.GetDirectoryName(path) ?? "";
var arg = cfg.GenshinStartArgs;
if (cfg.StartGameWithCmd)
{
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c start \"\" /d \"{workdir}\" \"{path}\" {arg}",
UseShellExecute = false,
CreateNoWindow = true
};
Process.Start(psi);
}
else
{
Process.Start(new ProcessStartInfo(path)
{
UseShellExecute = true,
Arguments = arg,
WorkingDirectory = workdir
});
}
for (var i = 0; i < 5; i++)
{
var handle = FindGenshinImpactHandle();
if (handle != 0)
{
await Task.Delay(2333);
handle = FindGenshinImpactHandle();
await Task.Delay(2577);
return handle;
}
await Task.Delay(5577);
}
return FindGenshinImpactHandle();
}
public static bool IsGenshinImpactActiveByProcess()
{
var name = GetActiveProcessName();
return name is "YuanShen" or "yuanshen" or "GenshinImpact" or "Genshin Impact Cloud Game";
}
public static string GetActiveByProcess()
{
return GetActiveProcessName() ?? "Unknown";
}
public static bool IsGenshinImpactActive()
{
var hWnd = User32.GetForegroundWindow();
return hWnd == TaskContext.Instance().GameHandle;
}
public static nint GetForegroundWindowHandle()
{
return (nint)User32.GetForegroundWindow();
}
public static nint FindHandleByProcessName(params string[] names)
{
foreach (var name in names)
{
var pros = Process.GetProcessesByName(name);
if (pros.Length is not 0)
{
return pros[0].MainWindowHandle;
}
}
return 0;
}
public static nint FindHandleByWindowName()
{
var handle = (nint)User32.FindWindow("UnityWndClass", "原神");
if (handle != 0)
{
return handle;
}
handle = (nint)User32.FindWindow("UnityWndClass", "Genshin Impact");
if (handle != 0)
{
return handle;
}
handle = (nint)User32.FindWindow("Qt5152QWindowIcon", "云·原神");
if (handle != 0)
{
return handle;
}
return 0;
}
public static string? GetActiveProcessName()
{
try
{
var hWnd = User32.GetForegroundWindow();
_ = User32.GetWindowThreadProcessId(hWnd, out var pid);
var p = Process.GetProcessById((int)pid);
return p.ProcessName;
}
catch
{
return null;
}
}
public static Process? GetProcessByHandle(nint hWnd)
{
try
{
_ = User32.GetWindowThreadProcessId(hWnd, out var pid);
var p = Process.GetProcessById((int)pid);
return p;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return null;
}
}
/// <summary>
/// 获取窗口位置
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
public static RECT GetWindowRect(nint hWnd)
{
// User32.GetWindowRect(hWnd, out var windowRect);
DwmApi.DwmGetWindowAttribute<RECT>(hWnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out var windowRect);
return windowRect;
}
/// <summary>
/// 游戏本身分辨率获取
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
public static RECT GetGameScreenRect(nint hWnd)
{
User32.GetClientRect(hWnd, out var clientRect);
return clientRect;
}
/// <summary>
/// GetWindowRect or GetGameScreenRect
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
public static RECT GetCaptureRect(nint hWnd)
{
var windowRect = GetWindowRect(hWnd);
var gameScreenRect = GetGameScreenRect(hWnd);
var left = windowRect.Left;
var top = windowRect.Top + windowRect.Height - gameScreenRect.Height;
var right = left + gameScreenRect.Width;
var bottom = top + gameScreenRect.Height;
return new RECT(left, top, right, bottom);
}
public static void ActivateWindow(nint hWnd)
{
User32.ShowWindow(hWnd, ShowWindowCommand.SW_RESTORE);
User32.SetForegroundWindow(hWnd);
}
public static void ActivateWindow()
{
if (!TaskContext.Instance().IsInitialized)
{
throw new Exception("请先启动BetterGI");
}
ActivateWindow(TaskContext.Instance().GameHandle);
}
public static void RestartApplication(string[] newArgs)
{
// 获取当前程序路径
string exePath = Process.GetCurrentProcess().MainModule.FileName;
// 构建参数字符串
string arguments = string.Join(" ", [..newArgs,"--no-single"]);
// 启动新进程
Process.Start(new ProcessStartInfo
{
FileName = exePath,
Arguments = arguments,
UseShellExecute = false
});
// 关闭当前程序
Environment.Exit(0);
}
public static void FocusWindow(nint hWnd)
{
if (User32.IsWindow(hWnd))
{
_ = User32.SendMessage(hWnd, User32.WindowMessage.WM_SYSCOMMAND, User32.SysCommand.SC_RESTORE, 0);
_ = User32.SetForegroundWindow(hWnd);
while (User32.IsIconic(hWnd))
{
continue;
}
_ = User32.BringWindowToTop(hWnd);
_ = User32.SetActiveWindow(hWnd);
}
}
public static void MinimizeAndActivateWindow(nint hWnd)
{
HWND hShell = User32.FindWindow("Shell_TrayWnd", null);
User32.SendMessage(hShell, 0x0111, (IntPtr)419, IntPtr.Zero);
Thread.Sleep(500);
FocusWindow(hWnd);
}
public static void RestoreWindow(nint hWnd)
{
if (User32.IsWindow(hWnd))
{
_ = User32.SendMessage(hWnd, User32.WindowMessage.WM_SYSCOMMAND, User32.SysCommand.SC_RESTORE, 0);
_ = User32.SetForegroundWindow(hWnd);
if (User32.IsIconic(hWnd))
{
_ = User32.ShowWindow(hWnd, ShowWindowCommand.SW_RESTORE);
}
_ = User32.BringWindowToTop(hWnd);
_ = User32.SetActiveWindow(hWnd);
}
}
public static bool IsFullScreenMode(IntPtr hWnd)
{
if (hWnd == IntPtr.Zero)
{
return false;
}
var exStyle = User32.GetWindowLong(hWnd, User32.WindowLongFlags.GWL_EXSTYLE);
return (exStyle & (int)User32.WindowStylesEx.WS_EX_TOPMOST) != 0;
}
// private static void StartFromLauncher(string path)
// {
// // 通过launcher启动
// var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
// Thread.Sleep(1000);
// // 获取launcher窗口句柄
// var hWnd = FindHandleByProcessName("launcher");
// var rect = GetWindowRect(hWnd);
// var dpiScale = Helpers.DpiHelper.ScaleY;
// // 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
// Thread.Sleep(1000);
// Simulation.MouseEvent.Click((int)((float)rect.right * dpiScale) - (rect.Width / 5), (int)((float)rect.bottom * dpiScale) - (rect.Height / 8));
// }
//
// private static void StartCloudYaunShen(string path)
// {
// // 通过launcher启动
// var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
// Thread.Sleep(10000);
// // 获取launcher窗口句柄
// var hWnd = FindHandleByProcessName("Genshin Impact Cloud Game");
// var rect = GetWindowRect(hWnd);
// var dpiScale = Helpers.DpiHelper.ScaleY;
// // 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
// Simulation.MouseEvent.Click(rect.right - (rect.Width / 6), rect.bottom - (rect.Height / 13 * 3));
// // TODO点完之后有个15s的倒计时好像不处理也没什么问题直接睡个20s吧
// Thread.Sleep(20000);
// }
public static void CloseGame()
{
try
{
// 尝试通过进程名称查找原神进程
var processes = Process.GetProcessesByName("YuanShen")
.Concat(Process.GetProcessesByName("GenshinImpact"))
.Concat(Process.GetProcessesByName("Genshin Impact Cloud Game"))
.ToArray();
if (processes.Length > 0)
{
foreach (var process in processes)
{
try
{
// 尝试正常关闭进程
process.CloseMainWindow();
// 给进程一些时间来响应关闭请求
if (!process.WaitForExit(5000))
{
// 如果进程没有在5秒内关闭则强制终止它
process.Kill();
}
}
catch (Exception ex)
{
Debug.WriteLine($"关闭游戏进程时出错: {ex.Message}");
}
finally
{
process.Dispose();
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"CloseGame方法执行出错: {ex.Message}");
}
}
public static void Shutdown()
{
try
{
// 使用Windows API安全关闭系统
// 这里使用的是标准的Windows关机命令需要适当的权限
Process.Start("shutdown", "/s /t 60 /c \"系统将在60秒后关闭请保存您的工作。\"");
}
catch (Exception ex)
{
Debug.WriteLine($"Shutdown方法执行出错: {ex.Message}");
}
}
}