Registering and Managing Keybindings

Updated 21 October, 2026

Registering and Managing Keybindings

Nexus manages keybinds for all addons in one place. You register a named keybind with a default key combination and a handler, and Nexus takes care of the rest: detecting the keys, letting the user rebind them on the Keybinds page, warning about conflicts and saving their choice. You never need to write your own window procedure for this. This guide covers registering and handling keybinds, triggering them from code, pressing game keys and processing raw window messages.

Registering a keybind

A keybind has an identifier, a handler and a default key combination. The easiest way is to pass the default as a string:

#define KB_TOGGLE "KB_MYADDON_TOGGLE"

void ProcessKeybind(const char* aIdentifier, bool aIsRelease);

void AddonLoad(AddonAPI_t* aApi)
{
	APIDefs = aApi;
	APIDefs->InputBinds_RegisterWithString(KB_TOGGLE, ProcessKeybind, "ALT+SHIFT+M");
}
  • Identifiers are global across all addons. Prefix them with your addon's name, for example KB_MYADDON_TOGGLE.
  • The default only applies once. When a keybind is registered for the first time, Nexus stores the default. From then on, the user's choice is used, even if you change the default in a later version.
  • Defaults never steal. If another keybind already uses your default combination, yours is registered without a key, and the user can assign one.
  • Choose defaults carefully. A default that collides with a game keybind takes that key away from the game until the user notices. Use modifier combinations, or register toggles without a default by passing "(null)" and let users choose a key, especially if your addon also has a Quick Access shortcut.

The string format

The string consists of optional modifiers ALT, CTRL and SHIFT and one key, separated by +, for example "CTRL+SHIFT+F5". Mouse buttons are written as MMB, M4 and M5. Key names are resolved with the user's keyboard layout, which works reliably for letters, digits and function keys. For other keys, whose names can differ between layouts and languages, register with a struct instead.

Registering with a struct

InputBinds_RegisterWithStruct takes a Keybind_t. Its Key field is a keyboard scan code, not a virtual-key code. Convert virtual-key codes with MapVirtualKeyA, which also sets the 0xE0 prefix that extended keys such as the arrow keys need:

Keybind_t kb{};
kb.Key   = (uint16_t)MapVirtualKeyA(VK_PRIOR, MAPVK_VK_TO_VSC_EX); /* Page Up */
kb.Alt   = false;
kb.Ctrl  = true;
kb.Shift = false;

APIDefs->InputBinds_RegisterWithStruct("KB_MYADDON_PAGEUP", ProcessKeybind, kb);

Handling key presses

Your handler receives the identifier of the keybind and whether the keys were pressed or released. It is called once when the combination is pressed, and once when it is released again. Key repeat while the keys are held does not trigger it again.

static std::atomic s_IsVisible = false;

void ProcessKeybind(const char* aIdentifier, bool aIsRelease)
{
	if (aIsRelease) { return; }

	if (strcmp(aIdentifier, KB_TOGGLE) == 0)
	{
		s_IsVisible = !s_IsVisible;
	}
}
  • One handler can serve several keybinds. Compare the identifier with strcmp, never by pointer.
  • Most toggles should ignore releases, as above. Releases are useful for hold-to-show behavior.
  • Handlers run on their own short-lived thread, not on the render thread, and the press and release of the same keybind may even run concurrently. Do not call ImGui from a handler. Set a flag or queue a message, and act on it in your render callback. Use atomics or a mutex for anything the handler shares with other code.
  • Keep handlers quick, and do not keep the aIdentifier pointer after the handler returns.

Readable names on the Keybinds page

The Keybinds page shows each keybind under your addon, labelled with its identifier. Provide a readable name through the localization system, which also lets you translate it:

APIDefs->Localization_Set(KB_TOGGLE, "en", "Toggle My Addon");
APIDefs->Localization_Set(KB_TOGGLE, "de", "My Addon ein-/ausblenden");

See Localizing Nexus Addons for more.

Deregistering

Call InputBinds_Deregister for every keybind in your unload function. This removes your handler, but the user's chosen key combination is kept, so it is still there when your addon loads again.

void AddonUnload()
{
	APIDefs->InputBinds_Deregister(KB_TOGGLE);
}

Keys and the game

When a key combination triggers a keybind, Nexus does not pass the key press on to the game. Users can change this per keybind with Allow keys to pass through to the game on the Keybinds page. You do not need to handle this yourself.

Triggering keybinds from code

InputBinds_Invoke(identifier, isRelease) calls the handler of any registered keybind, as if the user had pressed it. This is how Quick Access shortcuts work, and it lets addons offer actions to each other without sharing code:

APIDefs->InputBinds_Invoke("KB_OTHERADDON_TOGGLE", false);

Pressing game keys

The GameBinds_* functions press the keys the user has bound to a game action, identified by EGameBinds, for example GB_SkillWeaponSwap or GB_Loadout3. Nexus translates the action into the user's actual keys, based on the game keybinds the user has set up in Nexus.

Function Effect
GameBinds_IsBound(bind) Whether the user has a key set for the action. Check this first and tell the user if it is missing.
GameBinds_InvokeAsync(bind, durationMs) Presses the keys, holds them for the given duration and releases them, without blocking.
GameBinds_Press(bind), GameBinds_Release(bind) Presses or releases the keys immediately.
GameBinds_PressAsync(bind), GameBinds_ReleaseAsync(bind) The same, without blocking the calling thread.

Pressing game keys on the player's behalf is exactly what ArenaNet's macro policy regulates. One user action may lead to one game action. Addons in the Nexus library that do this are labelled Uses Macros, see the Addon Policy.

Processing window messages

For input that keybinds cannot express, such as text input, mouse movement or holding keys while dragging, register a window procedure callback. It receives every message sent to the game window before the game sees it:

UINT AddonWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (uMsg == WM_KEYDOWN && wParam == VK_F8 && s_IsCapturing)
	{
		return 0; /* Consumed: neither the game, Nexus nor later addons receive it. */
	}

	return uMsg; /* Pass the message on. */
}

APIDefs->WndProc_Register(AddonWndProc);

/* In Unload: */
APIDefs->WndProc_Deregister(AddonWndProc);

Return the message unchanged to pass it on, or 0 to consume it. Consume messages only when you are sure, since doing so takes input away from the game and from every other addon. The callback runs on the game's window thread for every message, so keep it fast.

To send a message straight to the game, bypassing Nexus, ImGui and all other addons, use WndProc_SendToGameOnly with the same parameters as a regular window procedure.

If you only need to know whether ImGui wants the keyboard or mouse, for example to avoid reacting to keys while the user types into an ImGui text field, check ImGui::GetIO().WantCaptureKeyboard in your render callback instead.