keeweb/helper/win32/src/KeeWebHelper/WindowsInput/InputBuilder.cs

486 lines
19 KiB
C#
Executable File

using System;
using System.Collections;
using System.Collections.Generic;
using WindowsInput.Native;
namespace WindowsInput
{
/// <summary>
/// A helper class for building a list of <see cref="INPUT"/> messages ready to be sent to the native Windows API.
/// </summary>
internal class InputBuilder : IEnumerable<INPUT>
{
/// <summary>
/// The public list of <see cref="INPUT"/> messages being built by this instance.
/// </summary>
private readonly List<INPUT> _inputList;
/// <summary>
/// Initializes a new instance of the <see cref="InputBuilder"/> class.
/// </summary>
public InputBuilder()
{
_inputList = new List<INPUT>();
}
/// <summary>
/// Returns the list of <see cref="INPUT"/> messages as a <see cref="System.Array"/> of <see cref="INPUT"/> messages.
/// </summary>
/// <returns>The <see cref="System.Array"/> of <see cref="INPUT"/> messages.</returns>
public INPUT[] ToArray()
{
return _inputList.ToArray();
}
/// <summary>
/// Returns an enumerator that iterates through the list of <see cref="INPUT"/> messages.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the list of <see cref="INPUT"/> messages.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<INPUT> GetEnumerator()
{
return _inputList.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through the list of <see cref="INPUT"/> messages.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the list of <see cref="INPUT"/> messages.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Gets the <see cref="INPUT"/> at the specified position.
/// </summary>
/// <value>The <see cref="INPUT"/> message at the specified position.</value>
public INPUT this[int position]
{
get
{
return _inputList[position];
}
}
/// <summary>
/// Determines if the <see cref="VirtualKeyCode"/> is an ExtendedKey
/// </summary>
/// <param name="keyCode">The key code.</param>
/// <returns>true if the key code is an extended key; otherwise, false.</returns>
/// <remarks>
/// 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"
/// </remarks>
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;
}
}
/// <summary>
/// Adds a key down to the list of <see cref="INPUT"/> messages.
/// </summary>
/// <param name="keyCode">The <see cref="VirtualKeyCode"/>.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a key up to the list of <see cref="INPUT"/> messages.
/// </summary>
/// <param name="keyCode">The <see cref="VirtualKeyCode"/>.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a key press to the list of <see cref="INPUT"/> messages which is equivalent to a key down followed by a key up.
/// </summary>
/// <param name="keyCode">The <see cref="VirtualKeyCode"/>.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddKeyPress(VirtualKeyCode keyCode)
{
AddKeyDown(keyCode);
AddKeyUp(keyCode);
return this;
}
/// <summary>
/// Adds the character to the list of <see cref="INPUT"/> messages.
/// </summary>
/// <param name="character">The <see cref="System.Char"/> to be added to the list of <see cref="INPUT"/> messages.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds all of the characters in the specified <see cref="IEnumerable{T}"/> of <see cref="char"/>.
/// </summary>
/// <param name="characters">The characters to add.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddCharacters(IEnumerable<char> characters)
{
foreach (var character in characters)
{
AddCharacter(character);
}
return this;
}
/// <summary>
/// Adds the characters in the specified <see cref="string"/>.
/// </summary>
/// <param name="characters">The string of <see cref="char"/> to add.</param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddCharacters(string characters)
{
return AddCharacters(characters.ToCharArray());
}
/// <summary>
/// Moves the mouse relative to its current position.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Move the mouse to an absolute position.
/// </summary>
/// <param name="absoluteX"></param>
/// <param name="absoluteY"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Move the mouse to the absolute position on the virtual desktop.
/// </summary>
/// <param name="absoluteX"></param>
/// <param name="absoluteY"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a mouse button down for the specified button.
/// </summary>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a mouse button down for the specified button.
/// </summary>
/// <param name="xButtonId"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a mouse button up for the specified button.
/// </summary>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a mouse button up for the specified button.
/// </summary>
/// <param name="xButtonId"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Adds a single click of the specified button.
/// </summary>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddMouseButtonClick(MouseButton button)
{
return AddMouseButtonDown(button).AddMouseButtonUp(button);
}
/// <summary>
/// Adds a single click of the specified button.
/// </summary>
/// <param name="xButtonId"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddMouseXButtonClick(int xButtonId)
{
return AddMouseXButtonDown(xButtonId).AddMouseXButtonUp(xButtonId);
}
/// <summary>
/// Adds a double click of the specified button.
/// </summary>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddMouseButtonDoubleClick(MouseButton button)
{
return AddMouseButtonClick(button).AddMouseButtonClick(button);
}
/// <summary>
/// Adds a double click of the specified button.
/// </summary>
/// <param name="xButtonId"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddMouseXButtonDoubleClick(int xButtonId)
{
return AddMouseXButtonClick(xButtonId).AddMouseXButtonClick(xButtonId);
}
/// <summary>
/// Scroll the vertical mouse wheel by the specified amount.
/// </summary>
/// <param name="scrollAmount"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
/// <summary>
/// Scroll the horizontal mouse wheel by the specified amount.
/// </summary>
/// <param name="scrollAmount"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
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;
}
}
}
}