diff --git a/core/input/input.cpp b/core/input/input.cpp index 38da1c6e85ac..115aba74ef41 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -179,6 +179,10 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_joy_motion_sensors_calibration", "device", "calibration_info"), &Input::set_joy_motion_sensors_calibration); ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrated", "device"), &Input::is_joy_motion_sensors_calibrated); ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrating", "device"), &Input::is_joy_motion_sensors_calibrating); + ClassDB::bind_method(D_METHOD("get_joy_touchpad_finger_position", "device", "finger", "touchpad"), &Input::get_joy_touchpad_finger_position, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_joy_touchpad_finger_pressure", "device", "finger", "touchpad"), &Input::get_joy_touchpad_finger_pressure, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_joy_touchpad_fingers", "device", "touchpad"), &Input::get_joy_touchpad_fingers); + ClassDB::bind_method(D_METHOD("get_joy_num_touchpads", "device"), &Input::get_joy_num_touchpads); ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity); ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer); ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer); @@ -798,6 +802,64 @@ Vector3 Input::get_gyroscope() const { return gyroscope; } +Vector2 Input::get_joy_touchpad_finger_position(int p_device, int p_finger, int p_touchpad) const { + _THREAD_SAFE_METHOD_ + const TouchpadInfo *touch = joy_touch.getptr(p_device); + if (touch == nullptr) { + return Vector2(); + } + + uint16_t index = p_finger | (p_touchpad << 8); + const TouchpadFingerInfo *finger_info = touch->finger_info.getptr(index); + if (finger_info == nullptr) { + return Vector2(); + } + + return finger_info->position; +} + +float Input::get_joy_touchpad_finger_pressure(int p_device, int p_finger, int p_touchpad) const { + _THREAD_SAFE_METHOD_ + const TouchpadInfo *touch = joy_touch.getptr(p_device); + if (touch == nullptr) { + return 0.0f; + } + + uint16_t index = p_finger | (p_touchpad << 8); + const TouchpadFingerInfo *finger_info = touch->finger_info.getptr(index); + if (finger_info == nullptr) { + return 0.0f; + } + + return finger_info->pressure; +} + +PackedInt32Array Input::get_joy_touchpad_fingers(int p_device, int p_touchpad) const { + _THREAD_SAFE_METHOD_ + const TouchpadInfo *touch = joy_touch.getptr(p_device); + if (touch == nullptr) { + return PackedInt32Array(); + } + + PackedInt32Array result; + for (const KeyValue &index : touch->finger_info) { + int touchpad = index.key >> 8; + if (touchpad == p_touchpad) { + result.append(index.key & 0xFF); + } + } + return result; +} + +int Input::get_joy_num_touchpads(int p_device) const { + _THREAD_SAFE_METHOD_ + const TouchpadInfo *touch = joy_touch.getptr(p_device); + if (touch == nullptr) { + return 0; + } + return touch->num_touchpads; +} + void Input::_parse_input_event_impl(const Ref &p_event, bool p_is_emulated) { // This function does the final delivery of the input event to user land. // Regardless where the event came from originally, this has to happen on the main thread. @@ -1620,6 +1682,9 @@ void Input::release_pressed_events() { for (int device : get_connected_joypads()) { stop_joy_vibration(device); + + TouchpadInfo &touch = joy_touch[device]; + touch.finger_info.clear(); } } else { for (KeyValue &E : action_states) { @@ -1823,6 +1888,22 @@ void Input::joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, con motion->gamepad_motion->ProcessMotion(gyro_degrees.x, gyro_degrees.y, gyro_degrees.z, accel_g.x, accel_g.y, accel_g.z, delta_time); } +void Input::joy_touchpad(int p_device, int p_touchpad, int p_finger, const Vector2 &p_value, float p_pressure) { + _THREAD_SAFE_METHOD_ + + if (_should_ignore_joypad_events()) { + return; + } + + TouchpadInfo &touch = joy_touch[p_device]; + uint16_t index = p_finger | (p_touchpad << 8); + if (p_pressure > 0.0) { + touch.finger_info[index] = TouchpadFingerInfo{ p_value, p_pressure }; + } else { + touch.finger_info.erase(index); + } +} + void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) { Ref ievent; ievent.instantiate(); @@ -1887,6 +1968,9 @@ void Input::_update_joypad_features(int p_device) { } motion.last_timestamp = OS::get_singleton()->get_ticks_msec(); } + if (joypad->features->get_joy_num_touchpads() > 0) { + joy_touch[p_device].num_touchpads = joypad->features->get_joy_num_touchpads(); + } } Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) { diff --git a/core/input/input.h b/core/input/input.h index 6d732877efba..fb3b14133555 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -99,6 +99,8 @@ class Input : public Object { virtual bool has_joy_motion_sensors() const { return false; } virtual void set_joy_motion_sensors_enabled(bool p_enable) {} + + virtual int get_joy_num_touchpads() const { return 0; } }; static constexpr int32_t JOYPADS_MAX = 16; @@ -192,6 +194,18 @@ class Input : public Object { HashMap joy_motion; + struct TouchpadFingerInfo { + Vector2 position; + float pressure; + }; + + struct TouchpadInfo { + int num_touchpads = 0; + HashMap finger_info; + }; + + HashMap joy_touch; + struct VelocityTrack { uint64_t last_tick = 0; Vector2 velocity; @@ -385,6 +399,12 @@ class Input : public Object { Vector3 get_magnetometer() const; Vector3 get_gyroscope() const; + Vector2 get_joy_touchpad_finger_position(int p_device, int p_finger, int p_touchpad = 0) const; + float get_joy_touchpad_finger_pressure(int p_device, int p_finger, int p_touchpad = 0) const; + PackedInt32Array get_joy_touchpad_fingers(int p_device, int p_touchpad = 0) const; + + int get_joy_num_touchpads(int p_device) const; + Point2 get_mouse_position() const; Vector2 get_last_mouse_velocity(); Vector2 get_last_mouse_screen_velocity(); @@ -457,6 +477,7 @@ class Input : public Object { void joy_axis(int p_device, JoyAxis p_axis, float p_value); void joy_hat(int p_device, BitField p_val); void joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, const Vector3 &p_gyroscope); + void joy_touchpad(int p_device, int p_touchpad, int p_finger, const Vector2 &p_position, float p_pressure); void add_joy_mapping(const String &p_mapping, bool p_update_existing = false); void remove_joy_mapping(const String &p_guid); diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index c8dac877810d..2528a8c30f1c 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -217,6 +217,47 @@ Returns the name of the joypad at the specified device index, e.g. [code]PS4 Controller[/code]. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names. + + + + + Returns the number of touchpads on the specified joypad, if it has any. Otherwise, the method returns [code]0[/code]. + [b]Note:[/b] This feature is only supported on Windows, Linux, macOS, and iOS. + + + + + + + + + Returns the position of the specified finger on the specified touchpad on the joypad. The X and Y values are in the range from [code]0.0[/code] to [code]1.0[/code], with [code](0.0, 0.0)[/code] representing the top left corner of the touchpad and [code](1.0, 1.0)[/code] representing the bottom right corner. + If the joypad doesn't have the specified touchpad or the specified finger is not currently touching the touchpad, this method returns [constant Vector2.ZERO]. + [b]Note:[/b] This feature is only supported on Windows, Linux, macOS, and iOS. + + + + + + + + + Returns the pressure of the specified finger on the specified touchpad on the joypad. The return value is in the range from [code]0.0[/code] to [code]1.0[/code]. + If the joypad doesn't have the specified touchpad or the specified finger is not currently touching the touchpad, this method returns [code]0.0[/code]. + [b]Note:[/b] This feature is only supported on Windows, Linux, macOS, and iOS. + + + + + + + + Returns an array of finger IDs that are currently touching the specified touchpad on the joypad. + If the joypad doesn't have the specified touchpad or no fingers are currently touching this touchpad, this method returns an empty array. + [b]Note:[/b] To retrieve the positions of the touchpad fingers, use [method get_joy_touchpad_finger_position]. + [b]Note:[/b] This feature is only supported on Windows, Linux, macOS, and iOS. + + diff --git a/drivers/sdl/joypad_sdl.cpp b/drivers/sdl/joypad_sdl.cpp index 669d766f7be9..7f715e19e2f9 100644 --- a/drivers/sdl/joypad_sdl.cpp +++ b/drivers/sdl/joypad_sdl.cpp @@ -280,6 +280,17 @@ void JoypadSDL::process_events() { static_cast(sdl_event.gbutton.button), // Godot button constants are intentionally the same as SDL's, so we can just straight up use them sdl_event.gbutton.down); break; + + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + Input::get_singleton()->joy_touchpad( + joy_id, + sdl_event.gtouchpad.touchpad, + sdl_event.gtouchpad.finger, + Vector2(sdl_event.gtouchpad.x, sdl_event.gtouchpad.y), + sdl_event.gtouchpad.pressure); + break; } } } @@ -346,6 +357,10 @@ bool JoypadSDL::Joypad::has_joy_vibration() const { return supports_force_feedback; } +int JoypadSDL::Joypad::get_joy_num_touchpads() const { + return SDL_GetNumGamepadTouchpads(get_sdl_gamepad()); +} + SDL_Joystick *JoypadSDL::Joypad::get_sdl_joystick() const { return SDL_GetJoystickFromID(sdl_instance_idx); } diff --git a/drivers/sdl/joypad_sdl.h b/drivers/sdl/joypad_sdl.h index e3c7c03e92a4..cbd6513afce7 100644 --- a/drivers/sdl/joypad_sdl.h +++ b/drivers/sdl/joypad_sdl.h @@ -63,6 +63,8 @@ class JoypadSDL { virtual bool has_joy_vibration() const override; + virtual int get_joy_num_touchpads() const override; + SDL_Joystick *get_sdl_joystick() const; SDL_Gamepad *get_sdl_gamepad() const; };