### Install SharpHook NuGet Packages Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Installs the core SharpHook package and optional reactive extensions packages for Rx.NET and R3 integration via NuGet. ```bash dotnet add package SharpHook dotnet add package SharpHook.Reactive dotnet add package SharpHook.R3 ``` -------------------------------- ### Install SharpHook Packages Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/index.md Installs the core SharpHook package and its reactive and R3 extensions using the .NET CLI. These packages are essential for utilizing SharpHook's functionalities. ```bash dotnet add package SharpHook dotnet add package SharpHook.Reactive dotnet add package SharpHook.R3 ``` -------------------------------- ### Implement Reactive Global Hooks with R3 Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Shows how to integrate the R3 reactive library with SharpHook for high-performance event stream processing. Includes examples of filtering, debouncing, and mapping input events. ```csharp using SharpHook.R3; using R3; var hook = new R3GlobalHook(); hook.KeyPressed .Where(e => e.Data.KeyCode >= KeyCode.VcA && e.Data.KeyCode <= KeyCode.VcZ) .Subscribe(e => Console.WriteLine($"Letter key: {e.Data.KeyCode}")); hook.MouseMoved .Debounce(TimeSpan.FromMilliseconds(50)) .Subscribe(e => Console.WriteLine($"Mouse position: ({e.Data.X}, {e.Data.Y})")); hook.MouseWheel .Select(e => e.Data.Rotation > 0 ? "Up" : "Down") .Subscribe(direction => Console.WriteLine($"Scroll {direction}")); await hook.RunAsync(); hook.Dispose(); ``` -------------------------------- ### Basic R3GlobalHook Usage in C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/reactive.md Demonstrates the basic setup and subscription to various global hook events using R3 observables. It shows how to instantiate R3GlobalHook, subscribe to key and mouse events, and run the hook asynchronously. ```csharp using SharpHook.R3; // ... var hook = new R3GlobalHook(); hook.HookEnabled.Subscribe(OnHookEnabled); hook.HookDisabled.Subscribe(OnHookDisabled); hook.KeyTyped.Subscribe(OnKeyTyped); hook.KeyPressed.Subscribe(OnKeyPressed); hook.KeyReleased.Subscribe(OnKeyReleased); hook.MouseClicked.Subscribe(OnMouseClicked); hook.MousePressed.Subscribe(OnMousePressed); hook.MouseReleased.Subscribe(OnMouseReleased); hook.MouseMoved .Debounce(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseMoved); hook.MouseDragged .Debounce(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseDragged); hook.MouseWheel.Subscribe(OnMouseWheel); hook.Run(); // or await hook.RunAsync(); ``` -------------------------------- ### Basic Global Hook Usage in C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/hooks.md Demonstrates the fundamental usage of SharpHook's IGlobalHook interface. It shows how to instantiate a hook, subscribe to various keyboard, mouse, and hook status events, and start the hook using Run() or RunAsync(). ```csharp using SharpHook; using SharpHook.Providers; // KeyTyped events may cause system-wide side effects, so they should be disabled if unused. UioHookProvider.Instance.KeyTypedEnabled = false; // or true var hook = new EventLoopGlobalHook(); hook.HookEnabled += OnHookEnabled; // EventHandler hook.HookDisabled += OnHookDisabled; // EventHandler hook.KeyTyped += OnKeyTyped; // EventHandler hook.KeyPressed += OnKeyPressed; // EventHandler hook.KeyReleased += OnKeyReleased; // EventHandler hook.MouseClicked += OnMouseClicked; // EventHandler hook.MousePressed += OnMousePressed; // EventHandler hook.MouseReleased += OnMouseReleased; // EventHandler hook.MouseMoved += OnMouseMoved; // EventHandler hook.MouseDragged += OnMouseDragged; // EventHandler hook.MouseWheel += OnMouseWheel; // EventHandler hook.Run(); // or await hook.RunAsync(); ``` -------------------------------- ### Custom Log Entry Parsing with LogEntryParser (C#) Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/logging.md Provides an example of implementing a custom log callback method in C# using `LogEntryParser`. This approach simplifies log handling by parsing native log entries into a usable format, avoiding direct manipulation of raw pointers. ```csharp private void OnLog(LogLevel level, IntPtr userData, IntPtr format, IntPtr args) { // Filter by log level if needed var logEntry = LogEntryParser.Instance.ParseNativeLogEntry(level, format, args); // Handle the log entry instead of the native format and arguments } ``` -------------------------------- ### Reactive Logging with SharpHook.R3 in C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/SharpHook.R3/README.md Illustrates how to set up reactive logging using SharpHook.R3. It shows the process of obtaining a log source, adapting it to the R3 reactive interface, and subscribing to log messages. This allows for handling log events in a stream-based manner. ```csharp using SharpHook.Logging; using SharpHook.R3.Logging; // ... var logSource = LogSource.RegisterOrGet(); var r3LogSource = new R3LogSourceAdapter(logSource); r3LogSource.MessageLogged.Subscribe(this.OnMessageLogged); ``` -------------------------------- ### Simulate Keyboard and Mouse Events with SharpHook Source: https://github.com/tolikpylypchuk/sharphook/blob/main/README.md Demonstrates cross-platform simulation of keyboard and mouse events using SharpHook's EventSimulator. Supports key presses, releases, key strokes, mouse button actions, mouse movement, and mouse wheel scrolling. Requires SharpHook and SharpHook.Native namespaces. ```csharp using SharpHook; using SharpHook.Native; // ... var simulator = new EventSimulator(); // Press Ctrl+C simulator.SimulateKeyPress(KeyCode.VcLeftControl); simulator.SimulateKeyPress(KeyCode.VcC); // Release Ctrl+C simulator.SimulateKeyRelease(KeyCode.VcC); simulator.SimulateKeyRelease(KeyCode.VcLeftControl); // Simulate pressing Ctrl, then pressing C, then releasing C, then releasing Ctrl simulator.SimulateKeyStroke(KeyCode.VcLeftControl, KeyCode.VcC); // Press the left mouse button simulator.SimulateMousePress(MouseButton.Button1); // Release the left mouse button simulator.SimulateMouseRelease(MouseButton.Button1); // Press the left mouse button at (0, 0) simulator.SimulateMousePress(0, 0, MouseButton.Button1); // Release the left mouse button at (0, 0) simulator.SimulateMouseRelease(0, 0, MouseButton.Button1); // Move the mouse pointer to (0, 0) simulator.SimulateMouseMovement(0, 0); // Move the mouse pointer 50 pixels to the right and 100 pixels down simulator.SimulateMouseMovementRelative(50, 100); // Scroll the mouse wheel simulator.SimulateMouseWheel( rotation: -120, direction: MouseWheelScrollDirection.Vertical, // Vertical by default type: MouseWheelScrollType.UnitScroll); // UnitScroll by default ``` -------------------------------- ### Build Event Sequences with IEventSimulationSequenceBuilder Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Explains how to construct complex input sequences, such as keyboard shortcuts and combined mouse-keyboard actions. It also demonstrates how to create and execute reusable simulation templates. ```csharp using SharpHook; using SharpHook.Data; var simulator = new EventSimulator(); // Build and simulate a sequence simulator.Sequence() .AddKeyStroke(KeyCode.VcLeftControl, KeyCode.VcA) .AddKeyStroke(KeyCode.VcLeftControl, KeyCode.VcC) .AddMouseMovement(100, 100) .AddMousePress(MouseButton.Button1) .AddMouseRelease(MouseButton.Button1) .AddKeyStroke(KeyCode.VcLeftControl, KeyCode.VcV) .Simulate(); // Create and execute a reusable template var template = simulator.Sequence() .AddKeyStroke(KeyCode.VcLeftControl, KeyCode.VcS) .CreateTemplate(); template.Simulate(); ``` -------------------------------- ### Configure Logging for SharpHook Events Source: https://github.com/tolikpylypchuk/sharphook/blob/main/SharpHook/README.md Shows how to set up logging for libuiohook messages using the LogSource class. It demonstrates registering a log source, setting a minimum log level, and subscribing to the MessageLogged event to process log entries. ```csharp using SharpHook.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); logSource.MessageLogged += this.OnMessageLogged; private void OnMessageLogged(object? sender, LogEventArgs e) => this.logger.Log(this.AdaptLogLevel(e.LogEntry.Level), e.LogEntry.FullText); ``` -------------------------------- ### Configure Text Simulation Delay on X11 Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/simulation.md Gets or sets the delay for text simulation on X11 systems. Longer delays improve consistency but may be noticeable. The default is 50 milliseconds. This property has no effect on Windows and macOS. ```csharp // Get the current delay var delay = simulator.TextSimulationDelayOnX11; // Set a new delay (e.g., 100 milliseconds) simulator.TextSimulationDelayOnX11 = TimeSpan.FromMilliseconds(100); ``` -------------------------------- ### Simulate Keyboard and Mouse Events with SharpHook Source: https://github.com/tolikpylypchuk/sharphook/blob/main/SharpHook/README.md Demonstrates how to simulate keyboard presses, releases, mouse button presses, releases, movements, and scrolling using the EventSimulator class. This functionality is cross-platform and relies on the SharpHook library. ```csharp using SharpHook; using SharpHook.Data; // ... var simulator = new EventSimulator(); // Press Ctrl+C simulator.SimulateKeyPress(KeyCode.VcLeftControl); simulator.SimulateKeyPress(KeyCode.VcC); // Release Ctrl+C simulator.SimulateKeyRelease(KeyCode.VcC); simulator.SimulateKeyRelease(KeyCode.VcLeftControl); // Press the left mouse button simulator.SimulateMousePress(MouseButton.Button1); // Release the left mouse button simulator.SimulateMouseRelease(MouseButton.Button1); // Press the left mouse button at (0, 0) simulator.SimulateMousePress(0, 0, MouseButton.Button1); // Release the left mouse button at (0, 0) simulator.SimulateMouseRelease(0, 0, MouseButton.Button1); // Move the mouse pointer to (0, 0) simulator.SimulateMouseMovement(0, 0); // Move the mouse pointer 50 pixels to the right and 100 pixels down simulator.SimulateMouseMovementRelative(50, 100); // Scroll the mouse wheel simulator.SimulateMouseWheel( rotation: -120, direction: MouseWheelScrollDirection.Vertical, // Vertical by default type: MouseWheelScrollType.UnitScroll); // UnitScroll by default ``` -------------------------------- ### Simulate Mouse Wheel Scrolling with SharpHook Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/simulation.md This example shows how to simulate mouse wheel scrolling using SharpHook's EventSimulator. It details the parameters for rotation, direction, and type, noting platform-specific recommendations for rotation values and scroll types on Windows, macOS, and Linux. ```csharp using SharpHook; using SharpHook.Data; // ... // Scroll the mouse wheel simulator.SimulateMouseWheel( rotation: -120, direction: MouseWheelScrollDirection.Vertical, // Vertical by default type: MouseWheelScrollType.UnitScroll); // UnitScroll by default ``` -------------------------------- ### Simulate Keyboard Events with EventSimulator Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Illustrates simulating keyboard input using the `EventSimulator` class. It covers simulating individual key presses and releases, complex key combinations using modifier keys, and simplified key strokes. The code also shows how to check the success of simulation operations. ```csharp using SharpHook; using SharpHook.Data; var simulator = new EventSimulator(); // Simulate a single key press and release var pressResult = simulator.SimulateKeyPress(KeyCode.VcA); if (pressResult == UioHookResult.Success) { Console.WriteLine("Key A pressed successfully"); } var releaseResult = simulator.SimulateKeyRelease(KeyCode.VcA); if (releaseResult == UioHookResult.Success) { Console.WriteLine("Key A released successfully"); } // Simulate Ctrl+C (copy shortcut) simulator.SimulateKeyPress(KeyCode.VcLeftControl); simulator.SimulateKeyPress(KeyCode.VcC); simulator.SimulateKeyRelease(KeyCode.VcC); simulator.SimulateKeyRelease(KeyCode.VcLeftControl); // Use SimulateKeyStroke for simpler key combinations // This presses all keys in order, then releases them in reverse order simulator.SimulateKeyStroke(KeyCode.VcLeftControl, KeyCode.VcV); // Ctrl+V (paste) simulator.SimulateKeyStroke(KeyCode.VcLeftAlt, KeyCode.VcTab); // Alt+Tab (switch window) simulator.SimulateKeyStroke(KeyCode.VcLeftControl, KeyCode.VcLeftShift, KeyCode.VcEscape); // Ctrl+Shift+Esc // Simulate function keys simulator.SimulateKeyPress(KeyCode.VcF5); simulator.SimulateKeyRelease(KeyCode.VcF5); ``` -------------------------------- ### Create Keyboard and Mouse Hooks with SharpHook Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Demonstrates how to initialize EventLoopGlobalHook with specific GlobalHookType parameters to capture only keyboard or mouse events, optimizing performance by avoiding unnecessary event processing. ```csharp using SharpHook; using SharpHook.Data; // Keyboard-only hook (captures only keyboard events) var keyboardHook = new EventLoopGlobalHook(GlobalHookType.Keyboard); keyboardHook.KeyPressed += (s, e) => Console.WriteLine($"Key: {e.Data.KeyCode}"); // Mouse-only hook (captures only mouse events) var mouseHook = new EventLoopGlobalHook(GlobalHookType.Mouse); mouseHook.MousePressed += (s, e) => Console.WriteLine($"Click at ({e.Data.X}, {e.Data.Y})"); mouseHook.MouseMoved += (s, e) => Console.WriteLine($"Move to ({e.Data.X}, {e.Data.Y})"); // Default captures all events var allHook = new EventLoopGlobalHook(GlobalHookType.All); // Run the appropriate hook await keyboardHook.RunAsync(); ``` -------------------------------- ### Preventing Garbage Collection with Delegate References in C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/custom.md Demonstrates how to correctly store delegate references to prevent them from being garbage collected prematurely when using SetDispatchProc. The C# compiler transforms direct method calls into delegate instantiations, which are not automatically protected from garbage collection after the method exits. Storing the delegate reference, for example, as a field, ensures its longevity. ```csharp provider.SetDispatchProc(someObj.SomeMethod, IntPtr.Zero); ``` ```csharp provider.SetDispatchProc(new DispatchProc(someObj.SomeMethod), IntPtr.Zero); ``` ```csharp DispatchProc dispatchProc = someObj.SomeMethod; // This reference should be stored, e.g., as a field of the object provider.SetDispatchProc(dispatchProc, IntPtr.Zero); ``` -------------------------------- ### Reactive Logging with SharpHook.R3 Source: https://github.com/tolikpylypchuk/sharphook/blob/main/README.md Enables reactive handling of libuiohook log messages using R3 (Reference-counted Reactive Extensions). Adapts the standard `LogSource` to an `IR3LogSource` for R3-style subscriptions. Requires SharpHook.Logging and SharpHook.R3.Logging namespaces. ```csharp using SharpHook.Logging; using SharpHook.R3.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); var reactiveLogSource = new R3LogSourceAdapter(logSource); reactiveLogSource.MessageLogged.Subscribe(this.OnMessageLogged); ``` -------------------------------- ### Create Global Keyboard and Mouse Hooks with EventLoopGlobalHook Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Demonstrates creating and managing global keyboard and mouse hooks using `EventLoopGlobalHook`. It shows how to subscribe to key press/release and mouse events, handle hook lifecycle events, and run the hook asynchronously or synchronously. The `KeyTypedEnabled` property is set to false to prevent potential system-wide side effects. ```csharp using SharpHook; using SharpHook.Data; using SharpHook.Providers; // Disable KeyTyped events if unused (can cause system-wide side effects) UioHookProvider.Instance.KeyTypedEnabled = false; // Create the hook instance var hook = new EventLoopGlobalHook(); // Subscribe to keyboard events hook.KeyPressed += (sender, e) => { Console.WriteLine($"Key pressed: {e.Data.KeyCode} at {e.EventTime}"); // Check for specific key combinations if (e.Data.KeyCode == KeyCode.VcEscape) { Console.WriteLine("Escape pressed - stopping hook"); hook.Stop(); } }; hook.KeyReleased += (sender, e) => { Console.WriteLine($"Key released: {e.Data.KeyCode}"); }; // Subscribe to mouse events hook.MousePressed += (sender, e) => { Console.WriteLine($"Mouse button {e.Data.Button} pressed at ({e.Data.X}, {e.Data.Y})"); }; hook.MouseMoved += (sender, e) => { Console.WriteLine($"Mouse moved to ({e.Data.X}, {e.Data.Y})"); }; hook.MouseWheel += (sender, e) => { Console.WriteLine($"Mouse wheel scrolled: rotation={e.Data.Rotation}, direction={e.Data.Direction}"); }; // Subscribe to hook lifecycle events hook.HookEnabled += (sender, e) => Console.WriteLine("Hook started"); hook.HookDisabled += (sender, e) => Console.WriteLine("Hook stopped"); // Run asynchronously (non-blocking) await hook.RunAsync(); // Or run synchronously (blocking) // hook.Run(); // When done, dispose the hook hook.Dispose(); ``` -------------------------------- ### Initialize and Use TestProvider with SimpleGlobalHook and EventSimulator (C#) Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/testing.md Demonstrates how to instantiate and utilize the TestProvider for mocking low-level functionality. It shows its integration with SimpleGlobalHook and EventSimulator, allowing for controlled testing scenarios. ```csharp var testProvider = new TestProvider(); // Calls to methods in testProvider will be reflected in the hook var hook = new SimpleGlobalHook(globalHookProvider: testProvider); // Calls to methods in testProvider will be reflected in the simulator var simulator = new EventSimulator(simulationProvider: testProvider); ``` -------------------------------- ### Implementing ReactiveGlobalHook for Rx.NET Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/reactive.md Demonstrates how to initialize a ReactiveGlobalHook and subscribe to various keyboard and mouse event streams. It shows the use of Rx operators like Throttle and the execution methods Run and RunAsync. ```csharp using SharpHook.Reactive; var hook = new ReactiveGlobalHook(); hook.HookEnabled.Subscribe(OnHookEnabled); hook.HookDisabled.Subscribe(OnHookDisabled); hook.KeyTyped.Subscribe(OnKeyTyped); hook.KeyPressed.Subscribe(OnKeyPressed); hook.KeyReleased.Subscribe(OnKeyReleased); hook.MouseClicked.Subscribe(OnMouseClicked); hook.MousePressed.Subscribe(OnMousePressed); hook.MouseReleased.Subscribe(OnMouseReleased); hook.MouseMoved .Throttle(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseMoved); hook.MouseDragged .Throttle(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseDragged); hook.MouseWheel.Subscribe(OnMouseWheel); hook.Run(); // or await hook.RunAsync(); ``` -------------------------------- ### Rx.NET Integration with SharpHook Reactive Source: https://github.com/tolikpylypchuk/sharphook/blob/main/README.md Demonstrates how to use SharpHook.Reactive to integrate SharpHook with Rx.NET. This allows subscribing to global input events using Rx.NET observables. It requires the SharpHook.Reactive package and provides a default implementation `ReactiveGlobalHook`. ```csharp using SharpHook.Reactive; // ... var hook = new ReactiveGlobalHook(); hook.HookEnabled.Subscribe(OnHookEnabled); hook.HookDisabled.Subscribe(OnHookDisabled); hook.KeyTyped.Subscribe(OnKeyTyped); hook.KeyPressed.Subscribe(OnKeyPressed); hook.KeyReleased.Subscribe(OnKeyReleased); hook.MouseClicked.Subscribe(OnMouseClicked); hook.MousePressed.Subscribe(OnMousePressed); hook.MouseReleased.Subscribe(OnMouseReleased); hook.MouseMoved .Throttle(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseMoved); hook.MouseDragged .Throttle(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseDragged); hook.MouseWheel.Subscribe(OnMouseWheel); hook.Run(); // or await hook.RunAsync(); ``` -------------------------------- ### R3 Global Hooks Subscription in C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/SharpHook.R3/README.md Demonstrates how to initialize and subscribe to various global keyboard and mouse events using SharpHook.R3's IR3GlobalHook interface. It shows how to use Rx.NET's Subscribe method and Debounce operator for event handling. The hook can be run synchronously or asynchronously. ```csharp using SharpHook.R3; // ... var hook = new R3GlobalHook(); hook.HookEnabled.Subscribe(OnHookEnabled); hook.HookDisabled.Subscribe(OnHookDisabled); hook.KeyTyped.Subscribe(OnKeyTyped); hook.KeyPressed.Subscribe(OnKeyPressed); hook.KeyReleased.Subscribe(OnKeyReleased); hook.MouseClicked.Subscribe(OnMouseClicked); hook.MousePressed.Subscribe(OnMousePressed); hook.MouseReleased.Subscribe(OnMouseReleased); hook.MouseMoved .Debouce(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseMoved); hook.MouseDragged .Debouce(TimeSpan.FromSeconds(0.5)) .Subscribe(OnMouseDragged); hook.MouseWheel.Subscribe(OnMouseWheel); hook.Run(); // or await hook.RunAsync(); ``` -------------------------------- ### Implement Reactive Global Hooks with Rx.NET Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Demonstrates using ReactiveGlobalHook to handle input events as IObservable streams. It showcases operators like Throttle, Where, Select, and Buffer to manage complex event sequences. ```csharp using SharpHook.Reactive; using System.Reactive.Linq; var hook = new ReactiveGlobalHook(); hook.KeyPressed .Where(e => e.Data.KeyCode == KeyCode.VcSpace) .Subscribe(e => Console.WriteLine("Space pressed!")); hook.MouseMoved .Throttle(TimeSpan.FromMilliseconds(100)) .Subscribe(e => Console.WriteLine($"Mouse at ({e.Data.X}, {e.Data.Y})")); var keyboardActivity = hook.KeyPressed.Select(_ => "Key"); var mouseActivity = hook.MousePressed.Select(_ => "Mouse"); keyboardActivity.Merge(mouseActivity) .Buffer(TimeSpan.FromSeconds(5)) .Subscribe(events => Console.WriteLine($"Last 5 seconds: {events.Count} input events")); hook.KeyPressed .Buffer(2, 1) .Where(keys => keys.Count == 2 && keys[0].Data.KeyCode == KeyCode.VcLeftControl && keys[1].Data.KeyCode == KeyCode.VcQ) .Subscribe(_ => { Console.WriteLine("Ctrl+Q detected - quitting"); hook.Stop(); }); hook.HookDisabled.Subscribe(_ => Console.WriteLine("Hook stopped")); await hook.RunAsync(); hook.Dispose(); ``` -------------------------------- ### Simulate Mouse Events with EventSimulator Source: https://context7.com/tolikpylypchuk/sharphook/llms.txt Demonstrates how to perform mouse clicks, absolute and relative cursor movements, and wheel scrolling. It supports various mouse buttons and provides specific parameters for vertical and horizontal scrolling. ```csharp using SharpHook; using SharpHook.Data; var simulator = new EventSimulator(); // Simulate left mouse button click at current position simulator.SimulateMousePress(MouseButton.Button1); simulator.SimulateMouseRelease(MouseButton.Button1); // Simulate right-click at specific coordinates simulator.SimulateMousePress(100, 200, MouseButton.Button2); simulator.SimulateMouseRelease(100, 200, MouseButton.Button2); // Move mouse cursor to absolute position simulator.SimulateMouseMovement(500, 300); // Move mouse cursor relative to current position simulator.SimulateMouseMovementRelative(50, -25); // Simulate mouse wheel scrolling simulator.SimulateMouseWheel( rotation: -120, direction: MouseWheelScrollDirection.Vertical, type: MouseWheelScrollType.UnitScroll ); // Horizontal scroll simulator.SimulateMouseWheel( rotation: 120, direction: MouseWheelScrollDirection.Horizontal, type: MouseWheelScrollType.UnitScroll ); ``` -------------------------------- ### Testing Global Hooks and Event Simulation with SharpHook.Testing Source: https://github.com/tolikpylypchuk/sharphook/blob/main/README.md Offers testing utilities for SharpHook, including `TestGlobalHook` which implements `IGlobalHook` and `IEventSimulator`. Allows for verification of simulated events and provides `TestProvider` for mocking low-level functionality. Requires SharpHook.Testing namespace. ```csharp using SharpHook.Testing; // ... // Using TestGlobalHook as an IEventSimulator for testing var testHook = new TestGlobalHook(); // Simulate events using testHook.Simulate... // Check the SimulatedEvents property to verify actions var simulatedEvents = testHook.SimulatedEvents; // Adapting TestGlobalHook for IReactiveGlobalHook or IR3GlobalHook is also possible. ``` -------------------------------- ### Subscribe to libuiohook logs using Reactive Extensions Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/logging.md Shows how to adapt a standard LogSource into an observable stream using ReactiveLogSourceAdapter for use with Reactive Extensions. ```csharp using SharpHook.Logging; using SharpHook.Native; using SharpHook.Reactive.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); var reactiveLogSource = new ReactiveLogSourceAdapter(logSource); reactiveLogSource.MessageLogged.Subscribe(this.OnMessageLogged); ``` -------------------------------- ### Subscribe to libuiohook logs using R3 Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/logging.md Demonstrates adapting a standard LogSource for use with the R3 library, providing an observable stream of log entries. ```csharp using SharpHook.Logging; using SharpHook.Native; using SharpHook.R3.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); var reactiveLogSource = new R3LogSourceAdapter(logSource); reactiveLogSource.MessageLogged.Subscribe(this.OnMessageLogged); ``` -------------------------------- ### Run macOS Main Run-Loop with C# Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/os-constraints.md Demonstrates how to run the main run-loop on macOS using C# P/Invoke calls to CoreFoundation functions. This is necessary when using global hooks in console applications or background services on threads other than the main thread. It ensures the application's event loop remains active. ```csharp internal static partial class CoreFoundation { private const string CoreFoundationLib = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"; // It's better to use a type derived from SafeHandle as the return type, but it's omitted for brevity [LibraryImport(CoreFoundationLib)] public static partial IntPtr CFRunLoopGetCurrent(); [LibraryImport(CoreFoundationLib)] public static partial void CFRunLoopRun(); [LibraryImport(CoreFoundationLib)] public static partial void CFRunLoopStop(IntPtr rl); } // ... // This method must be called on the main thread public static void RunMainLoop(CancellationToken token) { var loop = CoreFoundation.CFRunLoopGetCurrent(); token.Register(() => CoreFoundation.CFRunLoopStop(loop)); CoreFoundation.CFRunLoopRun(); // This method will block the current thread until CFRunLoopStop is called } // ... var tokenSource = new CancellationTokenSource(); hook.HookDisabled += (sender, e) => tokenSource.Cancel(); _ = hook.RunAsync(); // Ignore the result of RunAsync, do not await it RunMainLoop(tokenSource.Token); ``` -------------------------------- ### Reactive Logging with SharpHook.Reactive Source: https://github.com/tolikpylypchuk/sharphook/blob/main/README.md Provides a reactive approach to handling libuiohook log messages using Rx.NET. Adapts the standard `LogSource` to an `IReactiveLogSource` for use with Rx subscriptions. Requires SharpHook.Logging and SharpHook.Reactive.Logging namespaces. ```csharp using SharpHook.Logging; using SharpHook.Reactive.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); var reactiveLogSource = new ReactiveLogSourceAdapter(logSource); reactiveLogSource.MessageLogged.Subscribe(this.OnMessageLogged); ``` -------------------------------- ### Subscribe to libuiohook logs using LogSource Source: https://github.com/tolikpylypchuk/sharphook/blob/main/docs/articles/logging.md Demonstrates how to register a LogSource to receive log messages and handle them via the MessageLogged event. It includes setting a minimum log level to filter output. ```csharp using SharpHook.Data; using SharpHook.Logging; // ... var logSource = LogSource.RegisterOrGet(minLevel: LogLevel.Info); logSource.MessageLogged += this.OnMessageLogged; private void OnMessageLogged(object? sender, LogEventArgs e) => this.logger.Log(this.AdaptLogLevel(e.LogEntry.Level), e.LogEntry.FullText); ```