using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using JXHelper.Common;
namespace JXHelper.Platform;
///
/// Thực thi toàn bộ thao tác nhập liệu ngầm không chiếm chuột và phím thật của người chơi.
/// Tuân thủ bất biến kiến trúc: INV-BG-INPUT-NO-HIJACK.
///
public static class BackgroundInput
{
public static event Action? OnInputWarning;
///
/// Gửi phím ngầm qua Win32 Message Queue (ví dụ: F8 dùng Phù, F4 mở Túi đồ).
/// Đóng gói ScanCode chuẩn xác cho DirectX game engine.
///
public static async Task SendKeyAsync(IntPtr hWnd, int vkCode, int holdDurationMs = Constants.DefaultKeyStrokeDelayMs)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd)) return false;
IntPtr lParamDown = NativeMethods.MakeKeyLParam(vkCode, isKeyUp: false);
IntPtr lParamUp = NativeMethods.MakeKeyLParam(vkCode, isKeyUp: true);
bool downOk = NativeMethods.PostMessage(hWnd, Constants.WM_KEYDOWN, (IntPtr)vkCode, lParamDown);
if (!downOk)
{
int err = Marshal.GetLastWin32Error();
if (err == 5)
{
OnInputWarning?.Invoke("[CẢNH BÁO UIPI] Game đang chạy quyền Administrator. JXHelper cần chạy 'Run as administrator' để gửi lệnh!");
}
return false;
}
await Task.Delay(Math.Max(10, holdDurationMs));
NativeMethods.PostMessage(hWnd, Constants.WM_KEYUP, (IntPtr)vkCode, lParamUp);
return true;
}
///
/// Gửi ký tự ngầm (WM_CHAR) - Cần thiết cho việc chọn menu hội thoại trong JX (ví dụ: gõ '1' để chọn dòng 1).
///
public static async Task SendCharAsync(IntPtr hWnd, char c)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd)) return false;
// Kingsoft Sword3 engine checks ((lParam >> 16) & 0xFF) for key/char verification
short vkScan = NativeMethods.VkKeyScan(c);
int vk = vkScan & 0xFF;
uint sc = NativeMethods.MapVirtualKey((uint)vk, NativeMethods.MAPVK_VK_TO_VSC);
IntPtr lParam = sc > 0 ? (IntPtr)(long)(1 | (sc << 16)) : (IntPtr)(((int)c << 16) | 1);
bool ok = NativeMethods.PostMessage(hWnd, Constants.WM_CHAR, (IntPtr)c, lParam);
await Task.Delay(35);
return ok;
}
///
/// Click chuột phải ngầm tại tọa độ Client (X, Y).
/// Con trỏ chuột thật của người dùng trên Desktop hoàn toàn không bị dịch chuyển.
///
public static async Task SendRightClickAsync(IntPtr hWnd, int clientX, int clientY, int clickDurationMs = Constants.DefaultMouseClickDelayMs)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd)) return false;
IntPtr lParam = NativeMethods.MakeLParam(clientX, clientY);
// 1. Giả lập chuột lướt tới ô item trong game (kích hoạt hover trạng thái)
NativeMethods.PostMessage(hWnd, Constants.WM_MOUSEMOVE, IntPtr.Zero, lParam);
await Task.Delay(35);
// 2. Nhấn chuột phải ngầm
bool downOk = NativeMethods.PostMessage(hWnd, Constants.WM_RBUTTONDOWN, Constants.MK_RBUTTON, lParam);
if (!downOk)
{
int err = Marshal.GetLastWin32Error();
if (err == 5)
{
OnInputWarning?.Invoke("[CẢNH BÁO UIPI] Game đang chạy quyền Administrator. JXHelper cần chạy 'Run as administrator'!");
}
return false;
}
await Task.Delay(Math.Max(10, clickDurationMs));
// 3. Nhả chuột phải ngầm
NativeMethods.PostMessage(hWnd, Constants.WM_RBUTTONUP, IntPtr.Zero, lParam);
return true;
}
///
/// Click chuột trái ngầm tại tọa độ Client (X, Y).
///
public static async Task SendLeftClickAsync(IntPtr hWnd, int clientX, int clientY, int clickDurationMs = Constants.DefaultMouseClickDelayMs)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd)) return false;
IntPtr lParam = NativeMethods.MakeLParam(clientX, clientY);
NativeMethods.PostMessage(hWnd, Constants.WM_MOUSEMOVE, IntPtr.Zero, lParam);
await Task.Delay(35);
bool downOk = NativeMethods.PostMessage(hWnd, Constants.WM_LBUTTONDOWN, Constants.MK_LBUTTON, lParam);
if (!downOk) return false;
await Task.Delay(Math.Max(10, clickDurationMs));
NativeMethods.PostMessage(hWnd, Constants.WM_LBUTTONUP, IntPtr.Zero, lParam);
return true;
}
///
/// Double click chuột trái ngầm tại tọa độ Client (X, Y).
///
public static async Task SendLeftDoubleClickAsync(IntPtr hWnd, int clientX, int clientY)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd)) return false;
IntPtr lParam = NativeMethods.MakeLParam(clientX, clientY);
NativeMethods.PostMessage(hWnd, Constants.WM_MOUSEMOVE, IntPtr.Zero, lParam);
await Task.Delay(30);
NativeMethods.PostMessage(hWnd, Constants.WM_LBUTTONDOWN, Constants.MK_LBUTTON, lParam);
await Task.Delay(40);
NativeMethods.PostMessage(hWnd, Constants.WM_LBUTTONUP, IntPtr.Zero, lParam);
await Task.Delay(50);
NativeMethods.PostMessage(hWnd, 0x0203 /* WM_LBUTTONDBLCLK */, Constants.MK_LBUTTON, lParam);
await Task.Delay(40);
NativeMethods.PostMessage(hWnd, Constants.WM_LBUTTONUP, IntPtr.Zero, lParam);
return true;
}
///
/// Gửi một chuỗi văn bản ngầm (ví dụ: tài khoản, mật khẩu) qua WM_CHAR.
///
public static async Task SendTextAsync(IntPtr hWnd, string text, int charDelayMs = 25)
{
if (hWnd == IntPtr.Zero || !NativeMethods.IsWindow(hWnd) || string.IsNullOrEmpty(text)) return false;
foreach (char c in text)
{
await SendCharAsync(hWnd, c);
if (charDelayMs > 0) await Task.Delay(charDelayMs);
}
return true;
}
}