Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions src/BizHawk.Client.EmuHawk/Throttle.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

using BizHawk.Client.Common;
Expand Down Expand Up @@ -34,8 +35,8 @@ public void Step(Config config, Sound sound, bool allowSleep, int forceFrameSkip
skipNextFrame = false;
framesToSkip = 0;

//keep from burning CPU
Thread.Sleep(15);
//keep from burning CPU (but dispatch COM so screen-reader accessibility stays serviced)
ResponsiveSleep(15);
Comment thread
YoshiRulz marked this conversation as resolved.
return;
}

Expand Down Expand Up @@ -277,6 +278,34 @@ private int AutoFrameSkip_GetSkipAmount(int min, int max)
return rv;
}

[DllImport("ole32.dll")]
private static extern int CoWaitForMultipleHandles(uint dwFlags, uint dwTimeout, int cHandles, IntPtr[] pHandles, out uint lpdwindex);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateEventW(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, IntPtr lpName);

private const uint COWAIT_DISPATCH_CALLS = 0x8;
private static readonly IntPtr[] _responsiveSleepHandles = { CreateEventW(IntPtr.Zero, true, false, IntPtr.Zero) };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this will need OSTailoredCode.IsUnixHost ? [ default ] : to avoid crashing on startup.


/// <summary>
/// Sleeps ~<paramref name="ms"/> ms while still dispatching incoming COM calls. Screen readers'
/// UI Automation / MSAA queries are COM calls marshaled to this STA UI thread; a plain Thread.Sleep
/// does NOT service them, so during each frame's sleep the thread stops answering screen readers and
/// ALL of them (NVDA, Narrator, ...) go laggy while EmuHawk is foreground — even though the app stays
/// responsive to its own input. COWAIT_DISPATCH_CALLS dispatches only COM calls (not window
/// input/paint), keeping accessibility responsive without reentering the emulation loop.
/// </summary>
private static void ResponsiveSleep(int ms)
{
if (ms < 1) ms = 1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both callers already pass in >= 1, so this line can be removed.

if (OSTailoredCode.IsUnixHost)
{
Thread.Sleep(ms); // CoWaitForMultipleHandles is Windows-only
return;
}
_ = CoWaitForMultipleHandles(COWAIT_DISPATCH_CALLS, (uint)ms, 1, _responsiveSleepHandles, out _);
}

private void SpeedThrottle(Sound sound, bool paused)
{
AutoFrameSkip_BeforeThrottle();
Expand Down Expand Up @@ -326,7 +355,7 @@ private void SpeedThrottle(Sound sound, bool paused)
break;
}

Thread.Sleep(Math.Max(sleepTime, 1));
ResponsiveSleep(Math.Max(sleepTime, 1));
}
else if (sleepTime > 0) // spin for <1 millisecond waits
{
Expand Down
Loading