diff options
Diffstat (limited to 'platform/x11')
-rw-r--r-- | platform/x11/joystick_linux.cpp | 74 | ||||
-rw-r--r-- | platform/x11/joystick_linux.h | 7 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 33 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 3 |
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: |