SharpHook.Testing
8.0.0
dotnet add package SharpHook.Testing --version 8.0.0
NuGet\Install-Package SharpHook.Testing -Version 8.0.0
<PackageReference Include="SharpHook.Testing" Version="8.0.0" />
<PackageVersion Include="SharpHook.Testing" Version="8.0.0" />
<PackageReference Include="SharpHook.Testing" />
paket add SharpHook.Testing --version 8.0.0
#r "nuget: SharpHook.Testing, 8.0.0"
#:package SharpHook.Testing@8.0.0
#addin nuget:?package=SharpHook.Testing&version=8.0.0
#tool nuget:?package=SharpHook.Testing&version=8.0.0
SharpHook.Testing
SharpHook provides a cross-platform global keyboard and mouse hook, event simulation, and text entry simulation for .NET. It is a wrapper of libuiohook and provides direct access to its features as well as higher-level types to work with it.
SharpHook.Testing provides two classes which make testing easier. They aren't required since mocks can be used instead, but unlike mocks, no setup is required to use these classes.
Usage
Basic Usage
Refer to the SharpHook package for the basic usage guidelines.
Test Global Hook
SharpHook.Testing.TestGlobalHook provides an implementation of IGlobalHook and IEventSimulator which can be used
for testing. When the Run or RunAsync method is called, it will dispatch events using the various Simulate methods
from IEventSimulator.
[Fact]
public async Task TestLastPressedKey()
{
var hook = new TestGlobalHook();
var keyCode = KeyCode.VcA;
var componentUnderTest = new SomeClassWhichUsesGlobalHookEvents(hook);
var hookStopped = hook.RunAsync(); // Run the test hook asynchronously
hook.SimulateKeyPress(keyCode); // Dispatch the event to the test global hook
hook.Dispose();
await hookStopped; // Wait until the hook is actually stopped
Assert.Equal(keyCode, componentUnderTest.LastPressedKey);
}
If this class is used as an IEventSimulator in the tested code, then the SimulatedEvents property can be checked to
see which events were simulated using the test instance.
TestGlobalHook can be used with two different threading modes – the simple mode and the event loop mode.
When running in simple mode (the default mode) the hook will dispatch events immediately in the same thread which simulates them.
When running the event loop, the hook will run an actual even loop on the thread on which Run was called. When
simulating events, they will be posted to the event loop, and then dispatched in the hook thread. This mode is much more
difficult to use correctly, so it is useful only when it is important for event handlers to run in the same thread on
which the hook itself is running. It's recommended to stop the global hook and wait for it to stop before asserting any
events. Since these actions are done in different threads, it is not guaranteed that an event will be dispatched
immediately after it is simulated. Run and the task returned by RunAsync will complete after every event has been
dispatched.
Other than that, members of TestGlobalHook are quite straightforward; the API reference should be viewed for more
info.
If an IReactiveGlobalHook is needed for testing, then ReactiveGlobalHookAdapter or ReactiveUIGlobalHookAdapter can
be used to adapt an instance of TestGlobalHook. If an IR3GlobalHook is needed for testing, then
R3GlobalHookAdapter can be used to adapt an instance of TestGlobalHook.
Test Low-Level Functionality Provider
If the low-level functionality of SharpHook should be mocked, or mocking should be pushed as far away as possible,
then SharpHook.Testing.TestProvider can be used. It implements every interface in the SharpHook.Providers namespace,
so it can be used instead of normal low-level functionality providers.
Like TestGlobalHook, this class can post events using the PostEvent method and dispatch them if Run has been
called. It also contains the PostedEvents property.
TestProvider can be used with two different threading modes – the simple mode and the event loop mode.
When running in simple mode (the default mode) the provider will dispatch events immediately in the same thread which simulates them.
When running the event loop, the provider will run an actual even loop on the thread on which Run was called. When
simulating events, they will be posted to the event loop, and then dispatched in the hook thread. This mode is much more
difficult to use correctly, so it is useful only when it is important for event handlers to run in the same thread on
which the hook itself is running. It's recommended to stop the provider and wait for it to stop before asserting any
events. Since these actions are done in different threads, it is not guaranteed that an event will be dispatched
immediately after it is simulated. Run and the task returned by RunAsync will complete after every event has been
dispatched.
All classes in SharpHook use providers for low-level functionality, and the providers are selectable, so e.g., the following global hook can be used for testing:
var testProvider = new TestProvider();
// Calls to methods in testProvider will be reflected in the hook
var hook = new SimpleGlobalHook(testProvider);
// Calls to methods in testProvider will be reflected in the simulator
var simulator = EventSimulator.Create("Test app", testProvider);
EventLoopGlobalHook or TaskPoolGlobalHook shouldn't be used this way since their event handlers are asynchronous
and there is no built-in way to know when they are actually executed. As such, it's difficult to check event handler
results. If you want to use a real hook, e.g. for integration testing, then use SimpleGlobalHook instead.
Icon
Icon made by Freepik from www.flaticon.com.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 8.0.0 | 146 | 8/24/2026 |