diff --git a/driver.c b/driver.c index 254a782820..5852a02664 100644 --- a/driver.c +++ b/driver.c @@ -309,10 +309,10 @@ void driver_set_nonblock_state(bool nonblock) g_extern.audio_data.nonblock_chunk_size : g_extern.audio_data.block_chunk_size; } -bool driver_set_rumble_state(unsigned port, enum retro_rumble_effect effect, bool enable) +bool driver_set_rumble_state(unsigned port, enum retro_rumble_effect effect, uint16_t strength) { if (driver.input && driver.input_data && driver.input->set_rumble) - return driver.input->set_rumble(driver.input_data, port, effect, enable); + return driver.input->set_rumble(driver.input_data, port, effect, strength); else return false; } diff --git a/driver.h b/driver.h index d7ef4613ef..764c1e4ab5 100644 --- a/driver.h +++ b/driver.h @@ -335,7 +335,7 @@ typedef struct input_driver const char *ident; void (*grab_mouse)(void *data, bool state); - bool (*set_rumble)(void *data, unsigned port, enum retro_rumble_effect effect, bool state); + bool (*set_rumble)(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t state); } input_driver_t; struct rarch_viewport; @@ -497,7 +497,7 @@ uintptr_t driver_get_current_framebuffer(void); retro_proc_address_t driver_get_proc_address(const char *sym); // Used by RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE -bool driver_set_rumble_state(unsigned port, enum retro_rumble_effect effect, bool enable); +bool driver_set_rumble_state(unsigned port, enum retro_rumble_effect effect, uint16_t strength); extern driver_t driver; diff --git a/input/dinput.c b/input/dinput.c index 13d62fc8ab..5fd048f57c 100644 --- a/input/dinput.c +++ b/input/dinput.c @@ -334,10 +334,10 @@ static void dinput_grab_mouse(void *data, bool state) IDirectInputDevice8_Acquire(di->mouse); } -static bool dinput_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, bool state) +static bool dinput_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t strength) { struct dinput_input *di = (struct dinput_input*)data; - return input_joypad_set_rumble(di->joypad, port, effect, state); + return input_joypad_set_rumble(di->joypad, port, effect, strength); } const input_driver_t input_dinput = { diff --git a/input/input_common.c b/input/input_common.c index 3ddf32e3fc..c938b68128 100644 --- a/input/input_common.c +++ b/input/input_common.c @@ -107,7 +107,7 @@ const char *input_joypad_name(const rarch_joypad_driver_t *driver, unsigned joyp } bool input_joypad_set_rumble(const rarch_joypad_driver_t *driver, - unsigned port, enum retro_rumble_effect effect, bool state) + unsigned port, enum retro_rumble_effect effect, uint16_t strength) { if (!driver || !driver->set_rumble) return false; @@ -116,7 +116,7 @@ bool input_joypad_set_rumble(const rarch_joypad_driver_t *driver, if (joy_index < 0 || joy_index >= MAX_PLAYERS) return false; - return driver->set_rumble(joy_index, effect, state); + return driver->set_rumble(joy_index, effect, strength); } bool input_joypad_pressed(const rarch_joypad_driver_t *driver, diff --git a/input/input_common.h b/input/input_common.h index 66866b2ba1..704ce42306 100644 --- a/input/input_common.h +++ b/input/input_common.h @@ -66,7 +66,7 @@ typedef struct rarch_joypad_driver bool (*button)(unsigned, uint16_t); int16_t (*axis)(unsigned, uint32_t); void (*poll)(void); - bool (*set_rumble)(unsigned, enum retro_rumble_effect, bool); // Optional + bool (*set_rumble)(unsigned, enum retro_rumble_effect, uint16_t); // Optional const char *(*name)(unsigned); const char *ident; @@ -83,7 +83,7 @@ int16_t input_joypad_analog(const rarch_joypad_driver_t *driver, unsigned port, unsigned index, unsigned id, const struct retro_keybind *binds); bool input_joypad_set_rumble(const rarch_joypad_driver_t *driver, - unsigned port, enum retro_rumble_effect effect, bool state); + unsigned port, enum retro_rumble_effect effect, uint16_t strength); int16_t input_joypad_axis_raw(const rarch_joypad_driver_t *driver, unsigned joypad, unsigned axis); diff --git a/input/linuxraw_input.c b/input/linuxraw_input.c index 823c95e70f..5467ccc68d 100644 --- a/input/linuxraw_input.c +++ b/input/linuxraw_input.c @@ -285,10 +285,10 @@ static void linuxraw_input_free(void *data) free(data); } -static bool linuxraw_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, bool state) +static bool linuxraw_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t strength) { linuxraw_input_t *linuxraw = (linuxraw_input_t*)data; - return input_joypad_set_rumble(linuxraw->joypad, port, effect, state); + return input_joypad_set_rumble(linuxraw->joypad, port, effect, strength); } static void linuxraw_input_poll(void *data) diff --git a/input/sdl_input.c b/input/sdl_input.c index e2c2dcff2d..64e40b05aa 100644 --- a/input/sdl_input.c +++ b/input/sdl_input.c @@ -214,10 +214,10 @@ static void sdl_input_free(void *data) free(data); } -static bool sdl_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, bool state) +static bool sdl_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t strength) { sdl_input_t *sdl = (sdl_input_t*)data; - return input_joypad_set_rumble(sdl->joypad, port, effect, state); + return input_joypad_set_rumble(sdl->joypad, port, effect, strength); } static void sdl_poll_mouse(sdl_input_t *sdl) diff --git a/input/udev_joypad.c b/input/udev_joypad.c index dd5afb26db..4857c65527 100644 --- a/input/udev_joypad.c +++ b/input/udev_joypad.c @@ -57,6 +57,7 @@ struct udev_joypad int num_effects; int effects[2]; // [0] - strong, [1] - weak bool has_set_ff[2]; + uint16_t strength[2]; char *ident; char *path; @@ -177,7 +178,7 @@ end: udev_device_unref(dev); } -static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, bool state) +static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, uint16_t strength) { struct udev_joypad *pad = &g_pads[i]; @@ -186,6 +187,30 @@ static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, bool st if (pad->num_effects < 2) return false; + if (pad->strength[effect] == strength) + return true; + + if (pad->has_set_ff[effect] && strength != pad->strength[effect]) + { + struct input_event play; + memset(&play, 0, sizeof(play)); + play.type = EV_FF; + play.code = pad->effects[effect]; + play.value = 0; + if (write(pad->fd, &play, sizeof(play)) < (ssize_t)sizeof(play)) + { + RARCH_ERR("[udev]: Failed to set rumble effect %u on pad %u.\n", + effect, i); + return false; + } + + if (ioctl(pad->fd, EVIOCRMFF, (void*)(uintptr_t)pad->effects[effect]) < 0) + RARCH_WARN("[udev]: Failed to remove effect.\n"); + + pad->has_set_ff[effect] = false; + pad->effects[effect] = -1; + } + // Have to defer the force feedback settings to here. // For some reason, effects are getting dropped when they're set at init. // Setting at init seems to work for pads which are hotplugged ... @@ -199,8 +224,8 @@ static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, bool st e.id = -1; switch (effect) { - case RETRO_RUMBLE_STRONG: e.u.rumble.strong_magnitude = 0xc000; break; - case RETRO_RUMBLE_WEAK: e.u.rumble.weak_magnitude = 0xc000; break; + case RETRO_RUMBLE_STRONG: e.u.rumble.strong_magnitude = strength; break; + case RETRO_RUMBLE_WEAK: e.u.rumble.weak_magnitude = strength; break; default: return false; } @@ -212,13 +237,14 @@ static bool udev_set_rumble(unsigned i, enum retro_rumble_effect effect, bool st pad->has_set_ff[effect] = true; pad->effects[effect] = e.id; + pad->strength[effect] = strength; } struct input_event play; memset(&play, 0, sizeof(play)); play.type = EV_FF; play.code = pad->effects[effect]; - play.value = state; + play.value = strength != 0; if (write(pad->fd, &play, sizeof(play)) < (ssize_t)sizeof(play)) { RARCH_ERR("[udev]: Failed to set rumble effect %u on pad %u.\n", diff --git a/input/x11_input.c b/input/x11_input.c index c1a4ce7977..1783698d42 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -269,10 +269,10 @@ static void x_grab_mouse(void *data, bool state) x11->grab_mouse = state; } -static bool x_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, bool state) +static bool x_set_rumble(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t strength) { x11_input_t *x11 = (x11_input_t*)data; - return input_joypad_set_rumble(x11->joypad, port, effect, state); + return input_joypad_set_rumble(x11->joypad, port, effect, strength); } const input_driver_t input_x = { diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index 791818bc2a..c792a81cff 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -180,21 +180,17 @@ static void update_input(void) { static bool old_start; static bool old_select; + uint16_t strength_strong = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ? 0x4000 : 0xffff; + uint16_t strength_weak = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2) ? 0x4000 : 0xffff; bool start = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START); bool select = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT); if (old_start != start) - { fprintf(stderr, "Strong rumble: %s.\n", start ? "ON": "OFF"); - if (!rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, start)) - fprintf(stderr, "Strong rumble; failed to set state.\n"); - } + rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, start * strength_strong); if (old_select != select) - { fprintf(stderr, "Weak rumble: %s.\n", select ? "ON": "OFF"); - if (!rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, select)) - fprintf(stderr, "Weak rumble; failed to set state.\n"); - } + rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, select * strength_weak); old_start = start; old_select = select; diff --git a/libretro.h b/libretro.h index 973c9b36dc..e058be8c02 100755 --- a/libretro.h +++ b/libretro.h @@ -531,10 +531,10 @@ enum retro_rumble_effect // Sets rumble state for joypad plugged in port 'port'. Rumble effects are controlled independently, // and setting e.g. strong rumble does not override weak rumble. -// Should only be called when rumble state changes. +// Strength has a range of [0, 0xffff]. // // Returns true if rumble state request was honored. Calling this before first retro_run() is likely to return false. -typedef bool (*retro_set_rumble_state_t)(unsigned port, enum retro_rumble_effect effect, bool enable); +typedef bool (*retro_set_rumble_state_t)(unsigned port, enum retro_rumble_effect effect, uint16_t strength); struct retro_rumble_interface { retro_set_rumble_state_t set_rumble_state;