diff --git a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp index 955e50760..09dd3ddca 100644 --- a/core/linux-dist/evdev.cpp +++ b/core/linux-dist/evdev.cpp @@ -102,6 +102,7 @@ this->data_y.init(this->fd, this->mapping->Axis_Analog_Y, this->mapping->Axis_Analog_Y_Inverted); this->data_trigger_left.init(this->fd, this->mapping->Axis_Trigger_Left, this->mapping->Axis_Trigger_Left_Inverted); this->data_trigger_right.init(this->fd, this->mapping->Axis_Trigger_Right, this->mapping->Axis_Trigger_Right_Inverted); + this->rumble_effect_id = -1; } std::map loaded_mappings; @@ -202,7 +203,7 @@ printf("evdev: Trying to open device at '%s'\n", device); - int fd = open(device, O_RDONLY); + int fd = open(device, O_RDWR); if (fd >= 0) { @@ -446,5 +447,43 @@ } } } + + void input_evdev_rumble(EvdevController* controller, u16 pow_strong, u16 pow_weak) + { + if (controller->fd < 0 || controller->rumble_effect_id == -2) + { + // Either the controller is not used or previous rumble effect failed + printf("RUMBLE: %s\n", "Skipped!"); + return; + } + printf("RUMBLE: %u / %u (%d)\n", pow_strong, pow_weak, controller->rumble_effect_id); + struct ff_effect effect; + effect.type = FF_RUMBLE; + effect.id = controller->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(controller->fd, EVIOCSFF, &effect) == -1) + { + perror("evdev: Force feedback error"); + controller->rumble_effect_id = -2; + } + else + { + controller->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(controller->fd, (const void*) &play, sizeof(play)) == -1) + { + perror("evdev: Force feedback error"); + controller->rumble_effect_id = -2; + } + } + } #endif diff --git a/core/linux-dist/evdev.h b/core/linux-dist/evdev.h index ac18f5ac1..52ebad7d0 100644 --- a/core/linux-dist/evdev.h +++ b/core/linux-dist/evdev.h @@ -54,6 +54,7 @@ struct EvdevController EvdevAxisData data_y; EvdevAxisData data_trigger_left; EvdevAxisData data_trigger_right; + int rumble_effect_id; void init(); }; @@ -72,3 +73,4 @@ struct EvdevController extern int input_evdev_init(EvdevController* controller, const char* device, const char* mapping_fname); extern bool input_evdev_handle(EvdevController* controller, u32 port); +extern void input_evdev_rumble(EvdevController* controller, u16 pow_strong, u16 pow_weak); diff --git a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp index 1e8163019..e4a596b5b 100755 --- a/core/linux-dist/main.cpp +++ b/core/linux-dist/main.cpp @@ -193,7 +193,26 @@ void UpdateInputState(u32 port) void UpdateVibration(u32 port, u32 value) { - + #if defined(USE_EVDEV) + const u8 freq_l = 0x16; + //const u8 freq_h = 0x31; + + 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 / (double)freq_l); + + 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(&evdev_controllers[port], pow_strong, pow_weak); + #endif } void os_DoEvents()