Move all key input handlers into Input Actions rather than raw key presses #50
Labels
No labels
assets
bug
duplicate
enhancement
help wanted
invalid
question
testing
ui
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
liamjd/UntitledColonyBuilder#50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every keyboard control except building rotation and
ui_cancelis currently read as araw physical keycode. Move them all onto named InputMap actions, so bindings live in one
place, can be rebound later, and can be reasoned about when two systems want the same key.
Why now
#44 wanted E for counter-clockwise blueprint rotation. E is already taken by
camera_rig.gd:175(rotate view counter-clockwise), and the conflict is not resolvablewhile the camera reads keys the way it does — see "Polling bypasses event handling" below.
#44 shipped with R/T instead as a stopgap. E is reserved for counter-clockwise blueprint
rotation once this issue lands, at which point R/T should be revisited.
What is currently raw
entities/camera/camera_rig.gdInput.is_physical_key_pressed()common/game.gd_unhandled_key_inputui/debug_layer.gd_debug_commandsdictionary keyed by keycode_unhandled_inputentities/buildings/placement_controller.gdui/menus/options_panel.gdui_cancelGuidance
Polling vs. events is a separate axis from raw-key vs. action
These are two independent decisions and it is worth not conflating them:
_processand stayspolled. It becomes
Input.is_action_pressed("camera_pan_left"), not an event handler.belongs in
_unhandled_input/_unhandled_key_inputasevent.is_action_pressed("..."), so it can be consumed withget_viewport().set_input_as_handled().Migrating to actions does not mean migrating everything to events.
Polling bypasses event handling entirely
Input.is_physical_key_pressed()(andInput.is_action_pressed()) query OS-level keystate directly. They do not travel through the viewport's event pipeline, so
set_input_as_handled()cannot suppress them, and neither can node order or processpriority.
This is precisely why E cannot be shared today: bind it to blueprint rotation and the
press both rotates the blueprint and spins the camera, with no ordering trick available.
Once both sides read actions, the fix is a modal guard — the camera skips its rotate
actions while a blueprint is selected — rather than an attempt to consume the input.
Decide where that mode flag lives (
GameState, or the camera asking the placementcontroller) as part of this work.
Physical keycodes survive the migration
camera_rig.gd:18-20says keys are read as physical keycodes "so the project needs no[input]config and non-QWERTY layouts still work", implying actions would cost the layoutindependence. They would not. InputMap events carry
physical_keycodejust as rawevents do — the actions added in #44 already use it. Migrating keeps the layout behaviour
and gains rebindability. That comment should be corrected as part of this issue, not
treated as a reason to hesitate.
Modifier matching is subset-based — the Shift trap
An action matches when the modifiers it declares are a subset of those actually held. An
action bound to plain R therefore also fires on Shift+R, Ctrl+R and Alt+R.
#44 originally bound CW to R and CCW to Shift+R. Verified in 4.7.2:
Both handlers ran,
+1then-1, and CCW appeared to do nothing. Two ways out, if anybinding here ever wants a modifier:
elifthe plain one — itworks, but it looks arbitrary and needs a comment saying why the order matters; or
Prefer the second unless there is a reason not to. Shift is already the camera sprint
modifier, which is polled, so it is not a free modifier in any case.
Debug commands are keyed by keycode and display the key
ui/debug_layer.gdkeys_debug_commandsbyphysical_keycodeand renders the bindingwith
OS.get_keycode_string(code). Migrating means the dictionary is keyed by action nameand the label comes from
InputMap.action_get_events(name)instead, taking the firstInputEventKeyand readingphysical_keycodeoff it. This is the fiddliest part of thechange — it is the one place a binding is shown to the player, and it is what a rebinding
UI would later reuse.
Naming convention
Settle one and apply it throughout. The two actions added in #44 are
Rotate_building_CW/Rotate_building_CCW, which match neither Godot's built-inui_cancelstyle nor the project's snake_case GDScript. Suggest lowercase snake_case witha system prefix —
camera_pan_left,camera_rotate_cw,building_rotate_cw,debug_toggle— and rename the #44 actions to match rather than leaving two conventions.Scope
In: the three files in the table above, plus renaming the #44 actions.
Out: a rebinding UI, gamepad or mouse-button bindings, and input contexts/action sets.
Those become possible after this, but nothing here should be built speculatively for them.
Acceptance criteria
Input.is_physical_key_pressed(),Input.is_key_pressed()orevent.physical_keycodecomparison remains outside
ui/debug_layer.gd's label rendering.project.godot's[input]section usingphysical_keycode, under one naming convention.screen-relative, still snapping to 90 degrees.
in a release build.
the same time; it still turns the camera when nothing is selected.
camera_rig.gd:18-20is corrected.The debug layer keybindings will be exempt from this change. They are direct key bindings inside debug_layer and will not be configurable by the player.
Although the debug R key clashes with the building placement R key, I don't really care at this stage. Changing the map seed while attempting to place a building is a crazy thing to do.