rumble support for xinput and evdev

This commit is contained in:
Flyinghead 2019-02-22 19:23:03 +01:00
parent 91e7c45a5c
commit a39503dd56
15 changed files with 133 additions and 104 deletions

View File

@ -22,7 +22,7 @@ Plugins:
ImageUpdate(data);
*/
void UpdateInputState(u32 port);
void UpdateVibration(u32 port, u32 value);
void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms);
extern u16 kcode[4];
extern u32 vks[4];
@ -46,10 +46,10 @@ struct MapleConfigMap : IMapleConfigMap
this->player_num = player_num;
}
void SetVibration(u32 value)
void SetVibration(float power, float inclination, u32 duration_ms)
{
int player_num = this->player_num == -1 ? dev->bus_id : this->player_num;
UpdateVibration(player_num, value);
UpdateVibration(player_num, power, inclination, duration_ms);
}
void GetInput(PlainJoystickState* pjs)

View File

@ -52,7 +52,7 @@ struct PlainJoystickState
struct IMapleConfigMap
{
virtual void SetVibration(u32 value) = 0;
virtual void SetVibration(float power, float inclination, u32 duration_ms) = 0;
virtual void GetInput(PlainJoystickState* pjs)=0;
virtual void SetImage(void* img)=0;
virtual ~IMapleConfigMap() {}

View File

@ -957,7 +957,7 @@ struct maple_microphone: maple_base
struct maple_sega_purupuru : maple_base
{
u16 AST, AST_ms;
u16 AST = 19, AST_ms = 5000;
u32 VIBSET;
virtual MapleDeviceType get_device_type()
@ -1053,8 +1053,32 @@ struct maple_sega_purupuru : maple_base
case MDCF_SetCondition:
VIBSET = *(u32*)&dma_buffer_in[4];
//Do the rumble thing!
config->SetVibration(VIBSET);
{
//Do the rumble thing!
u8 POW_POS = (VIBSET >> 8) & 0x7;
u8 POW_NEG = (VIBSET >> 12) & 0x7;
u8 FREQ = (VIBSET >> 16) & 0xFF;
s16 INC = (VIBSET >> 24) & 0xFF;
if (VIBSET & 0x8000) // INH
INC = -INC;
else if (!(VIBSET & 0x0800)) // EXH
INC = 0;
bool CNT = VIBSET & 1;
float power = min((POW_POS + POW_NEG) / 7.0, 1.0);
u32 duration_ms;
if (FREQ > 0 && (!CNT || INC))
duration_ms = min((int)(1000 * (INC ? abs(INC) * max(POW_POS, POW_NEG) : 1) / FREQ), (int)AST_ms);
else
duration_ms = AST_ms;
float inclination;
if (INC == 0 || power == 0)
inclination = 0.0;
else
inclination = FREQ / (1000.0 * INC * max(POW_POS, POW_NEG));
config->SetVibration(power, inclination, duration_ms);
}
return MDRS_DeviceReply;

View File

@ -207,3 +207,14 @@ void GamepadDevice::save_mapping()
return;
input_mapper->save(make_mapping_filename().c_str());
}
void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms)
{
int i = GamepadDevice::GetGamepadCount() - 1;
for ( ; i >= 0; i--)
{
std::shared_ptr<GamepadDevice> gamepad = GamepadDevice::GetGamepad(i);
if (gamepad != NULL && gamepad->maple_port() == port && gamepad->is_rumble_enabled())
gamepad->rumble(power, inclination, duration_ms);
}
}

View File

@ -53,6 +53,10 @@ public:
void save_mapping();
bool remappable() { return _remappable && input_mapper != NULL; }
virtual void rumble(float power, float inclination, u32 duration_ms) {}
virtual void update_rumble() {}
bool is_rumble_enabled() { return _rumble_enabled; }
static void Register(std::shared_ptr<GamepadDevice> gamepad)
{
_gamepads_mutex.lock();
@ -101,6 +105,8 @@ private:
input_detected_cb _input_detected;
bool _remappable;
bool _rumble_enabled = true;
static std::vector<std::shared_ptr<GamepadDevice>> _gamepads;
static std::mutex _gamepads_mutex;
};

View File

@ -211,13 +211,5 @@ bool input_evdev_handle(u32 port)
return true;
}
void input_evdev_rumble(u32 port, u16 pow_strong, u16 pow_weak)
{
std::shared_ptr<EvdevGamepadDevice> dev = EvdevGamepadDevice::GetControllerForPort(port);
if (dev != NULL)
dev->Rumble(pow_strong, pow_weak);
}
#endif // USE_EVDEV

View File

@ -4,4 +4,3 @@
extern void input_evdev_init();
extern void input_evdev_close();
extern bool input_evdev_handle(u32 port);
extern void input_evdev_rumble(u32 port, u16 pow_strong, u16 pow_weak);

View File

@ -1,4 +1,5 @@
#include "../input/gamepad_device.h"
#include "oslib/oslib.h"
#include "evdev.h"
class EvdevGamepadDevice : public GamepadDevice
@ -60,36 +61,22 @@ public:
close(_fd);
}
// FIXME add to base class
void Rumble(u16 pow_strong, u16 pow_weak)
virtual void rumble(float power, float inclination, u32 duration_ms) override
{
printf("RUMBLE: %u / %u (%d)\n", pow_strong, pow_weak, _rumble_effect_id);
struct ff_effect effect;
effect.type = FF_RUMBLE;
effect.id = _rumble_effect_id;
effect.u.rumble.strong_magnitude = pow_strong;
effect.u.rumble.weak_magnitude = pow_weak;
effect.replay.length = 0;
effect.replay.delay = 0;
if (ioctl(_fd, EVIOCSFF, &effect) == -1)
{
perror("evdev: Force feedback error");
_rumble_effect_id = -2;
}
else
{
_rumble_effect_id = effect.id;
vib_inclination = inclination * power;
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
// Let's play the effect
input_event play;
play.type = EV_FF;
play.code = effect.id;
play.value = 1;
if (write(_fd, (const void*) &play, sizeof(play)) == -1)
{
perror("evdev: Force feedback error");
_rumble_effect_id = -2;
}
do_rumble(power, duration_ms);
}
virtual void update_rumble() override
{
if (vib_inclination > 0)
{
int rem_time = (vib_stop_time - os_GetSeconds()) * 1000;
if (rem_time <= 0)
vib_inclination = 0;
else
do_rumble(vib_inclination * rem_time, rem_time);
}
}
@ -151,6 +138,7 @@ protected:
private:
void read_input()
{
update_rumble();
input_event ie;
while (read(_fd, &ie, sizeof(ie)) == sizeof(ie))
@ -168,10 +156,47 @@ private:
}
}
void do_rumble(float power, u32 duration_ms)
{
// Remove previous effect
if (_rumble_effect_id != -1)
ioctl(_fd, EVIOCRMFF, _rumble_effect_id);
// Upload new effect
struct ff_effect effect;
effect.type = FF_RUMBLE;
effect.id = -1; // Let the driver assign one
effect.direction = 0;
effect.replay.length = (u16)duration_ms;
effect.replay.delay = 0;
effect.u.rumble.strong_magnitude = (s16)(power * 32767);
effect.u.rumble.weak_magnitude = (s16)(power * 32767);
if (ioctl(_fd, EVIOCSFF, &effect) == -1)
{
perror("evdev: Force feedback error");
_rumble_effect_id = -1;
}
else
{
_rumble_effect_id = effect.id;
// Let's play the effect
input_event play;
play.type = EV_FF;
play.code = effect.id;
play.value = 1;
if (write(_fd, (const void*) &play, sizeof(play)) == -1)
{
perror("evdev: Force feedback error");
}
}
}
int _fd;
std::string _devnode;
int _rumble_effect_id;
int _rumble_effect_id = -1;
float vib_inclination = 0;
double vib_stop_time = 0;
static std::map<std::string, std::shared_ptr<EvdevGamepadDevice>> evdev_gamepads;
};

View File

@ -147,27 +147,6 @@ void UpdateInputState(u32 port)
#endif
}
void UpdateVibration(u32 port, u32 value)
{
#if defined(USE_EVDEV)
u8 POW_POS = (value >> 8) & 0x3;
u8 POW_NEG = (value >> 12) & 0x3;
u8 FREQ = (value >> 16) & 0xFF;
double pow = (POW_POS + POW_NEG) / 7.0;
double pow_l = pow * (0x3B - FREQ) / 17.0;
double pow_r = pow * (FREQ - 0x07) / 15.0;
if (pow_l > 1.0) pow_l = 1.0;
if (pow_r > 1.0) pow_r = 1.0;
u16 pow_strong = (u16)(65535 * pow_l);
u16 pow_weak = (u16)(65535 * pow_r);
input_evdev_rumble(port, pow_strong, pow_weak);
#endif
}
void os_DoEvents()
{
#if defined(SUPPORT_X11)

View File

@ -263,10 +263,6 @@ void UpdateInputState(u32 port) {
}
void UpdateVibration(u32 port, u32 value) {
}
void os_CreateWindow() {
}

View File

@ -236,27 +236,6 @@ void UpdateInputState(u32 port)
#endif
}
void UpdateVibration(u32 port, u32 value)
{
u8 POW_POS = (value >> 8) & 0x3;
u8 POW_NEG = (value >> 12) & 0x3;
u8 FREQ = (value >> 16) & 0xFF;
XINPUT_VIBRATION vib;
double pow = (POW_POS + POW_NEG) / 7.0;
double pow_l = pow * (0x3B - FREQ) / 17.0;
double pow_r = pow * (FREQ - 0x07) / 15.0;
if (pow_l > 1.0) pow_l = 1.0;
if (pow_r > 1.0) pow_r = 1.0;
vib.wLeftMotorSpeed = (u16)(65535 * pow_l);
vib.wRightMotorSpeed = (u16)(65535 * pow_r);
XInputSetState(port, &vib);
}
// Windows class name to register
#define WINDOW_CLASS "nilDC"

View File

@ -40,6 +40,8 @@ public:
void ReadInput()
{
update_rumble();
XINPUT_STATE state;
if (XInputGetState(_xinput_port, &state) == 0)
@ -99,6 +101,23 @@ public:
last_right_thumb_y = 0;
}
}
virtual void rumble(float power, float inclination, u32 duration_ms) override
{
vib_inclination = inclination * power;
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
do_rumble(power);
}
virtual void update_rumble() override
{
if (vib_inclination > 0)
{
int rem_time = (vib_stop_time - os_GetSeconds()) * 1000;
if (rem_time <= 0)
vib_inclination = 0;
do_rumble(vib_inclination * rem_time);
}
}
void Open()
{
@ -153,6 +172,16 @@ protected:
}
private:
void do_rumble(float power)
{
XINPUT_VIBRATION vib;
vib.wLeftMotorSpeed = (u16)(65535 * power);
vib.wRightMotorSpeed = (u16)(65535 * power);
XInputSetState(_xinput_port, &vib);
}
const int _xinput_port;
u32 last_buttons_state = 0;
@ -162,6 +191,8 @@ private:
s16 last_left_thumb_y = 0;
s16 last_right_thumb_x = 0;
s16 last_right_thumb_y = 0;
double vib_stop_time;
float vib_inclination;
static std::vector<std::shared_ptr<XInputGamepadDevice>> xinput_gamepads;
};

View File

@ -175,11 +175,6 @@ void UpdateInputState(u32 Port)
// @@@ Nothing here yet
}
void UpdateVibration(u32 port, u32 value)
{
}
void *libPvr_GetRenderTarget()
{
return g_window; // the surface to render to

View File

@ -113,10 +113,6 @@ void UpdateInputState(u32 port) {
}
void UpdateVibration(u32 port, u32 value) {
}
void get_mic_data(u8* ) {
}

View File

@ -68,10 +68,6 @@ void UpdateInputState(u32 port) {
}
void UpdateVibration(u32 port, u32 value) {
}
void os_CreateWindow() {
}