Windows: Don't hang on exit when a HID pad stops sending reports

DualShock, DualSense and Switch Pro pads are read with a blocking
ReadFile on the input thread, and WM_DESTROY joins that thread. If the
pad stops sending reports the read never returns, so the window is gone
but the process stays. Cancel the thread's I/O until it stops, retrying
in case a cancel lands just before a read starts. This also covers the
synchronous writes the pads' shutdown does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-17 13:51:56 +02:00
1 parent bd3df9de3c
commit 2968debfe7
1 file changed
+15
+15
View File
@@ -83,8 +83,23 @@ void InputManager::BeginPolling() {
}
void InputManager::StopPolling() {
INFO_LOG(Log::System, "Stopping the input thread");
runThread_.store(false, std::memory_order_relaxed);
#if !PPSSPP_PLATFORM(UWP)
// The HID pads are read with a blocking ReadFile, which never returns if the pad stops sending
// reports, and then the join below waits forever with the window already gone. Cancel whatever
// I/O the thread is blocked in. Repeat it, since a cancel that lands just before a read starts
// does nothing.
HANDLE thread = (HANDLE)inputThread_.native_handle();
for (int tries = 0; WaitForSingleObject(thread, 100) == WAIT_TIMEOUT; tries++) {
if (tries == 0) {
WARN_LOG(Log::System, "Input thread didn't stop, cancelling its I/O");
}
CancelSynchronousIo(thread);
}
#endif
inputThread_.join();
INFO_LOG(Log::System, "Input thread stopped");
}
bool InputManager::AnyAccelerometer() const {