Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented better way to map inputs in godot #16797

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 80 additions & 64 deletions core/input_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,32 +37,32 @@ InputMap *InputMap::singleton = NULL;

void InputMap::_bind_methods() {

ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("has_action", "controller_action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
ClassDB::bind_method(D_METHOD("add_action", "action"), &InputMap::add_action);
ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
ClassDB::bind_method(D_METHOD("add_action", "controller_action"), &InputMap::add_action);
ClassDB::bind_method(D_METHOD("erase_action", "controller_action"), &InputMap::erase_action);

ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
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("get_action_list", "controller_action"), &InputMap::_get_action_list);
ClassDB::bind_method(D_METHOD("event_is_action", "event", "controller_action"), &InputMap::event_is_action);
ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
}

void InputMap::add_action(const StringName &p_action) {
void InputMap::add_action(const StringName &p_controller_action) {

ERR_FAIL_COND(input_map.has(p_action));
input_map[p_action] = Action();
ERR_FAIL_COND(input_map.has(p_controller_action));
input_map[p_controller_action] = Action();
static int last_id = 1;
input_map[p_action].id = last_id;
input_map[p_controller_action].id = last_id;
last_id++;
}

void InputMap::erase_action(const StringName &p_action) {
void InputMap::erase_action(const StringName &p_controller_action) {

ERR_FAIL_COND(!input_map.has(p_action));
input_map.erase(p_action);
ERR_FAIL_COND(!input_map.has(p_controller_action));
input_map.erase(p_controller_action);
}

Array InputMap::_get_actions() {
Expand Down Expand Up @@ -112,40 +112,60 @@ List<Ref<InputEvent> >::Element *InputMap::_find_event(List<Ref<InputEvent> > &p
return NULL;
}

bool InputMap::has_action(const StringName &p_action) const {
bool InputMap::has_action(const StringName &p_controller_action) const {

return input_map.has(p_action);
return input_map.has(p_controller_action);
}

void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {

ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!input_map.has(p_action));
if (_find_event(input_map[p_action].inputs, p_event))

String controller_action = (p_event->get_data() == "" ? "0" : p_event->get_data()) + ":" + p_action;

ERR_FAIL_COND(!input_map.has(controller_action));
if (_find_event(input_map[controller_action].inputs, p_event))
return; //already gots

input_map[controller_action].inputs.push_back(p_event);
}

void InputMap::add_action_with_event(const StringName &p_action, const Ref<InputEvent> &p_event) {

ERR_FAIL_COND(p_event.is_null());

String controller_action = (p_event->get_data() == "" ? "0" : p_event->get_data()) + ":" + p_action;
if (!input_map.has(controller_action))
add_action(controller_action);

if (_find_event(input_map[controller_action].inputs, p_event))
return; //already gots

input_map[p_action].inputs.push_back(p_event);
input_map[controller_action].inputs.push_back(p_event);
}

bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {

ERR_FAIL_COND_V(!input_map.has(p_action), false);
return (_find_event(input_map[p_action].inputs, p_event) != NULL);
String controller_action = (p_event->get_data() == "" ? "0" : p_event->get_data()) + ":" + p_action;

ERR_FAIL_COND_V(!input_map.has(controller_action), false);
return (_find_event(input_map[controller_action].inputs, p_event) != NULL);
}

void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {

ERR_FAIL_COND(!input_map.has(p_action));
String controller_action = (p_event->get_data() == "" ? "0" : p_event->get_data()) + ":" + p_action;
ERR_FAIL_COND(!input_map.has(controller_action));

List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action].inputs, p_event);
List<Ref<InputEvent> >::Element *E = _find_event(input_map[controller_action].inputs, p_event);
if (E)
input_map[p_action].inputs.erase(E);
input_map[controller_action].inputs.erase(E);
}

Array InputMap::_get_action_list(const StringName &p_action) {
Array InputMap::_get_action_list(const StringName &p_controller_action) {

Array ret;
const List<Ref<InputEvent> > *al = get_action_list(p_action);
const List<Ref<InputEvent> > *al = get_action_list(p_controller_action);
if (al) {
for (const List<Ref<InputEvent> >::Element *E = al->front(); E; E = E->next()) {

Expand All @@ -156,29 +176,39 @@ Array InputMap::_get_action_list(const StringName &p_action) {
return ret;
}

const List<Ref<InputEvent> > *InputMap::get_action_list(const StringName &p_action) {
const List<Ref<InputEvent> > *InputMap::get_action_list(const StringName &p_controller_action) {

const Map<StringName, Action>::Element *E = input_map.find(p_action);
const Map<StringName, Action>::Element *E = input_map.find(p_controller_action);
if (!E)
return NULL;

return &E->get().inputs;
}

bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const {
Ref<InputEvent> InputMap::event_get_input_event_if_action(const Ref<InputEvent> &p_event, const StringName &p_controller_action) const {

Map<StringName, Action>::Element *E = input_map.find(p_action);
Map<StringName, Action>::Element *E = input_map.find(p_controller_action);
if (!E) {
ERR_EXPLAIN("Request for nonexistent InputMap action: " + String(p_action));
ERR_FAIL_COND_V(!E, false);
ERR_EXPLAIN("Request for nonexistent InputMap action: " + String(p_controller_action));
ERR_FAIL_COND_V(!E, Ref<InputEvent>());
}

Ref<InputEventAction> iea = p_event;
if (iea.is_valid()) {
return iea->get_action() == p_action;
if (iea->get_action() == p_controller_action)
return iea;
}

return _find_event(E->get().inputs, p_event, true) != NULL;
List<Ref<InputEvent> >::Element *E_ie = _find_event(E->get().inputs, p_event, true);
if (E_ie)
return E_ie->get();
else
return Ref<InputEvent>();
}

bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_controller_action) const {

return event_get_input_event_if_action(p_event, p_controller_action).is_valid();
}

const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
Expand All @@ -198,9 +228,7 @@ void InputMap::load_from_globals() {
if (!pi.name.begins_with("input/"))
continue;

String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());

add_action(name);
String name = pi.name.get_slice("/", 1);

Array va = ProjectSettings::get_singleton()->get(pi.name);

Expand All @@ -209,7 +237,8 @@ void InputMap::load_from_globals() {
Ref<InputEvent> ie = va[i];
if (ie.is_null())
continue;
action_add_event(name, ie);

add_action_with_event(name, ie);
}
}
}
Expand All @@ -218,79 +247,66 @@ void InputMap::load_default() {

Ref<InputEventKey> key;

add_action("ui_accept");
key.instance();
key->set_scancode(KEY_ENTER);
action_add_event("ui_accept", key);
add_action_with_event("ui_accept", key);

key.instance();
key->set_scancode(KEY_KP_ENTER);
action_add_event("ui_accept", key);
add_action_with_event("ui_accept", key);

key.instance();
key->set_scancode(KEY_SPACE);
action_add_event("ui_accept", key);
add_action_with_event("ui_accept", key);

add_action("ui_select");
key.instance();
key->set_scancode(KEY_SPACE);
action_add_event("ui_select", key);
add_action_with_event("ui_select", key);

add_action("ui_cancel");
key.instance();
key->set_scancode(KEY_ESCAPE);
action_add_event("ui_cancel", key);
add_action_with_event("ui_cancel", key);

add_action("ui_focus_next");
key.instance();
key->set_scancode(KEY_TAB);
action_add_event("ui_focus_next", key);
add_action_with_event("ui_focus_next", key);

add_action("ui_focus_prev");
key.instance();
key->set_scancode(KEY_TAB);
key->set_shift(true);
action_add_event("ui_focus_prev", key);
add_action_with_event("ui_focus_prev", key);

add_action("ui_left");
key.instance();
key->set_scancode(KEY_LEFT);
action_add_event("ui_left", key);
add_action_with_event("ui_left", key);

add_action("ui_right");
key.instance();
key->set_scancode(KEY_RIGHT);
action_add_event("ui_right", key);
add_action_with_event("ui_right", key);

add_action("ui_up");
key.instance();
key->set_scancode(KEY_UP);
action_add_event("ui_up", key);
add_action_with_event("ui_up", key);

add_action("ui_down");
key.instance();
key->set_scancode(KEY_DOWN);
action_add_event("ui_down", key);
add_action_with_event("ui_down", key);

add_action("ui_page_up");
key.instance();
key->set_scancode(KEY_PAGEUP);
action_add_event("ui_page_up", key);
add_action_with_event("ui_page_up", key);

add_action("ui_page_down");
key.instance();
key->set_scancode(KEY_PAGEDOWN);
action_add_event("ui_page_down", key);
add_action_with_event("ui_page_down", key);

add_action("ui_home");
key.instance();
key->set_scancode(KEY_HOME);
action_add_event("ui_home", key);
add_action_with_event("ui_home", key);

add_action("ui_end");
key.instance();
key->set_scancode(KEY_END);
action_add_event("ui_end", key);
add_action_with_event("ui_end", key);

//set("display/window/handheld/orientation", "landscape");
}
Expand Down
14 changes: 8 additions & 6 deletions core/input_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class InputMap : public Object {

List<Ref<InputEvent> >::Element *_find_event(List<Ref<InputEvent> > &p_list, const Ref<InputEvent> &p_event, bool p_action_test = false) const;

Array _get_action_list(const StringName &p_action);
Array _get_action_list(const StringName &p_controller_action);
Array _get_actions();

protected:
Expand All @@ -60,17 +60,19 @@ class InputMap : public Object {
public:
static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }

bool has_action(const StringName &p_action) const;
bool has_action(const StringName &p_controller_action) const;
List<StringName> get_actions() const;
void add_action(const StringName &p_action);
void erase_action(const StringName &p_action);
void add_action(const StringName &p_controller_action);
void erase_action(const StringName &p_controller_action);

void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
void add_action_with_event(const StringName &p_action, const Ref<InputEvent> &p_event);
bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);

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;
const List<Ref<InputEvent> > *get_action_list(const StringName &p_controller_action);
Ref<InputEvent> event_get_input_event_if_action(const Ref<InputEvent> &p_event, const StringName &p_controller_action) const;
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_controller_action) const;

const Map<StringName, Action> &get_action_map() const;
void load_from_globals();
Expand Down
24 changes: 17 additions & 7 deletions core/os/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ void Input::_bind_methods() {
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_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_just_pressed", "action"), &Input::is_action_just_pressed);
ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "device"), &Input::is_action_pressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "controller"), &Input::is_action_just_pressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "controller"), &Input::is_action_just_released, DEFVAL(0));
ClassDB::bind_method(D_METHOD("is_action_just_changed", "action", "controller"), &Input::is_action_just_changed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_action_axis_value", "action", "controller"), &Input::get_action_axis_value, DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
Expand All @@ -83,8 +85,8 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("action_press", "action", "controller"), &Input::action_press, DEFVAL(0));
ClassDB::bind_method(D_METHOD("action_release", "action", "controller"), &Input::action_release, DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);

Expand Down Expand Up @@ -118,7 +120,12 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
#ifdef TOOLS_ENABLED

String pf = p_function;
if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released")) {

bool search_actions = true;
if (pf == "is_action_just_changed" || pf == "get_action_axis_value")
search_actions = false;

if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "is_action_just_changed" || pf == "get_action_axis_value")) {

List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
Expand All @@ -129,7 +136,10 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
if (!pi.name.begins_with("input/"))
continue;

String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
if (!search_actions && !pi.name.ends_with("/axis"))
continue;

String name = pi.name.get_slice("/", 1);
r_options->push_back("\"" + name + "\"");
}
}
Expand Down
13 changes: 8 additions & 5 deletions core/os/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ class Input : public Object {
virtual bool is_key_pressed(int p_scancode) 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_action_pressed(const StringName &p_action) const = 0;
virtual bool is_action_just_pressed(const StringName &p_action) const = 0;
virtual bool is_action_just_released(const StringName &p_action) const = 0;

virtual bool is_action_pressed(const StringName &p_action, int p_device = 0) const = 0;
virtual bool is_action_just_pressed(const StringName &p_action, int p_device = 0) const = 0;
virtual bool is_action_just_released(const StringName &p_action, int p_device = 0) const = 0;
virtual bool is_action_just_changed(const StringName &p_action, int p_device = 0) const = 0;
virtual float get_action_axis_value(const StringName &p_name, int p_device = 0) const = 0;

virtual float get_joy_axis(int p_device, int p_axis) const = 0;
virtual String get_joy_name(int p_idx) = 0;
Expand Down Expand Up @@ -112,8 +115,8 @@ class Input : public Object {
virtual Vector3 get_magnetometer() const = 0;
virtual Vector3 get_gyroscope() const = 0;

virtual void action_press(const StringName &p_action) = 0;
virtual void action_release(const StringName &p_action) = 0;
virtual void action_press(const StringName &p_action, int p_device = 0) = 0;
virtual void action_release(const StringName &p_action, int p_device = 0) = 0;

void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;

Expand Down
Loading