Merge pull request #50874 from raulsntos/backport-44355

This commit is contained in:
Rémi Verschelde 2021-07-30 16:43:03 +02:00 committed by GitHub
commit 18f09492b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 106 additions and 56 deletions

View file

@ -51,7 +51,7 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events); ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list); ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list);
ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
} }
@ -125,7 +125,7 @@ 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_pressed, float *p_strength, float *p_raw_strength) const { List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr); ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
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()) {
@ -136,7 +136,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int device = e->get_device(); int device = e->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) { if (device == ALL_DEVICES || device == p_event->get_device()) {
if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { if (p_exact_match && e->shortcut_match(p_event)) {
return E;
} else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
return E; return E;
} }
} }
@ -165,8 +167,8 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object."); ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action)); ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
if (_find_event(input_map[p_action], p_event)) { if (_find_event(input_map[p_action], p_event, true)) {
return; //already gots return; // Already added.
} }
input_map[p_action].inputs.push_back(p_event); input_map[p_action].inputs.push_back(p_event);
@ -175,13 +177,13 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) { bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, _suggest_actions(p_action)); ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, _suggest_actions(p_action));
return (_find_event(input_map[p_action], p_event) != nullptr); return (_find_event(input_map[p_action], p_event, true) != nullptr);
} }
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) { void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action)); ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event); 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)) {
@ -217,11 +219,11 @@ const List<Ref<InputEvent>> *InputMap::get_action_list(const StringName &p_actio
return &E->get().inputs; return &E->get().inputs;
} }
bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const { bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
return event_get_action_status(p_event, p_action); 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_pressed, float *p_strength, float *p_raw_strength) const { bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
Map<StringName, Action>::Element *E = input_map.find(p_action); Map<StringName, Action>::Element *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));
@ -239,7 +241,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
bool pressed; bool pressed;
float strength; float strength;
float raw_strength; float raw_strength;
List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength); List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, p_exact_match, &pressed, &strength, &raw_strength);
if (event != nullptr) { if (event != nullptr) {
if (p_pressed != nullptr) { if (p_pressed != nullptr) {
*p_pressed = pressed; *p_pressed = pressed;

View file

@ -54,7 +54,7 @@ private:
mutable Map<StringName, Action> input_map; mutable Map<StringName, Action> input_map;
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
Array _get_action_list(const StringName &p_action); Array _get_action_list(const StringName &p_action);
Array _get_actions(); Array _get_actions();
@ -79,8 +79,8 @@ public:
void action_erase_events(const StringName &p_action); void action_erase_events(const StringName &p_action);
const List<Ref<InputEvent>> *get_action_list(const StringName &p_action); const List<Ref<InputEvent>> *get_action_list(const StringName &p_action);
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) 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_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
const Map<StringName, Action> &get_action_map() const; const Map<StringName, Action> &get_action_map() const;
void load_from_globals(); void load_from_globals();

View file

@ -57,11 +57,11 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_key_pressed", "scancode"), &Input::is_key_pressed); ClassDB::bind_method(D_METHOD("is_key_pressed", "scancode"), &Input::is_key_pressed);
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed); ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed); ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact"), &Input::is_action_pressed, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed); ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact"), &Input::is_action_just_pressed, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released); ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact"), &Input::is_action_just_released, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength); ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact"), &Input::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_raw_strength); ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact"), &Input::get_action_raw_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis); ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f)); ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));

View file

@ -81,11 +81,11 @@ public:
virtual bool is_key_pressed(int p_scancode) const = 0; virtual bool is_key_pressed(int p_scancode) const = 0;
virtual bool is_mouse_button_pressed(int p_button) const = 0; virtual bool is_mouse_button_pressed(int p_button) const = 0;
virtual bool is_joy_button_pressed(int p_device, int p_button) const = 0; virtual bool is_joy_button_pressed(int p_device, int p_button) const = 0;
virtual bool is_action_pressed(const StringName &p_action) const = 0; virtual bool is_action_pressed(const StringName &p_action, bool p_exact = false) const = 0;
virtual bool is_action_just_pressed(const StringName &p_action) const = 0; virtual bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const = 0;
virtual bool is_action_just_released(const StringName &p_action) const = 0; virtual bool is_action_just_released(const StringName &p_action, bool p_exact = false) const = 0;
virtual float get_action_strength(const StringName &p_action) const = 0; virtual float get_action_strength(const StringName &p_action, bool p_exact = false) const = 0;
virtual float get_action_raw_strength(const StringName &p_action) const = 0; virtual float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const = 0;
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const; float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const; Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;

View file

@ -44,31 +44,31 @@ int InputEvent::get_device() const {
return device; return device;
} }
bool InputEvent::is_action(const StringName &p_action) const { bool InputEvent::is_action(const StringName &p_action, bool p_exact_match) const {
return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match);
} }
bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const { bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo, bool p_exact_match) const {
bool pressed; bool pressed;
bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && pressed && (p_allow_echo || !is_echo()); return valid && pressed && (p_allow_echo || !is_echo());
} }
bool InputEvent::is_action_released(const StringName &p_action) const { bool InputEvent::is_action_released(const StringName &p_action, bool p_exact_match) const {
bool pressed; bool pressed;
bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && !pressed; return valid && !pressed;
} }
float InputEvent::get_action_strength(const StringName &p_action) const { float InputEvent::get_action_strength(const StringName &p_action, bool p_exact_match) const {
float strength; float strength;
bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength); bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, &strength, nullptr);
return valid ? strength : 0.0f; return valid ? strength : 0.0f;
} }
float InputEvent::get_action_raw_strength(const StringName &p_action) const { float InputEvent::get_action_raw_strength(const StringName &p_action, bool p_exact_match) const {
float raw_strength; float raw_strength;
bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength); bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, nullptr, &raw_strength);
return valid ? raw_strength : 0.0f; return valid ? raw_strength : 0.0f;
} }
@ -104,10 +104,10 @@ void InputEvent::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device); ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device);
ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device);
ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); ClassDB::bind_method(D_METHOD("is_action", "action", "exact_match"), &InputEvent::is_action, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false)); ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo", "exact_match"), &InputEvent::is_action_pressed, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); ClassDB::bind_method(D_METHOD("is_action_released", "action", "exact_match"), &InputEvent::is_action_released, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &InputEvent::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed);
ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo); ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo);

View file

@ -198,11 +198,11 @@ public:
void set_device(int p_device); void set_device(int p_device);
int get_device() const; int get_device() const;
bool is_action(const StringName &p_action) const; bool is_action(const StringName &p_action, bool p_exact_match = false) const;
bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const; bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
bool is_action_released(const StringName &p_action) const; bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
float get_action_strength(const StringName &p_action) const; float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
float get_action_raw_strength(const StringName &p_action) const; float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
// To be removed someday, since they do not make sense for all events // To be removed someday, since they do not make sense for all events
virtual bool is_pressed() const; virtual bool is_pressed() const;

View file

@ -59,8 +59,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact" type="bool" default="false">
</argument>
<description> <description>
Returns a value between 0 and 1 representing the raw intensity of the given action, ignoring the action's deadzone. In most cases, you should use [method get_action_strength] instead. Returns a value between 0 and 1 representing the raw intensity of the given action, ignoring the action's deadzone. In most cases, you should use [method get_action_strength] instead.
If [code]exact[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="get_action_strength" qualifiers="const"> <method name="get_action_strength" qualifiers="const">
@ -68,8 +71,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact" type="bool" default="false">
</argument>
<description> <description>
Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1. Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1.
If [code]exact[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="get_axis" qualifiers="const"> <method name="get_axis" qualifiers="const">
@ -250,9 +256,12 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] when the user starts pressing the action event, meaning it's [code]true[/code] only on the frame that the user pressed down the button. Returns [code]true[/code] when the user starts pressing the action event, meaning it's [code]true[/code] only on the frame that the user pressed down the button.
This is useful for code that needs to run only once when an action is pressed, instead of every frame while it's pressed. This is useful for code that needs to run only once when an action is pressed, instead of every frame while it's pressed.
If [code]exact[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action_just_released" qualifiers="const"> <method name="is_action_just_released" qualifiers="const">
@ -260,8 +269,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] when the user stops pressing the action event, meaning it's [code]true[/code] only on the frame that the user released the button. Returns [code]true[/code] when the user stops pressing the action event, meaning it's [code]true[/code] only on the frame that the user released the button.
If [code]exact[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action_pressed" qualifiers="const"> <method name="is_action_pressed" qualifiers="const">
@ -269,8 +281,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] if you are pressing the action event. Note that if an action has multiple buttons assigned and more than one of them is pressed, releasing one button will release the action, even if some other button assigned to this action is still pressed. Returns [code]true[/code] if you are pressing the action event. Note that if an action has multiple buttons assigned and more than one of them is pressed, releasing one button will release the action, even if some other button assigned to this action is still pressed.
If [code]exact[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_joy_button_pressed" qualifiers="const"> <method name="is_joy_button_pressed" qualifiers="const">

View file

@ -35,8 +35,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact_match" type="bool" default="false">
</argument>
<description> <description>
Returns a value between 0.0 and 1.0 depending on the given actions' state. Useful for getting the value of events of type [InputEventJoypadMotion]. Returns a value between 0.0 and 1.0 depending on the given actions' state. Useful for getting the value of events of type [InputEventJoypadMotion].
If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action" qualifiers="const"> <method name="is_action" qualifiers="const">
@ -44,8 +47,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact_match" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] if this input event matches a pre-defined action of any type. Returns [code]true[/code] if this input event matches a pre-defined action of any type.
If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action_pressed" qualifiers="const"> <method name="is_action_pressed" qualifiers="const">
@ -55,8 +61,11 @@
</argument> </argument>
<argument index="1" name="allow_echo" type="bool" default="false"> <argument index="1" name="allow_echo" type="bool" default="false">
</argument> </argument>
<argument index="2" name="exact_match" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action_released" qualifiers="const"> <method name="is_action_released" qualifiers="const">
@ -64,8 +73,11 @@
</return> </return>
<argument index="0" name="action" type="String"> <argument index="0" name="action" type="String">
</argument> </argument>
<argument index="1" name="exact_match" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] if the given action is released (i.e. not pressed). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. Returns [code]true[/code] if the given action is released (i.e. not pressed). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="is_action_type" qualifiers="const"> <method name="is_action_type" qualifiers="const">

View file

@ -100,8 +100,11 @@
</argument> </argument>
<argument index="1" name="action" type="String"> <argument index="1" name="action" type="String">
</argument> </argument>
<argument index="2" name="exact_match" type="bool" default="false">
</argument>
<description> <description>
Returns [code]true[/code] if the given event is part of an existing action. This method ignores keyboard modifiers if the given [InputEvent] is not pressed (for proper release detection). See [method action_has_event] if you don't want this behavior. Returns [code]true[/code] if the given event is part of an existing action. This method ignores keyboard modifiers if the given [InputEvent] is not pressed (for proper release detection). See [method action_has_event] if you don't want this behavior.
If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description> </description>
</method> </method>
<method name="get_action_list"> <method name="get_action_list">

View file

@ -90,15 +90,15 @@ bool InputDefault::is_joy_button_pressed(int p_device, int p_button) const {
return joy_buttons_pressed.has(_combine_device(p_button, p_device)); return joy_buttons_pressed.has(_combine_device(p_button, p_device));
} }
bool InputDefault::is_action_pressed(const StringName &p_action) const { bool InputDefault::is_action_pressed(const StringName &p_action, bool p_exact) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
bool has_action = InputMap::get_singleton()->has_action(p_action); bool has_action = InputMap::get_singleton()->has_action(p_action);
ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
#endif #endif
return action_state.has(p_action) && action_state[p_action].pressed; return action_state.has(p_action) && action_state[p_action].pressed && (p_exact ? action_state[p_action].exact : true);
} }
bool InputDefault::is_action_just_pressed(const StringName &p_action) const { bool InputDefault::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
bool has_action = InputMap::get_singleton()->has_action(p_action); bool has_action = InputMap::get_singleton()->has_action(p_action);
ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@ -108,6 +108,10 @@ bool InputDefault::is_action_just_pressed(const StringName &p_action) const {
return false; return false;
} }
if (p_exact && E->get().exact == false) {
return false;
}
if (Engine::get_singleton()->is_in_physics_frame()) { if (Engine::get_singleton()->is_in_physics_frame()) {
return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else { } else {
@ -115,7 +119,7 @@ bool InputDefault::is_action_just_pressed(const StringName &p_action) const {
} }
} }
bool InputDefault::is_action_just_released(const StringName &p_action) const { bool InputDefault::is_action_just_released(const StringName &p_action, bool p_exact) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
bool has_action = InputMap::get_singleton()->has_action(p_action); bool has_action = InputMap::get_singleton()->has_action(p_action);
ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@ -125,6 +129,10 @@ bool InputDefault::is_action_just_released(const StringName &p_action) const {
return false; return false;
} }
if (p_exact && E->get().exact == false) {
return false;
}
if (Engine::get_singleton()->is_in_physics_frame()) { if (Engine::get_singleton()->is_in_physics_frame()) {
return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else { } else {
@ -132,7 +140,7 @@ bool InputDefault::is_action_just_released(const StringName &p_action) const {
} }
} }
float InputDefault::get_action_strength(const StringName &p_action) const { float InputDefault::get_action_strength(const StringName &p_action, bool p_exact) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
bool has_action = InputMap::get_singleton()->has_action(p_action); bool has_action = InputMap::get_singleton()->has_action(p_action);
ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@ -142,10 +150,14 @@ float InputDefault::get_action_strength(const StringName &p_action) const {
return 0.0f; return 0.0f;
} }
if (p_exact && E->get().exact == false) {
return 0.0f;
}
return E->get().strength; return E->get().strength;
} }
float InputDefault::get_action_raw_strength(const StringName &p_action) const { float InputDefault::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
bool has_action = InputMap::get_singleton()->has_action(p_action); bool has_action = InputMap::get_singleton()->has_action(p_action);
ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@ -155,6 +167,10 @@ float InputDefault::get_action_raw_strength(const StringName &p_action) const {
return 0.0f; return 0.0f;
} }
if (p_exact && E->get().exact == false) {
return 0.0f;
}
return E->get().raw_strength; return E->get().raw_strength;
} }
@ -462,14 +478,15 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) { for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) {
if (InputMap::get_singleton()->event_is_action(p_event, E->key())) { if (InputMap::get_singleton()->event_is_action(p_event, E->key())) {
// Save the action's state // If not echo and action pressed state has changed
if (!p_event->is_echo() && is_action_pressed(E->key()) != p_event->is_action_pressed(E->key())) { if (!p_event->is_echo() && is_action_pressed(E->key(), false) != p_event->is_action_pressed(E->key())) {
Action action; Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.idle_frame = Engine::get_singleton()->get_idle_frames(); action.idle_frame = Engine::get_singleton()->get_idle_frames();
action.pressed = p_event->is_action_pressed(E->key()); action.pressed = p_event->is_action_pressed(E->key());
action.strength = 0.0f; action.strength = 0.0f;
action.raw_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()] = action;
} }
action_state[E->key()].strength = p_event->get_action_strength(E->key()); action_state[E->key()].strength = p_event->get_action_strength(E->key());

View file

@ -54,6 +54,7 @@ class InputDefault : public Input {
uint64_t physics_frame; uint64_t physics_frame;
uint64_t idle_frame; uint64_t idle_frame;
bool pressed; bool pressed;
bool exact;
float strength; float strength;
float raw_strength; float raw_strength;
}; };
@ -221,11 +222,11 @@ public:
virtual bool is_key_pressed(int p_scancode) const; virtual bool is_key_pressed(int p_scancode) const;
virtual bool is_mouse_button_pressed(int p_button) const; virtual bool is_mouse_button_pressed(int p_button) const;
virtual bool is_joy_button_pressed(int p_device, int p_button) const; virtual bool is_joy_button_pressed(int p_device, int p_button) const;
virtual bool is_action_pressed(const StringName &p_action) const; virtual bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
virtual bool is_action_just_pressed(const StringName &p_action) const; virtual bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
virtual bool is_action_just_released(const StringName &p_action) const; virtual bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
virtual float get_action_strength(const StringName &p_action) const; virtual float get_action_strength(const StringName &p_action, bool p_exact = false) const;
virtual float get_action_raw_strength(const StringName &p_action) const; virtual float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
virtual float get_joy_axis(int p_device, int p_axis) const; virtual float get_joy_axis(int p_device, int p_axis) const;
String get_joy_name(int p_idx); String get_joy_name(int p_idx);