# How YimMenuV2 HotkeySystem Registers and Handles Keyboard Shortcuts

> Discover how YimMenuV2's HotkeySystem registers and handles keyboard shortcuts. Learn about startup registration, key polling, and JSON persistence for seamless menu command binding.

- Repository: [YimMenu/YimMenuV2](https://github.com/YimMenu/YimMenuV2)
- Tags: how-to-guide
- Published: 2026-07-17

---

**YimMenuV2 binds every menu command to arbitrary key combinations through a centralized HotkeySystem that registers commands on startup, polls for key states in a dedicated script loop, and persists bindings via JSON serialization.**

YimMenuV2 implements a flexible input layer through its **HotkeySystem**, allowing users to bind commands to complex key chains like `Ctrl + F`. According to the YimMenu/YimMenuV2 source code, the system is encapsulated in `src/core/commands/HotkeySystem.{hpp,cpp}` and operates through three distinct stages: registration, runtime listening, and persistence.

## Command Registration at Startup

During initialization, [`main.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/main.cpp) invokes `g_HotkeySystem.RegisterCommands()` to populate the internal command map. As implemented in [`src/core/commands/HotkeySystem.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/core/commands/HotkeySystem.cpp) (lines 21-33), this method iterates over the global registry returned by `Commands::GetCommands()` and instantiates a `CommandLink` structure for each entry. These links are stored in the `m_CommandHotkeys` map, keyed by command hash.

The system pre-binds the special "chathelper" command to the **T** key (virtual-key code `0x54`) to ensure the chat overlay remains accessible regardless of user configuration.

## Runtime Key State Listening

Once registered, the hotkey engine executes within its own script fiber added via `ScriptMgr::AddScript(&HotkeySystem::RunScript)`. The `RunScriptImpl()` method, found in [`src/core/commands/HotkeySystem.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/core/commands/HotkeySystem.cpp) (lines 95-132), runs continuously and performs the following checks each tick:

- Verifies the game window is foreground, not paused, and that the UI is not currently capturing keyboard input.
- Confirms the system is not in edit mode (`!m_BeingModified`).
- Iterates through each registered `CommandLink` and validates its `m_Chain` (a `std::vector<int>` of virtual-key codes) using `GetAsyncKeyState`.

Only when **all** keys in a chain report down-state and at least **100 ms** have elapsed since the previous trigger does the system fetch the command via `Commands::GetCommand(hash)` and execute it. Chat commands specifically run on a separate fiber to prevent blocking the main loop.

## Creating and Editing Hotkeys

When users open the hotkey editor UI ([`DrawHotkey.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/DrawHotkey.cpp)), the system calls `HotkeySystem::SetBeingModifed(true)` to pause the listening loop and prevent accidental triggers during configuration.

The `CreateHotkey()` method (lines 71-92 in [`HotkeySystem.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/HotkeySystem.cpp)) drives the capture process:

1. Invokes `ListenAndApply(pressed_key, chain)`, which scans all virtual keys from `0` to `VK_OEM_CLEAR`.
2. Applies a blacklist filter (defaulting to key `0`) to ignore unintended inputs.
3. Uses an `is_key_unique` lambda to prevent duplicate keys within the same chain.
4. Appends valid new keys to the `m_Chain` vector and marks the state dirty for persistence.

Once editing completes, `SetBeingModifed(false)` resumes normal listening.

## Persistence Layer

Hotkey bindings survive game restarts through the `IStateSerializer` interface. In [`src/core/commands/HotkeySystem.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/core/commands/HotkeySystem.cpp) (lines 43-67), `SaveStateImpl()` serializes each non-empty `m_Chain` to a JSON object keyed by command hash, while `LoadStateImpl()` restores these bindings during startup. This ensures user configurations persist across sessions without manual file editing.

## Implementation Example

The following snippet demonstrates the integration points in [`main.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/main.cpp) and the UI layer:

```cpp
// src/main.cpp - Initialization
g_HotkeySystem.RegisterCommands();
ScriptMgr::AddScript(std::make_unique<Script>(&HotkeySystem::RunScript));

```

```cpp
// src/game/frontend/items/DrawHotkey.cpp - Editing mode
HotkeySystem::SetBeingModifed(true);        // Pause detection
g_HotkeySystem.CreateHotkey(link->m_Chain); // Capture user input
HotkeySystem::SetBeingModifed(false);       // Resume detection

```

## Summary

- **Registration**: `RegisterCommands()` populates `m_CommandHotkeys` with `CommandLink` entries for every available command, including the default chathelper binding.
- **Runtime Detection**: `RunScriptImpl()` uses `GetAsyncKeyState` to validate complete key chains stored in `m_Chain`, enforcing a 100ms cooldown between triggers.
- **Edit Mode**: `SetBeingModifed()` toggles a boolean flag that pauses key listening while users configure new bindings via `CreateHotkey()`.
- **Persistence**: The `IStateSerializer` implementation saves and loads key chains as JSON, keyed by command hash, ensuring bindings persist across game sessions.

## Frequently Asked Questions

### Where is the HotkeySystem implemented in YimMenuV2?

The core logic resides in [`src/core/commands/HotkeySystem.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/core/commands/HotkeySystem.hpp) and [`src/core/commands/HotkeySystem.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/core/commands/HotkeySystem.cpp), with UI integration in [`src/game/frontend/items/DrawHotkey.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/frontend/items/DrawHotkey.cpp) and initialization in [`src/main.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/main.cpp).

### How does the system prevent hotkeys from firing while editing bindings?

When the hotkey editor opens, `SetBeingModifed(true)` sets the `m_BeingModified` flag to `true`, causing `RunScriptImpl()` to skip command execution until editing completes.

### What is the cooldown period between hotkey triggers?

The system enforces a **100 millisecond** debounce timer to prevent rapid-fire activation when holding a key combination.

### How are multi-key combinations stored internally?

Key chains are stored as `std::vector<int>` in the `m_Chain` member of `CommandLink`, where each integer represents a Windows virtual-key code (e.g., `0x11` for Ctrl, `0x46` for F).