summaryrefslogtreecommitdiff
path: root/platform/x11
diff options
context:
space:
mode:
Diffstat (limited to 'platform/x11')
-rw-r--r--platform/x11/joystick_linux.cpp74
-rw-r--r--platform/x11/joystick_linux.h7
-rw-r--r--platform/x11/os_x11.cpp33
-rw-r--r--platform/x11/os_x11.h3
4 files changed, 107 insertions, 10 deletions
diff --git a/platform/x11/joystick_linux.cpp b/platform/x11/joystick_linux.cpp
index 2793cc5734..5ce0219df7 100644
--- a/platform/x11/joystick_linux.cpp
+++ b/platform/x11/joystick_linux.cpp
@@ -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) {
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) {
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 {
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)) {
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();
return p_event_id;
diff --git a/platform/x11/joystick_linux.h b/platform/x11/joystick_linux.h
index 4f0533721b..7ea2664ebb 100644
--- a/platform/x11/joystick_linux.h
+++ b/platform/x11/joystick_linux.h
@@ -61,6 +61,10 @@ private:
String devpath;
input_absinfo *abs_info[MAX_ABS];
+ bool force_feedback;
+ int ff_effect_id;
+ uint64_t ff_effect_timestamp;
+
Joystick();
~Joystick();
void reset();
@@ -88,6 +92,9 @@ private:
void run_joystick_thread();
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;
};
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index eb576b11f4..1ca779ef7c 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -120,15 +120,33 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
const char* err;
xrr_get_monitors = NULL;
+ xrr_free_monitors = NULL;
+ int xrandr_major = 0;
+ int xrandr_minor = 0;
+ int event_base, error_base;
+ xrandr_ext_ok = XRRQueryExtension(x11_display,&event_base, &error_base);
xrandr_handle = dlopen("libXrandr.so", RTLD_LAZY);
err = dlerror();
if (!xrandr_handle) {
- fprintf(stderr, "could not load libXrandr.so, dpi detection disabled. Error: %s\n", err);
+ fprintf(stderr, "could not load libXrandr.so, Error: %s\n", err);
}
else {
- xrr_get_monitors = (xrr_get_monitors_t) dlsym(xrandr_handle, "XRRGetMonitors");
- if (!xrr_get_monitors)
- fprintf(stderr, "could not find symbol XRRGetMonitors, dpi detection will only work on the first screen\nError: %s\n", err);
+ XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
+ if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
+ xrr_get_monitors = (xrr_get_monitors_t) dlsym(xrandr_handle, "XRRGetMonitors");
+ if (!xrr_get_monitors) {
+ err = dlerror();
+ fprintf(stderr, "could not find symbol XRRGetMonitors\nError: %s\n", err);
+ }
+ else {
+ xrr_free_monitors = (xrr_free_monitors_t) dlsym(xrandr_handle, "XRRFreeMonitors");
+ if (!xrr_free_monitors) {
+ err = dlerror();
+ fprintf(stderr, "could not find XRRFreeMonitors\nError: %s\n", err);
+ xrr_get_monitors = NULL;
+ }
+ }
+ }
}
xim = XOpenIM (x11_display, NULL, NULL, NULL);
@@ -745,19 +763,18 @@ int OS_X11::get_screen_dpi(int p_screen) const {
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0);
//Get physical monitor Dimensions through XRandR and calculate dpi
- int event_base, error_base;
- const Bool ext_okay = XRRQueryExtension(x11_display,&event_base, &error_base);
-
Size2 sc = get_screen_size(p_screen);
- if (ext_okay) {
+ if (xrandr_ext_ok) {
int count = 0;
if (xrr_get_monitors) {
xrr_monitor_info *monitors = xrr_get_monitors(x11_display, x11_window, true, &count);
if (p_screen < count) {
double xdpi = sc.width / (double) monitors[p_screen].mwidth * 25.4;
double ydpi = sc.height / (double) monitors[p_screen].mheight * 25.4;
+ xrr_free_monitors(monitors);
return (xdpi + ydpi) / 2;
}
+ xrr_free_monitors(monitors);
}
else if (p_screen == 0) {
XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 3a4579d818..71bbe726dd 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -178,8 +178,11 @@ class OS_X11 : public OS_Unix {
void set_wm_fullscreen(bool p_enabled);
typedef xrr_monitor_info* (*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
+ typedef void (*xrr_free_monitors_t)(xrr_monitor_info* monitors);
xrr_get_monitors_t xrr_get_monitors;
+ xrr_free_monitors_t xrr_free_monitors;
void *xrandr_handle;
+ Bool xrandr_ext_ok;
protected: