GlobalHotKeys.Latur 1.0.6

dotnet add package GlobalHotKeys.Latur --version 1.0.6
                    
NuGet\Install-Package GlobalHotKeys.Latur -Version 1.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GlobalHotKeys.Latur" Version="1.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GlobalHotKeys.Latur" Version="1.0.6" />
                    
Directory.Packages.props
<PackageReference Include="GlobalHotKeys.Latur" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GlobalHotKeys.Latur --version 1.0.6
                    
#r "nuget: GlobalHotKeys.Latur, 1.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GlobalHotKeys.Latur@1.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GlobalHotKeys.Latur&version=1.0.6
                    
Install as a Cake Addin
#tool nuget:?package=GlobalHotKeys.Latur&version=1.0.6
                    
Install as a Cake Tool

GlobalHotKeys

A universal C# library for handling global hotkeys using keyboard and mouse combinations at a low level. Built with modularity, cross-project reuse, and developer ergonomics in mind.


โœ… Features

  • ๐Ÿ“ฆ Global low-level input hook (keyboard + mouse)
  • ๐Ÿ”€ Unified KeyCode enum for keyboard and mouse
  • ๐Ÿง  Combo logic with support for modifier + button combos (e.g. Ctrl + Shift + XButton1)
  • ๐Ÿ”ง Easy registration using Bind and HotkeyCombination
  • ๐Ÿ” Trigger-once execution until all keys are released
  • ๐Ÿงผ Clean modular architecture (fully self-contained)
  • ๐ŸชŸ Built on Win32 SendInput and SetWindowsHookEx

๐Ÿ“‚ Project Structure

File Description
KeyCode.cs Universal enum for all keyboard/mouse keys (like A, F5, XButton1)
HotkeyCombination.cs Represents a set of keys that define a hotkey
Bind.cs Simplifies registration by bundling an ID + combo
ActiveCombination.cs Tracks active/completed state of an input combo
HotkeyRegistry.cs Maps IDs and combos to actions
HookLifecycle.cs Manages low-level Win32 hooks (start, stop, dispose)
Interop.cs Isolated Win32 imports and constants
HotKeys.cs High-level manager for using all of the above

๐Ÿš€ Quick Start

dotnet add package GlobalHotKeys.Latur
using GlobalHotKeys;
using GlobalHotKeys.Structs;

var manager = new GlobalHotKeys.HotKeys();

manager.Register(new Bind("screenshot", KeyCode.Control, KeyCode.F5), async () =>
{
    Console.WriteLine("Screenshot triggered!");
});

manager.Start();

๐Ÿง  How It Works

  1. Low-level hooks are installed using optimized Win32 APIs (no blocking calls)
  2. Keys and mouse buttons are unified into a HashSet<KeyCode>
  3. When a combination is pressed, it's matched against registered actions
  4. The action is only invoked once per full press-release cycle
  5. You can dynamically register, update, or remove combos during runtime

โšก Performance Improvements (v1.0.6+)

  • Instant startup: Eliminated blocking Process.MainModule calls
  • Optimized hook installation: Uses GetModuleHandle(null) for maximum speed
  • Removed unnecessary async overhead: Windows handles callbacks directly
  • Better error handling: Proper cleanup on hook installation failures

๐Ÿ”ง Example Usage

Register a Hotkey:

manager.Register(new Bind("open-dev", KeyCode.LControl, KeyCode.LShift, KeyCode.D), async () =>
{
    Console.WriteLine("Dev Tools Opened");
});

Change an Existing Combo:

manager.Change("open-dev", new HotkeyCombination(false, KeyCode.Control, KeyCode.F1));

Remove a Combo:

manager.Unregister("open-dev");

๐Ÿ–ฅ๏ธ Console Applications

Important: Console applications require a Windows message loop to process low-level hooks. Without a message loop, hotkeys will not work even if the hooks are installed successfully.

Add a reference to System.Windows.Forms and use Application.Run():

using System;
using System.Threading.Tasks;
using System.Windows.Forms; // Add this using
using GlobalHotKeys;
using GlobalHotKeys.Structs;

[STAThread]
public static async Task Main(string[] args)
{
    var hotKeys = new HotKeys();
    hotKeys.Start();

    hotKeys.Register(new Bind("test-hotkey", () => 
    {
        Console.WriteLine("Hotkey triggered!");
        return Task.CompletedTask;
    }, KeyCode.F1, KeyCode.LControl));

    // This runs a proper Windows message loop
    Application.Run();
}

Solution 2: Custom Message Loop (No Dependencies)

If you prefer not to add WinForms dependency, implement a minimal message loop:

using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using GlobalHotKeys;
using GlobalHotKeys.Structs;

[STAThread]
public static async Task Main(string[] args)
{
    var hotKeys = new HotKeys();
    hotKeys.Start();

    hotKeys.Register(new Bind("test-hotkey", () => 
    {
        Console.WriteLine("Hotkey triggered!");
        return Task.CompletedTask;
    }, KeyCode.F1, KeyCode.LControl));

    // Run a minimal message loop
    while (true)
    {
        var msg = new MSG();
        var result = GetMessage(ref msg, IntPtr.Zero, 0, 0);
        
        if (result <= 0) break; // WM_QUIT or error
        
        TranslateMessage(ref msg);
        DispatchMessage(ref msg);
    }
}

// Required P/Invoke declarations
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
    public IntPtr hwnd;
    public uint message;
    public IntPtr wParam;
    public IntPtr lParam;
    public uint time;
    public POINT pt;
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int x, y;
}

[DllImport("user32.dll")]
static extern int GetMessage(ref MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);

[DllImport("user32.dll")]
static extern bool TranslateMessage(ref MSG lpMsg);

[DllImport("user32.dll")]
static extern IntPtr DispatchMessage(ref MSG lpMsg);

Why This Is Required

Low-level hooks (WH_KEYBOARD_LL and WH_MOUSE_LL) are processed by Windows through the message queue. Console applications don't have a message loop by default, so:

  1. โœ… Hooks install successfully
  2. โœ… Windows calls your hook procedures when input occurs
  3. โŒ Without a message loop, the thread doesn't process messages
  4. โŒ Hotkeys appear to not work

The message loop ensures that Windows can properly deliver hook callbacks to your application.


๐Ÿ”’ Limitations

  • Windows-only (relies on SetWindowsHookEx)
  • Must run on STA thread for hook reliability
  • Cannot detect keys consumed by some protected fullscreen games
  • Console applications require a message loop (see Console Apps section below)

๐Ÿ› Fixed Issues

  • โœ… Startup lag in WinForm applications (especially when debugging)
  • โœ… Infinite stutter in Console applications
  • โœ… Performance issues with hook installation
  • โœ… Resource leaks on hook installation failures

๐Ÿ”ง Troubleshooting

Common Issues

Q: My application still has startup lag after updating A: Make sure you're using the latest version (v1.0.6+). The performance improvements are significant.

Q: Hooks don't work in my Console application A: Console applications require a Windows message loop to process low-level hooks. See the Console Applications section above for complete solutions.

Q: Hotkeys don't trigger in some games A: Some games with anti-cheat systems may block low-level hooks. This is a security feature, not a library issue.

Q: Getting "Failed to install hook" errors A: Ensure your application has sufficient permissions and isn't running in a sandboxed environment.


๐Ÿงฑ Building from Source

git clone https://github.com/latur-h/GlobalHotKeys
cd GlobalHotKeys
dotnet build -c Release

๐Ÿ“‹ Version History

v1.0.6+ (Latest)

  • โšก Major Performance Improvements
    • Eliminated startup lag in WinForm and Console applications
    • Replaced blocking Process.MainModule with fast GetModuleHandle(null)
    • Removed unnecessary async task overhead
    • Added robust error handling and cleanup
  • ๐Ÿ›ก๏ธ Enhanced Reliability
    • Better hook installation error handling
    • Proper resource cleanup on failures
    • Improved thread safety

v1.0.5 and earlier

  • Initial release with basic hotkey functionality
  • Global keyboard and mouse hook support
  • Hotkey combination matching and execution

๐Ÿ“œ License

MIT โ€” free for personal and commercial use.

Product 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 was computed.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

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
1.0.6 404 9/16/2025
1.0.5 233 5/27/2025
1.0.4 237 5/27/2025
1.0.3 232 5/27/2025
1.0.2 231 5/27/2025
1.0.1 232 5/27/2025
1.0.0 229 5/26/2025