diff options
Diffstat (limited to 'core/input')
-rw-r--r-- | core/input/default_controller_mappings.h | 4 | ||||
-rw-r--r-- | core/input/gamecontrollerdb.txt | 2 | ||||
-rw-r--r-- | core/input/godotcontrollerdb.txt | 21 | ||||
-rw-r--r-- | core/input/input.cpp | 362 | ||||
-rw-r--r-- | core/input/input.h | 22 | ||||
-rw-r--r-- | core/input/input_event.cpp | 343 | ||||
-rw-r--r-- | core/input/input_event.h | 102 | ||||
-rw-r--r-- | core/input/input_map.cpp | 36 | ||||
-rw-r--r-- | core/input/input_map.h | 13 |
9 files changed, 549 insertions, 356 deletions
diff --git a/core/input/default_controller_mappings.h b/core/input/default_controller_mappings.h index 9e2a69acec..ba5e650226 100644 --- a/core/input/default_controller_mappings.h +++ b/core/input/default_controller_mappings.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index 2a3cb23202..180708cea6 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -338,7 +338,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, # Mac OS X -030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, 03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, 03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt index 51ddda1e4e..e8e250e3be 100644 --- a/core/input/godotcontrollerdb.txt +++ b/core/input/godotcontrollerdb.txt @@ -8,13 +8,20 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftst Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android, # Javascript -Default HTML5 Gamepad, Default Mapping,leftx:a0,lefty:a1,dpdown:b13,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:b14,lefttrigger:a6,x:b2,dpup:b12,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:b15,righttrigger:a7,b:b1,platform:Javascript, -c2a94d6963726f736f66742058626f78,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,platform:Javascript, -303534632d303563342d576972656c65,PS4 Controller USB/Win,leftx:a0,lefty:a1,dpdown:b15,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a5,lefttrigger:a3,x:b0,dpup:b14,dpleft:b16,dpright:b17,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b1,righttrigger:b7,b:b2,platform:Javascript, -303534632d303563342d536f6e792043,PS4 Controller USB/Linux,leftx:a0,lefty:a1,dpdown:a7,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a5,dpleft:a6,lefttrigger:a3,x:b0,dpup:a7,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b1,dpright:a6,righttrigger:a4,b:b2,platform:Javascript, -303534632d303236382d536f6e792050,PS3 Controller USB/Linux,leftx:a0,lefty:a1,dpdown:b6,rightstick:b2,rightshoulder:b11,rightx:a2,start:b3,righty:a3,dpleft:b7,lefttrigger:b8,x:b15,dpup:b4,back:b0,leftstick:b1,leftshoulder:b10,y:b12,a:b14,dpright:b5,righttrigger:b9,b:b13,platform:Javascript, -303435652d303731392d58626f782033,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,platform:Javascript, -303435652d303238652d4d6963726f73,Wired X360 Controller,leftx:a0,lefty:a1,dpdown:a7,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:a6,lefttrigger:a2,x:b2,dpup:a7,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:a6,righttrigger:a5,b:b1,platform:Javascript, +standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Javascript, +Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript, +Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Javascript, +Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Javascript, +MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript +MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript +MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript +MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript +MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript # UWP __UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP, diff --git a/core/input/input.cpp b/core/input/input.cpp index 4d152c1ac4..2e3f112ebc 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,16 +30,16 @@ #include "input.h" +#include "core/config/project_settings.h" #include "core/input/default_controller_mappings.h" #include "core/input/input_map.h" #include "core/os/os.h" -#include "core/project_settings.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #endif -static const char *_joy_buttons[JOY_SDL_BUTTONS + 1] = { +static const char *_joy_buttons[JOY_BUTTON_SDL_MAX] = { "a", "b", "x", @@ -55,69 +55,15 @@ static const char *_joy_buttons[JOY_SDL_BUTTONS + 1] = { "dpdown", "dpleft", "dpright", - nullptr }; -static const char *_joy_button_names[JOY_BUTTON_MAX] = { - "Face Bottom", - "Face Right", - "Face Left", - "Face Top", - "Select", - "Guide", - "Start", - "Left Stick", - "Right Stick", - "Left Shoulder", - "Right Shoulder", - "D-Pad Up", - "D-Pad Down", - "D-Pad Left", - "D-Pad Right", - "Button 15", - "Button 16", - "Button 17", - "Button 18", - "Button 19", - "Button 20", - "Button 21", - "Button 22", - "Button 23", - "Button 24", - "Button 25", - "Button 26", - "Button 27", - "Button 28", - "Button 29", - "Button 30", - "Button 31", - "Button 32", - "Button 33", - "Button 34", - "Button 35" -}; - -static const char *_joy_axes[JOY_SDL_AXES + 1] = { +static const char *_joy_axes[JOY_AXIS_SDL_MAX] = { "leftx", "lefty", "rightx", "righty", "lefttrigger", "righttrigger", - nullptr -}; - -static const char *_joy_axis_names[JOY_AXIS_MAX] = { - "Left Stick X", - "Left Stick Y", - "Right Stick X", - "Right Stick Y", - "Left Trigger", - "Right Trigger", - "Joystick 3 Stick X", - "Joystick 3 Stick Y", - "Joystick 4 Stick X", - "Joystick 4 Stick Y" }; Input *Input::singleton = nullptr; @@ -149,6 +95,9 @@ void Input::_bind_methods() { 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("get_action_strength", "action"), &Input::get_action_strength); + ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_strength); + 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("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); @@ -159,10 +108,6 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads); ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength); ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration); - ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &Input::get_joy_button_string); - ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &Input::get_joy_button_index_from_string); - ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &Input::get_joy_axis_string); - ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string); ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0)); ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration); ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500)); @@ -215,7 +160,9 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\""; 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" || pf == "get_action_strength")) { + 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 == "get_action_strength" || pf == "get_axis" || pf == "get_vector")) { List<PropertyInfo> pinfo; ProjectSettings::get_singleton()->get_property_list(&pinfo); @@ -300,7 +247,7 @@ bool Input::is_action_just_pressed(const StringName &p_action) const { if (Engine::get_singleton()->is_in_physics_frame()) { return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); } else { - return E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames(); + return E->get().pressed && E->get().process_frame == Engine::get_singleton()->get_process_frames(); } } @@ -313,7 +260,7 @@ bool Input::is_action_just_released(const StringName &p_action) const { if (Engine::get_singleton()->is_in_physics_frame()) { return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); } else { - return !E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames(); + return !E->get().pressed && E->get().process_frame == Engine::get_singleton()->get_process_frames(); } } @@ -326,6 +273,46 @@ float Input::get_action_strength(const StringName &p_action) const { return E->get().strength; } +float Input::get_action_raw_strength(const StringName &p_action) const { + const Map<StringName, Action>::Element *E = action_state.find(p_action); + if (!E) { + return 0.0f; + } + + return E->get().raw_strength; +} + +float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const { + return get_action_strength(p_positive_action) - get_action_strength(p_negative_action); +} + +Vector2 Input::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) const { + Vector2 vector = Vector2( + get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x), + get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y)); + + if (p_deadzone < 0.0f) { + // If the deadzone isn't specified, get it from the average of the actions. + p_deadzone = (InputMap::get_singleton()->action_get_deadzone(p_positive_x) + + InputMap::get_singleton()->action_get_deadzone(p_negative_x) + + InputMap::get_singleton()->action_get_deadzone(p_positive_y) + + InputMap::get_singleton()->action_get_deadzone(p_negative_y)) / + 4; + } + + // Circular length limiting and deadzone. + float length = vector.length(); + if (length <= p_deadzone) { + return Vector2(); + } else if (length > 1.0f) { + return vector / length; + } else { + // Inverse lerp length to map (p_deadzone, 1) to (0, 1). + return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length); + } + return vector; +} + float Input::get_joy_axis(int p_device, int p_axis) const { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); @@ -601,12 +588,14 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (!p_event->is_echo() && is_action_pressed(E->key()) != p_event->is_action_pressed(E->key())) { Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.idle_frame = Engine::get_singleton()->get_idle_frames(); + action.process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = p_event->is_action_pressed(E->key()); - action.strength = 0.f; + action.strength = 0.0f; + action.raw_strength = 0.0f; action_state[E->key()] = action; } action_state[E->key()].strength = p_event->get_action_strength(E->key()); + action_state[E->key()].raw_strength = p_event->get_action_raw_strength(E->key()); } } @@ -725,7 +714,7 @@ void Input::action_press(const StringName &p_action, float p_strength) { Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.idle_frame = Engine::get_singleton()->get_idle_frames(); + action.process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = true; action.strength = p_strength; @@ -736,7 +725,7 @@ void Input::action_release(const StringName &p_action) { Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.idle_frame = Engine::get_singleton()->get_idle_frames(); + action.process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = false; action.strength = 0.f; @@ -817,7 +806,7 @@ void Input::accumulate_input_event(const Ref<InputEvent> &p_event) { parse_input_event(p_event); return; } - if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) { + if (!accumulated_events.is_empty() && accumulated_events.back()->get()->accumulate(p_event)) { return; //event was accumulated, exit } @@ -874,7 +863,7 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) { } if (map.type == TYPE_AXIS) { - _axis_event(p_device, map.index, p_pressed ? 1.0 : 0.0); + _axis_event(p_device, map.index, p_pressed ? map.value : 0.0); } // no event? } @@ -890,14 +879,6 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { return; } - if (p_value.value > joy.last_axis[p_axis]) { - if (p_value.value < joy.last_axis[p_axis] + joy.filter) { - return; - } - } else if (p_value.value > joy.last_axis[p_axis] - joy.filter) { - return; - } - //when changing direction quickly, insert fake event to release pending inputmap actions float last = joy.last_axis[p_axis]; if (p_value.min == 0 && (last < 0.25 || last > 0.75) && (last - 0.5) * (p_value.value - 0.5) < 0) { @@ -905,10 +886,10 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { jx.min = p_value.min; jx.value = p_value.value < 0.5 ? 0.6 : 0.4; joy_axis(p_device, p_axis, jx); - } else if (ABS(last) > 0.5 && last * p_value.value < 0) { + } else if (ABS(last) > 0.5 && last * p_value.value <= 0) { JoyAxis jx; jx.min = p_value.min; - jx.value = p_value.value < 0 ? 0.1 : -0.1; + jx.value = last > 0 ? 0.1 : -0.1; joy_axis(p_device, p_axis, jx); } @@ -920,55 +901,42 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { return; } - JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value); + JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, val); if (map.type == TYPE_BUTTON) { - if (map.index == JOY_BUTTON_DPAD_UP || map.index == JOY_BUTTON_DPAD_DOWN) { - bool pressed = p_value.value != 0.0f; - int button = p_value.value < 0 ? JOY_BUTTON_DPAD_UP : JOY_BUTTON_DPAD_DOWN; + bool pressed = map.value > 0.5; + if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) { + // Button already pressed or released; so ignore. + return; + } + _button_event(p_device, map.index, pressed); - if (!pressed) { - if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_UP, p_device))) { - _button_event(p_device, JOY_BUTTON_DPAD_UP, false); - } + // Ensure opposite D-Pad button is also released. + switch (map.index) { + case JOY_BUTTON_DPAD_UP: if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_DOWN, p_device))) { _button_event(p_device, JOY_BUTTON_DPAD_DOWN, false); } - } - if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) { - return; - } - _button_event(p_device, button, true); - return; - } - - if (map.index == JOY_BUTTON_DPAD_LEFT || map.index == JOY_BUTTON_DPAD_RIGHT) { - bool pressed = p_value.value != 0.0f; - int button = p_value.value < 0 ? JOY_BUTTON_DPAD_LEFT : JOY_BUTTON_DPAD_RIGHT; - - if (!pressed) { - if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_LEFT, p_device))) { - _button_event(p_device, JOY_BUTTON_DPAD_LEFT, false); + break; + case JOY_BUTTON_DPAD_DOWN: + if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_UP, p_device))) { + _button_event(p_device, JOY_BUTTON_DPAD_UP, false); } + break; + case JOY_BUTTON_DPAD_LEFT: if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_RIGHT, p_device))) { _button_event(p_device, JOY_BUTTON_DPAD_RIGHT, false); } - } - if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) { - return; - } - _button_event(p_device, button, true); - return; - } - - float deadzone = p_value.min == 0 ? 0.5f : 0.0f; - bool pressed = p_value.value > deadzone; - if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) { - // button already pressed or released, this is an axis bounce value - return; + break; + case JOY_BUTTON_DPAD_RIGHT: + if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_LEFT, p_device))) { + _button_event(p_device, JOY_BUTTON_DPAD_LEFT, false); + } + break; + default: + // Nothing to do. + break; } - - _button_event(p_device, map.index, pressed); return; } @@ -1007,18 +975,15 @@ void Input::joy_hat(int p_device, int p_val) { int cur_val = joy_names[p_device].hat_current; - if ((p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP)) { - _button_event(p_device, map[HAT_UP].index, p_val & HAT_MASK_UP); - } - - if ((p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT)) { - _button_event(p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT); - } - if ((p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN)) { - _button_event(p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN); - } - if ((p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT)) { - _button_event(p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT); + for (int hat_direction = 0, hat_mask = 1; hat_direction < HAT_MAX; hat_direction++, hat_mask <<= 1) { + if ((p_val & hat_mask) != (cur_val & hat_mask)) { + if (map[hat_direction].type == TYPE_BUTTON) { + _button_event(p_device, map[hat_direction].index, p_val & hat_mask); + } + if (map[hat_direction].type == TYPE_AXIS) { + _axis_event(p_device, map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0); + } + } } joy_names[p_device].hat_current = p_val; @@ -1058,6 +1023,19 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, return event; case TYPE_AXIS: event.index = binding.output.axis.axis; + switch (binding.output.axis.range) { + case POSITIVE_HALF_AXIS: + event.value = 1; + break; + case NEGATIVE_HALF_AXIS: + event.value = -1; + break; + case FULL_AXIS: + // It doesn't make sense for a button to map to a full axis, + // but keeping as a default for a trigger with a positive half-axis. + event.value = 1; + break; + } return event; default: ERR_PRINT_ONCE("Joypad button mapping error."); @@ -1067,14 +1045,14 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, return event; } -Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value) { +Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value) { JoyEvent event; event.type = TYPE_MAX; for (int i = 0; i < mapping.bindings.size(); i++) { const JoyBinding binding = mapping.bindings[i]; if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) { - float value = p_value.value; + float value = p_value; if (binding.input.axis.invert) { value = -value; } @@ -1082,26 +1060,40 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, i (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) || (binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) { event.type = binding.outputType; + float shifted_positive_value = 0; + switch (binding.input.axis.range) { + case POSITIVE_HALF_AXIS: + shifted_positive_value = value; + break; + case NEGATIVE_HALF_AXIS: + shifted_positive_value = value + 1; + break; + case FULL_AXIS: + shifted_positive_value = (value + 1) / 2; + break; + } switch (binding.outputType) { case TYPE_BUTTON: event.index = binding.output.button; + switch (binding.input.axis.range) { + case POSITIVE_HALF_AXIS: + event.value = shifted_positive_value; + break; + case NEGATIVE_HALF_AXIS: + event.value = 1 - shifted_positive_value; + break; + case FULL_AXIS: + // It doesn't make sense for a full axis to map to a button, + // but keeping as a default for a trigger with a positive half-axis. + event.value = (shifted_positive_value * 2) - 1; + ; + break; + } return event; case TYPE_AXIS: event.index = binding.output.axis.axis; event.value = value; if (binding.output.axis.range != binding.input.axis.range) { - float shifted_positive_value = 0; - switch (binding.input.axis.range) { - case POSITIVE_HALF_AXIS: - shifted_positive_value = value; - break; - case NEGATIVE_HALF_AXIS: - shifted_positive_value = value + 1; - break; - case FULL_AXIS: - shifted_positive_value = (value + 1) / 2; - break; - } switch (binding.output.axis.range) { case POSITIVE_HALF_AXIS: event.value = shifted_positive_value; @@ -1128,32 +1120,45 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J for (int i = 0; i < mapping.bindings.size(); i++) { const JoyBinding binding = mapping.bindings[i]; if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) { - int index; + int hat_direction; switch (binding.input.hat.hat_mask) { case HAT_MASK_UP: - index = 0; + hat_direction = HAT_UP; break; case HAT_MASK_RIGHT: - index = 1; + hat_direction = HAT_RIGHT; break; case HAT_MASK_DOWN: - index = 2; + hat_direction = HAT_DOWN; break; case HAT_MASK_LEFT: - index = 3; + hat_direction = HAT_LEFT; break; default: ERR_PRINT_ONCE("Joypad button mapping error."); continue; } - r_events[index].type = binding.outputType; + r_events[hat_direction].type = binding.outputType; switch (binding.outputType) { case TYPE_BUTTON: - r_events[index].index = binding.output.button; + r_events[hat_direction].index = binding.output.button; break; case TYPE_AXIS: - r_events[index].index = binding.output.axis.axis; + r_events[hat_direction].index = binding.output.axis.axis; + switch (binding.output.axis.range) { + case POSITIVE_HALF_AXIS: + r_events[hat_direction].value = 1; + break; + case NEGATIVE_HALF_AXIS: + r_events[hat_direction].value = -1; + break; + case FULL_AXIS: + // It doesn't make sense for a hat direction to map to a full axis, + // but keeping as a default for a trigger with a positive half-axis. + r_events[hat_direction].value = 1; + break; + } break; default: ERR_PRINT_ONCE("Joypad button mapping error."); @@ -1163,21 +1168,21 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J } JoyButtonList Input::_get_output_button(String output) { - for (int i = 0; _joy_buttons[i]; i++) { + for (int i = 0; i < JOY_BUTTON_SDL_MAX; i++) { if (output == _joy_buttons[i]) { return JoyButtonList(i); } } - return JoyButtonList::JOY_INVALID_BUTTON; + return JoyButtonList::JOY_BUTTON_INVALID; } JoyAxisList Input::_get_output_axis(String output) { - for (int i = 0; _joy_axes[i]; i++) { + for (int i = 0; i < JOY_AXIS_SDL_MAX; i++) { if (output == _joy_axes[i]) { return JoyAxisList(i); } } - return JoyAxisList::JOY_INVALID_AXIS; + return JoyAxisList::JOY_AXIS_INVALID; } void Input::parse_mapping(String p_mapping) { @@ -1206,19 +1211,19 @@ void Input::parse_mapping(String p_mapping) { ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2, String(entry[idx] + "\nInvalid device mapping entry: " + entry[idx])); - if (output == "platform") { + if (output == "platform" || output == "hint") { continue; } JoyAxisRange output_range = FULL_AXIS; if (output[0] == '+' || output[0] == '-') { ERR_CONTINUE_MSG(output.length() < 2, String(entry[idx] + "\nInvalid output: " + entry[idx])); - output = output.right(1); if (output[0] == '+') { output_range = POSITIVE_HALF_AXIS; } else if (output[0] == '-') { output_range = NEGATIVE_HALF_AXIS; } + output = output.right(1); } JoyAxisRange input_range = FULL_AXIS; @@ -1232,20 +1237,21 @@ void Input::parse_mapping(String p_mapping) { bool invert_axis = false; if (input[input.length() - 1] == '~') { invert_axis = true; + input = input.left(input.length() - 1); } JoyButtonList output_button = _get_output_button(output); JoyAxisList output_axis = _get_output_axis(output); - ERR_CONTINUE_MSG(output_button == JOY_INVALID_BUTTON && output_axis == JOY_INVALID_AXIS, + ERR_CONTINUE_MSG(output_button == JOY_BUTTON_INVALID && output_axis == JOY_AXIS_INVALID, String(entry[idx] + "\nUnrecognised output string: " + output)); - ERR_CONTINUE_MSG(output_button != JOY_INVALID_BUTTON && output_axis != JOY_INVALID_AXIS, + ERR_CONTINUE_MSG(output_button != JOY_BUTTON_INVALID && output_axis != JOY_AXIS_INVALID, String("BUG: Output string matched both button and axis: " + output)); JoyBinding binding; - if (output_button != JOY_INVALID_BUTTON) { + if (output_button != JOY_BUTTON_INVALID) { binding.outputType = TYPE_BUTTON; binding.output.button = output_button; - } else if (output_axis != JOY_INVALID_AXIS) { + } else if (output_axis != JOY_AXIS_INVALID) { binding.outputType = TYPE_AXIS; binding.output.axis.axis = output_axis; binding.output.axis.range = output_range; @@ -1337,20 +1343,6 @@ Array Input::get_connected_joypads() { return ret; } -String Input::get_joy_button_string(int p_button) { - ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "Invalid button"); - return _joy_button_names[p_button]; -} - -int Input::get_joy_button_index_from_string(String p_button) { - for (int i = 0; i < JOY_BUTTON_MAX; i++) { - if (p_button == _joy_button_names[i]) { - return i; - } - } - ERR_FAIL_V(JOY_INVALID_BUTTON); -} - int Input::get_unused_joy_id() { for (int i = 0; i < JOYPADS_MAX; i++) { if (!joy_names.has(i) || !joy_names[i].connected) { @@ -1360,20 +1352,6 @@ int Input::get_unused_joy_id() { return -1; } -String Input::get_joy_axis_string(int p_axis) { - ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "Invalid axis"); - return _joy_axis_names[p_axis]; -} - -int Input::get_joy_axis_index_from_string(String p_axis) { - for (int i = 0; i < JOY_AXIS_MAX; i++) { - if (p_axis == _joy_axis_names[i]) { - return i; - } - } - ERR_FAIL_V(JOY_INVALID_AXIS); -} - Input::Input() { singleton = this; diff --git a/core/input/input.h b/core/input/input.h index 775663503b..445b7ff0cf 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define INPUT_H #include "core/input/input_event.h" -#include "core/object.h" +#include "core/object/object.h" #include "core/os/thread_safe.h" class Input : public Object { @@ -114,9 +114,10 @@ private: struct Action { uint64_t physics_frame; - uint64_t idle_frame; + uint64_t process_frame; bool pressed; float strength; + float raw_strength; }; Map<StringName, Action> action_state; @@ -146,7 +147,6 @@ private: bool connected = false; bool last_buttons[JOY_BUTTON_MAX] = { false }; float last_axis[JOY_AXIS_MAX] = { 0.0f }; - float filter = 0.01f; int last_hat = HAT_MASK_CENTER; int mapping = -1; int hat_current = 0; @@ -217,13 +217,12 @@ private: Vector<JoyDeviceMapping> map_db; JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button); - JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value); + JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value); void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]); JoyButtonList _get_output_button(String output); JoyAxisList _get_output_axis(String output); void _button_event(int p_device, int p_index, bool p_pressed); void _axis_event(int p_device, int p_axis, float p_value); - float _handle_deadzone(int p_device, int p_axis, float p_value); void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated); @@ -266,6 +265,10 @@ public: bool is_action_just_pressed(const StringName &p_action) const; bool is_action_just_released(const StringName &p_action) const; float get_action_strength(const StringName &p_action) const; + float get_action_raw_strength(const StringName &p_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; float get_joy_axis(int p_device, int p_axis) const; String get_joy_name(int p_idx); @@ -327,11 +330,6 @@ public: void add_joy_mapping(String p_mapping, bool p_update_existing = false); void remove_joy_mapping(String p_guid); - String get_joy_button_string(int p_button); - String get_joy_axis_string(int p_axis); - int get_joy_axis_index_from_string(String p_axis); - int get_joy_button_index_from_string(String p_button); - int get_unused_joy_id(); bool is_joy_known(int p_device); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 6ba082f86f..2771a15b80 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,12 +61,17 @@ bool InputEvent::is_action_released(const StringName &p_action) const { } float InputEvent::get_action_strength(const StringName &p_action) const { - bool pressed; float strength; - bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength); + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength); return valid ? strength : 0.0f; } +float InputEvent::get_action_raw_strength(const StringName &p_action) const { + float raw_strength; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength); + return valid ? raw_strength : 0.0f; +} + bool InputEvent::is_pressed() const { return false; } @@ -79,11 +84,7 @@ Ref<InputEvent> InputEvent::xformed_by(const Transform2D &p_xform, const Vector2 return Ref<InputEvent>((InputEvent *)this); } -String InputEvent::as_text() const { - return String(); -} - -bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { return false; } @@ -138,6 +139,14 @@ int64_t InputEventFromWindow::get_window_id() const { /////////////////////////////////// +void InputEventWithModifiers::set_store_command(bool p_enabled) { + store_command = p_enabled; +} + +bool InputEventWithModifiers::is_storing_command() const { + return store_command; +} + void InputEventWithModifiers::set_shift(bool p_enabled) { shift = p_enabled; } @@ -185,7 +194,37 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif set_metakey(event->get_metakey()); } +String InputEventWithModifiers::as_text() const { + Vector<String> mod_names; + + if (get_control()) { + mod_names.push_back(find_keycode_name(KEY_CONTROL)); + } + if (get_shift()) { + mod_names.push_back(find_keycode_name(KEY_SHIFT)); + } + if (get_alt()) { + mod_names.push_back(find_keycode_name(KEY_ALT)); + } + if (get_metakey()) { + mod_names.push_back(find_keycode_name(KEY_META)); + } + + if (!mod_names.is_empty()) { + return String("+").join(mod_names); + } else { + return ""; + } +} + +String InputEventWithModifiers::to_string() { + return as_text(); +} + void InputEventWithModifiers::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_store_command", "enable"), &InputEventWithModifiers::set_store_command); + ClassDB::bind_method(D_METHOD("is_storing_command"), &InputEventWithModifiers::is_storing_command); + ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt); ClassDB::bind_method(D_METHOD("get_alt"), &InputEventWithModifiers::get_alt); @@ -201,6 +240,7 @@ void InputEventWithModifiers::_bind_methods() { ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command); ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "store_command"), "set_store_command", "is_storing_command"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt"), "set_alt", "get_alt"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift"), "set_shift", "get_shift"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "control"), "set_control", "get_control"); @@ -208,6 +248,28 @@ void InputEventWithModifiers::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command"), "set_command", "get_command"); } +void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { + if (store_command) { + // If we only want to Store "Command". +#ifdef APPLE_STYLE_KEYS + // Don't store "Meta" on Mac. + if (property.name == "meta") { + property.usage ^= PROPERTY_USAGE_STORAGE; + } +#else + // Don't store "Control". + if (property.name == "control") { + property.usage ^= PROPERTY_USAGE_STORAGE; + } +#endif + } else { + // We don't want to store command, only control or meta (on mac). + if (property.name == "command") { + property.usage ^= PROPERTY_USAGE_STORAGE; + } + } +} + /////////////////////////////////// void InputEventKey::set_pressed(bool p_pressed) { @@ -287,27 +349,42 @@ uint32_t InputEventKey::get_physical_keycode_with_modifiers() const { } String InputEventKey::as_text() const { - String kc = keycode_get_string(keycode); + String kc; + + if (keycode == 0) { + kc = keycode_get_string(physical_keycode) + " (" + RTR("Physical") + ")"; + } else { + kc = keycode_get_string(keycode); + } + if (kc == String()) { return kc; } - if (get_metakey()) { - kc = find_keycode_name(KEY_META) + ("+" + kc); - } - if (get_alt()) { - kc = find_keycode_name(KEY_ALT) + ("+" + kc); - } - if (get_shift()) { - kc = find_keycode_name(KEY_SHIFT) + ("+" + kc); - } - if (get_control()) { - kc = find_keycode_name(KEY_CONTROL) + ("+" + kc); + String mods_text = InputEventWithModifiers::as_text(); + return mods_text == "" ? kc : mods_text + "+" + kc; +} + +String InputEventKey::to_string() { + String p = is_pressed() ? "true" : "false"; + String e = is_echo() ? "true" : "false"; + + String kc = ""; + String physical = "false"; + if (keycode == 0) { + kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode); + physical = "true"; + } else { + kc = itos(keycode) + " " + keycode_get_string(keycode); } - return kc; + + String mods = InputEventWithModifiers::as_text(); + mods = mods == "" ? TTR("None") : mods; + + return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e); } -bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { Ref<InputEventKey> key = p_event; if (key.is_null()) { return false; @@ -329,8 +406,12 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed if (p_pressed != nullptr) { *p_pressed = key->is_pressed(); } + float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; if (p_strength != nullptr) { - *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; + *p_strength = strength; + } + if (p_raw_strength != nullptr) { + *p_raw_strength = strength; } } return match; @@ -470,7 +551,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co return mb; } -bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { Ref<InputEventMouseButton> mb = p_event; if (mb.is_null()) { return false; @@ -481,49 +562,91 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p if (p_pressed != nullptr) { *p_pressed = mb->is_pressed(); } + float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; if (p_strength != nullptr) { - *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; + *p_strength = strength; + } + if (p_raw_strength != nullptr) { + *p_raw_strength = strength; } } return match; } +static const char *_mouse_button_descriptions[9] = { + TTRC("Left Mouse Button"), + TTRC("Right Mouse Button"), + TTRC("Middle Mouse Button"), + TTRC("Mouse Wheel Up"), + TTRC("Mouse Wheel Down"), + TTRC("Mouse Wheel Left"), + TTRC("Mouse Wheel Right"), + TTRC("Mouse Thumb Button 1"), + TTRC("Mouse Thumb Button 2") +}; + String InputEventMouseButton::as_text() const { - String button_index_string = ""; - switch (get_button_index()) { + // Modifiers + String mods_text = InputEventWithModifiers::as_text(); + String full_string = mods_text == "" ? "" : mods_text + "+"; + + // Button + int idx = get_button_index(); + switch (idx) { case BUTTON_LEFT: - button_index_string = "BUTTON_LEFT"; - break; case BUTTON_RIGHT: - button_index_string = "BUTTON_RIGHT"; - break; case BUTTON_MIDDLE: - button_index_string = "BUTTON_MIDDLE"; - break; case BUTTON_WHEEL_UP: - button_index_string = "BUTTON_WHEEL_UP"; - break; case BUTTON_WHEEL_DOWN: - button_index_string = "BUTTON_WHEEL_DOWN"; - break; case BUTTON_WHEEL_LEFT: - button_index_string = "BUTTON_WHEEL_LEFT"; - break; case BUTTON_WHEEL_RIGHT: - button_index_string = "BUTTON_WHEEL_RIGHT"; - break; case BUTTON_XBUTTON1: - button_index_string = "BUTTON_XBUTTON1"; + case BUTTON_XBUTTON2: + full_string += RTR(_mouse_button_descriptions[idx - 1]); // button index starts from 1, array index starts from 0, so subtract 1 break; + default: + full_string += RTR("Button") + " #" + itos(idx); + break; + } + + // Double Click + if (doubleclick) { + full_string += " (" + RTR("Double Click") + ")"; + } + + return full_string; +} + +String InputEventMouseButton::to_string() { + String p = is_pressed() ? "true" : "false"; + String d = doubleclick ? "true" : "false"; + + int idx = get_button_index(); + String button_string = itos(idx); + + switch (idx) { + case BUTTON_LEFT: + case BUTTON_RIGHT: + case BUTTON_MIDDLE: + case BUTTON_WHEEL_UP: + case BUTTON_WHEEL_DOWN: + case BUTTON_WHEEL_LEFT: + case BUTTON_WHEEL_RIGHT: + case BUTTON_XBUTTON1: case BUTTON_XBUTTON2: - button_index_string = "BUTTON_XBUTTON2"; + button_string += " (" + RTR(_mouse_button_descriptions[idx - 1]) + ")"; // button index starts from 1, array index starts from 0, so subtract 1 break; default: - 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"); + + String mods = InputEventWithModifiers::as_text(); + mods = mods == "" ? TTR("None") : mods; + + // Work around the fact vformat can only take 5 substitutions but 6 need to be passed. + String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods); + return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s doubleclick=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d); } void InputEventMouseButton::_bind_methods() { @@ -606,27 +729,32 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co } String InputEventMouseMotion::as_text() const { - String button_mask_string = ""; + return vformat(RTR("Mouse motion at position (%s) with speed (%s)"), String(get_position()), String(get_speed())); +} + +String InputEventMouseMotion::to_string() { + int button_mask = get_button_mask(); + String button_mask_string = itos(button_mask); switch (get_button_mask()) { case BUTTON_MASK_LEFT: - button_mask_string = "BUTTON_MASK_LEFT"; + button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_LEFT - 1]) + ")"; break; case BUTTON_MASK_MIDDLE: - button_mask_string = "BUTTON_MASK_MIDDLE"; + button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_MIDDLE - 1]) + ")"; break; case BUTTON_MASK_RIGHT: - button_mask_string = "BUTTON_MASK_RIGHT"; + button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_RIGHT - 1]) + ")"; break; case BUTTON_MASK_XBUTTON1: - button_mask_string = "BUTTON_MASK_XBUTTON1"; + button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON1 - 1]) + ")"; break; case BUTTON_MASK_XBUTTON2: - button_mask_string = "BUTTON_MASK_XBUTTON2"; + button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON2 - 1]) + ")"; break; default: - button_mask_string = itos(get_button_mask()); break; } + return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + "), pressure=(" + rtos(get_pressure()) + "), tilt=(" + String(get_tilt()) + ")"; } @@ -713,7 +841,7 @@ bool InputEventJoypadMotion::is_pressed() const { return Math::abs(axis_value) >= 0.5f; } -bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { Ref<InputEventJoypadMotion> jm = p_event; if (jm.is_null()) { return false; @@ -721,8 +849,9 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool * bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event. if (match) { + float jm_abs_axis_value = Math::abs(jm->get_axis_value()); bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0); - bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false; + bool pressed = same_direction && jm_abs_axis_value >= p_deadzone; if (p_pressed != nullptr) { *p_pressed = pressed; } @@ -731,17 +860,43 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool * if (p_deadzone == 1.0f) { *p_strength = 1.0f; } else { - *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f); + *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, jm_abs_axis_value), 0.0f, 1.0f); } } else { *p_strength = 0.0f; } } + if (p_raw_strength != nullptr) { + if (same_direction) { // NOT pressed, because we want to ignore the deadzone. + *p_raw_strength = jm_abs_axis_value; + } else { + *p_raw_strength = 0.0f; + } + } } return match; } +static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = { + TTRC("Left Stick X-Axis, Joystick 0 X-Axis"), + TTRC("Left Stick Y-Axis, Joystick 0 Y-Axis"), + TTRC("Right Stick X-Axis, Joystick 1 X-Axis"), + TTRC("Right Stick Y-Axis, Joystick 1 Y-Axis"), + TTRC("Joystick 2 X-Axis, Left Trigger, Sony L2, Xbox LT"), + TTRC("Joystick 2 Y-Axis, Right Trigger, Sony R2, Xbox RT"), + TTRC("Joystick 3 X-Axis"), + TTRC("Joystick 3 Y-Axis"), + TTRC("Joystick 4 X-Axis"), + TTRC("Joystick 4 Y-Axis"), +}; + String InputEventJoypadMotion::as_text() const { + String desc = axis < JOY_AXIS_MAX ? RTR(_joy_axis_descriptions[axis]) : TTR("Unknown Joypad Axis"); + + return vformat(TTR("Joypad Motion on Axis %s (%s) with Value %s"), itos(axis), desc, String(Variant(axis_value))); +} + +String InputEventJoypadMotion::to_string() { return "InputEventJoypadMotion : axis=" + itos(axis) + ", axis_value=" + String(Variant(axis_value)); } @@ -782,7 +937,7 @@ float InputEventJoypadButton::get_pressure() const { return pressure; } -bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { Ref<InputEventJoypadButton> jb = p_event; if (jb.is_null()) { return false; @@ -793,8 +948,12 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool * if (p_pressed != nullptr) { *p_pressed = jb->is_pressed(); } + float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; if (p_strength != nullptr) { - *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; + *p_strength = strength; + } + if (p_raw_strength != nullptr) { + *p_raw_strength = strength; } } @@ -810,7 +969,39 @@ bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) cons return button_index == button->button_index; } +static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = { + TTRC("Bottom Action, Sony Cross, Xbox A, Nintendo B"), + TTRC("Right Action, Sony Circle, Xbox B, Nintendo A"), + TTRC("Left Action, Sony Square, Xbox X, Nintendo Y"), + TTRC("Top Action, Sony Triangle, Xbox Y, Nintendo X"), + TTRC("Back, Sony Select, Xbox Back, Nintendo -"), + TTRC("Guide, Sony PS, Xbox Home"), + TTRC("Start, Nintendo +"), + TTRC("Left Stick, Sony L3, Xbox L/LS"), + TTRC("Right Stick, Sony R3, Xbox R/RS"), + TTRC("Left Shoulder, Sony L1, Xbox LB"), + TTRC("Right Shoulder, Sony R1, Xbox RB"), + TTRC("D-pad Up"), + TTRC("D-pad Down"), + TTRC("D-pad Left"), + TTRC("D-pad Right"), +}; + String InputEventJoypadButton::as_text() const { + String text = "Joypad Button " + itos(button_index); + + if (button_index < JOY_BUTTON_SDL_MAX) { + text += vformat(" (%s)", _joy_button_descriptions[button_index]); + } + + if (pressure != 0) { + text += ", Pressure:" + String(Variant(pressure)); + } + + return text; +} + +String InputEventJoypadButton::to_string() { return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure)); } @@ -868,6 +1059,12 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co } String InputEventScreenTouch::as_text() const { + String status = pressed ? RTR("touched") : RTR("released"); + + return vformat(RTR("Screen %s at (%s) with %s touch points"), status, String(get_position()), itos(index)); +} + +String InputEventScreenTouch::to_string() { return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")"; } @@ -937,6 +1134,10 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con } String InputEventScreenDrag::as_text() const { + return vformat(RTR("Screen dragged with %s touch points at position (%s) with speed of (%s)"), itos(index), String(get_position()), String(get_speed())); +} + +String InputEventScreenDrag::to_string() { return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")"; } @@ -997,7 +1198,7 @@ bool InputEventAction::is_action(const StringName &p_action) const { return action == p_action; } -bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { +bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const { Ref<InputEventAction> act = p_event; if (act.is_null()) { return false; @@ -1008,14 +1209,22 @@ bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pres if (p_pressed != nullptr) { *p_pressed = act->pressed; } + float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; if (p_strength != nullptr) { - *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f; + *p_strength = strength; + } + if (p_raw_strength != nullptr) { + *p_raw_strength = strength; } } return match; } String InputEventAction::as_text() const { + return vformat(RTR("Input Action %s was %s"), action, pressed ? "pressed" : "released"); +} + +String InputEventAction::to_string() { return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false"); } @@ -1079,6 +1288,10 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, } String InputEventMagnifyGesture::as_text() const { + return vformat(RTR("Magnify Gesture at (%s) with factor %s"), String(get_position()), rtos(get_factor())); +} + +String InputEventMagnifyGesture::to_string() { return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")"; } @@ -1115,6 +1328,10 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con } String InputEventPanGesture::as_text() const { + return vformat(RTR("Pan Gesture at (%s) with delta (%s)"), String(get_position()), String(get_delta())); +} + +String InputEventPanGesture::to_string() { return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")"; } @@ -1192,7 +1409,11 @@ int InputEventMIDI::get_controller_value() const { } String InputEventMIDI::as_text() const { - return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")"; + return vformat(RTR("MIDI Input on Channel=%s Message=%s"), itos(channel), itos(message)); +} + +String InputEventMIDI::to_string() { + return vformat("InputEvenMIDI: channel=%s message=%s pitch=%s velocity=%s pressure=%s", itos(channel), itos(message), itos(pitch), itos(velocity), itos(pressure)); } void InputEventMIDI::_bind_methods() { diff --git a/core/input/input_event.h b/core/input/input_event.h index 815ba5ae80..1500faa24c 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,11 @@ #ifndef INPUT_EVENT_H #define INPUT_EVENT_H +#include "core/io/resource.h" #include "core/math/transform_2d.h" #include "core/os/copymem.h" -#include "core/resource.h" +#include "core/string/ustring.h" #include "core/typedefs.h" -#include "core/ustring.h" /** * Input Event classes. These are used in the main loop. @@ -60,10 +60,7 @@ enum ButtonList { }; enum JoyButtonList { - - JOY_INVALID_BUTTON = -1, - - // SDL Buttons + JOY_BUTTON_INVALID = -1, JOY_BUTTON_A = 0, JOY_BUTTON_B = 1, JOY_BUTTON_X = 2, @@ -79,64 +76,20 @@ enum JoyButtonList { JOY_BUTTON_DPAD_DOWN = 12, JOY_BUTTON_DPAD_LEFT = 13, JOY_BUTTON_DPAD_RIGHT = 14, - JOY_SDL_BUTTONS = 15, - - // Sony Buttons - JOY_SONY_X = JOY_BUTTON_A, - JOY_SONY_CROSS = JOY_BUTTON_A, - JOY_SONY_CIRCLE = JOY_BUTTON_B, - JOY_SONY_SQUARE = JOY_BUTTON_X, - JOY_SONY_TRIANGLE = JOY_BUTTON_Y, - JOY_SONY_SELECT = JOY_BUTTON_BACK, - JOY_SONY_START = JOY_BUTTON_START, - JOY_SONY_PS = JOY_BUTTON_GUIDE, - JOY_SONY_L1 = JOY_BUTTON_LEFT_SHOULDER, - JOY_SONY_R1 = JOY_BUTTON_RIGHT_SHOULDER, - JOY_SONY_L3 = JOY_BUTTON_LEFT_STICK, - JOY_SONY_R3 = JOY_BUTTON_RIGHT_STICK, - - // Xbox Buttons - JOY_XBOX_A = JOY_BUTTON_A, - JOY_XBOX_B = JOY_BUTTON_B, - JOY_XBOX_X = JOY_BUTTON_X, - JOY_XBOX_Y = JOY_BUTTON_Y, - JOY_XBOX_BACK = JOY_BUTTON_BACK, - JOY_XBOX_START = JOY_BUTTON_START, - JOY_XBOX_HOME = JOY_BUTTON_GUIDE, - JOY_XBOX_LS = JOY_BUTTON_LEFT_STICK, - JOY_XBOX_RS = JOY_BUTTON_RIGHT_STICK, - JOY_XBOX_LB = JOY_BUTTON_LEFT_SHOULDER, - JOY_XBOX_RB = JOY_BUTTON_RIGHT_SHOULDER, - - JOY_BUTTON_MAX = 36 // Apparently Android supports up to 36 buttons. + JOY_BUTTON_SDL_MAX = 15, + JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons. }; enum JoyAxisList { - - JOY_INVALID_AXIS = -1, - - // SDL Axes + JOY_AXIS_INVALID = -1, JOY_AXIS_LEFT_X = 0, JOY_AXIS_LEFT_Y = 1, JOY_AXIS_RIGHT_X = 2, JOY_AXIS_RIGHT_Y = 3, JOY_AXIS_TRIGGER_LEFT = 4, JOY_AXIS_TRIGGER_RIGHT = 5, - JOY_SDL_AXES = 6, - - // Joystick axes. - JOY_AXIS_0_X = 0, - JOY_AXIS_0_Y = 1, - JOY_AXIS_1_X = 2, - JOY_AXIS_1_Y = 3, - JOY_AXIS_2_X = 4, - JOY_AXIS_2_Y = 5, - JOY_AXIS_3_X = 6, - JOY_AXIS_3_Y = 7, - JOY_AXIS_4_X = 8, - JOY_AXIS_4_Y = 9, - - JOY_AXIS_MAX = 10 // OpenVR supports up to 5 Joysticks making a total of 10 axes. + JOY_AXIS_SDL_MAX = 6, + JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes. }; enum MidiMessageList { @@ -173,16 +126,17 @@ public: bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const; bool is_action_released(const StringName &p_action) const; float get_action_strength(const StringName &p_action) const; + float get_action_raw_strength(const StringName &p_action) const; // To be removed someday, since they do not make sense for all events virtual bool is_pressed() const; virtual bool is_echo() const; - virtual String as_text() const; + virtual String as_text() const = 0; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const; @@ -209,6 +163,8 @@ public: class InputEventWithModifiers : public InputEventFromWindow { GDCLASS(InputEventWithModifiers, InputEventFromWindow); + bool store_command = true; + bool shift = false; bool alt = false; #ifdef APPLE_STYLE_KEYS @@ -228,8 +184,12 @@ class InputEventWithModifiers : public InputEventFromWindow { protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const override; public: + void set_store_command(bool p_enabled); + bool is_storing_command() const; + void set_shift(bool p_enabled); bool get_shift() const; @@ -247,6 +207,9 @@ public: void set_modifiers_from_event(const InputEventWithModifiers *event); + virtual String as_text() const override; + virtual String to_string() override; + InputEventWithModifiers() {} }; @@ -283,12 +246,13 @@ public: uint32_t get_keycode_with_modifiers() const; uint32_t get_physical_keycode_with_modifiers() const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; + virtual String to_string() override; InputEventKey() {} }; @@ -342,10 +306,11 @@ public: bool is_doubleclick() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; + virtual String to_string() override; InputEventMouseButton() {} }; @@ -376,6 +341,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; virtual String as_text() const override; + virtual String to_string() override; virtual bool accumulate(const Ref<InputEvent> &p_event) override; @@ -399,10 +365,11 @@ public: virtual bool is_pressed() const override; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; + virtual String to_string() override; InputEventJoypadMotion() {} }; @@ -426,11 +393,12 @@ public: void set_pressure(float p_pressure); float get_pressure() const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; + virtual String to_string() override; InputEventJoypadButton() {} }; @@ -456,6 +424,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; virtual String as_text() const override; + virtual String to_string() override; InputEventScreenTouch() {} }; @@ -485,6 +454,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; virtual String as_text() const override; + virtual String to_string() override; InputEventScreenDrag() {} }; @@ -511,11 +481,12 @@ public: virtual bool is_action(const StringName &p_action) const; - virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; + virtual String to_string() override; InputEventAction() {} }; @@ -546,6 +517,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; virtual String as_text() const override; + virtual String to_string() override; InputEventMagnifyGesture() {} }; @@ -563,6 +535,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; virtual String as_text() const override; + virtual String to_string() override; InputEventPanGesture() {} }; @@ -608,6 +581,7 @@ public: int get_controller_value() const; virtual String as_text() const override; + virtual String to_string() override; InputEventMIDI() {} }; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 6319ffc8f1..53ed925c1f 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,9 @@ #include "input_map.h" +#include "core/config/project_settings.h" +#include "core/input/input.h" #include "core/os/keyboard.h" -#include "core/project_settings.h" InputMap *InputMap::singleton = nullptr; @@ -50,7 +51,7 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events); ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events); ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); - ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); + ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings); } void InputMap::add_action(const StringName &p_action, float p_deadzone) { @@ -70,7 +71,7 @@ void InputMap::erase_action(const StringName &p_action) { Array InputMap::_get_actions() { Array ret; List<StringName> actions = get_actions(); - if (actions.empty()) { + if (actions.is_empty()) { return ret; } @@ -83,7 +84,7 @@ Array InputMap::_get_actions() { List<StringName> InputMap::get_actions() const { List<StringName> actions = List<StringName>(); - if (input_map.empty()) { + if (input_map.is_empty()) { return actions; } @@ -94,7 +95,7 @@ List<StringName> InputMap::get_actions() const { return actions; } -List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const { +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 { ERR_FAIL_COND_V(!p_event.is_valid(), nullptr); for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) { @@ -105,7 +106,7 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re int device = e->get_device(); if (device == ALL_DEVICES || device == p_event->get_device()) { - if (e->action_match(p_event, p_pressed, p_strength, p_action.deadzone)) { + if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { return E; } } @@ -118,6 +119,12 @@ bool InputMap::has_action(const StringName &p_action) const { return input_map.has(p_action); } +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) + "'."); + + 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) + "'."); @@ -145,6 +152,9 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event); if (E) { input_map[p_action].inputs.erase(E); + if (Input::get_singleton()->is_action_pressed(p_action)) { + Input::get_singleton()->action_release(p_action); + } } } @@ -179,7 +189,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName return event_get_action_status(p_event, p_action); } -bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength) const { +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 { Map<StringName, Action>::Element *E = input_map.find(p_action); ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); @@ -196,7 +206,8 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str bool pressed; float strength; - List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength); + float raw_strength; + List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength); if (event != nullptr) { if (p_pressed != nullptr) { *p_pressed = pressed; @@ -204,6 +215,9 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str if (p_strength != nullptr) { *p_strength = strength; } + if (p_raw_strength != nullptr) { + *p_raw_strength = raw_strength; + } return true; } else { return false; @@ -214,7 +228,7 @@ const Map<StringName, InputMap::Action> &InputMap::get_action_map() const { return input_map; } -void InputMap::load_from_globals() { +void InputMap::load_from_project_settings() { input_map.clear(); List<PropertyInfo> pinfo; diff --git a/core/input/input_map.h b/core/input/input_map.h index 548553ed31..1646e7fadb 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define INPUT_MAP_H #include "core/input/input_event.h" -#include "core/object.h" +#include "core/object/class_db.h" class InputMap : public Object { GDCLASS(InputMap, Object); @@ -54,7 +54,7 @@ private: 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) const; + 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; Array _action_get_events(const StringName &p_action); Array _get_actions(); @@ -70,6 +70,7 @@ public: void add_action(const StringName &p_action, float p_deadzone = 0.5); void erase_action(const StringName &p_action); + float action_get_deadzone(const StringName &p_action); void action_set_deadzone(const StringName &p_action, float p_deadzone); void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event); bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event); @@ -78,10 +79,10 @@ public: const List<Ref<InputEvent>> *action_get_events(const StringName &p_action); bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const; - bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr) 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; const Map<StringName, Action> &get_action_map() const; - void load_from_globals(); + void load_from_project_settings(); void load_default(); InputMap(); |