@@ -210,7 +210,13 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
210210{
211211 auto device = (PWINUHID_XONE_GAMEPAD)lpParameter;
212212
213- Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> timer{ CreateWaitableTimerW (NULL , TRUE , NULL ) };
213+ //
214+ // Use a high resolution timer to ensure maximum effect timing accuracy. This timer
215+ // will only be set while a FF effect is playing on the device, so it won't impact
216+ // system power usage in any meaningful way.
217+ //
218+ Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> timer{
219+ CreateWaitableTimerExW (NULL , NULL , CREATE_WAITABLE_TIMER_MANUAL_RESET | CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, NULL ) };
214220 if (!timer.IsValid ()) {
215221 return GetLastError ();
216222 }
@@ -258,14 +264,16 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
258264 //
259265 // Wait for the delay period before initiating the FF effect
260266 //
261- dueTime.QuadPart = XONE_TIME_TO_FILETIME (outputReport.u .Delay );
262- SetWaitableTimer (timer.Get (), &dueTime, 0 , NULL , NULL , FALSE );
263- result = WaitForMultipleObjects (ARRAYSIZE (objects), objects, FALSE , INFINITE);
264- if (result == WAIT_OBJECT_0 || device->Stopping ) {
265- //
266- // We got a new output report, so break and start over
267- //
268- break ;
267+ if (outputReport.u .Delay != 0 ) {
268+ dueTime.QuadPart = XONE_TIME_TO_FILETIME (outputReport.u .Delay );
269+ SetWaitableTimer (timer.Get (), &dueTime, 0 , NULL , NULL , FALSE );
270+ result = WaitForMultipleObjects (ARRAYSIZE (objects), objects, FALSE , INFINITE);
271+ if (result == WAIT_OBJECT_0 || device->Stopping ) {
272+ //
273+ // We got a new output report, so break and start over
274+ //
275+ break ;
276+ }
269277 }
270278
271279 //
@@ -277,6 +285,15 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
277285 // Wait for the duration period before stopping the FF effect
278286 //
279287 dueTime.QuadPart = XONE_TIME_TO_FILETIME (outputReport.u .Duration );
288+ if (outputReport.u .Delay == 0 && outputReport.u .Repeat != 0 ) {
289+ //
290+ // We specially handle the common case of repeats with no delay specified.
291+ // We can optimize the series of short waits and motor on/off cycles by
292+ // consolidating all the repeats into the initial wait.
293+ //
294+ dueTime.QuadPart += dueTime.QuadPart * outputReport.u .Repeat ;
295+ outputReport.u .Repeat = 0 ;
296+ }
280297 SetWaitableTimer (timer.Get (), &dueTime, 0 , NULL , NULL , FALSE );
281298 result = WaitForMultipleObjects (ARRAYSIZE (objects), objects, FALSE , INFINITE);
282299 if (result == WAIT_OBJECT_0 || device->Stopping ) {
0 commit comments