Input - fix just pressed and released with short presses

Previously if an action was both pressed and released on the same tick or frame, `is_action_just_pressed()` would return false, resulting in missed input.

This PR separately the timestamp for pressing and releasing so each can be tested independently.
This commit is contained in:
lawnjelly
2023-05-14 08:53:36 +01:00
parent dcd31a25b4
commit a3ef092f18
4 changed files with 56 additions and 31 deletions

View File

@ -297,10 +297,13 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
return false;
}
// Backward compatibility for legacy behavior, only return true if currently pressed.
bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames();
return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
return E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames();
return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
}
}
@ -315,10 +318,13 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
return false;
}
// Backward compatibility for legacy behavior, only return true if currently released.
bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true;
if (Engine::get_singleton()->is_in_physics_frame()) {
return !E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames();
return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
return !E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames();
return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
}
}
@ -686,19 +692,24 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
if (InputMap::get_singleton()->event_is_action(p_event, E.key)) {
Action &action = action_state[E.key];
// If not echo and action pressed state has changed
if (!p_event->is_echo() && is_action_pressed(E.key, false) != p_event->is_action_pressed(E.key)) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = p_event->is_action_pressed(E.key);
if (p_event->is_action_pressed(E.key)) {
action.pressed = true;
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
} else {
action.pressed = false;
action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
action.released_process_frame = Engine::get_singleton()->get_process_frames();
}
action.strength = 0.0f;
action.raw_strength = 0.0f;
action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
action_state[E.key] = action;
}
action_state[E.key].strength = p_event->get_action_strength(E.key);
action_state[E.key].raw_strength = p_event->get_action_raw_strength(E.key);
action.strength = p_event->get_action_strength(E.key);
action.raw_strength = p_event->get_action_raw_strength(E.key);
}
}
@ -813,29 +824,27 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
}
void Input::action_press(const StringName &p_action, float p_strength) {
Action action;
// Create or retrieve existing action.
Action &action = action_state[p_action];
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = true;
action.strength = p_strength;
action.raw_strength = p_strength;
action.exact = true;
action_state[p_action] = action;
}
void Input::action_release(const StringName &p_action) {
Action action;
// Create or retrieve existing action.
Action &action = action_state[p_action];
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.process_frame = Engine::get_singleton()->get_process_frames();
action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
action.released_process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = false;
action.strength = 0.f;
action.raw_strength = 0.f;
action.strength = 0.0f;
action.raw_strength = 0.0f;
action.exact = true;
action_state[p_action] = action;
}
void Input::set_emulate_touch_from_mouse(bool p_emulate) {
@ -1531,6 +1540,12 @@ Input::Input() {
parse_mapping(entries[i]);
}
}
legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
if (Engine::get_singleton()->is_editor_hint()) {
// Always use standard behaviour in the editor.
legacy_just_pressed_behavior = false;
}
}
Input::~Input() {

View File

@ -96,14 +96,17 @@ private:
Vector3 gyroscope;
Vector2 mouse_pos;
int64_t mouse_window = 0;
bool legacy_just_pressed_behavior = false;
struct Action {
uint64_t physics_frame;
uint64_t process_frame;
bool pressed;
bool exact;
float strength;
float raw_strength;
uint64_t pressed_physics_frame = UINT64_MAX;
uint64_t pressed_process_frame = UINT64_MAX;
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
bool pressed = false;
bool exact = true;
float strength = 0.0f;
float raw_strength = 0.0f;
};
HashMap<StringName, Action> action_state;