xiaohongshu
xiaohongshu
global-hotkey
Cross-platform global keyboard shortcuts
Full skill instructions
Cross-platform Rust library for registering system-wide keyboard shortcuts that work even when your application isn't focused. Part of the Tauri ecosystem.
Crate: global-hotkey (v0.7.0) Docs: https://docs.rs/global-hotkey
The central manager that handles hotkey registration with the OS.
use global_hotkey::GlobalHotKeyManager;
let manager = GlobalHotKeyManager::new().unwrap();
Methods:
new() - Create a new manager (must be on correct thread per platform)register(hotkey: HotKey) - Register a single hotkeyunregister(hotkey: HotKey) - Unregister a hotkeyregister_all(&[HotKey]) - Register multiple hotkeysunregister_all(&[HotKey]) - Unregister multiple hotkeysRepresents a keyboard shortcut (modifiers + key).
use global_hotkey::hotkey::{HotKey, Code, Modifiers};
// Programmatic construction
let hotkey = HotKey::new(Some(Modifiers::SHIFT | Modifiers::META), Code::KeyK);
// Parse from string (modifiers before key)
let hotkey: HotKey = "shift+alt+KeyQ".parse().unwrap();
Fields:
mods: Modifiers - Modifier keyskey: Code - The main keyid: u32 - Unique ID (hash of modifiers + key)Methods:
id() - Get the hotkey's unique IDmatches(modifiers, key) - Check if modifiers/key matchinto_string() - Convert to string representationBitflags for modifier keys:
use global_hotkey::hotkey::Modifiers;
let mods = Modifiers::META | Modifiers::SHIFT;
let mods = Modifiers::CONTROL | Modifiers::ALT;
let mods = Modifiers::empty(); // No modifiers
Modifiers::ALT (Option on macOS)Modifiers::CONTROLModifiers::META (Cmd on macOS, Win on Windows)Modifiers::SHIFTModifiers::SUPER (alias for META)Constant: CMD_OR_CTRL - META on macOS, CONTROL elsewhere
Physical key codes (from keyboard-types crate):
use global_hotkey::hotkey::Code;
// Letters
Code::KeyA, Code::KeyB, ..., Code::KeyZ
// Numbers
Code::Digit0, Code::Digit1, ..., Code::Digit9
// Function keys
Code::F1, Code::F2, ..., Code::F12
// Special keys
Code::Space, Code::Enter, Code::Tab, Code::Escape
Code::Backspace, Code::Delete
Code::ArrowUp, Code::ArrowDown, Code::ArrowLeft, Code::ArrowRight
Code::Home, Code::End, Code::PageUp, Code::PageDown
// Punctuation
Code::Semicolon, Code::Quote, Code::Comma, Code::Period
Code::Slash, Code::Backslash, Code::Minus, Code::Equal
Code::BracketLeft, Code::BracketRight, Code::Backquote
Event emitted when a hotkey is pressed or released.
use global_hotkey::{GlobalHotKeyEvent, HotKeyState};
let receiver = GlobalHotKeyEvent::receiver();
// Blocking receive
if let Ok(event) = receiver.recv() {
if event.state == HotKeyState::Pressed {
println!("Hotkey {} pressed", event.id);
}
}
// Non-blocking
if let Ok(event) = receiver.try_recv() {
// Handle event
}
Fields:
id: u32 - The hotkey ID that was triggeredstate: HotKeyState - Pressed or Releaseduse global_hotkey::Error;
match manager.register(hotkey) {
Ok(()) => println!("Registered"),
Err(Error::AlreadyRegistered(hk)) => {
println!("Hotkey {} already registered", hk.id());
}
Err(Error::FailedToRegister(msg)) => {
println!("System rejected: {}", msg);
}
Err(Error::OsError(e)) => {
println!("OS error: {}", e);
}
Err(e) => println!("Other error: {}", e),
}
Variants:
AlreadyRegistered(HotKey) - Another app has this hotkeyFailedToRegister(String) - System rejected (reserved hotkey)FailedToUnRegister(HotKey) - Unregister failedOsError(io::Error) - Platform-specific errorHotKeyParseError(String) - Invalid hotkey stringUnrecognizedHotKeyCode(String) - Unknown key codesrc/hotkeys.rs - Main hotkey management with unified routingsrc/shortcuts/hotkey_compat.rs - Shortcut string parsingscript-kit-gpui uses a unified routing table pattern:
// Global manager stored in OnceLock
static MAIN_MANAGER: OnceLock<Mutex<GlobalHotKeyManager>> = OnceLock::new();
// Routing table maps hotkey ID -> action
struct HotkeyRoutes {
routes: HashMap<u32, RegisteredHotkey>,
script_paths: HashMap<String, u32>, // Reverse lookup
main_id: Option<u32>,
notes_id: Option<u32>,
ai_id: Option<u32>,
}
pub enum HotkeyAction {
Main, // Main launcher
Notes, // Notes window
Ai, // AI window
Script(String), // Run script at path
}
Transactional rebind - register new BEFORE unregistering old:
fn rebind_hotkey_transactional(
manager: &GlobalHotKeyManager,
action: HotkeyAction,
mods: Modifiers,
code: Code,
display: &str,
) -> bool {
let new_hotkey = HotKey::new(Some(mods), code);
// 1. Register new first (fail-safe)
if let Err(e) = manager.register(new_hotkey) {
return false; // Keep existing hotkey working
}
// 2. Update routing table
// 3. Unregister old (best-effort)
}
The parse_shortcut function supports flexible formats:
// All equivalent:
parse_shortcut("cmd shift k") // Space-separated
parse_shortcut("cmd+shift+k") // Plus-separated
parse_shortcut("Cmd + Shift + K") // Mixed with spaces
// Modifier aliases:
// cmd, command, meta, super, win -> Modifiers::META
// ctrl, control, ctl -> Modifiers::CONTROL
// alt, opt, option -> Modifiers::ALT
// shift, shft -> Modifiers::SHIFT
On macOS, script-kit-gpui uses GCD dispatch for immediate main-thread execution:
#[cfg(target_os = "macos")]
mod gcd {
pub fn dispatch_to_main<F: FnOnce() + Send + 'static>(f: F) {
// Uses dispatch_async_f to run on main thread
// Works even before GPUI event loop is "warmed up"
}
}
pub(crate) fn start_hotkey_listener(config: Config) {
std::thread::spawn(move || {
let manager = GlobalHotKeyManager::new().unwrap();
// Register builtin hotkeys (main, notes, ai)
// Register script shortcuts
let receiver = GlobalHotKeyEvent::receiver();
loop {
if let Ok(event) = receiver.recv() {
if event.state != HotKeyState::Pressed {
continue;
}
// Look up action in routing table
let action = routes().read().unwrap().get_action(event.id);
match action {
Some(HotkeyAction::Main) => { /* toggle main window */ }
Some(HotkeyAction::Script(path)) => { /* run script */ }
// ...
}
}
}
});
}
// WRONG on macOS - will fail silently
std::thread::spawn(|| {
let manager = GlobalHotKeyManager::new(); // May work but events won't fire
});
// CORRECT - create on main thread, store globally
let manager = GlobalHotKeyManager::new().unwrap();
static MANAGER: OnceLock<Mutex<GlobalHotKeyManager>> = OnceLock::new();
MANAGER.set(Mutex::new(manager)).unwrap();
// WRONG - can't unregister later
manager.register(HotKey::new(Some(mods), code));
// CORRECT - store the HotKey object
let hotkey = HotKey::new(Some(mods), code);
stored_hotkeys.insert(hotkey.id(), hotkey);
manager.register(hotkey);
// Later...
manager.unregister(stored_hotkeys.remove(&id).unwrap());
// WRONG - silent failure
let _ = manager.register(hotkey);
// CORRECT - handle errors
match manager.register(hotkey) {
Ok(()) => log!("Registered {}", shortcut),
Err(Error::AlreadyRegistered(_)) => {
log!("Conflict: {} used by another app", shortcut);
}
Err(e) => log!("Failed: {}", e),
}
// WRONG - user loses hotkey if new registration fails
manager.unregister(old_hotkey);
if manager.register(new_hotkey).is_err() {
// Old hotkey is gone, new didn't work - user has no hotkey!
}
// CORRECT - transactional: register new first
if manager.register(new_hotkey).is_ok() {
manager.unregister(old_hotkey); // Safe to remove old
} else {
// Old hotkey still works
}
// WRONG - fires twice (press and release)
if let Ok(event) = receiver.recv() {
run_action(event.id);
}
// CORRECT - only handle press events
if let Ok(event) = receiver.recv() {
if event.state == HotKeyState::Pressed {
run_action(event.id);
}
}
// WRONG on macOS - blocks the main thread event loop
fn main() {
let receiver = GlobalHotKeyEvent::receiver();
loop {
receiver.recv(); // Blocks forever, NSApplication never runs
}
}
// CORRECT - run listener in separate thread
std::thread::spawn(|| {
let receiver = GlobalHotKeyEvent::receiver();
loop {
if let Ok(event) = receiver.recv() {
// Dispatch to main thread
}
}
});
// Main thread runs the GUI event loop
serde - Enable serialization for HotKeytracing - Add tracing instrumentationxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience