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;
}
}
}
}