18using System.Collections.Generic;
21using System.Runtime.InteropServices;
23using System.Threading;
24using System.Threading.Tasks;
25using System.Windows.Input;
34 internal class HardwareHelper
38 static byte scanCode = 0;
41 private static readonly Random _random =
new Random();
50 internal static int GetTypingDelay(
int ceilingMs)
55 int floorMs = Math.Min(25, ceilingMs);
56 return _random.Next(floorMs, ceilingMs + 1);
65 [DllImport(
"user32.dll")]
66 public static extern short VkKeyScan(
char ch);
76 [DllImport(
"user32.dll")]
77 public static extern void keybd_event(
byte bVk,
byte bScan, uint dwFlags, uint dwExtraInfo);
86 [DllImport(
"user32.dll", EntryPoint =
"SetCursorPos")]
87 [
return: MarshalAs(UnmanagedType.Bool)]
88 private static extern bool SetCursorPos(
int x,
int y);
95 [DllImport(
"user32.dll")]
96 public static extern bool GetCursorPos(out Point p);
107 [DllImport(
"user32.dll")]
108 static extern void mouse_event(
int dwFlags,
int dx,
int dy,
109 int dwData,
int dwExtraInfo);
115 public enum MouseEventFlags
117 LEFTDOWN = 0x00000002,
119 MIDDLEDOWN = 0x00000020,
120 MIDDLEUP = 0x00000040,
122 ABSOLUTE = 0x00008000,
123 RIGHTDOWN = 0x00000008,
133 public static void MouseDown(
int x,
int y, ClickType clickType)
136 if (ClickType.LeftClick == clickType)
137 mouse_event((
int)(MouseEventFlags.LEFTDOWN), x, y, 0, 0);
138 else if (ClickType.MiddleClick == clickType)
139 mouse_event((
int)(MouseEventFlags.MIDDLEDOWN), x, y, 0, 0);
140 else if (ClickType.RightClick == clickType)
141 mouse_event((
int)(MouseEventFlags.RIGHTDOWN), x, y, 0, 0);
143 GPAL.PublishSimpleEvent(GPALEventType.ERROR, $
"Unknown mouse down clicktype [{clickType}]",
null, GPALObjectType.None);
151 public static void MouseUp(
int x,
int y, ClickType clickType)
154 if (ClickType.LeftClick == clickType)
155 mouse_event((
int)(MouseEventFlags.LEFTUP), x, y, 0, 0);
156 else if (ClickType.MiddleClick == clickType)
157 mouse_event((
int)(MouseEventFlags.MIDDLEUP), x, y, 0, 0);
158 else if (ClickType.RightClick == clickType)
159 mouse_event((
int)(MouseEventFlags.RIGHTUP), x, y, 0, 0);
161 GPAL.PublishSimpleEvent(GPALEventType.ERROR, $
"Unknown mouse down clicktype [{clickType}]",
null, GPALObjectType.None);
169 public static void MiddleClick(
int x,
int y)
174 mouse_event((
int)(MouseEventFlags.MIDDLEDOWN), x, y, 0, 0);
176 mouse_event((
int)(MouseEventFlags.MIDDLEUP), x, y, 0, 0);
183 public static void LeftClick(
int x,
int y)
188 mouse_event((
int)(MouseEventFlags.LEFTDOWN), x, y, 0, 0);
190 mouse_event((
int)(MouseEventFlags.LEFTUP), x, y, 0, 0);
197 public static void LeftDoubleClick(
int x,
int y)
200 mouse_event((
int)(MouseEventFlags.LEFTDOWN | MouseEventFlags.LEFTUP), x, y, 0, 0);
202 mouse_event((
int)(MouseEventFlags.LEFTDOWN | MouseEventFlags.LEFTUP), x, y, 0, 0);
209 public static void RightClick(
int x,
int y)
213 mouse_event((
int)MouseEventFlags.RIGHTDOWN, x, y, 0, 0);
216 mouse_event((
int)MouseEventFlags.RIGHTUP, x, y, 0, 0);
224 public static void MoveMouse(
int x,
int y)
236 internal static void PressModifierKey(ModifierKeys modifierKeys,
bool dontPubolish =
false)
238 if (
false == dontPubolish)
239 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Pressed [{Browser.Browser.GetModifierKeys(modifierKeys)}]", modifierKeys, GPALObjectType.Other);
241 if (0 != (ModifierKeys.Control & modifierKeys))
243 keybd_event(GPAL.VK_CONTROL_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
244 keybd_event(GPAL.VK_CONTROL_RIGHT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
247 if (0 != (ModifierKeys.Shift & modifierKeys))
249 keybd_event(GPAL.VK_SHIFT_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
250 keybd_event(GPAL.VK_SHIFT_RIGHT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
253 if (0 != (ModifierKeys.Alt & modifierKeys))
255 keybd_event(GPAL.VK_LMENU, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
256 keybd_event(GPAL.VK_RMENU, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
259 if (0 != (ModifierKeys.Windows & modifierKeys))
261 keybd_event(GPAL.VK_LWIN, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
262 keybd_event(GPAL.VK_RWIN, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
265 if (0 != (ModifierKeys.Application & modifierKeys))
267 keybd_event(GPAL.VK_APPS, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
270 if (0 != (ModifierKeys.ScrollLock & modifierKeys))
272 keybd_event(GPAL.VK_SCROLL, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
281 internal static void ReleaseModifierKeys(ModifierKeys modifierKeys,
bool dontPublish =
false)
283 if (
false == dontPublish)
284 GPAL.PublishSimpleEvent(GPALEventType.INFO, $
"Released [{Browser.Browser.GetModifierKeys(modifierKeys)}]", modifierKeys, GPALObjectType.Other);
286 if (0 != (ModifierKeys.Alt & modifierKeys))
288 keybd_event(GPAL.VK_RMENU, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
290 keybd_event(GPAL.VK_LMENU, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
293 if (0 != (ModifierKeys.Control & modifierKeys))
295 keybd_event(GPAL.VK_CONTROL_RIGHT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
297 keybd_event(GPAL.VK_CONTROL_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
300 if (0 != (ModifierKeys.Shift & modifierKeys))
302 keybd_event(GPAL.VK_SHIFT_RIGHT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
304 keybd_event(GPAL.VK_SHIFT_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
307 if (0 != (ModifierKeys.Windows & modifierKeys))
309 keybd_event(GPAL.VK_RWIN, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
311 keybd_event(GPAL.VK_LWIN, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
314 if (0 != (ModifierKeys.Application & modifierKeys))
316 keybd_event(GPAL.VK_APPS, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
319 if (0 != (ModifierKeys.ScrollLock & modifierKeys))
321 keybd_event(GPAL.VK_SCROLL, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
330 public static bool SendKey(
byte keyToSend, ModifierKeys modifierKeys = ModifierKeys.NONE)
333 if (ModifierKeys.NONE != modifierKeys)
334 PressModifierKey(modifierKeys);
338 keybd_event(keyToSend, scanCode, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
339 Thread.Sleep(_random.Next(10, 30));
340 keybd_event(keyToSend, scanCode, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
344 if (ModifierKeys.NONE != modifierKeys)
345 ReleaseModifierKeys(modifierKeys);
356 public static void SendString(
string stringToSend,
int delayMs = 0)
359 foreach (
char c
in stringToSend)
361 if (
false == first && 0 < delayMs)
362 Thread.Sleep(GetTypingDelay(delayMs));
363 SendChar(c, ModifierKeys.NONE,
true);
373 public static void SendChar(
char charToSend, ModifierKeys modifierKeys = ModifierKeys.NONE,
bool dontPublish =
false)
375 short vkKeyScan = HardwareHelper.VkKeyScan(charToSend);
376 System.Windows.Forms.Keys vkCode = (System.Windows.Forms.Keys)(vkKeyScan & 0xff);
378 var shift = (vkKeyScan & 0x100) > 0;
384 keybd_event(GPAL.VK_SHIFT_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
387 if (ModifierKeys.NONE != modifierKeys)
388 PressModifierKey(modifierKeys, dontPublish);
392 keybd_event((
byte)vkCode, (
byte)vkKeyScan, GPAL.KEYEVENTF_EXTENDEDKEY | 0, 0);
393 Thread.Sleep(_random.Next(10, 30));
394 keybd_event((
byte)vkCode, (
byte)vkKeyScan, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
398 if (ModifierKeys.NONE != modifierKeys)
399 ReleaseModifierKeys(modifierKeys, dontPublish);
403 keybd_event(GPAL.VK_SHIFT_LEFT, 0, GPAL.KEYEVENTF_EXTENDEDKEY | GPAL.KEYEVENTF_KEYUP, 0);
414 public static void HardwareClick(
int x,
int y, ClickType clickType)
418 case ClickType.LeftClick:
421 case ClickType.LeftDoubleClick:
422 LeftDoubleClick(x, y);
424 case ClickType.MiddleClick:
427 case ClickType.RightClick:
436 #region Improved WindMouse - Less Bounce, More Natural (C# 8 Compatible)
446 public static void MoveMouse(
int targetX,
int targetY,
int randomnessX = 4,
int randomnessY = 4,
double speed = 1.0)
448 Point current =
new Point();
449 GetCursorPos(out current);
451 Random rnd =
new Random();
454 targetX = Math.Max(0, targetX + rnd.Next(-randomnessX, randomnessX + 1));
455 targetY = Math.Max(0, targetY + rnd.Next(-randomnessY, randomnessY + 1));
457 double adjustedSpeed = Math.Max(0.4, speed);
460 current.X, current.Y,
464 minWait: 7.0 / adjustedSpeed,
465 maxWait: 16.0 / adjustedSpeed,
466 maxStep: 38.0 * adjustedSpeed,
484 private static void ImprovedWindMouse(
double xs,
double ys,
double xe,
double ye,
485 double gravity,
double wind,
double minWait,
double maxWait,
486 double maxStep,
double targetArea)
488 double dist, windX = 0, windY = 0, veloX = 0, veloY = 0;
489 int oldX, oldY, newX = (int)Math.Round(xs), newY = (int)Math.Round(ys);
491 double waitDiff = maxWait - minWait;
492 double sqrt2 = Math.Sqrt(2.0);
493 double sqrt3 = Math.Sqrt(3.0);
494 double sqrt5 = Math.Sqrt(5.0);
496 Random rnd =
new Random();
498 dist = Hypot(xe - xs, ye - ys);
502 wind = Math.Min(wind, dist * 0.8);
504 if (dist >= targetArea)
507 windX = windX / sqrt3 + (rnd.NextDouble() * wind * 2 - wind) / sqrt5;
508 windY = windY / sqrt3 + (rnd.NextDouble() * wind * 2 - wind) / sqrt5;
513 windX = windX / sqrt2 * 0.75;
514 windY = windY / sqrt2 * 0.75;
517 maxStep = 3.0 + rnd.NextDouble() * 2;
519 maxStep = maxStep / sqrt5 * 0.85;
523 double pull = gravity * (dist > 1.0 ? 1.0 : dist);
524 veloX += windX + pull * (xe - xs) / dist;
525 veloY += windY + pull * (ye - ys) / dist;
528 double mag = Hypot(veloX, veloY);
531 double stepSize = maxStep * 0.55 + rnd.NextDouble() * (maxStep * 0.45);
532 veloX = (veloX / mag) * stepSize;
533 veloY = (veloY / mag) * stepSize;
537 if (dist < targetArea * 0.6)
543 oldX = (int)Math.Round(xs);
544 oldY = (int)Math.Round(ys);
547 dist = Hypot(xe - xs, ye - ys);
549 newX = (int)Math.Round(xs);
550 newY = (int)Math.Round(ys);
552 if (oldX != newX || oldY != newY)
553 SetCursorPos(newX, newY);
555 double step = Hypot(xs - oldX, ys - oldY);
556 int wait = (int)Math.Round(waitDiff * (step / maxStep) + minWait);
557 Thread.Sleep(Math.Max(1, wait));
561 int finalX = (int)Math.Round(xe);
562 int finalY = (int)Math.Round(ye);
564 if (Math.Abs(newX - finalX) > 1 || Math.Abs(newY - finalY) > 1)
566 while (Math.Abs(newX - finalX) > 0 || Math.Abs(newY - finalY) > 0)
568 int dx = Math.Sign(finalX - newX) * rnd.Next(1, 3);
569 int dy = Math.Sign(finalY - newY) * rnd.Next(1, 3);
571 newX = Math.Max(finalX - 3, Math.Min(finalX + 3, newX + dx));
572 newY = Math.Max(finalY - 3, Math.Min(finalY + 3, newY + dy));
574 SetCursorPos(newX, newY);
575 Thread.Sleep(rnd.Next(8, 18));
579 SetCursorPos(finalX, finalY);
588 private static double Hypot(
double dx,
double dy)
590 return Math.Sqrt(dx * dx + dy * dy);
594 #region VKCODE to ASCII
598 internal static class KeyboardUtils
610 [DllImport(
"user32.dll")]
611 private static extern int ToAscii(uint uVirtKey, uint uScanCode,
byte[] lpKeyState,
612 [Out] StringBuilder lpChar, uint uFlags);
619 [DllImport(
"user32.dll")]
620 private static extern int GetKeyboardState(
byte[] lpKeyState);
628 [DllImport(
"user32.dll")]
629 private static extern uint MapVirtualKey(uint uCode, uint uMapType);
636 internal static string VkCodeToAscii(uint vkCode)
639 uint scanCode = MapVirtualKey(vkCode, 0);
642 byte[] keyState =
new byte[256];
643 if (GetKeyboardState(keyState) == 0)
652 StringBuilder charBuffer =
new StringBuilder(2);
655 int result = ToAscii(vkCode, scanCode, keyState, charBuffer, 0);
660 return charBuffer[0].ToString();
662 else if (result == 2)
665 return charBuffer[0].ToString();
674 #endregion VKCODE to ASCII