MouseKeyHook

repository·vNext·Indexed 22 days ago

https://github.com/gmamaladze/globalmousekeyhook

A C# library for Windows and .NET Framework 4.0+ that allows developers to detect and record global keyboard and mouse events, even when an application is running in the background. It provides capabilities for input suppression, tracking mouse coordinates and button states, and detecting complex keyboard shortcuts via the Combination class, key sequences via the Sequence class, and managed hotkey sets using HotKeySetsListener.

Tokens
2.6K
Snippets
8
Records
9
Agent score
75%

What's inside MouseKeyHook

  1. How MouseKeyHook works and available data

    vNext

    The library attaches to Windows global hooks to track input and raises standard .NET events.

    Standard events provide:

    • Mouse coordinates
    • Mouse buttons clicked
    • Mouse drag actions
    • Mouse wheel scrolls
    • Key presses and releases
    • Special key states

    Extended arguments (MouseEventExtArgs and KeyEventExtArgs) provide additional capabilities:

    • Input suppression: You can prevent an input from reaching other applications by setting e.Handled = true within the event handler.
    • Timestamp: The exact time the event occurred.
    • State detection: IsMouseDown/Up for mouse and IsKeyDown/Up for keys.
  2. Subscribe to global keyboard and mouse events

    vNext

    To detect keyboard and mouse activity globally (even when your application is in the background), use Hook.GlobalEvents() to obtain an IKeyboardMouseEvents instance.

    If you only want to capture events occurring within your own application, use Hook.AppEvents() instead.

    Lifecycle Management:

    • Subscribe: Attach event handlers to the IKeyboardMouseEvents instance.
    • Unsubscribe: Detach event handlers and call .Dispose() on the hook instance to release resources.
    private IKeyboardMouseEvents m_GlobalHook;
    
    public void Subscribe()
    {
        // Use Hook.AppEvents() for application-only hooks
        m_GlobalHook = Hook.GlobalEvents();
    
        m_GlobalHook.MouseDownExt += GlobalHookMouseDownExt;
        m_GlobalHook.KeyPress += GlobalHookKeyPress;
    }
    
    private void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
    {
        Console.WriteLine("KeyPress: \t{0}", e.KeyChar);
    }
    
    private void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
    {
        Console.WriteLine("MouseDown: \t{0}; \t System Timestamp: \t{1}", e.Button, e.Timestamp);
    }
    
    public void Unsubscribe()
    {
        m_GlobalHook.MouseDownExt -= GlobalHookMouseDownExt;
        m_GlobalHook.KeyPress -= GlobalHookKeyPress;
    
        // It is recommended to dispose it
        m_GlobalHook.Dispose();
    }
  3. Assign actions to key combinations

    vNext

    Once combinations are defined, you must map them to Action objects (methods with void return and no arguments, or trivial lambdas).

    To start listening, use Hook.GlobalEvents().OnCombination(assignment). The assignment parameter accepts an IEnumerable<KeyValuePair<Combination, Action>>, meaning you can pass a Dictionary<Combination, Action> or a collection that allows multiple actions per combination.

    Use Hook.GlobalEvents() to listen to all keyboard events from all applications, or Hook.AppEvents() to limit listening to events originating from your own application.

    // 1. Define combinations
    var undo = Combination.FromString("Control+Z");
    
    // 2. Define actions
    Action actionUndo = DoSomething;
    void DoSomething() => Console.WriteLine("You pressed UNDO");
    
    // 3. Assign and start
    var assignment = new Dictionary<Combination, Action>
    {
        {undo, actionUndo}
    };
    
    Hook.GlobalEvents().OnCombination(assignment);
  4. Configure HotKeySetsListener and HotKeySetCollection

    vNext

    To manage multiple hotkey combinations, use HotKeySetCollection to store HotKeySet objects and pass the collection to a HotKeySetsListener. The HotKeySetsListener must be initialized with a GlobalHooker and its Enabled property must be set to true to begin intercepting input.

    Key components:

    • HotKeySetCollection: A container for multiple HotKeySet definitions.
    • HotKeySetsListener: A listener that manages the lifecycle of the hotkeys within a collection.
    • GlobalHooker: The underlying engine used to hook into global input events.
    HotKeySetCollection hkscoll = new HotKeySetCollection();
    // Initialize the listener with the collection and a GlobalHooker
    m_KeyboardHookManager = new HotKeySetsListener(hkscoll, new GlobalHooker()) { Enabled = true };
  5. Detect key combinations using the Combination class

    vNext

    To detect keyboard shortcuts (e.g., Control+Z), use the Combination class. You can define combinations using Combination.FromString(string) or by chaining methods.

    In a combination string, the last key is the trigger key. The combination is detected when the trigger key is pressed while all other keys in the string are already held down. The order of keys preceding the trigger key does not matter (e.g., Shift+Alt+Enter is equivalent to Alt+Shift+Enter).

    Key names must correspond to Keys enum member names.

    // Using strings (most convenient)
    var undo = Combination.FromString("Control+Z");
    var fullScreen = Combination.FromString("Shift+Alt+Enter");
    
    // Using builder methods
    var undo2 = Combination.TriggeredBy(Keys.Z).With(Keys.Control);
  6. Detect key sequences using the Sequence class

    vNext

    To detect a series of key presses (e.g., Escape,Escape,Escape), use the Sequence class. A sequence is treated as a series of combinations, defined as a comma-separated list of combination strings.

    Map sequences to actions using Hook.GlobalEvents().OnSequence(assignment).

    Note on overlapping sequences: If you define overlapping sequences (e.g., A,B,C and B,C), the library follows the "longest sequence matches" rule. If the user types A,B,C, only the action for the longest sequence (A,B,C) will fire; the shorter sequence (B,C) will be ignored.

    // 1. Define sequences
    var exitVim = Sequence.FromString("Shift+Z,Z");
    var rename = Sequence.FromString("Control+R,R");
    var exitReally = Sequence.FromString("Escape,Escape,Escape");
    
    // 2. Define actions and assignment
    var assignment = new Dictionary<Sequence, Action>
    {
        {exitVim, () => Console.WriteLine("No!")},
        {rename, () => Console.WriteLine("rename2")},
        {exitReally, () => Console.WriteLine("Ok.")},
    };
    
    // 3. Start listening
    Hook.GlobalEvents().OnSequence(assignment);
  7. Define a HotKeySet with XOR (OR) logic

    vNext

    A HotKeySet defines a specific combination of keys that trigger events. You can use RegisterExclusiveOrKey to specify that certain keys in the set should be treated as an 'OR' condition (e.g., LShiftKey OR RShiftKey) rather than an 'AND' condition.

    Rules for XOR keys:

    1. The xorKeys array must be a subset of the primary keys provided to the HotKeySet constructor.
    2. If RegisterExclusiveOrKey returns Keys.None, the registration failed (likely because the subset was not contained within the original set).

    Events available on HotKeySet:

    • OnHotKeysDownOnce: Fired the first time the key combination is pressed.
    • OnHotKeysDownHold: Fired repeatedly as long as the keys are held down (but not on the initial press).
    • OnHotKeysUp: Fired when any key from the set is released.
    // Define keys: T and (LShift OR RShift)
    HotKeySet hks = new HotKeySet(new[] { Keys.T, Keys.LShiftKey, Keys.RShiftKey });
    
    // Register LShiftKey and RShiftKey as an OR subset
    if (hks.RegisterExclusiveOrKey(new[] { Keys.LShiftKey, Keys.RShiftKey }) != Keys.None)
    {
        // Success
    }
    
    // Subscribe to events
    hks.OnHotKeysDownOnce += MyDownOnceHandler;
    hks.OnHotKeysDownHold += MyDownHoldHandler;
    hks.OnHotKeysUp += MyKeyUpHandler;
  8. Handle HotKeySet events

    vNext

    Event handlers for HotKeySet receive the HotKeySet instance as the sender and HotKeyArgs as the event arguments. HotKeyArgs provides a Time property indicating when the event occurred.

    Example handler signature:

    private void OnHotKeyDownOnce1(object sender, HotKeyArgs e)
    {
        HotKeySet hks = sender as HotKeySet;
        DateTime time = e.Time;
        // Access hks.HotKeys to see the keys involved
    }
    private void OnHotKeyDownOnce1(object sender, HotKeyArgs e)
    {
        GeneralHotKeyEvent(sender, e.Time, "ONCE");
    }