SHARE
TWEET

Untitled

a guest May 26th, 2019 105 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top