mirror of
https://github.com/godotengine/godot.git
synced 2024-11-22 12:12:28 +00:00
Add joystick vibration support on Linux (#5043)
This commit is contained in:
parent
333de40180
commit
f665200df7
@ -59,6 +59,10 @@ void Input::_bind_methods() {
|
|||||||
ObjectTypeDB::bind_method(_MD("get_joy_axis","device","axis"),&Input::get_joy_axis);
|
ObjectTypeDB::bind_method(_MD("get_joy_axis","device","axis"),&Input::get_joy_axis);
|
||||||
ObjectTypeDB::bind_method(_MD("get_joy_name","device"),&Input::get_joy_name);
|
ObjectTypeDB::bind_method(_MD("get_joy_name","device"),&Input::get_joy_name);
|
||||||
ObjectTypeDB::bind_method(_MD("get_joy_guid","device"),&Input::get_joy_guid);
|
ObjectTypeDB::bind_method(_MD("get_joy_guid","device"),&Input::get_joy_guid);
|
||||||
|
ObjectTypeDB::bind_method(_MD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
|
||||||
|
ObjectTypeDB::bind_method(_MD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
|
||||||
|
ObjectTypeDB::bind_method(_MD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration);
|
||||||
|
ObjectTypeDB::bind_method(_MD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
|
||||||
ObjectTypeDB::bind_method(_MD("get_accelerometer"),&Input::get_accelerometer);
|
ObjectTypeDB::bind_method(_MD("get_accelerometer"),&Input::get_accelerometer);
|
||||||
ObjectTypeDB::bind_method(_MD("get_magnetometer"),&Input::get_magnetometer);
|
ObjectTypeDB::bind_method(_MD("get_magnetometer"),&Input::get_magnetometer);
|
||||||
//ObjectTypeDB::bind_method(_MD("get_mouse_pos"),&Input::get_mouse_pos); - this is not the function you want
|
//ObjectTypeDB::bind_method(_MD("get_mouse_pos"),&Input::get_mouse_pos); - this is not the function you want
|
||||||
|
@ -67,6 +67,11 @@ public:
|
|||||||
virtual void remove_joy_mapping(String p_guid)=0;
|
virtual void remove_joy_mapping(String p_guid)=0;
|
||||||
virtual bool is_joy_known(int p_device)=0;
|
virtual bool is_joy_known(int p_device)=0;
|
||||||
virtual String get_joy_guid(int p_device) const=0;
|
virtual String get_joy_guid(int p_device) const=0;
|
||||||
|
virtual Vector2 get_joy_vibration_strength(int p_device)=0;
|
||||||
|
virtual float get_joy_vibration_duration(int p_device)=0;
|
||||||
|
virtual uint64_t get_joy_vibration_timestamp(int p_device)=0;
|
||||||
|
virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration)=0;
|
||||||
|
virtual void stop_joy_vibration(int p_device)=0;
|
||||||
|
|
||||||
virtual Point2 get_mouse_pos() const=0;
|
virtual Point2 get_mouse_pos() const=0;
|
||||||
virtual Point2 get_mouse_speed() const=0;
|
virtual Point2 get_mouse_speed() const=0;
|
||||||
|
@ -15788,6 +15788,23 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8)
|
|||||||
Returns a SDL2 compatible device guid on platforms that use gamepad remapping. Returns "Default Gamepad" otherwise.
|
Returns a SDL2 compatible device guid on platforms that use gamepad remapping. Returns "Default Gamepad" otherwise.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_joy_vibration_strength">
|
||||||
|
<return type="Vector2">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="device" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Returns the strength of the joystick vibration: x is the strength of the weak motor, and y is the strength of the strong motor.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_joy_vibration_duration">
|
||||||
|
<return type="float">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="device" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Returns the duration of the current vibration effect in seconds.
|
||||||
|
</description>
|
||||||
<method name="get_accelerometer">
|
<method name="get_accelerometer">
|
||||||
<return type="Vector3">
|
<return type="Vector3">
|
||||||
</return>
|
</return>
|
||||||
@ -15830,6 +15847,26 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8)
|
|||||||
Return the mouse mode. See the constants for more information.
|
Return the mouse mode. See the constants for more information.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="start_joy_vibration">
|
||||||
|
<argument index="0" name="device" type="int">
|
||||||
|
</argument>
|
||||||
|
<argument index="1" name="weak_magnitude" type="float">
|
||||||
|
</argument>
|
||||||
|
<argument index="2" name="strong_magnitude" type="float">
|
||||||
|
</argument>
|
||||||
|
<argument index="3" name="duration" type="float">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Starts to vibrate the joystick. Joysticks usually come with two rumble motors, a strong and a weak one. weak_magnitude is the strength of the weak motor (between 0 and 1) and strong_magnitude is the strength of the strong motor (between 0 and 1). duration is the duration of the effect in seconds (a duration of 0 will play the vibration indefinitely).
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="stop_joy_vibration">
|
||||||
|
<argument index="0" name="device" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Stops the vibration of the joystick.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="warp_mouse_pos">
|
<method name="warp_mouse_pos">
|
||||||
<argument index="0" name="to" type="Vector2">
|
<argument index="0" name="to" type="Vector2">
|
||||||
</argument>
|
</argument>
|
||||||
|
@ -137,6 +137,30 @@ String InputDefault::get_joy_name(int p_idx) {
|
|||||||
return joy_names[p_idx].name;
|
return joy_names[p_idx].name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Vector2 InputDefault::get_joy_vibration_strength(int p_device) {
|
||||||
|
if (joy_vibration.has(p_device)) {
|
||||||
|
return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
|
||||||
|
} else {
|
||||||
|
return Vector2(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t InputDefault::get_joy_vibration_timestamp(int p_device) {
|
||||||
|
if (joy_vibration.has(p_device)) {
|
||||||
|
return joy_vibration[p_device].timestamp;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float InputDefault::get_joy_vibration_duration(int p_device) {
|
||||||
|
if (joy_vibration.has(p_device)) {
|
||||||
|
return joy_vibration[p_device].duration;
|
||||||
|
} else {
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static String _hex_str(uint8_t p_byte) {
|
static String _hex_str(uint8_t p_byte) {
|
||||||
|
|
||||||
static const char* dict = "0123456789abcdef";
|
static const char* dict = "0123456789abcdef";
|
||||||
@ -294,6 +318,29 @@ void InputDefault::set_joy_axis(int p_device,int p_axis,float p_value) {
|
|||||||
_joy_axis[c]=p_value;
|
_joy_axis[c]=p_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputDefault::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
|
||||||
|
_THREAD_SAFE_METHOD_
|
||||||
|
if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VibrationInfo vibration;
|
||||||
|
vibration.weak_magnitude = p_weak_magnitude;
|
||||||
|
vibration.strong_magnitude = p_strong_magnitude;
|
||||||
|
vibration.duration = p_duration;
|
||||||
|
vibration.timestamp = OS::get_singleton()->get_unix_time();
|
||||||
|
joy_vibration[p_device] = vibration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputDefault::stop_joy_vibration(int p_device) {
|
||||||
|
_THREAD_SAFE_METHOD_
|
||||||
|
VibrationInfo vibration;
|
||||||
|
vibration.weak_magnitude = 0;
|
||||||
|
vibration.strong_magnitude = 0;
|
||||||
|
vibration.duration = 0;
|
||||||
|
vibration.timestamp = OS::get_singleton()->get_unix_time();
|
||||||
|
joy_vibration[p_device] = vibration;
|
||||||
|
}
|
||||||
|
|
||||||
void InputDefault::set_accelerometer(const Vector3& p_accel) {
|
void InputDefault::set_accelerometer(const Vector3& p_accel) {
|
||||||
|
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "os/input.h"
|
#include "os/input.h"
|
||||||
|
|
||||||
|
|
||||||
class InputDefault : public Input {
|
class InputDefault : public Input {
|
||||||
|
|
||||||
OBJ_TYPE( InputDefault, Input );
|
OBJ_TYPE( InputDefault, Input );
|
||||||
@ -19,6 +20,16 @@ class InputDefault : public Input {
|
|||||||
MainLoop *main_loop;
|
MainLoop *main_loop;
|
||||||
|
|
||||||
bool emulate_touch;
|
bool emulate_touch;
|
||||||
|
|
||||||
|
struct VibrationInfo {
|
||||||
|
float weak_magnitude;
|
||||||
|
float strong_magnitude;
|
||||||
|
float duration; // Duration in seconds
|
||||||
|
uint64_t timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<int, VibrationInfo> joy_vibration;
|
||||||
|
|
||||||
struct SpeedTrack {
|
struct SpeedTrack {
|
||||||
|
|
||||||
uint64_t last_tick;
|
uint64_t last_tick;
|
||||||
@ -129,6 +140,9 @@ public:
|
|||||||
|
|
||||||
virtual float get_joy_axis(int p_device,int p_axis);
|
virtual float get_joy_axis(int p_device,int p_axis);
|
||||||
String get_joy_name(int p_idx);
|
String get_joy_name(int p_idx);
|
||||||
|
virtual Vector2 get_joy_vibration_strength(int p_device);
|
||||||
|
virtual float get_joy_vibration_duration(int p_device);
|
||||||
|
virtual uint64_t get_joy_vibration_timestamp(int p_device);
|
||||||
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
|
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
|
||||||
void parse_joystick_mapping(String p_mapping, bool p_update_existing);
|
void parse_joystick_mapping(String p_mapping, bool p_update_existing);
|
||||||
|
|
||||||
@ -147,6 +161,9 @@ public:
|
|||||||
void set_magnetometer(const Vector3& p_magnetometer);
|
void set_magnetometer(const Vector3& p_magnetometer);
|
||||||
void set_joy_axis(int p_device,int p_axis,float p_value);
|
void set_joy_axis(int p_device,int p_axis,float p_value);
|
||||||
|
|
||||||
|
virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration);
|
||||||
|
virtual void stop_joy_vibration(int p_device);
|
||||||
|
|
||||||
void set_main_loop(MainLoop *main_loop);
|
void set_main_loop(MainLoop *main_loop);
|
||||||
void set_mouse_pos(const Point2& p_posf);
|
void set_mouse_pos(const Point2& p_posf);
|
||||||
|
|
||||||
|
@ -316,13 +316,21 @@ void joystick_linux::setup_joystick_properties(int p_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
joy->force_feedback = false;
|
||||||
|
joy->ff_effect_timestamp = 0;
|
||||||
|
unsigned long ffbit[NBITS(FF_CNT)];
|
||||||
|
if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) {
|
||||||
|
if (test_bit(FF_RUMBLE, ffbit)) {
|
||||||
|
joy->force_feedback = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void joystick_linux::open_joystick(const char *p_path) {
|
void joystick_linux::open_joystick(const char *p_path) {
|
||||||
|
|
||||||
int joy_num = get_free_joy_slot();
|
int joy_num = get_free_joy_slot();
|
||||||
int fd = open(p_path, O_RDONLY | O_NONBLOCK);
|
int fd = open(p_path, O_RDWR | O_NONBLOCK);
|
||||||
if (fd != -1 && joy_num != -1) {
|
if (fd != -1 && joy_num != -1) {
|
||||||
|
|
||||||
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
|
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
|
||||||
@ -392,6 +400,55 @@ void joystick_linux::open_joystick(const char *p_path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void joystick_linux::joystick_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp)
|
||||||
|
{
|
||||||
|
Joystick& joy = joysticks[p_id];
|
||||||
|
if (!joy.force_feedback || joy.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (joy.ff_effect_id != -1) {
|
||||||
|
joystick_vibration_stop(p_id, p_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ff_effect effect;
|
||||||
|
effect.type = FF_RUMBLE;
|
||||||
|
effect.id = -1;
|
||||||
|
effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff);
|
||||||
|
effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff);
|
||||||
|
effect.replay.length = floor(p_duration * 1000);
|
||||||
|
effect.replay.delay = 0;
|
||||||
|
|
||||||
|
if (ioctl(joy.fd, EVIOCSFF, &effect) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct input_event play;
|
||||||
|
play.type = EV_FF;
|
||||||
|
play.code = effect.id;
|
||||||
|
play.value = 1;
|
||||||
|
write(joy.fd, (const void*)&play, sizeof(play));
|
||||||
|
|
||||||
|
joy.ff_effect_id = effect.id;
|
||||||
|
joy.ff_effect_timestamp = p_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void joystick_linux::joystick_vibration_stop(int p_id, uint64_t p_timestamp)
|
||||||
|
{
|
||||||
|
Joystick& joy = joysticks[p_id];
|
||||||
|
if (!joy.force_feedback || joy.fd == -1 || joy.ff_effect_id == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct input_event stop;
|
||||||
|
stop.type = EV_FF;
|
||||||
|
stop.code = joy.ff_effect_id;
|
||||||
|
stop.value = 0;
|
||||||
|
write(joy.fd, (const void*)&stop, sizeof(stop));
|
||||||
|
|
||||||
|
joy.ff_effect_id = -1;
|
||||||
|
joy.ff_effect_timestamp = p_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
InputDefault::JoyAxis joystick_linux::axis_correct(const input_absinfo *p_abs, int p_value) const {
|
InputDefault::JoyAxis joystick_linux::axis_correct(const input_absinfo *p_abs, int p_value) const {
|
||||||
|
|
||||||
int min = p_abs->minimum;
|
int min = p_abs->minimum;
|
||||||
@ -485,6 +542,19 @@ uint32_t joystick_linux::process_joysticks(uint32_t p_event_id) {
|
|||||||
if (len == 0 || (len < 0 && errno != EAGAIN)) {
|
if (len == 0 || (len < 0 && errno != EAGAIN)) {
|
||||||
close_joystick(i);
|
close_joystick(i);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (joy->force_feedback) {
|
||||||
|
uint64_t timestamp = input->get_joy_vibration_timestamp(i);
|
||||||
|
if (timestamp > joy->ff_effect_timestamp) {
|
||||||
|
Vector2 strength = input->get_joy_vibration_strength(i);
|
||||||
|
float duration = input->get_joy_vibration_duration(i);
|
||||||
|
if (strength.x == 0 && strength.y == 0) {
|
||||||
|
joystick_vibration_stop(i, timestamp);
|
||||||
|
} else {
|
||||||
|
joystick_vibration_start(i, strength.x, strength.y, duration, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
joy_mutex->unlock();
|
joy_mutex->unlock();
|
||||||
return p_event_id;
|
return p_event_id;
|
||||||
|
@ -61,6 +61,10 @@ private:
|
|||||||
String devpath;
|
String devpath;
|
||||||
input_absinfo *abs_info[MAX_ABS];
|
input_absinfo *abs_info[MAX_ABS];
|
||||||
|
|
||||||
|
bool force_feedback;
|
||||||
|
int ff_effect_id;
|
||||||
|
uint64_t ff_effect_timestamp;
|
||||||
|
|
||||||
Joystick();
|
Joystick();
|
||||||
~Joystick();
|
~Joystick();
|
||||||
void reset();
|
void reset();
|
||||||
@ -88,6 +92,9 @@ private:
|
|||||||
void run_joystick_thread();
|
void run_joystick_thread();
|
||||||
void open_joystick(const char* path);
|
void open_joystick(const char* path);
|
||||||
|
|
||||||
|
void joystick_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
|
||||||
|
void joystick_vibration_stop(int p_id, uint64_t p_timestamp);
|
||||||
|
|
||||||
InputDefault::JoyAxis axis_correct(const input_absinfo *abs, int value) const;
|
InputDefault::JoyAxis axis_correct(const input_absinfo *abs, int value) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user