Add methods to check which event first triggered "just pressed/released" state.

This commit is contained in:
Pāvels Nadtočajevs
2025-08-12 11:56:35 +03:00
parent ca452113d4
commit 10fd7163d4
7 changed files with 114 additions and 17 deletions

View File

@@ -123,6 +123,8 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_pressed_by_event", "action", "event", "exact_match"), &Input::is_action_just_pressed_by_event, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_released_by_event", "action", "event", "exact_match"), &Input::is_action_just_released_by_event, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_raw_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
@@ -411,6 +413,37 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
}
}
bool Input::is_action_just_pressed_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
ERR_FAIL_COND_V(p_event.is_null(), false);
if (disable_input) {
return false;
}
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return false;
}
if (p_exact && E->value.exact == false) {
return false;
}
if (E->value.pressed_event_id != p_event->get_instance_id()) {
return false;
}
// Backward compatibility for legacy behavior, only return true if currently pressed.
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
}
}
bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
@@ -437,6 +470,37 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
}
}
bool Input::is_action_just_released_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action));
ERR_FAIL_COND_V(p_event.is_null(), false);
if (disable_input) {
return false;
}
HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action);
if (!E) {
return false;
}
if (p_exact && E->value.exact == false) {
return false;
}
if (E->value.released_event_id != p_event->get_instance_id()) {
return false;
}
// Backward compatibility for legacy behavior, only return true if currently released.
bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
}
}
float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action));
@@ -895,10 +959,12 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
_update_action_cache(E.key, action_state);
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
if (action_state.cache.pressed && !was_pressed) {
action_state.pressed_event_id = p_event->get_instance_id();
action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
if (!action_state.cache.pressed && was_pressed) {
action_state.released_event_id = p_event->get_instance_id();
action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
}
@@ -1027,6 +1093,7 @@ void Input::action_press(const StringName &p_action, float p_strength) {
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
if (!action_state.cache.pressed) {
action_state.pressed_event_id = ObjectID();
action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
@@ -1045,6 +1112,7 @@ void Input::action_release(const StringName &p_action) {
action_state.cache.strength = 0.0;
action_state.cache.raw_strength = 0.0;
// As input may come in part way through a physics tick, the earliest we can react to it is the next physics tick.
action_state.released_event_id = ObjectID();
action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames() + 1;
action_state.released_process_frame = Engine::get_singleton()->get_process_frames();
action_state.device_states.clear();

View File

@@ -109,6 +109,8 @@ private:
uint64_t pressed_process_frame = UINT64_MAX;
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
ObjectID pressed_event_id;
ObjectID released_event_id;
bool exact = true;
struct DeviceState {
@@ -306,6 +308,8 @@ public:
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
bool is_action_just_pressed_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact = false) const;
bool is_action_just_released_by_event(const StringName &p_action, const Ref<InputEvent> &p_event, bool p_exact = false) const;
float get_action_strength(const StringName &p_action, bool p_exact = false) const;
float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;