using System; using System.Collections; using System.Collections.Generic; using WindowsInput.Native; namespace WindowsInput { /// /// A helper class for building a list of messages ready to be sent to the native Windows API. /// internal class InputBuilder : IEnumerable { /// /// The public list of messages being built by this instance. /// private readonly List _inputList; /// /// Initializes a new instance of the class. /// public InputBuilder() { _inputList = new List(); } /// /// Returns the list of messages as a of messages. /// /// The of messages. public INPUT[] ToArray() { return _inputList.ToArray(); } /// /// Returns an enumerator that iterates through the list of messages. /// /// /// A that can be used to iterate through the list of messages. /// /// 1 public IEnumerator GetEnumerator() { return _inputList.GetEnumerator(); } /// /// Returns an enumerator that iterates through the list of messages. /// /// /// An object that can be used to iterate through the list of messages. /// /// 2 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Gets the at the specified position. /// /// The message at the specified position. public INPUT this[int position] { get { return _inputList[position]; } } /// /// Determines if the is an ExtendedKey /// /// The key code. /// true if the key code is an extended key; otherwise, false. /// /// The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. /// /// See http://msdn.microsoft.com/en-us/library/ms646267(v=vs.85).aspx Section "Extended-Key Flag" /// public static bool IsExtendedKey(VirtualKeyCode keyCode) { if (keyCode == VirtualKeyCode.MENU || keyCode == VirtualKeyCode.LMENU || keyCode == VirtualKeyCode.RMENU || keyCode == VirtualKeyCode.CONTROL || keyCode == VirtualKeyCode.RCONTROL || keyCode == VirtualKeyCode.INSERT || keyCode == VirtualKeyCode.DELETE || keyCode == VirtualKeyCode.HOME || keyCode == VirtualKeyCode.END || keyCode == VirtualKeyCode.PRIOR || keyCode == VirtualKeyCode.NEXT || keyCode == VirtualKeyCode.RIGHT || keyCode == VirtualKeyCode.UP || keyCode == VirtualKeyCode.LEFT || keyCode == VirtualKeyCode.DOWN || keyCode == VirtualKeyCode.NUMLOCK || keyCode == VirtualKeyCode.CANCEL || keyCode == VirtualKeyCode.SNAPSHOT || keyCode == VirtualKeyCode.DIVIDE) { return true; } else { return false; } } /// /// Adds a key down to the list of messages. /// /// The . /// This instance. public InputBuilder AddKeyDown(VirtualKeyCode keyCode) { var down = new INPUT { Type = (UInt32) InputType.Keyboard, Data = { Keyboard = new KEYBDINPUT { KeyCode = (UInt16) keyCode, Scan = 0, Flags = IsExtendedKey(keyCode) ? (UInt32) KeyboardFlag.ExtendedKey : 0, Time = 0, ExtraInfo = IntPtr.Zero } } }; _inputList.Add(down); return this; } /// /// Adds a key up to the list of messages. /// /// The . /// This instance. public InputBuilder AddKeyUp(VirtualKeyCode keyCode) { var up = new INPUT { Type = (UInt32) InputType.Keyboard, Data = { Keyboard = new KEYBDINPUT { KeyCode = (UInt16) keyCode, Scan = 0, Flags = (UInt32) (IsExtendedKey(keyCode) ? KeyboardFlag.KeyUp | KeyboardFlag.ExtendedKey : KeyboardFlag.KeyUp), Time = 0, ExtraInfo = IntPtr.Zero } } }; _inputList.Add(up); return this; } /// /// Adds a key press to the list of messages which is equivalent to a key down followed by a key up. /// /// The . /// This instance. public InputBuilder AddKeyPress(VirtualKeyCode keyCode) { AddKeyDown(keyCode); AddKeyUp(keyCode); return this; } /// /// Adds the character to the list of messages. /// /// The to be added to the list of messages. /// This instance. public InputBuilder AddCharacter(char character) { UInt16 scanCode = character; var down = new INPUT { Type = (UInt32)InputType.Keyboard, Data = { Keyboard = new KEYBDINPUT { KeyCode = 0, Scan = scanCode, Flags = (UInt32)KeyboardFlag.Unicode, Time = 0, ExtraInfo = IntPtr.Zero } } }; var up = new INPUT { Type = (UInt32)InputType.Keyboard, Data = { Keyboard = new KEYBDINPUT { KeyCode = 0, Scan = scanCode, Flags = (UInt32)(KeyboardFlag.KeyUp | KeyboardFlag.Unicode), Time = 0, ExtraInfo = IntPtr.Zero } } }; // Handle extended keys: // If the scan code is preceded by a prefix byte that has the value 0xE0 (224), // we need to include the KEYEVENTF_EXTENDEDKEY flag in the Flags property. if ((scanCode & 0xFF00) == 0xE000) { down.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.ExtendedKey; up.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.ExtendedKey; } _inputList.Add(down); _inputList.Add(up); return this; } /// /// Adds all of the characters in the specified of . /// /// The characters to add. /// This instance. public InputBuilder AddCharacters(IEnumerable characters) { foreach (var character in characters) { AddCharacter(character); } return this; } /// /// Adds the characters in the specified . /// /// The string of to add. /// This instance. public InputBuilder AddCharacters(string characters) { return AddCharacters(characters.ToCharArray()); } /// /// Moves the mouse relative to its current position. /// /// /// /// This instance. public InputBuilder AddRelativeMouseMovement(int x, int y) { var movement = new INPUT { Type = (UInt32)InputType.Mouse }; movement.Data.Mouse.Flags = (UInt32)MouseFlag.Move; movement.Data.Mouse.X = x; movement.Data.Mouse.Y = y; _inputList.Add(movement); return this; } /// /// Move the mouse to an absolute position. /// /// /// /// This instance. public InputBuilder AddAbsoluteMouseMovement(int absoluteX, int absoluteY) { var movement = new INPUT { Type = (UInt32)InputType.Mouse }; movement.Data.Mouse.Flags = (UInt32)(MouseFlag.Move | MouseFlag.Absolute); movement.Data.Mouse.X = absoluteX; movement.Data.Mouse.Y = absoluteY; _inputList.Add(movement); return this; } /// /// Move the mouse to the absolute position on the virtual desktop. /// /// /// /// This instance. public InputBuilder AddAbsoluteMouseMovementOnVirtualDesktop(int absoluteX, int absoluteY) { var movement = new INPUT { Type = (UInt32)InputType.Mouse }; movement.Data.Mouse.Flags = (UInt32)(MouseFlag.Move | MouseFlag.Absolute | MouseFlag.VirtualDesk); movement.Data.Mouse.X = absoluteX; movement.Data.Mouse.Y = absoluteY; _inputList.Add(movement); return this; } /// /// Adds a mouse button down for the specified button. /// /// /// This instance. public InputBuilder AddMouseButtonDown(MouseButton button) { var buttonDown = new INPUT { Type = (UInt32)InputType.Mouse }; buttonDown.Data.Mouse.Flags = (UInt32)ToMouseButtonDownFlag(button); _inputList.Add(buttonDown); return this; } /// /// Adds a mouse button down for the specified button. /// /// /// This instance. public InputBuilder AddMouseXButtonDown(int xButtonId) { var buttonDown = new INPUT { Type = (UInt32)InputType.Mouse }; buttonDown.Data.Mouse.Flags = (UInt32)MouseFlag.XDown; buttonDown.Data.Mouse.MouseData = (UInt32)xButtonId; _inputList.Add(buttonDown); return this; } /// /// Adds a mouse button up for the specified button. /// /// /// This instance. public InputBuilder AddMouseButtonUp(MouseButton button) { var buttonUp = new INPUT { Type = (UInt32)InputType.Mouse }; buttonUp.Data.Mouse.Flags = (UInt32)ToMouseButtonUpFlag(button); _inputList.Add(buttonUp); return this; } /// /// Adds a mouse button up for the specified button. /// /// /// This instance. public InputBuilder AddMouseXButtonUp(int xButtonId) { var buttonUp = new INPUT { Type = (UInt32)InputType.Mouse }; buttonUp.Data.Mouse.Flags = (UInt32)MouseFlag.XUp; buttonUp.Data.Mouse.MouseData = (UInt32)xButtonId; _inputList.Add(buttonUp); return this; } /// /// Adds a single click of the specified button. /// /// /// This instance. public InputBuilder AddMouseButtonClick(MouseButton button) { return AddMouseButtonDown(button).AddMouseButtonUp(button); } /// /// Adds a single click of the specified button. /// /// /// This instance. public InputBuilder AddMouseXButtonClick(int xButtonId) { return AddMouseXButtonDown(xButtonId).AddMouseXButtonUp(xButtonId); } /// /// Adds a double click of the specified button. /// /// /// This instance. public InputBuilder AddMouseButtonDoubleClick(MouseButton button) { return AddMouseButtonClick(button).AddMouseButtonClick(button); } /// /// Adds a double click of the specified button. /// /// /// This instance. public InputBuilder AddMouseXButtonDoubleClick(int xButtonId) { return AddMouseXButtonClick(xButtonId).AddMouseXButtonClick(xButtonId); } /// /// Scroll the vertical mouse wheel by the specified amount. /// /// /// This instance. public InputBuilder AddMouseVerticalWheelScroll(int scrollAmount) { var scroll = new INPUT { Type = (UInt32)InputType.Mouse }; scroll.Data.Mouse.Flags = (UInt32)MouseFlag.VerticalWheel; scroll.Data.Mouse.MouseData = (UInt32)scrollAmount; _inputList.Add(scroll); return this; } /// /// Scroll the horizontal mouse wheel by the specified amount. /// /// /// This instance. public InputBuilder AddMouseHorizontalWheelScroll(int scrollAmount) { var scroll = new INPUT { Type = (UInt32)InputType.Mouse }; scroll.Data.Mouse.Flags = (UInt32)MouseFlag.HorizontalWheel; scroll.Data.Mouse.MouseData = (UInt32)scrollAmount; _inputList.Add(scroll); return this; } private static MouseFlag ToMouseButtonDownFlag(MouseButton button) { switch (button) { case MouseButton.LeftButton: return MouseFlag.LeftDown; case MouseButton.MiddleButton: return MouseFlag.MiddleDown; case MouseButton.RightButton: return MouseFlag.RightDown; default: return MouseFlag.LeftDown; } } private static MouseFlag ToMouseButtonUpFlag(MouseButton button) { switch (button) { case MouseButton.LeftButton: return MouseFlag.LeftUp; case MouseButton.MiddleButton: return MouseFlag.MiddleUp; case MouseButton.RightButton: return MouseFlag.RightUp; default: return MouseFlag.LeftUp; } } } }