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; } }