Advertisement
Guest User

Untitled

a guest
May 26th, 2019
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.20 KB | None | 0 0
  1. using System;
  2. using System.ComponentModel;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Security;
  7. using System.Security.Permissions;
  8. using System.Windows.Input;
  9.  
  10. namespace Demo
  11. {
  12.  
  13. /// <summary>
  14. /// Native methods
  15. /// </summary>
  16. internal static class NativeMethods
  17. {
  18. //User32 wrappers cover API's used for Mouse input
  19. #region User32
  20. // Two special bitmasks we define to be able to grab
  21. // shift and character information out of a VKey.
  22. internal const int VKeyShiftMask = 0x0100;
  23. internal const int VKeyCharMask = 0x00FF;
  24.  
  25. // Various Win32 constants
  26. internal const int KeyeventfExtendedkey = 0x0001;
  27. internal const int KeyeventfKeyup = 0x0002;
  28. internal const int KeyeventfScancode = 0x0008;
  29.  
  30. internal const int MouseeventfVirtualdesk = 0x4000;
  31.  
  32. internal const int SMXvirtualscreen = 76;
  33. internal const int SMYvirtualscreen = 77;
  34. internal const int SMCxvirtualscreen = 78;
  35. internal const int SMCyvirtualscreen = 79;
  36.  
  37. internal const int XButton1 = 0x0001;
  38. internal const int XButton2 = 0x0002;
  39. internal const int WheelDelta = 120;
  40.  
  41. internal const int InputMouse = 0;
  42. internal const int InputKeyboard = 1;
  43.  
  44. // Various Win32 data structures
  45. [StructLayout(LayoutKind.Sequential)]
  46. internal struct INPUT
  47. {
  48. internal int type;
  49. internal INPUTUNION union;
  50. };
  51.  
  52. [StructLayout(LayoutKind.Explicit)]
  53. internal struct INPUTUNION
  54. {
  55. [FieldOffset(0)]
  56. internal MOUSEINPUT mouseInput;
  57. [FieldOffset(0)]
  58. internal KEYBDINPUT keyboardInput;
  59. };
  60.  
  61. [StructLayout(LayoutKind.Sequential)]
  62. internal struct MOUSEINPUT
  63. {
  64. internal int dx;
  65. internal int dy;
  66. internal int mouseData;
  67. internal int dwFlags;
  68. internal int time;
  69. internal IntPtr dwExtraInfo;
  70. };
  71.  
  72. [StructLayout(LayoutKind.Sequential)]
  73. internal struct KEYBDINPUT
  74. {
  75. internal short wVk;
  76. internal short wScan;
  77. internal int dwFlags;
  78. internal int time;
  79. internal IntPtr dwExtraInfo;
  80. };
  81.  
  82. [Flags]
  83. internal enum SendMouseInputFlags
  84. {
  85. Move = 0x0001,
  86. LeftDown = 0x0002,
  87. LeftUp = 0x0004,
  88. RightDown = 0x0008,
  89. RightUp = 0x0010,
  90. MiddleDown = 0x0020,
  91. MiddleUp = 0x0040,
  92. XDown = 0x0080,
  93. XUp = 0x0100,
  94. Wheel = 0x0800,
  95. Absolute = 0x8000,
  96. };
  97.  
  98. // Importing various Win32 APIs that we need for input
  99. [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
  100. internal static extern int GetSystemMetrics(int nIndex);
  101.  
  102. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  103. internal static extern int MapVirtualKey(int nVirtKey, int nMapType);
  104.  
  105. [DllImport("user32.dll", SetLastError = true)]
  106. internal static extern int SendInput(int nInputs, ref INPUT mi, int cbSize);
  107.  
  108. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  109. internal static extern short VkKeyScan(char ch);
  110.  
  111. #endregion
  112. }
  113.  
  114.  
  115. /// <summary>
  116. /// Exposes a simple interface to common mouse operations, allowing the user to simulate mouse input.
  117. /// </summary>
  118. /// <example>The following code moves to screen coordinate 100,100 and left clicks.
  119. /// <code>
  120. /**
  121. Mouse.MoveTo(new Point(100, 100));
  122. Mouse.Click(MouseButton.Left);
  123. */
  124. /// </code>
  125. /// </example>
  126. public static class Mouse
  127. {
  128. /// <summary>
  129. /// Clicks a mouse button.
  130. /// </summary>
  131. /// <param name="mouseButton">The mouse button to click.</param>
  132. public static void Click(MouseButton mouseButton)
  133. {
  134. Down(mouseButton);
  135. Up(mouseButton);
  136. }
  137.  
  138. /// <summary>
  139. /// Double-clicks a mouse button.
  140. /// </summary>
  141. /// <param name="mouseButton">The mouse button to click.</param>
  142. public static void DoubleClick(MouseButton mouseButton)
  143. {
  144. Click(mouseButton);
  145. Click(mouseButton);
  146. }
  147.  
  148. /// <summary>
  149. /// Performs a mouse-down operation for a specified mouse button.
  150. /// </summary>
  151. /// <param name="mouseButton">The mouse button to use.</param>
  152. public static void Down(MouseButton mouseButton)
  153. {
  154. switch (mouseButton)
  155. {
  156. case MouseButton.Left:
  157. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.LeftDown);
  158. break;
  159. case MouseButton.Right:
  160. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.RightDown);
  161. break;
  162. case MouseButton.Middle:
  163. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.MiddleDown);
  164. break;
  165. case MouseButton.XButton1:
  166. SendMouseInput(0, 0, NativeMethods.XButton1, NativeMethods.SendMouseInputFlags.XDown);
  167. break;
  168. case MouseButton.XButton2:
  169. SendMouseInput(0, 0, NativeMethods.XButton2, NativeMethods.SendMouseInputFlags.XDown);
  170. break;
  171. default:
  172. throw new InvalidOperationException("Unsupported MouseButton input.");
  173. }
  174. }
  175.  
  176. /// <summary>
  177. /// Moves the mouse pointer to the specified screen coordinates.
  178. /// </summary>
  179. /// <param name="point">The screen coordinates to move to.</param>
  180. public static void MoveTo(Point point)
  181. {
  182. SendMouseInput(point.X, point.Y, 0, NativeMethods.SendMouseInputFlags.Move | NativeMethods.SendMouseInputFlags.Absolute);
  183. }
  184.  
  185. /// <summary>
  186. /// Resets the system mouse to a clean state.
  187. /// </summary>
  188. public static void Reset()
  189. {
  190. MoveTo(new Point(0, 0));
  191.  
  192. if (System.Windows.Input.Mouse.LeftButton == MouseButtonState.Pressed)
  193. {
  194. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.LeftUp);
  195. }
  196.  
  197. if (System.Windows.Input.Mouse.MiddleButton == MouseButtonState.Pressed)
  198. {
  199. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.MiddleUp);
  200. }
  201.  
  202. if (System.Windows.Input.Mouse.RightButton == MouseButtonState.Pressed)
  203. {
  204. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.RightUp);
  205. }
  206.  
  207. if (System.Windows.Input.Mouse.XButton1 == MouseButtonState.Pressed)
  208. {
  209. SendMouseInput(0, 0, NativeMethods.XButton1, NativeMethods.SendMouseInputFlags.XUp);
  210. }
  211.  
  212. if (System.Windows.Input.Mouse.XButton2 == MouseButtonState.Pressed)
  213. {
  214. SendMouseInput(0, 0, NativeMethods.XButton2, NativeMethods.SendMouseInputFlags.XUp);
  215. }
  216. }
  217.  
  218. /// <summary>
  219. /// Simulates scrolling of the mouse wheel up or down.
  220. /// </summary>
  221. /// <param name="lines">The number of lines to scroll. Use positive numbers to scroll up and negative numbers to scroll down.</param>
  222. public static void Scroll(double lines)
  223. {
  224. int amount = (int)(NativeMethods.WheelDelta * lines);
  225.  
  226. SendMouseInput(0, 0, amount, NativeMethods.SendMouseInputFlags.Wheel);
  227. }
  228.  
  229. /// <summary>
  230. /// Performs a mouse-up operation for a specified mouse button.
  231. /// </summary>
  232. /// <param name="mouseButton">The mouse button to use.</param>
  233. public static void Up(MouseButton mouseButton)
  234. {
  235. switch (mouseButton)
  236. {
  237. case MouseButton.Left:
  238. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.LeftUp);
  239. break;
  240. case MouseButton.Right:
  241. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.RightUp);
  242. break;
  243. case MouseButton.Middle:
  244. SendMouseInput(0, 0, 0, NativeMethods.SendMouseInputFlags.MiddleUp);
  245. break;
  246. case MouseButton.XButton1:
  247. SendMouseInput(0, 0, NativeMethods.XButton1, NativeMethods.SendMouseInputFlags.XUp);
  248. break;
  249. case MouseButton.XButton2:
  250. SendMouseInput(0, 0, NativeMethods.XButton2, NativeMethods.SendMouseInputFlags.XUp);
  251. break;
  252. default:
  253. throw new InvalidOperationException("Unsupported MouseButton input.");
  254. }
  255. }
  256.  
  257. /// <summary>
  258. /// Sends mouse input.
  259. /// </summary>
  260. /// <param name="x">x coordinate</param>
  261. /// <param name="y">y coordinate</param>
  262. /// <param name="data">scroll wheel amount</param>
  263. /// <param name="flags">SendMouseInputFlags flags</param>
  264. [PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
  265. private static void SendMouseInput(int x, int y, int data, NativeMethods.SendMouseInputFlags flags)
  266. {
  267. PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted);
  268. permissions.Demand();
  269.  
  270. int intflags = (int)flags;
  271.  
  272. if ((intflags & (int)NativeMethods.SendMouseInputFlags.Absolute) != 0)
  273. {
  274. // Absolute position requires normalized coordinates.
  275. NormalizeCoordinates(ref x, ref y);
  276. intflags |= NativeMethods.MouseeventfVirtualdesk;
  277. }
  278.  
  279. NativeMethods.INPUT mi = new NativeMethods.INPUT();
  280. mi.type = NativeMethods.InputMouse;
  281. mi.union.mouseInput.dx = x;
  282. mi.union.mouseInput.dy = y;
  283. mi.union.mouseInput.mouseData = data;
  284. mi.union.mouseInput.dwFlags = intflags;
  285. mi.union.mouseInput.time = 0;
  286. mi.union.mouseInput.dwExtraInfo = new IntPtr(0);
  287.  
  288. if (NativeMethods.SendInput(1, ref mi, Marshal.SizeOf(mi)) == 0)
  289. {
  290. throw new Win32Exception(Marshal.GetLastWin32Error());
  291. }
  292. }
  293.  
  294. private static void NormalizeCoordinates(ref int x, ref int y)
  295. {
  296. int vScreenWidth = NativeMethods.GetSystemMetrics(NativeMethods.SMCxvirtualscreen);
  297. int vScreenHeight = NativeMethods.GetSystemMetrics(NativeMethods.SMCyvirtualscreen);
  298. int vScreenLeft = NativeMethods.GetSystemMetrics(NativeMethods.SMXvirtualscreen);
  299. int vScreenTop = NativeMethods.GetSystemMetrics(NativeMethods.SMYvirtualscreen);
  300.  
  301. // Absolute input requires that input is in 'normalized' coords - with the entire
  302. // desktop being (0,0)...(65536,65536). Need to convert input x,y coords to this
  303. // first.
  304. //
  305. // In this normalized world, any pixel on the screen corresponds to a block of values
  306. // of normalized coords - eg. on a 1024x768 screen,
  307. // y pixel 0 corresponds to range 0 to 85.333,
  308. // y pixel 1 corresponds to range 85.333 to 170.666,
  309. // y pixel 2 correpsonds to range 170.666 to 256 - and so on.
  310. // Doing basic scaling math - (x-top)*65536/Width - gets us the start of the range.
  311. // However, because int math is used, this can end up being rounded into the wrong
  312. // pixel. For example, if we wanted pixel 1, we'd get 85.333, but that comes out as
  313. // 85 as an int, which falls into pixel 0's range - and that's where the pointer goes.
  314. // To avoid this, we add on half-a-"screen pixel"'s worth of normalized coords - to
  315. // push us into the middle of any given pixel's range - that's the 65536/(Width*2)
  316. // part of the formula. So now pixel 1 maps to 85+42 = 127 - which is comfortably
  317. // in the middle of that pixel's block.
  318. // The key ting here is that unlike points in coordinate geometry, pixels take up
  319. // space, so are often better treated like rectangles - and if you want to target
  320. // a particular pixel, target its rectangle's midpoint, not its edge.
  321. x = ((x - vScreenLeft) * 65536) / vScreenWidth + 65536 / (vScreenWidth * 2);
  322. y = ((y - vScreenTop) * 65536) / vScreenHeight + 65536 / (vScreenHeight * 2);
  323. }
  324. }
  325.  
  326. /// <summary>
  327. /// Exposes a simple interface to common keyboard operations, allowing the user to simulate keyboard input.
  328. /// </summary>
  329. /// <example>
  330. /// The following code types "Hello world" with the specified casing,
  331. /// and then types "hello, capitalized world" which will be in all caps because
  332. /// the left shift key is being held down.
  333. /// <code>
  334. /**
  335. Keyboard.Type("Hello world");
  336. Keyboard.Press(Key.LeftShift);
  337. Keyboard.Type("hello, capitalized world");
  338. Keyboard.Release(Key.LeftShift);
  339. */
  340. /// </code>
  341. /// </example>
  342. public static class Keyboard
  343. {
  344. #region Public Members
  345.  
  346. /// <summary>
  347. /// Presses down a key.
  348. /// </summary>
  349. /// <param name="key">The key to press.</param>
  350. public static void Press(Key key)
  351. {
  352. SendKeyboardInput(key, true);
  353. }
  354.  
  355. /// <summary>
  356. /// Releases a key.
  357. /// </summary>
  358. /// <param name="key">The key to release.</param>
  359. public static void Release(Key key)
  360. {
  361. SendKeyboardInput(key, false);
  362. }
  363.  
  364. /// <summary>
  365. /// Resets the system keyboard to a clean state.
  366. /// </summary>
  367. public static void Reset()
  368. {
  369. foreach (Key key in Enum.GetValues(typeof(Key)))
  370. {
  371. if (key != Key.None && (System.Windows.Input.Keyboard.GetKeyStates(key) & KeyStates.Down) > 0)
  372. {
  373. Release(key);
  374. }
  375. }
  376. }
  377.  
  378. /// <summary>
  379. /// Performs a press-and-release operation for the specified key, which is effectively equivallent to typing.
  380. /// </summary>
  381. /// <param name="key">The key to press.</param>
  382. public static void Type(Key key)
  383. {
  384. Press(key);
  385. Release(key);
  386. }
  387.  
  388. /// <summary>
  389. /// Types the specified text.
  390. /// </summary>
  391. /// <param name="text">The text to type.</param>
  392. public static void Type(string text)
  393. {
  394. foreach (char c in text)
  395. {
  396. // We get the vKey value for the character via a Win32 API. We then use bit masks to pull the
  397. // upper and lower bytes to get the shift state and key information. We then use WPF KeyInterop
  398. // to go from the vKey key info into a System.Windows.Input.Key data structure. This work is
  399. // necessary because Key doesn't distinguish between upper and lower case, so we have to wrap
  400. // the key type inside a shift press/release if necessary.
  401. int vKeyValue = NativeMethods.VkKeyScan(c);
  402. bool keyIsShifted = (vKeyValue & NativeMethods.VKeyShiftMask) == NativeMethods.VKeyShiftMask;
  403. Key key = KeyInterop.KeyFromVirtualKey(vKeyValue & NativeMethods.VKeyCharMask);
  404.  
  405. if (keyIsShifted)
  406. {
  407. Type(key, new Key[] { Key.LeftShift });
  408. }
  409. else
  410. {
  411. Type(key);
  412. }
  413. }
  414. }
  415.  
  416. #endregion
  417.  
  418. #region Private Members
  419.  
  420. /// <summary>
  421. /// Types a key while a set of modifier keys are being pressed. Modifer keys
  422. /// are pressed in the order specified and released in reverse order.
  423. /// </summary>
  424. /// <param name="key">Key to type.</param>
  425. /// <param name="modifierKeys">Set of keys to hold down with key is typed.</param>
  426. private static void Type(Key key, Key[] modifierKeys)
  427. {
  428. foreach (Key modiferKey in modifierKeys)
  429. {
  430. Press(modiferKey);
  431. }
  432.  
  433. Type(key);
  434.  
  435. foreach (Key modifierKey in modifierKeys.Reverse())
  436. {
  437. Release(modifierKey);
  438. }
  439. }
  440.  
  441. /// <summary>
  442. /// Injects keyboard input into the system.
  443. /// </summary>
  444. /// <param name="key">Indicates the key pressed or released. Can be one of the constants defined in the Key enum.</param>
  445. /// <param name="press">True to inject a key press, false to inject a key release.</param>
  446. [PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
  447. private static void SendKeyboardInput(Key key, bool press)
  448. {
  449. PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted);
  450. permissions.Demand();
  451.  
  452. NativeMethods.INPUT ki = new NativeMethods.INPUT();
  453. ki.type = NativeMethods.InputKeyboard;
  454. ki.union.keyboardInput.wVk = (short)KeyInterop.VirtualKeyFromKey(key);
  455. ki.union.keyboardInput.wScan = (short)NativeMethods.MapVirtualKey(ki.union.keyboardInput.wVk, 0);
  456.  
  457. int dwFlags = 0;
  458.  
  459. if (ki.union.keyboardInput.wScan > 0)
  460. {
  461. dwFlags |= NativeMethods.KeyeventfScancode;
  462. }
  463.  
  464. if (!press)
  465. {
  466. dwFlags |= NativeMethods.KeyeventfKeyup;
  467. }
  468.  
  469. ki.union.keyboardInput.dwFlags = dwFlags;
  470.  
  471. if (ExtendedKeys.Contains(key))
  472. {
  473. ki.union.keyboardInput.dwFlags |= NativeMethods.KeyeventfExtendedkey;
  474. }
  475.  
  476. ki.union.keyboardInput.time = 0;
  477. ki.union.keyboardInput.dwExtraInfo = new IntPtr(0);
  478.  
  479. if (NativeMethods.SendInput(1, ref ki, Marshal.SizeOf(ki)) == 0)
  480. {
  481. throw new Win32Exception(Marshal.GetLastWin32Error());
  482. }
  483. }
  484.  
  485. // From the SDK:
  486. // The extended-key flag indicates whether the keystroke message originated from one of
  487. // the additional keys on the enhanced keyboard. The extended keys consist of the ALT and
  488. // CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP,
  489. // PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK
  490. // key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in
  491. // the numeric keypad. The extended-key flag is set if the key is an extended key.
  492. //
  493. // - docs appear to be incorrect. Use of Spy++ indicates that break is not an extended key.
  494. // Also, menu key and windows keys also appear to be extended.
  495. private static readonly Key[] ExtendedKeys = new Key[] {
  496. Key.RightAlt,
  497. Key.RightCtrl,
  498. Key.NumLock,
  499. Key.Insert,
  500. Key.Delete,
  501. Key.Home,
  502. Key.End,
  503. Key.Prior,
  504. Key.Next,
  505. Key.Up,
  506. Key.Down,
  507. Key.Left,
  508. Key.Right,
  509. Key.Apps,
  510. Key.RWin,
  511. Key.LWin };
  512. // Note that there are no distinct values for the following keys:
  513. // numpad divide
  514. // numpad enter
  515.  
  516. #endregion
  517. }
  518. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement