using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; internal static class NativeMethods { internal const int WM_HOTKEY = 0x0312; internal const int HOTKEY_ID = 1; internal const uint KEYEVENTF_KEYUP = 0x0002; internal const byte VK_CONTROL = 0x11; internal const uint MOUSEEVENTF_LEFTDOWN = 0x0002; internal const uint MOUSEEVENTF_LEFTUP = 0x0004; [DllImport("user32.dll")] internal static extern bool RegisterHotKey(IntPtr hWnd, int id, uint modifiers, uint key); [DllImport("user32.dll")] internal static extern bool UnregisterHotKey(IntPtr hWnd, int id); [DllImport("user32.dll")] internal static extern void keybd_event(byte virtualKey, byte scanCode, uint flags, UIntPtr extraInfo); [DllImport("user32.dll")] internal static extern void mouse_event(uint flags, uint dx, uint dy, uint data, UIntPtr extraInfo); } internal sealed class HelperForm : Form { private const int DwellMilliseconds = 100; private const int MovementThreshold = 6; private readonly Timer timer; private readonly Button toggleButton; private readonly Label statusLabel; private Point anchor; private DateTime stableSince; private DateTime cooldownUntil; private bool enabled; private bool clickLocked; internal HelperForm() { Text = "PoE2 Accessibility Click Helper"; ClientSize = new Size(500, 250); MinimumSize = new Size(500, 250); StartPosition = FormStartPosition.CenterScreen; TopMost = true; BackColor = Color.FromArgb(15, 15, 24); ForeColor = Color.White; Font = new Font("Segoe UI", 12F); var title = new Label { Text = "Помощник Ctrl + Left Click", Font = new Font("Segoe UI", 18F, FontStyle.Bold), ForeColor = Color.FromArgb(220, 190, 100), AutoSize = false, TextAlign = ContentAlignment.MiddleCenter, Bounds = new Rectangle(15, 15, 470, 45) }; toggleButton = new Button { Text = "ВКЛЮЧИТЬ (F8)", Font = new Font("Segoe UI", 18F, FontStyle.Bold), BackColor = Color.FromArgb(40, 110, 65), ForeColor = Color.White, FlatStyle = FlatStyle.Flat, Bounds = new Rectangle(60, 70, 380, 70) }; toggleButton.Click += delegate { Toggle(); }; statusLabel = new Label { Text = "ВЫКЛЮЧЕНО — кликов не будет", Font = new Font("Segoe UI", 12F, FontStyle.Bold), ForeColor = Color.FromArgb(255, 100, 100), AutoSize = false, TextAlign = ContentAlignment.MiddleCenter, Bounds = new Rectangle(20, 148, 460, 35) }; var help = new Label { Text = "Наведи курсор и удерживай 0,1с. Один Ctrl+Click, затем сдвинь курсор.\nF8 — мгновенно включить или выключить.", ForeColor = Color.FromArgb(190, 190, 200), AutoSize = false, TextAlign = ContentAlignment.MiddleCenter, Bounds = new Rectangle(20, 185, 460, 50) }; Controls.Add(title); Controls.Add(toggleButton); Controls.Add(statusLabel); Controls.Add(help); timer = new Timer { Interval = 20 }; timer.Tick += OnTimerTick; timer.Start(); anchor = Cursor.Position; stableSince = DateTime.UtcNow; } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); NativeMethods.RegisterHotKey(Handle, NativeMethods.HOTKEY_ID, 0, (uint)Keys.F8); } protected override void OnHandleDestroyed(EventArgs e) { NativeMethods.UnregisterHotKey(Handle, NativeMethods.HOTKEY_ID); base.OnHandleDestroyed(e); } protected override void WndProc(ref Message message) { if (message.Msg == NativeMethods.WM_HOTKEY && message.WParam.ToInt32() == NativeMethods.HOTKEY_ID) { Toggle(); return; } base.WndProc(ref message); } private void Toggle() { enabled = !enabled; clickLocked = false; cooldownUntil = DateTime.MinValue; anchor = Cursor.Position; stableSince = DateTime.UtcNow; toggleButton.Text = enabled ? "ВЫКЛЮЧИТЬ (F8)" : "ВКЛЮЧИТЬ (F8)"; toggleButton.BackColor = enabled ? Color.FromArgb(135, 45, 45) : Color.FromArgb(40, 110, 65); statusLabel.Text = enabled ? "ВКЛЮЧЕНО — удержание 0,1с" : "ВЫКЛЮЧЕНО — кликов не будет"; statusLabel.ForeColor = enabled ? Color.FromArgb(90, 230, 125) : Color.FromArgb(255, 100, 100); } private void OnTimerTick(object sender, EventArgs e) { if (!enabled) return; DateTime now = DateTime.UtcNow; Point current = Cursor.Position; int dx = current.X - anchor.X; int dy = current.Y - anchor.Y; bool moved = (dx * dx + dy * dy) >= MovementThreshold * MovementThreshold; if (moved) { anchor = current; stableSince = now; } if (clickLocked) { if (now < cooldownUntil) { double remaining = Math.Ceiling((cooldownUntil - now).TotalMilliseconds / 100.0) / 10.0; statusLabel.Text = "Пауза " + remaining.ToString("0.0") + "с"; return; } clickLocked = false; stableSince = now; statusLabel.Text = "ВКЛЮЧЕНО — готов к следующему клику"; } if (Bounds.Contains(current)) return; if ((now - stableSince).TotalMilliseconds < DwellMilliseconds) return; clickLocked = true; cooldownUntil = now.AddSeconds(3); PerformControlClick(); statusLabel.Text = "CTRL + CLICK выполнен — пауза 3,0с"; } private static void PerformControlClick() { NativeMethods.keybd_event(NativeMethods.VK_CONTROL, 0, 0, UIntPtr.Zero); NativeMethods.mouse_event(NativeMethods.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, UIntPtr.Zero); NativeMethods.mouse_event(NativeMethods.MOUSEEVENTF_LEFTUP, 0, 0, 0, UIntPtr.Zero); NativeMethods.keybd_event(NativeMethods.VK_CONTROL, 0, NativeMethods.KEYEVENTF_KEYUP, UIntPtr.Zero); } } internal static class Program { [STAThread] private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new HelperForm()); } }