190 lines
6.6 KiB
C#
190 lines
6.6 KiB
C#
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());
|
||
}
|
||
}
|