summaryrefslogtreecommitdiff
path: root/core/input
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-04-18 11:39:12 +0200
committerGitHub <noreply@github.com>2021-04-18 11:39:12 +0200
commit7e215a4b546dd5d2bd7088d95dfccd5d3a894b7e (patch)
tree36d806917e6efeda545b23c06956239fd25847a8 /core/input
parentd8447d51758024219abe8cbebdf69d41d2659ad7 (diff)
parent71b254f68e348cff181a037098dc0b93f97315ae (diff)
Merge pull request #35666 from Calinou/inputmap-nonexistent-suggestions
Print suggestions when requesting a nonexistent InputMap action
Diffstat (limited to 'core/input')
-rw-r--r--core/input/input_map.cpp47
-rw-r--r--core/input/input_map.h1
2 files changed, 39 insertions, 9 deletions
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 7d85fd6492..aab4e6593c 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -54,8 +54,36 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
+/**
+ * Returns an nonexistent action error message with a suggestion of the closest
+ * matching action name (if possible).
+ */
+String InputMap::_suggest_actions(const StringName &p_action) const {
+ List<StringName> actions = get_actions();
+ StringName closest_action;
+ float closest_similarity = 0.0;
+
+ // Find the most action with the most similar name.
+ for (List<StringName>::Element *E = actions.front(); E; E = E->next()) {
+ const float similarity = String(E->get()).similarity(p_action);
+
+ if (similarity > closest_similarity) {
+ closest_action = E->get();
+ closest_similarity = similarity;
+ }
+ }
+
+ String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
+
+ if (closest_similarity >= 0.4) {
+ // Only include a suggestion in the error message if it's similar enough.
+ error_message += vformat(" Did you mean \"%s\"?", closest_action);
+ }
+ return error_message;
+}
+
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\".");
input_map[p_action] = Action();
static int last_id = 1;
input_map[p_action].id = last_id;
@@ -64,7 +92,8 @@ void InputMap::add_action(const StringName &p_action, float p_deadzone) {
}
void InputMap::erase_action(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
+
input_map.erase(p_action);
}
@@ -122,20 +151,20 @@ bool InputMap::has_action(const StringName &p_action) const {
}
float InputMap::action_get_deadzone(const StringName &p_action) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, _suggest_actions(p_action));
return input_map[p_action].deadzone;
}
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].deadzone = p_deadzone;
}
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
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), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
if (_find_event(input_map[p_action], p_event, true)) {
return; // Already addded.
}
@@ -144,12 +173,12 @@ 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) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, "Request for nonexistent InputMap action '" + String(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, true) != nullptr);
}
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(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, true);
if (E) {
@@ -161,7 +190,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
}
void InputMap::action_erase_events(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].inputs.clear();
}
@@ -193,7 +222,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
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 {
OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
- ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!E, false, _suggest_actions(p_action));
Ref<InputEventAction> input_event_action = p_event;
if (input_event_action.is_valid()) {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 99c71e1e53..0e0567464a 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -61,6 +61,7 @@ private:
Array _action_get_events(const StringName &p_action);
Array _get_actions();
+ String _suggest_actions(const StringName &p_action) const;
protected:
static void _bind_methods();