livesplit-core icon indicating copy to clipboard operation
livesplit-core copied to clipboard

Add support for detecting press and release events in `livesplit-hotkey` via new API `register_specific`

Open SpikeHD opened this issue 4 months ago • 0 comments

Closes #633

Changes

Adds register_specific, which allows the developer to provide a callback that takes a single boolean argument that dictates whether the event was a press or release.

Disclaimer

I understand that the issue this is linked to was labelled "needs further discussion" due to it being a bit out of scope of the needs of livesplit, which is totally fair. I originally implemented this for my own use, but decided it was worth PR'ing just in case it would be considered.

The entire implementation is feature-gated, partly due to this concern:

especially in our case where the timing is really important.

which is valid! The feature gating means it should not effect the existing hotkey registration/performance in any way, so long as the feature is not explicitly enabled.

Other notes

  • The reason I chose this crate over others is due to it having the most comprehensive keycode support I've seen, as well as the direct mapping from JS/browser keycodes to the Rust KeyCode struct you provide, both of which are important to my use-case. I might even say (as someone who has explored many) that this is one of the best global-keyboard-input-reading crates in the ecosystem right now, so thank you for providing it publicly!
  • I have tested on my Windows, Linux, and macOS machines, but had trouble figuring out testing WASM (it's new to me), so that's untested
  • I should also note that I am not married to the naming scheme I chose and would be happy to change it to whatever fits better. I don't totally think register_specific is obvious enough in expressing what it actually does/allows haha

Test Program

use livesplit_hotkey::{ConsumePreference, Hook, Hotkey, KeyCode, Modifiers};

pub fn main() {
    let hook = Hook::with_consume_preference(ConsumePreference::NoPreference).unwrap();
    let hotkey = Hotkey {
        key_code: KeyCode::ArrowUp,
        modifiers: Modifiers::CONTROL,
    };

    hook.register_specific(hotkey, |pressed| {
        if pressed {
            println!("Control + Up Arrow was pressed!");
        } else {
            println!("Control + Up Arrow was released!");
        }
    }).unwrap();

    loop {
      std::thread::park();
      std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

SpikeHD avatar Aug 17 '25 21:08 SpikeHD