Improvements to XInput vibration:

- use std::chrono to measure 20ms between XInputSetState calls, because clock() measures cpu time and not real time (so calls were made more often than intended)
- fixup data types for cached vibration values to prevent u8 values overflowing and giving false positives on m_dev->newVibrateData
This commit is contained in:
Silent 2019-07-14 17:47:06 +02:00 committed by Megamouse
parent b3aff3a1c6
commit 87ffa04a2b
2 changed files with 13 additions and 13 deletions

View file

@ -415,28 +415,28 @@ void xinput_pad_handler::ThreadProc()
// The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor.
// The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535.
int idx_l = profile->switch_vibration_motors ? 1 : 0;
int idx_s = profile->switch_vibration_motors ? 0 : 1;
size_t idx_l = profile->switch_vibration_motors ? 1 : 0;
size_t idx_s = profile->switch_vibration_motors ? 0 : 1;
int speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min;
int speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min;
u16 speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value : static_cast<u16>(vibration_min);
u16 speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value : static_cast<u16>(vibration_min);
m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small;
m_dev->newVibrateData |= m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small;
m_dev->largeVibrate = speed_large;
m_dev->smallVibrate = speed_small;
// XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable.
if (m_dev->newVibrateData && (clock() - m_dev->last_vibration > 20))
if (m_dev->newVibrateData && (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_dev->last_vibration) > 20ms))
{
XINPUT_VIBRATION vibrate;
vibrate.wLeftMotorSpeed = speed_large;
vibrate.wRightMotorSpeed = speed_small;
vibrate.wLeftMotorSpeed = speed_large * 257;
vibrate.wRightMotorSpeed = speed_small * 257;
if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS)
{
m_dev->newVibrateData = false;
m_dev->last_vibration = clock();
m_dev->last_vibration = std::chrono::high_resolution_clock::now();
}
}
break;

View file

@ -5,7 +5,7 @@
#define NOMINMAX
#include <Windows.h>
#include <Xinput.h>
#include <ctime>
#include <chrono>
namespace XINPUT_INFO
{
@ -91,9 +91,9 @@ class xinput_pad_handler final : public PadHandlerBase
{
u32 deviceNumber{ 0 };
bool newVibrateData{ true };
u8 largeVibrate{ 0 };
u8 smallVibrate{ 0 };
clock_t last_vibration{ 0 };
u16 largeVibrate{ 0 };
u16 smallVibrate{ 0 };
std::chrono::high_resolution_clock::time_point last_vibration;
pad_config* config{ nullptr };
};