diff --git a/core/input_map.cpp b/core/input_map.cpp index bd03d61196f3..5c0a6c286e85 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -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() { @@ -112,40 +112,60 @@ List >::Element *InputMap::_find_event(List > &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 &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 &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 &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 &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 >::Element *E = _find_event(input_map[p_action].inputs, p_event); + List >::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 > *al = get_action_list(p_action); + const List > *al = get_action_list(p_controller_action); if (al) { for (const List >::Element *E = al->front(); E; E = E->next()) { @@ -156,29 +176,39 @@ Array InputMap::_get_action_list(const StringName &p_action) { return ret; } -const List > *InputMap::get_action_list(const StringName &p_action) { +const List > *InputMap::get_action_list(const StringName &p_controller_action) { - const Map::Element *E = input_map.find(p_action); + const Map::Element *E = input_map.find(p_controller_action); if (!E) return NULL; return &E->get().inputs; } -bool InputMap::event_is_action(const Ref &p_event, const StringName &p_action) const { +Ref InputMap::event_get_input_event_if_action(const Ref &p_event, const StringName &p_controller_action) const { - Map::Element *E = input_map.find(p_action); + Map::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()); } Ref 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 >::Element *E_ie = _find_event(E->get().inputs, p_event, true); + if (E_ie) + return E_ie->get(); + else + return Ref(); +} + +bool InputMap::event_is_action(const Ref &p_event, const StringName &p_controller_action) const { + + return event_get_input_event_if_action(p_event, p_controller_action).is_valid(); } const Map &InputMap::get_action_map() const { @@ -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); @@ -209,7 +237,8 @@ void InputMap::load_from_globals() { Ref ie = va[i]; if (ie.is_null()) continue; - action_add_event(name, ie); + + add_action_with_event(name, ie); } } } @@ -218,79 +247,66 @@ void InputMap::load_default() { Ref 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"); } diff --git a/core/input_map.h b/core/input_map.h index 84d90f6f2adf..f62a0d50521d 100644 --- a/core/input_map.h +++ b/core/input_map.h @@ -51,7 +51,7 @@ class InputMap : public Object { List >::Element *_find_event(List > &p_list, const Ref &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: @@ -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 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 &p_event); + void add_action_with_event(const StringName &p_action, const Ref &p_event); bool action_has_event(const StringName &p_action, const Ref &p_event); void action_erase_event(const StringName &p_action, const Ref &p_event); - const List > *get_action_list(const StringName &p_action); - bool event_is_action(const Ref &p_event, const StringName &p_action) const; + const List > *get_action_list(const StringName &p_controller_action); + Ref event_get_input_event_if_action(const Ref &p_event, const StringName &p_controller_action) const; + bool event_is_action(const Ref &p_event, const StringName &p_controller_action) const; const Map &get_action_map() const; void load_from_globals(); diff --git a/core/os/input.cpp b/core/os/input.cpp index 3089ab2ce337..98f52742f346 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -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); @@ -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); @@ -118,7 +120,12 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List pinfo; ProjectSettings::get_singleton()->get_property_list(&pinfo); @@ -129,7 +136,10 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, Listpush_back("\"" + name + "\""); } } diff --git a/core/os/input.h b/core/os/input.h index 9c7595ff7f27..2b716ea7ee45 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -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; @@ -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 *r_options) const; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index b9607632f7e8..3b51ebc48883 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -41,14 +41,30 @@ int InputEvent::get_device() const { return device; } -bool InputEvent::is_pressed() const { +void InputEvent::set_pressed(bool p_pressed) { - return false; + pressed = p_pressed; +} + +void InputEvent::set_axis_factor(float p_axis_factor) { + axis_factor = p_axis_factor; +} + +bool InputEvent::is_simulating_axis() { + return ABS(axis_factor) > 0; +} + +void InputEvent::set_data(const String &p_data) { + data = p_data; +} + +float InputEvent::get_axis_value() const { + return pressed; } bool InputEvent::is_action(const StringName &p_action) const { - return InputMap::get_singleton()->event_is_action(Ref((InputEvent *)this), p_action); + return InputMap::get_singleton()->event_is_action(Ref((InputEvent *)this), (get_data() == "" ? "0" : get_data()) + ":" + p_action); } bool InputEvent::is_action_pressed(const StringName &p_action) const { @@ -95,7 +111,18 @@ void InputEvent::_bind_methods() { 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("set_pressed", "pressed"), &InputEvent::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); + + ClassDB::bind_method(D_METHOD("set_axis_factor", "factor"), &InputEvent::set_axis_factor); + ClassDB::bind_method(D_METHOD("get_axis_factor"), &InputEvent::get_axis_factor); + + ClassDB::bind_method(D_METHOD("set_data", "data"), &InputEvent::set_data); + ClassDB::bind_method(D_METHOD("get_data"), &InputEvent::get_data); + + ClassDB::bind_method(D_METHOD("is_simulating_axis"), &InputEvent::is_simulating_axis); + ClassDB::bind_method(D_METHOD("get_axis_value"), &InputEvent::get_axis_value); + ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputEvent::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); @@ -111,11 +138,15 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2())); ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "axis_factor"), "set_axis_factor", "get_axis_factor"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "data"), "set_data", "get_data"); } InputEvent::InputEvent() { device = 0; + axis_factor = 0; } ////////////////// @@ -208,16 +239,6 @@ InputEventWithModifiers::InputEventWithModifiers() { ////////////////////////////////// -void InputEventKey::set_pressed(bool p_pressed) { - - pressed = p_pressed; -} - -bool InputEventKey::is_pressed() const { - - return pressed; -} - void InputEventKey::set_scancode(uint32_t p_scancode) { scancode = p_scancode; @@ -307,8 +328,6 @@ bool InputEventKey::shortcut_match(const Ref &p_event) const { void InputEventKey::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventKey::set_pressed); - ClassDB::bind_method(D_METHOD("set_scancode", "scancode"), &InputEventKey::set_scancode); ClassDB::bind_method(D_METHOD("get_scancode"), &InputEventKey::get_scancode); @@ -319,7 +338,6 @@ void InputEventKey::_bind_methods() { ClassDB::bind_method(D_METHOD("get_scancode_with_modifiers"), &InputEventKey::get_scancode_with_modifiers); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scancode"), "set_scancode", "get_scancode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "echo"), "set_echo", "is_echo"); @@ -404,15 +422,6 @@ int InputEventMouseButton::get_button_index() const { return button_index; } -void InputEventMouseButton::set_pressed(bool p_pressed) { - - pressed = p_pressed; -} -bool InputEventMouseButton::is_pressed() const { - - return pressed; -} - void InputEventMouseButton::set_doubleclick(bool p_doubleclick) { doubleclick = p_doubleclick; @@ -438,7 +447,7 @@ Ref InputEventMouseButton::xformed_by(const Transform2D &p_xform, co mb->set_global_position(g); mb->set_button_mask(get_button_mask()); - mb->set_pressed(pressed); + mb->set_pressed(is_pressed()); mb->set_doubleclick(doubleclick); mb->set_factor(factor); mb->set_button_index(button_index); @@ -484,7 +493,7 @@ String InputEventMouseButton::as_text() const { button_index_string = itos(get_button_index()); break; } - return "InputEventMouseButton : button_index=" + button_index_string + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + "), button_mask=" + itos(get_button_mask()) + ", doubleclick=" + (doubleclick ? "true" : "false"); + return "InputEventMouseButton : button_index=" + button_index_string + ", pressed=" + (is_pressed() ? "true" : "false") + ", position=(" + String(get_position()) + "), button_mask=" + itos(get_button_mask()) + ", doubleclick=" + (doubleclick ? "true" : "false"); } void InputEventMouseButton::_bind_methods() { @@ -495,15 +504,11 @@ void InputEventMouseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_index", "button_index"), &InputEventMouseButton::set_button_index); ClassDB::bind_method(D_METHOD("get_button_index"), &InputEventMouseButton::get_button_index); - ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventMouseButton::set_pressed); - // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventMouseButton::is_pressed); - ClassDB::bind_method(D_METHOD("set_doubleclick", "doubleclick"), &InputEventMouseButton::set_doubleclick); ClassDB::bind_method(D_METHOD("is_doubleclick"), &InputEventMouseButton::is_doubleclick); ADD_PROPERTY(PropertyInfo(Variant::REAL, "factor"), "set_factor", "get_factor"); ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "doubleclick"), "set_doubleclick", "is_doubleclick"); } @@ -511,7 +516,6 @@ InputEventMouseButton::InputEventMouseButton() { factor = 1; button_index = 0; - pressed = false; doubleclick = false; } @@ -610,13 +614,13 @@ void InputEventJoypadMotion::set_axis_value(float p_value) { axis_value = p_value; } + float InputEventJoypadMotion::get_axis_value() const { return axis_value; } bool InputEventJoypadMotion::is_pressed() const { - return Math::abs(axis_value) > 0.5f; } @@ -626,7 +630,7 @@ bool InputEventJoypadMotion::action_match(const Ref &p_event) const if (jm.is_null()) return false; - return (axis == jm->axis && ((axis_value < 0) == (jm->axis_value < 0) || jm->axis_value == 0)); + return axis == jm->axis; } String InputEventJoypadMotion::as_text() const { @@ -640,7 +644,6 @@ void InputEventJoypadMotion::_bind_methods() { ClassDB::bind_method(D_METHOD("get_axis"), &InputEventJoypadMotion::get_axis); ClassDB::bind_method(D_METHOD("set_axis_value", "axis_value"), &InputEventJoypadMotion::set_axis_value); - ClassDB::bind_method(D_METHOD("get_axis_value"), &InputEventJoypadMotion::get_axis_value); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis"), "set_axis", "get_axis"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "axis_value"), "set_axis_value", "get_axis_value"); @@ -663,15 +666,6 @@ int InputEventJoypadButton::get_button_index() const { return button_index; } -void InputEventJoypadButton::set_pressed(bool p_pressed) { - - pressed = p_pressed; -} -bool InputEventJoypadButton::is_pressed() const { - - return pressed; -} - void InputEventJoypadButton::set_pressure(float p_pressure) { pressure = p_pressure; @@ -692,7 +686,7 @@ bool InputEventJoypadButton::action_match(const Ref &p_event) const String InputEventJoypadButton::as_text() const { - return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure)); + return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (is_pressed() ? "true" : "false") + ", pressure=" + String(Variant(pressure)); } void InputEventJoypadButton::_bind_methods() { @@ -703,19 +697,14 @@ void InputEventJoypadButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventJoypadButton::set_pressure); ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventJoypadButton::get_pressure); - ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventJoypadButton::set_pressed); - // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventJoypadButton::is_pressed); - ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure"), "set_pressure", "get_pressure"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); } InputEventJoypadButton::InputEventJoypadButton() { button_index = 0; pressure = 0; - pressed = false; } ////////////////////////////////////////////// @@ -738,15 +727,6 @@ Vector2 InputEventScreenTouch::get_position() const { return pos; } -void InputEventScreenTouch::set_pressed(bool p_pressed) { - - pressed = p_pressed; -} -bool InputEventScreenTouch::is_pressed() const { - - return pressed; -} - Ref InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref st; @@ -754,14 +734,14 @@ Ref InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co st->set_device(get_device()); st->set_index(index); st->set_position(p_xform.xform(pos + p_local_ofs)); - st->set_pressed(pressed); + st->set_pressed(is_pressed()); return st; } String InputEventScreenTouch::as_text() const { - return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")"; + return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (is_pressed() ? "true" : "false") + ", position=(" + String(get_position()) + ")"; } void InputEventScreenTouch::_bind_methods() { @@ -772,18 +752,13 @@ void InputEventScreenTouch::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenTouch::set_position); ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenTouch::get_position); - ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed); - //ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed); - ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); } InputEventScreenTouch::InputEventScreenTouch() { index = 0; - pressed = false; } ///////////////////////////// @@ -881,15 +856,6 @@ StringName InputEventAction::get_action() const { return action; } -void InputEventAction::set_pressed(bool p_pressed) { - - pressed = p_pressed; -} -bool InputEventAction::is_pressed() const { - - return pressed; -} - bool InputEventAction::is_action(const StringName &p_action) const { return action == p_action; @@ -897,7 +863,7 @@ bool InputEventAction::is_action(const StringName &p_action) const { String InputEventAction::as_text() const { - return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false"); + return "InputEventAction : action=" + action + ", pressed=(" + (is_pressed() ? "true" : "false"); } void InputEventAction::_bind_methods() { @@ -905,18 +871,12 @@ void InputEventAction::_bind_methods() { ClassDB::bind_method(D_METHOD("set_action", "action"), &InputEventAction::set_action); ClassDB::bind_method(D_METHOD("get_action"), &InputEventAction::get_action); - ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventAction::set_pressed); - //ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventAction::is_pressed); - // ClassDB::bind_method(D_METHOD("is_action", "name"), &InputEventAction::is_action); ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action", "get_action"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); } -InputEventAction::InputEventAction() { - pressed = false; -} +InputEventAction::InputEventAction() {} ///////////////////////////// void InputEventGesture::set_position(const Vector2 &p_pos) { diff --git a/core/os/input_event.h b/core/os/input_event.h index 0a33ab18a735..efcadf25334a 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -145,7 +145,11 @@ enum JoystickList { class InputEvent : public Resource { GDCLASS(InputEvent, Resource) +protected: int device; + bool pressed; + float axis_factor; // Used to simulate axis on buttons event or to scale the axis value in case of axis event + String data; // Used to store extra information protected: static void _bind_methods(); @@ -154,7 +158,19 @@ class InputEvent : public Resource { void set_device(int p_device); int get_device() const; - virtual bool is_pressed() const; + void set_pressed(bool p_pressed); + _FORCE_INLINE_ virtual bool is_pressed() const { return pressed; } + + void set_axis_factor(float p_axis_factor); + _FORCE_INLINE_ float get_axis_factor() const { return axis_factor; } + + bool is_simulating_axis(); + + void set_data(const String &p_data); + _FORCE_INLINE_ const String &get_data() const { return data; } + + virtual float get_axis_value() const; + virtual bool is_action(const StringName &p_action) const; virtual bool is_action_pressed(const StringName &p_action) const; virtual bool is_action_released(const StringName &p_action) const; @@ -230,9 +246,6 @@ class InputEventKey : public InputEventWithModifiers { static void _bind_methods(); public: - void set_pressed(bool p_pressed); - virtual bool is_pressed() const; - void set_scancode(uint32_t p_scancode); uint32_t get_scancode() const; @@ -285,7 +298,6 @@ class InputEventMouseButton : public InputEventMouse { float factor; int button_index; - bool pressed; //otherwise released bool doubleclick; //last even less than doubleclick time protected: @@ -298,9 +310,6 @@ class InputEventMouseButton : public InputEventMouse { void set_button_index(int p_index); int get_button_index() const; - void set_pressed(bool p_pressed); - virtual bool is_pressed() const; - void set_doubleclick(bool p_doubleclick); bool is_doubleclick() const; @@ -349,9 +358,10 @@ class InputEventJoypadMotion : public InputEvent { int get_axis() const; void set_axis_value(float p_value); - float get_axis_value() const; + virtual float get_axis_value() const; // return value -1 to 1 virtual bool is_pressed() const; + virtual bool action_match(const Ref &p_event) const; virtual bool is_action_type() const { return true; } @@ -364,7 +374,6 @@ class InputEventJoypadButton : public InputEvent { GDCLASS(InputEventJoypadButton, InputEvent) int button_index; - bool pressed; float pressure; //0 to 1 protected: static void _bind_methods(); @@ -373,9 +382,6 @@ class InputEventJoypadButton : public InputEvent { void set_button_index(int p_index); int get_button_index() const; - void set_pressed(bool p_pressed); - virtual bool is_pressed() const; - void set_pressure(float p_pressure); float get_pressure() const; @@ -391,7 +397,6 @@ class InputEventScreenTouch : public InputEvent { GDCLASS(InputEventScreenTouch, InputEvent) int index; Vector2 pos; - bool pressed; protected: static void _bind_methods(); @@ -403,9 +408,6 @@ class InputEventScreenTouch : public InputEvent { void set_position(const Vector2 &p_pos); Vector2 get_position() const; - void set_pressed(bool p_pressed); - virtual bool is_pressed() const; - virtual Ref xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual String as_text() const; @@ -447,7 +449,6 @@ class InputEventAction : public InputEvent { GDCLASS(InputEventAction, InputEvent) StringName action; - bool pressed; protected: static void _bind_methods(); @@ -456,9 +457,6 @@ class InputEventAction : public InputEvent { void set_action(const StringName &p_action); StringName get_action() const; - void set_pressed(bool p_pressed); - virtual bool is_pressed() const; - virtual bool is_action(const StringName &p_action) const; virtual bool is_action_type() const { return true; } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 75523cd843b1..fadb37fb325d 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -59,18 +59,17 @@ static const char *_button_names[JOY_BUTTON_MAX] = { "D-Pad Right" }; -static const char *_axis_names[JOY_AXIS_MAX * 2] = { - " (Left Stick Left)", - " (Left Stick Right)", - " (Left Stick Up)", - " (Left Stick Down)", - " (Right Stick Left)", - " (Right Stick Right)", - " (Right Stick Up)", - " (Right Stick Down)", - "", "", "", "", - "", " (L2)", - "", " (R2)" +static const char *_axis_names[JOY_AXIS_MAX] = { + " (Left Stick X)", + " (Left Stick Y)", + " (Right Stick X)", + " (Right Stick Y)", + "", + "", + " (L2)", + " (R2)", + "", + "" }; void ProjectSettingsEditor::_notification(int p_what) { @@ -138,7 +137,7 @@ void ProjectSettingsEditor::_action_selected() { if (!ti || !ti->is_editable(0)) return; - add_at = "input/" + ti->get_text(0); + add_at = "input/" + ti->get_text(0) + (updating_actions ? "" : "/axis"); edit_idx = -1; } @@ -149,7 +148,7 @@ void ProjectSettingsEditor::_action_edited() { return; String new_name = ti->get_text(0); - String old_name = add_at.substr(add_at.find("/") + 1, add_at.length()); + String old_name = add_at.get_slice("/", 1); if (new_name == old_name) return; @@ -157,19 +156,19 @@ void ProjectSettingsEditor::_action_edited() { if (new_name == "" || !_validate_action_name(new_name)) { ti->set_text(0, old_name); - add_at = "input/" + old_name; + add_at = "input/" + old_name + (updating_actions ? "" : "/axis"); message->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'")); message->popup_centered(Size2(300, 100) * EDSCALE); return; } - String action_prop = "input/" + new_name; + String action_prop = "input/" + new_name + (updating_actions ? "" : "/axis"); if (ProjectSettings::get_singleton()->has_setting(action_prop)) { ti->set_text(0, old_name); - add_at = "input/" + old_name; + add_at = "input/" + old_name + (updating_actions ? "" : "/axis"); message->set_text(vformat(TTR("Action '%s' already exists!"), new_name)); message->popup_centered(Size2(300, 100) * EDSCALE); @@ -201,7 +200,8 @@ void ProjectSettingsEditor::_device_input_add() { Ref ie; String name = add_at; - int idx = edit_idx; + const float axis_factor = sim_axis_sb->get_value(); + const int idx = edit_idx; Array old_val = ProjectSettings::get_singleton()->get(name); Array arr = old_val.duplicate(); @@ -212,14 +212,16 @@ void ProjectSettingsEditor::_device_input_add() { Ref mb; mb.instance(); mb->set_button_index(device_index->get_selected() + 1); - mb->set_device(device_id->get_value()); + mb->set_device(0); + mb->set_data(String::num(controller_id_sb->get_value())); + mb->set_axis_factor(updating_actions ? 0 : axis_factor); for (int i = 0; i < arr.size(); i++) { Ref aie = arr[i]; if (aie.is_null()) continue; - if (aie->get_device() == mb->get_device() && aie->get_button_index() == mb->get_button_index()) { + if (aie->get_device() == mb->get_device() && aie->get_button_index() == mb->get_button_index() && aie->get_axis_factor() == mb->get_axis_factor()) { return; } } @@ -231,16 +233,17 @@ void ProjectSettingsEditor::_device_input_add() { Ref jm; jm.instance(); - jm->set_axis(device_index->get_selected() >> 1); - jm->set_axis_value(device_index->get_selected() & 1 ? 1 : -1); + jm->set_axis(device_index->get_selected()); jm->set_device(device_id->get_value()); + jm->set_data(String::num(controller_id_sb->get_value())); + jm->set_axis_factor(updating_actions ? 0 : axis_factor); for (int i = 0; i < arr.size(); i++) { Ref aie = arr[i]; if (aie.is_null()) continue; - if (aie->get_device() == jm->get_device() && aie->get_axis() == jm->get_axis() && aie->get_axis_value() == jm->get_axis_value()) { + if (aie->get_device() == jm->get_device() && aie->get_axis() == jm->get_axis() && aie->get_axis_factor() == jm->get_axis_factor()) { return; } } @@ -255,13 +258,15 @@ void ProjectSettingsEditor::_device_input_add() { jb->set_button_index(device_index->get_selected()); jb->set_device(device_id->get_value()); + jb->set_data(String::num(controller_id_sb->get_value())); + jb->set_axis_factor(updating_actions ? 0 : axis_factor); for (int i = 0; i < arr.size(); i++) { Ref aie = arr[i]; if (aie.is_null()) continue; - if (aie->get_device() == jb->get_device() && aie->get_button_index() == jb->get_button_index()) { + if (aie->get_device() == jb->get_device() && aie->get_button_index() == jb->get_button_index() && aie->get_axis_factor() == jb->get_axis_factor()) { return; } } @@ -301,6 +306,9 @@ void ProjectSettingsEditor::_press_a_key_confirm() { ie->set_alt(last_wait_for_key->get_alt()); ie->set_control(last_wait_for_key->get_control()); ie->set_metakey(last_wait_for_key->get_metakey()); + ie->set_axis_factor(updating_actions ? 0 : sim_axis_sb->get_value()); + ie->set_device(0); + ie->set_data(String::num(controller_id_sb->get_value())); String name = add_at; int idx = edit_idx; @@ -313,7 +321,7 @@ void ProjectSettingsEditor::_press_a_key_confirm() { Ref aie = arr[i]; if (aie.is_null()) continue; - if (aie->get_scancode_with_modifiers() == ie->get_scancode_with_modifiers()) { + if (aie->get_scancode_with_modifiers() == ie->get_scancode_with_modifiers() && aie->get_axis_factor() == ie->get_axis_factor()) { return; } } @@ -395,12 +403,17 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even add_type = InputType(p_item); + if (sim_axis_vbc->get_parent()) { + sim_axis_vbc->get_parent()->remove_child(sim_axis_vbc); + } switch (add_type) { case INPUT_KEY: { press_a_key_label->set_text(TTR("Press a Key..")); last_wait_for_key = Ref(); + if (!updating_actions) + press_a_key_vbc->add_child(sim_axis_vbc); press_a_key->popup_centered(Size2(250, 80) * EDSCALE); press_a_key->grab_focus(); } break; @@ -417,6 +430,8 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even device_index->add_item(TTR("Button 7")); device_index->add_item(TTR("Button 8")); device_index->add_item(TTR("Button 9")); + if (!updating_actions) + device_input_vbc->add_child(sim_axis_vbc); device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE); Ref mb = p_exiting_event; @@ -433,11 +448,13 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even device_index_label->set_text(TTR("Joypad Axis Index:")); device_index->clear(); - for (int i = 0; i < JOY_AXIS_MAX * 2; i++) { + for (int i = 0; i < JOY_AXIS_MAX; i++) { String desc = _axis_names[i]; - device_index->add_item(TTR("Axis") + " " + itos(i / 2) + " " + (i & 1 ? "+" : "-") + desc); + device_index->add_item(TTR("Axis") + " " + itos(i) + " " + desc); } + if (!updating_actions) + device_input_vbc->add_child(sim_axis_vbc); device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE); Ref jm = p_exiting_event; @@ -459,6 +476,8 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even device_index->add_item(itos(i) + ": " + String(_button_names[i])); } + if (!updating_actions) + device_input_vbc->add_child(sim_axis_vbc); device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE); Ref jb = p_exiting_event; @@ -474,6 +493,12 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even } break; default: {} } + + if (p_exiting_event.is_valid()) { + sim_axis_sb->set_value(p_exiting_event->get_axis_factor()); + } else { + sim_axis_sb->set_value(1); + } } void ProjectSettingsEditor::_edit_item(Ref p_exiting_event) { @@ -505,7 +530,7 @@ void ProjectSettingsEditor::_action_activated() { if (!ti || ti->get_parent() == input_editor->get_root()) return; - String name = "input/" + ti->get_parent()->get_text(0); + String name = "input/" + ti->get_parent()->get_text(0) + (updating_actions ? "" : "/axis"); int idx = ti->get_metadata(0); Array va = ProjectSettings::get_singleton()->get(name); @@ -535,7 +560,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, ofs.x -= 100; popup_add->set_position(ofs); popup_add->popup(); - add_at = "input/" + ti->get_text(0); + add_at = "input/" + ti->get_text(0) + (updating_actions ? "" : "/axis"); edit_idx = -1; } else if (p_id == 2) { @@ -545,7 +570,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, //remove main thing - String name = "input/" + ti->get_text(0); + String name = "input/" + ti->get_text(0) + (updating_actions ? "" : "/axis"); Variant old_val = ProjectSettings::get_singleton()->get(name); int order = ProjectSettings::get_singleton()->get_order(name); @@ -561,7 +586,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, } else { //remove action - String name = "input/" + ti->get_parent()->get_text(0); + String name = "input/" + ti->get_parent()->get_text(0) + (updating_actions ? "" : "/axis"); Variant old_val = ProjectSettings::get_singleton()->get(name); int idx = ti->get_metadata(0); @@ -595,7 +620,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, } else { //edit action - String name = "input/" + ti->get_parent()->get_text(0); + String name = "input/" + ti->get_parent()->get_text(0) + (updating_actions ? "" : "/axis"); int idx = ti->get_metadata(0); Array va = ProjectSettings::get_singleton()->get(name); @@ -626,11 +651,22 @@ void ProjectSettingsEditor::_update_actions() { List props; ProjectSettings::get_singleton()->get_property_list(&props); + int current_controller_id((int)controller_id_sb->get_value()); for (List::Element *E = props.front(); E; E = E->next()) { const PropertyInfo &pi = E->get(); - if (!pi.name.begins_with("input/")) + if (!pi.name.begins_with("input/")) { continue; + } + if (updating_actions) { + if (pi.name.ends_with("/axis")) { + continue; + } + } else { + if (!pi.name.ends_with("/axis")) { + continue; + } + } String name = pi.name.get_slice("/", 1); if (name == "") @@ -653,8 +689,17 @@ void ProjectSettingsEditor::_update_actions() { if (ie.is_null()) continue; + // If current device id is different + if (current_controller_id != ie->get_data().to_int()) + continue; + TreeItem *action = input_editor->create_item(item); + String sim_axis_factor = ""; + if (!updating_actions) { + sim_axis_factor = "[ " + rtos(ie->get_axis_factor()) + " ] "; + } + Ref k = ie; if (k.is_valid()) { @@ -668,7 +713,7 @@ void ProjectSettingsEditor::_update_actions() { if (k->get_control()) str = TTR("Control+") + str; - action->set_text(0, str); + action->set_text(0, sim_axis_factor + str); action->set_icon(0, get_icon("Keyboard", "EditorIcons")); } @@ -682,7 +727,7 @@ void ProjectSettingsEditor::_update_actions() { else str += "."; - action->set_text(0, str); + action->set_text(0, sim_axis_factor + str); action->set_icon(0, get_icon("JoyButton", "EditorIcons")); } @@ -699,7 +744,7 @@ void ProjectSettingsEditor::_update_actions() { default: str += TTR("Button") + " " + itos(mb->get_button_index()) + "."; } - action->set_text(0, str); + action->set_text(0, sim_axis_factor + str); action->set_icon(0, get_icon("Mouse", "EditorIcons")); } @@ -708,10 +753,9 @@ void ProjectSettingsEditor::_update_actions() { if (jm.is_valid()) { int ax = jm->get_axis(); - int n = 2 * ax + (jm->get_axis_value() < 0 ? 0 : 1); - String desc = _axis_names[n]; - String str = TTR("Device") + " " + itos(jm->get_device()) + ", " + TTR("Axis") + " " + itos(ax) + " " + (jm->get_axis_value() < 0 ? "-" : "+") + desc + "."; - action->set_text(0, str); + String desc = _axis_names[ax]; + String str = TTR("Device") + " " + itos(jm->get_device()) + ", " + TTR("Axis") + " " + itos(ax) + " " + desc + "."; + action->set_text(0, sim_axis_factor + str); action->set_icon(0, get_icon("JoyAxis", "EditorIcons")); } action->add_button(0, get_icon("Edit", "EditorIcons"), 3, false, TTR("Edit")); @@ -854,7 +898,7 @@ void ProjectSettingsEditor::_action_check(String p_action) { action_add->set_disabled(true); return; } - if (ProjectSettings::get_singleton()->has_setting("input/" + p_action)) { + if (ProjectSettings::get_singleton()->has_setting("input/" + p_action) || ProjectSettings::get_singleton()->has_setting("input/" + p_action + "/axis")) { action_add_error->set_text(TTR("Already existing")); action_add_error->show(); @@ -878,7 +922,7 @@ void ProjectSettingsEditor::_action_adds(String) { void ProjectSettingsEditor::_action_add() { Array va; - String name = "input/" + action_name->get_text(); + String name = "input/" + action_name->get_text() + (updating_actions ? "" : "/axis"); undo_redo->create_action(TTR("Add Input Action")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, va); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); @@ -906,6 +950,32 @@ void ProjectSettingsEditor::_action_add() { action_name->clear(); } +void ProjectSettingsEditor::_controller_changed(double p_value) { + _update_actions(); +} + +void ProjectSettingsEditor::_tab_container_changed(int p_tab) { + + if (input_map_vbc->get_parent()) { + input_map_vbc->get_parent()->remove_child(input_map_vbc); + } + + switch (p_tab) { + case 1: + updating_actions = true; + action_label->set_text(TTR("Action:")); + input_base_actions->add_child(input_map_vbc); + _update_actions(); + break; + case 2: + updating_actions = false; + action_label->set_text(TTR("Axis:")); + input_base_axis->add_child(input_map_vbc); + _update_actions(); + break; + } +} + void ProjectSettingsEditor::_item_checked(const String &p_item, bool p_check) { } @@ -1548,6 +1618,7 @@ void ProjectSettingsEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_item_add"), &ProjectSettingsEditor::_item_add); ClassDB::bind_method(D_METHOD("_item_adds"), &ProjectSettingsEditor::_item_adds); ClassDB::bind_method(D_METHOD("_item_del"), &ProjectSettingsEditor::_item_del); + ClassDB::bind_method(D_METHOD("_tab_container_changed", "tab"), &ProjectSettingsEditor::_tab_container_changed); ClassDB::bind_method(D_METHOD("_item_checked"), &ProjectSettingsEditor::_item_checked); ClassDB::bind_method(D_METHOD("_save"), &ProjectSettingsEditor::_save); ClassDB::bind_method(D_METHOD("_action_add"), &ProjectSettingsEditor::_action_add); @@ -1557,6 +1628,7 @@ void ProjectSettingsEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_action_edited"), &ProjectSettingsEditor::_action_edited); ClassDB::bind_method(D_METHOD("_action_activated"), &ProjectSettingsEditor::_action_activated); ClassDB::bind_method(D_METHOD("_action_button_pressed"), &ProjectSettingsEditor::_action_button_pressed); + ClassDB::bind_method(D_METHOD("_controller_changed", "value"), &ProjectSettingsEditor::_controller_changed); ClassDB::bind_method(D_METHOD("_update_actions"), &ProjectSettingsEditor::_update_actions); ClassDB::bind_method(D_METHOD("_wait_for_key"), &ProjectSettingsEditor::_wait_for_key); ClassDB::bind_method(D_METHOD("_add_item"), &ProjectSettingsEditor::_add_item, DEFVAL(Variant())); @@ -1600,6 +1672,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { tab_container = memnew(TabContainer); tab_container->set_tab_align(TabContainer::ALIGN_LEFT); + tab_container->connect("tab_changed", this, "_tab_container_changed"); add_child(tab_container); VBoxContainer *props_base = memnew(VBoxContainer); @@ -1705,23 +1778,27 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { message = memnew(AcceptDialog); add_child(message); - Control *input_base = memnew(Control); - input_base->set_name(TTR("Input Map")); - tab_container->add_child(input_base); + input_base_actions = memnew(Control); + input_base_actions->set_name(TTR("Input Map Action")); + tab_container->add_child(input_base_actions); + + input_base_axis = memnew(Control); + input_base_axis->set_name(TTR("Input Map Axis")); + tab_container->add_child(input_base_axis); - VBoxContainer *vbc = memnew(VBoxContainer); - input_base->add_child(vbc); - vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); - vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0); - vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); + // This same node is used by both Input Map tabs + input_map_vbc = memnew(VBoxContainer); + input_base_actions->add_child(input_map_vbc); + input_map_vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); + input_map_vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + input_map_vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0); + input_map_vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); hbc = memnew(HBoxContainer); - vbc->add_child(hbc); + input_map_vbc->add_child(hbc); - l = memnew(Label); - hbc->add_child(l); - l->set_text(TTR("Action:")); + action_label = memnew(Label); + hbc->add_child(action_label); action_name = memnew(LineEdit); action_name->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1740,8 +1817,30 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { add->connect("pressed", this, "_action_add"); action_add = add; + // Separator between Add action and Device ID Inputs + HSeparator *sep = memnew(HSeparator); + sep->set_h_size_flags(SIZE_EXPAND_FILL); + input_map_vbc->add_child(sep); + + // Controller input + hbc = memnew(HBoxContainer); + input_map_vbc->add_child(hbc); + + Label *controller_label = memnew(Label); + hbc->add_child(controller_label); + controller_label->set_text(TTR("Controller: ")); + + controller_id_sb = memnew(SpinBox); + controller_id_sb->set_min(0); + controller_id_sb->set_max(100); + controller_id_sb->set_step(1); + controller_id_sb->set_value(0); // Default controller 0 + controller_id_sb->set_h_size_flags(SIZE_EXPAND_FILL); + hbc->add_child(controller_id_sb); + controller_id_sb->connect("value_changed", this, "_controller_changed"); + input_editor = memnew(Tree); - vbc->add_child(input_editor); + input_map_vbc->add_child(input_editor); input_editor->set_v_size_flags(SIZE_EXPAND_FILL); input_editor->connect("item_edited", this, "_action_edited"); input_editor->connect("item_activated", this, "_action_activated"); @@ -1755,24 +1854,40 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { press_a_key->set_focus_mode(FOCUS_ALL); add_child(press_a_key); - l = memnew(Label); - l->set_text(TTR("Press a Key..")); - l->set_anchors_and_margins_preset(Control::PRESET_WIDE); - l->set_align(Label::ALIGN_CENTER); - l->set_margin(MARGIN_TOP, 20); - l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30); - press_a_key_label = l; - press_a_key->add_child(l); - press_a_key->connect("gui_input", this, "_wait_for_key"); - press_a_key->connect("confirmed", this, "_press_a_key_confirm"); + sim_axis_sb = memnew(SpinBox); + sim_axis_sb->set_min(-1000); + sim_axis_sb->set_max(1000); + sim_axis_sb->set_step(0.1); + + sim_axis_vbc = memnew(VBoxContainer); + sim_axis_vbc->add_child(sim_axis_sb); + + { + press_a_key_vbc = memnew(VBoxContainer); + press_a_key->add_child(press_a_key_vbc); + press_a_key->connect("gui_input", this, "_wait_for_key"); + press_a_key->connect("confirmed", this, "_press_a_key_confirm"); + + l = memnew(Label); + l->set_text(TTR("Press a Key..")); + l->set_anchors_and_margins_preset(Control::PRESET_WIDE); + l->set_align(Label::ALIGN_CENTER); + l->set_margin(MARGIN_TOP, 20); + l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30); + press_a_key_label = l; + press_a_key_vbc->add_child(l); + } device_input = memnew(ConfirmationDialog); add_child(device_input); device_input->get_ok()->set_text(TTR("Add")); device_input->connect("confirmed", this, "_device_input_add"); + device_input_vbc = memnew(VBoxContainer); + device_input->add_child(device_input_vbc); + hbc = memnew(HBoxContainer); - device_input->add_child(hbc); + device_input_vbc->add_child(hbc); VBoxContainer *vbc_left = memnew(VBoxContainer); hbc->add_child(vbc_left); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 9364b0ff2c32..eb720a2f6fd4 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -77,18 +77,28 @@ class ProjectSettingsEditor : public AcceptDialog { LineEdit *property; OptionButton *type; PopupMenu *popup_add; + VBoxContainer *sim_axis_vbc; + SpinBox *sim_axis_sb; ConfirmationDialog *press_a_key; + VBoxContainer *press_a_key_vbc; Label *press_a_key_label; ConfirmationDialog *device_input; + VBoxContainer *device_input_vbc; SpinBox *device_id; OptionButton *device_index; Label *device_index_label; MenuButton *popup_copy_to_feature; + Control *input_base_actions; + Control *input_base_axis; + VBoxContainer *input_map_vbc; + Label *action_label; LineEdit *action_name; Button *action_add; Label *action_add_error; + SpinBox *controller_id_sb; Tree *input_editor; + bool updating_actions; bool setting; bool updating_translations; @@ -126,6 +136,9 @@ class ProjectSettingsEditor : public AcceptDialog { void _action_add(); void _device_input_add(); + void _controller_changed(double p_value); + + void _tab_container_changed(int p_tab); void _item_checked(const String &p_item, bool p_check); void _action_selected(); void _action_edited(); diff --git a/main/input_default.cpp b/main/input_default.cpp index c3bc83b2dee1..51d6318e2ac9 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -96,14 +96,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)); } -bool InputDefault::is_action_pressed(const StringName &p_action) const { +bool InputDefault::is_action_pressed(const StringName &p_action, int p_device) const { - return action_state.has(p_action) && action_state[p_action].pressed; + const StringName &action(combine_controller_action(p_device, p_action)); + return action_state.has(action) && action_state[action].pressed; } -bool InputDefault::is_action_just_pressed(const StringName &p_action) const { +bool InputDefault::is_action_just_pressed(const StringName &p_action, int p_controller) const { - const Map::Element *E = action_state.find(p_action); + const Map::Element *E = action_state.find(combine_controller_action(p_controller, p_action)); if (!E) return false; @@ -114,9 +115,9 @@ 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, int p_controller) const { - const Map::Element *E = action_state.find(p_action); + const Map::Element *E = action_state.find(combine_controller_action(p_controller, p_action)); if (!E) return false; @@ -127,6 +128,23 @@ bool InputDefault::is_action_just_released(const StringName &p_action) const { } } +bool InputDefault::is_action_just_changed(const StringName &p_action, int p_controller) const { + const Map::Element *E = action_state.find(combine_controller_action(p_controller, p_action)); + if (!E) + return false; + + if (Engine::get_singleton()->is_in_physics_frame()) { + return E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); + } else { + return E->get().idle_frame == Engine::get_singleton()->get_idle_frames(); + } +} + +float InputDefault::get_action_axis_value(const StringName &p_action, int p_controller) const { + const StringName &action(combine_controller_action(p_controller, p_action)); + return action_state.has(action) ? action_state[action].axis_value : 0; +} + float InputDefault::get_joy_axis(int p_device, int p_axis) const { _THREAD_SAFE_METHOD_ @@ -318,6 +336,7 @@ void InputDefault::parse_input_event(const Ref &p_event) { Ref jm = p_event; if (jm.is_valid()) { + set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value()); } @@ -333,12 +352,16 @@ void InputDefault::parse_input_event(const Ref &p_event) { if (!p_event->is_echo()) { for (const Map::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) { - if (InputMap::get_singleton()->event_is_action(p_event, E->key()) && is_action_pressed(E->key()) != p_event->is_pressed()) { - Action action; - action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.idle_frame = Engine::get_singleton()->get_idle_frames(); - action.pressed = p_event->is_pressed(); - action_state[E->key()] = action; + Ref action_ie = InputMap::get_singleton()->event_get_input_event_if_action(p_event, E->key()); + if (action_ie.is_valid()) { + ActionState &a = action_state[E->key()]; + const float new_axis_value = action_ie->get_axis_factor() * p_event->get_axis_value(); + if (a.idle_frame == -1 || a.axis_value != new_axis_value || a.pressed != p_event->is_pressed()) { + a.physics_frame = Engine::get_singleton()->get_physics_frames(); + a.idle_frame = Engine::get_singleton()->get_idle_frames(); + a.pressed = p_event->is_pressed(); + a.axis_value = new_axis_value; + } } } } @@ -467,26 +490,26 @@ Point2i InputDefault::warp_mouse_motion(const Ref &p_moti void InputDefault::iteration(float p_step) { } -void InputDefault::action_press(const StringName &p_action) { +void InputDefault::action_press(const StringName &p_action, int p_controller) { - Action action; + ActionState action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.idle_frame = Engine::get_singleton()->get_idle_frames(); action.pressed = true; - action_state[p_action] = action; + action_state[combine_controller_action(p_controller, p_action)] = action; } -void InputDefault::action_release(const StringName &p_action) { +void InputDefault::action_release(const StringName &p_action, int p_controller) { - Action action; + ActionState action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.idle_frame = Engine::get_singleton()->get_idle_frames(); action.pressed = false; - action_state[p_action] = action; + action_state[combine_controller_action(p_controller, p_action)] = action; } void InputDefault::set_emulate_touch(bool p_emulate) { @@ -1016,3 +1039,7 @@ int InputDefault::get_joy_axis_index_from_string(String p_axis) { } ERR_FAIL_V(-1); } + +const StringName InputDefault::combine_controller_action(int p_controller, const StringName &p_action) const { + return String::num(p_controller) + ":" + p_action; +} diff --git a/main/input_default.h b/main/input_default.h index 0479fdc0ff01..134a4bcf5967 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -51,13 +51,20 @@ class InputDefault : public Input { Vector2 mouse_pos; MainLoop *main_loop; - struct Action { + struct ActionState { uint64_t physics_frame; uint64_t idle_frame; bool pressed; + float axis_value; + + ActionState() : + physics_frame(-1), + idle_frame(-1), + pressed(false), + axis_value(0.) {} }; - Map action_state; + Map action_state; bool emulate_touch; @@ -179,9 +186,12 @@ class InputDefault : public Input { virtual bool is_key_pressed(int p_scancode) 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_action_pressed(const StringName &p_action) const; - virtual bool is_action_just_pressed(const StringName &p_action) const; - virtual bool is_action_just_released(const StringName &p_action) const; + + virtual bool is_action_pressed(const StringName &p_action, int p_controller = 0) const; + virtual bool is_action_just_pressed(const StringName &p_action, int p_controller = 0) const; + virtual bool is_action_just_released(const StringName &p_action, int p_controller = 0) const; + virtual bool is_action_just_changed(const StringName &p_action, int p_controller = 0) const; + virtual float get_action_axis_value(const StringName &p_action, int p_controller = 0) const; virtual float get_joy_axis(int p_device, int p_axis) const; String get_joy_name(int p_idx); @@ -218,8 +228,8 @@ class InputDefault : public Input { void set_main_loop(MainLoop *p_main_loop); void set_mouse_position(const Point2 &p_posf); - void action_press(const StringName &p_action); - void action_release(const StringName &p_action); + void action_press(const StringName &p_action, int p_controller = 0); + void action_release(const StringName &p_action, int p_controller = 0); void iteration(float p_step); @@ -250,6 +260,9 @@ class InputDefault : public Input { String get_joy_guid_remapped(int p_device) const; void set_fallback_mapping(String p_guid); InputDefault(); + +private: + const StringName combine_controller_action(int p_controller, const StringName &p_action) const; }; #endif // INPUT_DEFAULT_H diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index c5654a5a20c1..df0ccf8b1c5b 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -3521,7 +3521,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { if (!pi.name.begins_with("input/")) continue; - String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); + String name = pi.name.get_slice("/", 1); al.push_back(name); }