SpyAgent.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using System.Runtime.InteropServices;
  2. using Timer = System.Windows.Forms.Timer;
  3. namespace DummyCursor.Spy
  4. {
  5. public class SpyAgent
  6. {
  7. private readonly Action<SpiedWindow> _selectedAction;
  8. private readonly Timer _timer;
  9. private SpyAgentLocator _locator;
  10. public SpyAgent(Action<SpiedWindow> selectedAction)
  11. {
  12. _selectedAction = selectedAction;
  13. _timer = new Timer { Interval = 25, Enabled = false };
  14. _timer.Tick += OnTimerTicked;
  15. BeginSpying();
  16. }
  17. private void OnTimerTicked(object sender, EventArgs e)
  18. {
  19. ShowLocator();
  20. if (0 == (Control.MouseButtons & MouseButtons.Left)) return;
  21. EndSpying();
  22. _selectedAction(GetHoveredWindow());
  23. }
  24. private void ShowLocator()
  25. {
  26. var window = GetHoveredWindow();
  27. if (window.Handle == IntPtr.Zero)
  28. {
  29. _locator.Hide();
  30. return;
  31. }
  32. _locator.Location = window.Area.Location;
  33. _locator.Size = window.Area.Size;
  34. _locator.TopLevel = true;
  35. _locator.TopMost = true;
  36. _locator.Show();
  37. }
  38. public void BeginSpying()
  39. {
  40. if (_locator != null)
  41. {
  42. _locator.Close();
  43. _locator.Dispose();
  44. }
  45. _locator = new SpyAgentLocator();
  46. MakePassThrough(_locator.Handle);
  47. _timer.Enabled = true;
  48. }
  49. public void EndSpying()
  50. {
  51. _timer.Enabled = false;
  52. _locator?.Close();
  53. _locator?.Dispose();
  54. _locator = null;
  55. }
  56. private class SpyAgentLocator : Form
  57. {
  58. public SpyAgentLocator()
  59. {
  60. FormBorderStyle = FormBorderStyle.None;
  61. BackColor = Color.OrangeRed;
  62. Opacity = 0.25;
  63. TopLevel = true;
  64. TopMost = true;
  65. }
  66. }
  67. #region Under the Hood
  68. private const int GWL_EXSTYLE = -20;
  69. private const int WS_EX_TRANSPARENT = 0x20;
  70. [DllImport("user32.dll")]
  71. private static extern IntPtr WindowFromPoint(POINT point);
  72. [DllImport("user32.dll")]
  73. private static extern IntPtr ChildWindowFromPoint(IntPtr hWndParent, POINT point);
  74. [DllImport("user32.dll", SetLastError = true)]
  75. private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
  76. [DllImport("user32.dll", SetLastError = true)]
  77. private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
  78. public static SpiedWindow GetHoveredWindow()
  79. {
  80. var handle = WindowFromPoint(Cursor.Position);
  81. return new SpiedWindow(handle);
  82. }
  83. private static void MakePassThrough(IntPtr handle)
  84. {
  85. var exstyle = GetWindowLong(handle, GWL_EXSTYLE);
  86. exstyle |= WS_EX_TRANSPARENT;
  87. SetWindowLong(handle, GWL_EXSTYLE, exstyle);
  88. }
  89. [StructLayout(LayoutKind.Sequential)]
  90. private struct POINT
  91. {
  92. public readonly int X;
  93. public readonly int Y;
  94. public POINT(int x, int y)
  95. {
  96. X = x;
  97. Y = y;
  98. }
  99. public POINT(Point pt)
  100. : this(pt.X, pt.Y)
  101. {
  102. }
  103. public static implicit operator Point(POINT p)
  104. {
  105. return new(p.X, p.Y);
  106. }
  107. public static implicit operator POINT(Point p)
  108. {
  109. return new(p.X, p.Y);
  110. }
  111. }
  112. #endregion Under the Hood
  113. }
  114. }