Keybinds — Keybind
Burnsie.Common.Input.Keybind represents a keyboard chord (main key + optional modifier)
with an optional controller equivalent. It fixes the two things plugins habitually get
wrong: modifier semantics and input suppression.
Quick start
// Keyboard-only chord — Ctrl+B (either Ctrl key):
var bind = new Keybind(Keys.B, Keys.Control);
// With a controller chord (hold RB, press A):
var bind2 = new Keybind(Keys.B, Keys.Control,
ControllerButtons.A, ControllerButtons.RightShoulder);
// In your tick loop:
if (bind.IsJustPressed())
{
// fired once per press; automatically suppressed when the console is open,
// the game is paused, or the user is typing into an on-screen keyboard
}
// For hold-to-confirm mechanics:
if (bind.IsHeld()) { /* level semantics — true every tick while held */ }
// For help text / config docs:
string label = bind.FriendlyName(); // "Ctrl+B", or "Ctrl+B (pad: RightShoulder+A)"
Bind values usually come from config — ConfigSchema.Enum parses Keys and
ControllerButtons by name (see Configuration):
var keyEntry = schema.Enum("Keybindings", "Key", Keys.B, "Activation key.");
var modEntry = schema.Enum("Keybindings", "Modifier", Keys.Control, "Hold with the key. None = no modifier.");
// after schema.Load():
var bind = new Keybind(keyEntry.Value, modEntry.Value);
Modifier semantics (the part v1 got wrong)
- Composite values —
Keys.Control,Keys.Shift,Keys.Alt— match either physical key (left or right). This is what users mean when they writeControlin an INI. - Explicit L/R keys —
Keys.LControlKey,Keys.RShiftKey, etc. — match exactly that key. Keys.Noneas the modifier means no modifier required;Keys.Noneas the main key disables the keyboard chord entirely (controller-only binds).- Any other key can be a modifier too (e.g. a two-key chord like
Keys.E+Keys.B).
Edge semantics: IsJustPressed() is edge-triggered on the main key (fires once per press)
with level checks on the modifier. IsHeld() is level-triggered on both.
Input suppression
All queries return false while:
- the RPH console is open,
- the game is paused,
- an on-screen keyboard (text input) is active — detected via
SafeNatives.IsOnScreenKeyboardActive, so hotkeys don't fire while the user types.
The static check is public if you need it for your own input handling:
if (Keybind.IsInputSuppressed()) return;
The talk key
The LSPDFR ecosystem convention for "talk / interact" is Y, exposed as a constant and a
suppression-aware helper for dialogue systems:
if (Keybind.TalkPressed()) // edge-fired Y, respecting suppression
{
AdvanceDialogue();
}
Friendly names
FriendlyName() produces human-readable labels for menus, help text and notifications:
digits render as 0–9 (not D0), OEM keys as their symbols (,, ., -, +), and
any Control/Shift/Alt variant renders as Ctrl+/Shift+/Alt+. Show it wherever you
tell the user what to press:
notifier.Show("Press " + Palette.Key(bind.FriendlyName()) + " to activate.");