mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Add force feedback.
This commit is contained in:
parent
b916c5ace1
commit
89fff9d790
@ -26,7 +26,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/joystick.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
// Udev/evdev Linux joypad driver.
|
||||
// More complex and extremely low level,
|
||||
@ -54,6 +54,10 @@ struct udev_joypad
|
||||
uint8_t axes_bind[ABS_MAX];
|
||||
struct input_absinfo absinfo[NUM_AXES];
|
||||
|
||||
int num_effects;
|
||||
int effects[2]; // [0] - strong, [1] - weak
|
||||
bool support_ff[2];
|
||||
|
||||
char *ident;
|
||||
char *path;
|
||||
};
|
||||
@ -173,6 +177,27 @@ end:
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
|
||||
static void udev_set_rumble(unsigned i, unsigned effect, bool state)
|
||||
{
|
||||
struct udev_joypad *pad = &g_pads[i];
|
||||
|
||||
if (pad->fd < 0)
|
||||
return;
|
||||
if (!pad->support_ff[effect])
|
||||
return;
|
||||
|
||||
struct input_event play;
|
||||
memset(&play, 0, sizeof(play));
|
||||
play.type = EV_FF;
|
||||
play.code = pad->effects[effect];
|
||||
play.value = state;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void udev_joypad_poll(void)
|
||||
{
|
||||
while (hotplug_available())
|
||||
@ -180,6 +205,19 @@ static void udev_joypad_poll(void)
|
||||
|
||||
for (unsigned i = 0; i < MAX_PLAYERS; i++)
|
||||
poll_pad(i);
|
||||
|
||||
#if 0 // Debug rumble.
|
||||
static bool old_0;
|
||||
static bool old_1;
|
||||
bool new_0 = g_pads[0].buttons[0];
|
||||
bool new_1 = g_pads[0].buttons[1];
|
||||
if (new_0 != old_0)
|
||||
udev_set_rumble(0, 0, new_0);
|
||||
if (new_1 != old_1)
|
||||
udev_set_rumble(0, 1, new_1);
|
||||
old_0 = new_0;
|
||||
old_1 = new_1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
@ -188,7 +226,7 @@ static void udev_joypad_poll(void)
|
||||
|
||||
static int open_joystick(const char *path)
|
||||
{
|
||||
int fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
int fd = open(path, O_RDWR | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
@ -223,7 +261,12 @@ static int find_vacant_pad(void)
|
||||
static void free_pad(unsigned pad)
|
||||
{
|
||||
if (g_pads[pad].fd >= 0)
|
||||
{
|
||||
udev_set_rumble(pad, 0, false);
|
||||
udev_set_rumble(pad, 1, false);
|
||||
close(g_pads[pad].fd);
|
||||
}
|
||||
|
||||
free(g_pads[pad].path);
|
||||
memset(&g_pads[pad], 0, sizeof(g_pads[pad]));
|
||||
g_pads[pad].fd = -1;
|
||||
@ -288,6 +331,55 @@ static bool add_pad(unsigned i, int fd, const char *path)
|
||||
if (*pad->ident)
|
||||
input_config_autoconfigure_joypad(i, pad->ident, "udev");
|
||||
|
||||
// Check for rumble features.
|
||||
unsigned long ffbit[NBITS(FF_MAX)] = {0};
|
||||
if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0)
|
||||
{
|
||||
if (test_bit(FF_RUMBLE, ffbit))
|
||||
RARCH_LOG("[udev]: Pad #%u (%s) supports force feedback.\n",
|
||||
i, path);
|
||||
|
||||
if (ioctl(fd, EVIOCGEFFECTS, &pad->num_effects) >= 0)
|
||||
RARCH_LOG("[udev]: Pad #%u (%s) supports %d force feedback effects.\n", i, path, pad->num_effects);
|
||||
|
||||
if (pad->num_effects >= 2)
|
||||
{
|
||||
struct ff_effect effect;
|
||||
|
||||
// Strong rumble.
|
||||
memset(&effect, 0, sizeof(effect));
|
||||
effect.type = FF_RUMBLE;
|
||||
effect.id = -1;
|
||||
effect.u.rumble.strong_magnitude = 0x8000;
|
||||
effect.u.rumble.weak_magnitude = 0;
|
||||
effect.replay.length = 20000;
|
||||
effect.replay.delay = 0;
|
||||
pad->support_ff[0] = ioctl(fd, EVIOCSFF, &effect) == 0;
|
||||
if (pad->support_ff[0])
|
||||
{
|
||||
RARCH_LOG("[udev]: Pad #%u (%s) supports \"strong\" rumble effect (id %d).\n",
|
||||
i, path, effect.id);
|
||||
pad->effects[0] = effect.id; // Gets updated by ioctl().
|
||||
}
|
||||
|
||||
// Weak rumble.
|
||||
memset(&effect, 0, sizeof(effect));
|
||||
effect.type = FF_RUMBLE;
|
||||
effect.id = -1;
|
||||
effect.u.rumble.strong_magnitude = 0;
|
||||
effect.u.rumble.weak_magnitude = 0xc000;
|
||||
effect.replay.length = 20000;
|
||||
effect.replay.delay = 0;
|
||||
pad->support_ff[1] = ioctl(fd, EVIOCSFF, &effect) == 0;
|
||||
if (pad->support_ff[1])
|
||||
{
|
||||
RARCH_LOG("[udev]: Pad #%u (%s) supports \"weak\" rumble effect (id %d).\n",
|
||||
i, path, effect.id);
|
||||
pad->effects[1] = effect.id; // Gets updated by ioctl().
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user