UGTK / Toolkit / Utility Systems / Key Input Action System Completed
Key Input Action System
Summary
The Key Input Action System binds keys and gamepad axes to UnityEvents from the inspector, and — this is
the part Unity does not give you — handles auto-repeat: hold the key and the event keeps firing at a
configurable interval, with an optional delay before the repetition starts.
That is the behaviour every menu needs (hold Down and the selection keeps scrolling), and the reason this
module exists instead of a two-line if (Input.GetKeyDown(...)).
Content
Modules Dependencies
- Input Compatibility: every read goes through
UGTKInput, so the module works with the legacy Input Manager and the new Input System alike. - Dictionary System: the legacy maps are
S_Dictionary<KeyCode, UnityEvent>, serializable in the inspector.
Setup
Drop the KeyInputAction prefab into the scene, or the XBox one for a controller-oriented setup:
Then fill in whichever of the three sections you need — they can be used together.
How To Use
1. Legacy map — key → event. The simplest form: add an entry to keyInputActions with a KeyCode and
what to do. A second map, keyInputReleaseActions, does the same on key up. Both can be switched off
with their own flag.
2. Key Repeat Actions — one entry per key, each with its own settings:
| Field | Meaning |
|---|---|
key |
the key to watch |
onTriggered |
what to do, on press and on each repetition |
onReleased |
what to do on release |
invokeImmediatelyOnKeyDown |
fire once as soon as the key goes down |
repeatWhileHeld |
keep firing while it is held |
useUnscaledTime |
keep repeating while the game is paused — turn it on for menus |
3. Axis Range Actions — fire while an axis sits inside a range, which is how you turn an analog stick into a directional command:
| Field | Meaning |
|---|---|
axisName |
the axis, e.g. Vertical |
useRawAxis |
read the raw value (no smoothing): snappier, the right choice for menus |
min / max |
the range that counts as "pressed" — 0.8..1.0 means "pushed nearly all the way up" |
deadzone |
below this the axis is treated as zero, to ignore a resting stick that does not centre |
onTriggered / onExitRange |
entering (and repeating) versus leaving the range |
From code, the component also exposes thin pass-throughs that already go through UGTKInput:
ReadAxis, ReadAxisRaw, ReadButton, ReadButtonDown, ReadKey, ReadKeyDown, ReadMouseButton,
ReadMouseButtonDown.
Good to know:
- The legacy maps need at least one entry to detect anything, and with the new Input System selected
in Player Settings they need
Bothin Active Input Handling — otherwiseKeyCodereads are not available at all. This is the usual reason "the keys do nothing". useUnscaledTimeis what makes a pause menu usable. WithTime.timeScale = 0the repeat driven by scaled time never advances: the first press works and holding does nothing.- A deadzone that is too small makes a worn stick auto-repeat on its own; too large and small pushes are
ignored.
0.1is a sensible starting point. - Ranges should not overlap between two axis actions on the same axis, or both fire together.
- Nothing is exclusive: a key bound in both the legacy map and a repeat action fires both events.
Repeat, In Detail
The sequence when a key goes down, with invokeImmediatelyOnKeyDown and repeatWhileHeld both on:
onTriggeredfires immediately.- Nothing happens for
firstRepeatDelayseconds — the pause that stops a single tap from turning into a burst. - From then on
onTriggeredfires everyrepeatIntervalseconds, until the key is released. - On release,
onReleasedfires.
With invokeImmediatelyOnKeyDown off the first fire is skipped and only the repetition remains; with
repeatWhileHeld off you get exactly one fire per press.
Testing Scene
Open KeyInputActionScene in the module's Debug/ folder.
What to do, in order:
- Press a bound key and watch its event fire.
- Hold it down and watch the repeat interval.
- Bind an action to a key the editor itself uses, and fire it from the inspector instead.
- Leave one binding with no listener attached.
Step 3 is why the inspector has buttons: some keys never reach the game because the editor eats them first, and a keyboard layout without the key you chose makes a binding untestable at your desk. Step 4 shows the silent case — a row that looks configured and does nothing.
The recording is step 3 in action. The demo's bindings are joystick buttons, which no keyboard
can press: select KeyInputActionXbox, and in Editor Test Tools press Invoke next to
JoystickButton0 - the "Jump" label appears beside the A button in the game, and the Release row
puts it away again. That is the whole reason those buttons exist: the binding is exercised through
the same entry point the key would use, with no gamepad in the room.
Note that the scene's other object, KeyInputAction, ships with an empty list - it is the blank
example, and its test block reads "no binding" until you add one.
Technical Info
| Path | Content |
|---|---|
Scripts/Runtime/KeyInputActionSystem.cs |
The whole system: the two legacy maps with their repeat settings, S_KeyRepeatAction, S_AxisRangeRepeatAction and the Read* pass-throughs |
Prefabs/KeyInputAction.prefab |
Ready-made component |
Prefabs/XBox.prefab |
Variant pre-filled for a controller |
Debug/KeyInputActionScene.unity |
Test scene |
© 2026 Marcello De Bonis. All rights reserved
Depends on 2
Used by 1
Measured from the repository: code references (asmdef) plus prefab and asset GUIDs. Importing this module alone brings in 2 modules in total.
UGTKengine within an engine


