Rework input actions to be reliable
This commit is contained in:
parent
9df6491853
commit
d9d0cfaf38
4 changed files with 106 additions and 63 deletions
|
@ -695,53 +695,34 @@ 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()) {
|
for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
|
||||||
if (InputMap::get_singleton()->event_is_action(p_event, E.key)) {
|
const int event_index = InputMap::get_singleton()->event_get_index(p_event, E.key);
|
||||||
Action &action = action_state[E.key];
|
if (event_index == -1) {
|
||||||
bool is_joypad_axis = jm.is_valid();
|
continue;
|
||||||
bool is_pressed = false;
|
|
||||||
if (!p_event->is_echo()) {
|
|
||||||
if (p_event->is_action_pressed(E.key)) {
|
|
||||||
bool is_joypad_axis_valid_zone_enter = false;
|
|
||||||
if (is_joypad_axis) {
|
|
||||||
if (!action.axis_pressed) {
|
|
||||||
is_joypad_axis_valid_zone_enter = true;
|
|
||||||
action.pressed++;
|
|
||||||
action.axis_pressed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
action.pressed++;
|
|
||||||
}
|
|
||||||
if (action.pressed == 1 && (is_joypad_axis_valid_zone_enter || !is_joypad_axis)) {
|
|
||||||
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
|
|
||||||
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
|
|
||||||
}
|
|
||||||
is_pressed = true;
|
|
||||||
} else {
|
|
||||||
bool is_released = true;
|
|
||||||
if (is_joypad_axis) {
|
|
||||||
if (action.axis_pressed) {
|
|
||||||
action.axis_pressed = false;
|
|
||||||
} else {
|
|
||||||
is_released = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_released) {
|
|
||||||
if (action.pressed == 1) {
|
|
||||||
action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
|
|
||||||
action.released_process_frame = Engine::get_singleton()->get_process_frames();
|
|
||||||
}
|
|
||||||
action.pressed = MAX(action.pressed - 1, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_pressed || action.pressed == 0) {
|
|
||||||
action.strength = p_event->get_action_strength(E.key);
|
|
||||||
action.raw_strength = p_event->get_action_raw_strength(E.key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action &action = action_state[E.key];
|
||||||
|
if (!p_event->is_echo()) {
|
||||||
|
if (p_event->is_action_pressed(E.key)) {
|
||||||
|
if (!action.pressed) {
|
||||||
|
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
|
||||||
|
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
|
||||||
|
}
|
||||||
|
action.pressed |= ((uint64_t)1 << event_index);
|
||||||
|
} else {
|
||||||
|
action.pressed &= ~((uint64_t)1 << event_index);
|
||||||
|
action.pressed &= ~(1 << MAX_EVENT); // Always release the event from action_press() method.
|
||||||
|
|
||||||
|
if (!action.pressed) {
|
||||||
|
action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
|
||||||
|
action.released_process_frame = Engine::get_singleton()->get_process_frames();
|
||||||
|
}
|
||||||
|
_update_action_strength(action, MAX_EVENT, 0.0);
|
||||||
|
_update_action_raw_strength(action, MAX_EVENT, 0.0);
|
||||||
|
}
|
||||||
|
action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
|
||||||
|
}
|
||||||
|
_update_action_strength(action, event_index, p_event->get_action_strength(E.key));
|
||||||
|
_update_action_raw_strength(action, event_index, p_event->get_action_raw_strength(E.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_dispatch_function) {
|
if (event_dispatch_function) {
|
||||||
|
@ -858,13 +839,13 @@ void Input::action_press(const StringName &p_action, float p_strength) {
|
||||||
// Create or retrieve existing action.
|
// Create or retrieve existing action.
|
||||||
Action &action = action_state[p_action];
|
Action &action = action_state[p_action];
|
||||||
|
|
||||||
action.pressed++;
|
if (!action.pressed) {
|
||||||
if (action.pressed == 1) {
|
|
||||||
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
|
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
|
||||||
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
|
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
|
||||||
}
|
}
|
||||||
action.strength = p_strength;
|
action.pressed |= 1 << MAX_EVENT;
|
||||||
action.raw_strength = p_strength;
|
_update_action_strength(action, MAX_EVENT, p_strength);
|
||||||
|
_update_action_raw_strength(action, MAX_EVENT, p_strength);
|
||||||
action.exact = true;
|
action.exact = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,13 +853,15 @@ void Input::action_release(const StringName &p_action) {
|
||||||
// Create or retrieve existing action.
|
// Create or retrieve existing action.
|
||||||
Action &action = action_state[p_action];
|
Action &action = action_state[p_action];
|
||||||
|
|
||||||
action.pressed--;
|
action.pressed = 0;
|
||||||
if (action.pressed == 0) {
|
action.strength = 0.0;
|
||||||
action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
|
action.raw_strength = 0.0;
|
||||||
action.released_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();
|
||||||
|
for (uint64_t i = 0; i <= MAX_EVENT; i++) {
|
||||||
|
action.strengths[i] = 0.0;
|
||||||
|
action.raw_strengths[i] = 0.0;
|
||||||
}
|
}
|
||||||
action.strength = 0.0f;
|
|
||||||
action.raw_strength = 0.0f;
|
|
||||||
action.exact = true;
|
action.exact = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1207,6 +1190,38 @@ void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
|
||||||
parse_input_event(ievent);
|
parse_input_event(ievent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Input::_update_action_strength(Action &p_action, int p_event_index, float p_strength) {
|
||||||
|
ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
|
||||||
|
|
||||||
|
float old_strength = p_action.strengths[p_event_index];
|
||||||
|
p_action.strengths[p_event_index] = p_strength;
|
||||||
|
|
||||||
|
if (p_strength > p_action.strength) {
|
||||||
|
p_action.strength = p_strength;
|
||||||
|
} else if (Math::is_equal_approx(old_strength, p_action.strength)) {
|
||||||
|
p_action.strength = p_strength;
|
||||||
|
for (uint64_t i = 0; i <= MAX_EVENT; i++) {
|
||||||
|
p_action.strength = MAX(p_action.strength, p_action.strengths[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::_update_action_raw_strength(Action &p_action, int p_event_index, float p_strength) {
|
||||||
|
ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
|
||||||
|
|
||||||
|
float old_strength = p_action.raw_strengths[p_event_index];
|
||||||
|
p_action.raw_strengths[p_event_index] = p_strength;
|
||||||
|
|
||||||
|
if (p_strength > p_action.raw_strength) {
|
||||||
|
p_action.raw_strength = p_strength;
|
||||||
|
} else if (Math::is_equal_approx(old_strength, p_action.raw_strength)) {
|
||||||
|
p_action.raw_strength = p_strength;
|
||||||
|
for (uint64_t i = 0; i <= MAX_EVENT; i++) {
|
||||||
|
p_action.raw_strength = MAX(p_action.raw_strength, p_action.raw_strengths[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
|
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
|
||||||
JoyEvent event;
|
JoyEvent event;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,8 @@ class Input : public Object {
|
||||||
|
|
||||||
static Input *singleton;
|
static Input *singleton;
|
||||||
|
|
||||||
|
static constexpr uint64_t MAX_EVENT = 31;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum MouseMode {
|
enum MouseMode {
|
||||||
MOUSE_MODE_VISIBLE,
|
MOUSE_MODE_VISIBLE,
|
||||||
|
@ -103,11 +105,22 @@ private:
|
||||||
uint64_t pressed_process_frame = UINT64_MAX;
|
uint64_t pressed_process_frame = UINT64_MAX;
|
||||||
uint64_t released_physics_frame = UINT64_MAX;
|
uint64_t released_physics_frame = UINT64_MAX;
|
||||||
uint64_t released_process_frame = UINT64_MAX;
|
uint64_t released_process_frame = UINT64_MAX;
|
||||||
int pressed = 0;
|
uint64_t pressed = 0;
|
||||||
bool axis_pressed = false;
|
|
||||||
bool exact = true;
|
bool exact = true;
|
||||||
float strength = 0.0f;
|
float strength = 0.0f;
|
||||||
float raw_strength = 0.0f;
|
float raw_strength = 0.0f;
|
||||||
|
LocalVector<float> strengths;
|
||||||
|
LocalVector<float> raw_strengths;
|
||||||
|
|
||||||
|
Action() {
|
||||||
|
strengths.resize(MAX_EVENT + 1);
|
||||||
|
raw_strengths.resize(MAX_EVENT + 1);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i <= MAX_EVENT; i++) {
|
||||||
|
strengths[i] = 0.0;
|
||||||
|
raw_strengths[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HashMap<StringName, Action> action_state;
|
HashMap<StringName, Action> action_state;
|
||||||
|
@ -227,6 +240,8 @@ private:
|
||||||
JoyAxis _get_output_axis(String output);
|
JoyAxis _get_output_axis(String output);
|
||||||
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
|
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
|
||||||
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
|
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
|
||||||
|
void _update_action_strength(Action &p_action, int p_event_index, float p_strength);
|
||||||
|
void _update_action_raw_strength(Action &p_action, int p_event_index, float p_strength);
|
||||||
|
|
||||||
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
|
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
|
||||||
|
|
||||||
|
|
|
@ -127,16 +127,21 @@ List<StringName> InputMap::get_actions() const {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
|
List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
|
||||||
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
|
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
|
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
|
||||||
int device = E->get()->get_device();
|
int device = E->get()->get_device();
|
||||||
if (device == ALL_DEVICES || device == p_event->get_device()) {
|
if (device == ALL_DEVICES || device == p_event->get_device()) {
|
||||||
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
|
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
|
||||||
|
if (r_event_index) {
|
||||||
|
*r_event_index = i;
|
||||||
|
}
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -179,6 +184,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
|
||||||
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
|
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
|
||||||
if (E) {
|
if (E) {
|
||||||
input_map[p_action].inputs.erase(E);
|
input_map[p_action].inputs.erase(E);
|
||||||
|
|
||||||
if (Input::get_singleton()->is_action_pressed(p_action)) {
|
if (Input::get_singleton()->is_action_pressed(p_action)) {
|
||||||
Input::get_singleton()->action_release(p_action);
|
Input::get_singleton()->action_release(p_action);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +222,13 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
|
||||||
return event_get_action_status(p_event, p_action, p_exact_match);
|
return event_get_action_status(p_event, p_action, p_exact_match);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
|
int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
|
||||||
|
int index = -1;
|
||||||
|
event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
|
||||||
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
|
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
|
||||||
ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
|
ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
|
||||||
|
|
||||||
|
@ -236,7 +248,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
|
||||||
return input_event_action->get_action() == p_action;
|
return input_event_action->get_action() == p_action;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength);
|
List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index);
|
||||||
return event != nullptr;
|
return event != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ private:
|
||||||
HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
|
HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
|
||||||
HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
|
HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
|
||||||
|
|
||||||
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
|
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
|
||||||
|
|
||||||
TypedArray<InputEvent> _action_get_events(const StringName &p_action);
|
TypedArray<InputEvent> _action_get_events(const StringName &p_action);
|
||||||
TypedArray<StringName> _get_actions();
|
TypedArray<StringName> _get_actions();
|
||||||
|
@ -86,7 +86,8 @@ public:
|
||||||
|
|
||||||
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
|
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
|
||||||
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
|
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
|
||||||
bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
|
int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
|
||||||
|
bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
|
||||||
|
|
||||||
const HashMap<StringName, Action> &get_action_map() const;
|
const HashMap<StringName, Action> &get_action_map() const;
|
||||||
void load_from_project_settings();
|
void load_from_project_settings();
|
||||||
|
|
Loading…
Reference in a new issue