Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ packages/

#Test files
*.testsettings
.vs/
66 changes: 64 additions & 2 deletions WindowsInput.Tests/InputSimulatorExamples.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using NUnit.Framework;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using WindowsInput.Native;

namespace WindowsInput.Tests
Expand Down Expand Up @@ -70,13 +75,70 @@ public void AnotherTest()
[Explicit]
public void TestMouseMoveTo()
{
var bounds = Screen.PrimaryScreen.WorkingArea;

var sim = new InputSimulator();
sim.Mouse
.MoveMouseTo(0, 0)
.Sleep(1000)
.MoveMouseTo(65535, 65535)
.MoveMouseTo(bounds.Width, bounds.Height)
.Sleep(1000)
.MoveMouseTo(65535/2, 65535/2);
.MoveMouseTo(bounds.Width / 2, bounds.Height / 2);
}

[Test]
[Explicit]
public void TestDragDrop()
{
Process notepad = Process.Start(Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "notepad.exe"));
notepad.WaitForInputIdle();

var sim = new InputSimulator();

var bounds = WaitForMainWindowPosition(notepad, sim);
Assert.IsFalse(bounds.IsEmpty, "Window is not showing up");

// get grab position in the title bar.
int x = bounds.Left + (bounds.Width / 2);
int y = bounds.Top + 10;

sim.Mouse
.MoveMouseTo(x, y)
.Sleep(100)
.LeftButtonDown();

for (int i = 0; i < 100; i += 1)
{
sim.Mouse.MoveMouseTo(x + i, y).Sleep(1);
}

sim.Mouse.LeftButtonUp();

notepad.Kill();
}

private Rectangle WaitForMainWindowPosition(Process process, InputSimulator sim, int timeoutMilliseconds = 5000)
{
int delay = 10;
for (int timeout = 0; timeout < timeoutMilliseconds; timeout += delay)
{
NativeMethods.WINDOWPLACEMENT placement = new NativeMethods.WINDOWPLACEMENT();
NativeMethods.GetWindowPlacement(process.MainWindowHandle, ref placement);
var width = (placement.rcNormalPosition.right - placement.rcNormalPosition.left);
if (width == 0)
{
sim.Mouse.Sleep(delay);
}
else
{
// find a position in the center of the title bar.
var height = (placement.rcNormalPosition.right - placement.rcNormalPosition.left);
var x = placement.rcNormalPosition.left;
var y = placement.rcNormalPosition.top;
return new Rectangle((int)x, (int)y, (int)width, (int)height);
}
}
return Rectangle.Empty;
}
}
}
46 changes: 46 additions & 0 deletions WindowsInput.Tests/NativeMethods/NativeMethods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Runtime.InteropServices;

namespace WindowsInput.Tests
{
internal class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
int x;
public int y;
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT
{
public UInt32 length;
public UInt32 flags;
public UInt32 showCmd;
public POINT ptMinPosition;
public POINT ptMaxPosition;
public RECT rcNormalPosition;
public RECT rcDevice;
}
;
/// <summary>
/// Retrieves the show state and the restored, minimized, and maximized positions of the specified window.
/// </summary>
/// <param name="hwnd"></param>
/// <param name=""></param>
/// <param name=""></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool GetWindowPlacement(IntPtr hwnd, ref WINDOWPLACEMENT placement);
}
}
20 changes: 16 additions & 4 deletions WindowsInput.Tests/WindowsInput.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\NUnit.3.13.3\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.13.3\build\NUnit.props')" />
<Import Project="..\packages\NUnit3TestAdapter.4.3.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.4.3.1\build\net35\NUnit3TestAdapter.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
Expand All @@ -10,11 +12,13 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindowsInput.Tests</RootNamespace>
<AssemblyName>WindowsInput.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand Down Expand Up @@ -45,8 +49,8 @@
<Reference Include="HtmlAgilityPack">
<HintPath>..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=3.13.3.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.13.3\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand All @@ -60,6 +64,7 @@
<ItemGroup>
<Compile Include="InputBuilderTests.cs" />
<Compile Include="InputSimulatorExamples.cs" />
<Compile Include="NativeMethods\NativeMethods.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UnicodeText\UnicodeRange.cs" />
<Compile Include="UnicodeText\UnicodeTestForm.cs">
Expand Down Expand Up @@ -87,6 +92,13 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\NUnit3TestAdapter.4.3.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.4.3.1\build\net35\NUnit3TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\NUnit.3.13.3\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.13.3\build\NUnit.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
Expand Down
3 changes: 2 additions & 1 deletion WindowsInput.Tests/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" />
<package id="NUnit" version="2.6.2" targetFramework="net35" />
<package id="NUnit" version="3.13.3" targetFramework="net48" />
<package id="NUnit3TestAdapter" version="4.3.1" targetFramework="net48" />
</packages>
50 changes: 41 additions & 9 deletions WindowsInput/InputBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using WindowsInput.Native;

namespace WindowsInput
Expand Down Expand Up @@ -262,16 +263,39 @@ public InputBuilder AddCharacters(string characters)
return AddCharacters(characters.ToCharArray());
}

private UInt32 GetMouseButtonDownFlag(MouseButton button)
{
UInt32 flag = 0;
switch (button)
{
case MouseButton.None:
break;
case MouseButton.LeftButton:
flag = (UInt32)(MouseFlag.LeftDown);
break;
case MouseButton.MiddleButton:
flag = (UInt32)(MouseFlag.MiddleDown);
break;
case MouseButton.RightButton:
flag = (UInt32)(MouseFlag.RightDown);
break;
default:
break;
}
return flag;
}

/// <summary>
/// Moves the mouse relative to its current position.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddRelativeMouseMovement(int x, int y)
public InputBuilder AddRelativeMouseMovement(int x, int y, MouseButton button = MouseButton.None)
{
var movement = new INPUT { Type = (UInt32)InputType.Mouse };
movement.Data.Mouse.Flags = (UInt32)MouseFlag.Move;
movement.Data.Mouse.Flags = (UInt32)MouseFlag.Move | GetMouseButtonDownFlag(button);
movement.Data.Mouse.X = x;
movement.Data.Mouse.Y = y;

Expand All @@ -285,13 +309,19 @@ public InputBuilder AddRelativeMouseMovement(int x, int y)
/// </summary>
/// <param name="absoluteX"></param>
/// <param name="absoluteY"></param>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddAbsoluteMouseMovement(int absoluteX, int absoluteY)
{
public InputBuilder AddAbsoluteMouseMovement(int absoluteX, int absoluteY, MouseButton button = MouseButton.None)
{
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;
var flags = (UInt32)(MouseFlag.Move | MouseFlag.Absolute) | GetMouseButtonDownFlag(button);
var bounds = Screen.PrimaryScreen.WorkingArea;
var vx = absoluteX * 65535 / bounds.Width;
var vy = absoluteY * 65535 / bounds.Height;

movement.Data.Mouse.Flags = flags;
movement.Data.Mouse.X = vx;
movement.Data.Mouse.Y = vy;

_inputList.Add(movement);

Expand All @@ -303,11 +333,13 @@ public InputBuilder AddAbsoluteMouseMovement(int absoluteX, int absoluteY)
/// </summary>
/// <param name="absoluteX"></param>
/// <param name="absoluteY"></param>
/// <param name="button"></param>
/// <returns>This <see cref="InputBuilder"/> instance.</returns>
public InputBuilder AddAbsoluteMouseMovementOnVirtualDesktop(int absoluteX, int absoluteY)
public InputBuilder AddAbsoluteMouseMovementOnVirtualDesktop(int absoluteX, int absoluteY, MouseButton button = MouseButton.None)
{
var movement = new INPUT { Type = (UInt32)InputType.Mouse };
movement.Data.Mouse.Flags = (UInt32)(MouseFlag.Move | MouseFlag.Absolute | MouseFlag.VirtualDesk);
var flags = (UInt32)(MouseFlag.Move | MouseFlag.Absolute | MouseFlag.VirtualDesk) | GetMouseButtonDownFlag(button);
movement.Data.Mouse.Flags = flags;
movement.Data.Mouse.X = absoluteX;
movement.Data.Mouse.Y = absoluteY;

Expand Down
4 changes: 4 additions & 0 deletions WindowsInput/MouseButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
/// </summary>
public enum MouseButton
{
/// <summary>
/// No button selected.
/// </summary>
None,
/// <summary>
/// Left mouse button
/// </summary>
Expand Down
Loading