Skip to content

Commit b3a7360

Browse files
committed
Implement asynchronous key-up handling so playback speed isn't affected
1 parent 598f378 commit b3a7360

2 files changed

Lines changed: 62 additions & 16 deletions

File tree

AutoMidiPlayer.WPF/AutoMidiPlayer.WPF.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<UseWPF>true</UseWPF>
77
<StartupObject>AutoMidiPlayer.WPF.App</StartupObject>
88
<ApplicationManifest>app.manifest</ApplicationManifest>
9-
<Version>6.13.0</Version>
9+
<Version>6.13.1</Version>
1010
<ApplicationIcon>Resources\logo.ico</ApplicationIcon>
1111
<Nullable>enable</Nullable>
1212
<RepositoryUrl>https://github.com/Jed556/AutoMidiPlayer</RepositoryUrl>

AutoMidiPlayer.WPF/Core/KeyboardPlayer.cs

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Runtime.InteropServices;
55
using System.Threading;
6+
using System.Threading.Tasks;
67
using AutoMidiPlayer.Data.Entities;
78
using WindowsInput;
89
using WindowsInput.Native;
@@ -67,7 +68,8 @@ private struct KEYBDINPUT
6768
/// Delay (in milliseconds) inserted between key-down and key-up when performing
6869
/// <see cref="KeyAction.Press"/> in InputSimulator, direct input, and window-message paths.
6970
/// A non-zero value can improve compatibility with games that require a
70-
/// slightly longer held press. Default is 0.
71+
/// slightly longer held press. Delay is handled asynchronously so playback timing
72+
/// is not blocked. Default is 0.
7173
/// </summary>
7274
public static int DirectInputPressDelayMs { get; set; } = 0;
7375

@@ -196,12 +198,21 @@ private static void SendKeyStrokeSimulated(Keyboard.KeyStroke keyStroke, KeyActi
196198
foreach (var modifier in modifiers)
197199
Input.Keyboard.KeyDown(modifier);
198200
Input.Keyboard.KeyDown(keyStroke.Key);
199-
if (DirectInputPressDelayMs > 0)
200-
Thread.Sleep(DirectInputPressDelayMs);
201+
201202
if (EnableKeyUp)
202-
Input.Keyboard.KeyUp(keyStroke.Key);
203-
for (int i = modifiers.Length - 1; i >= 0; i--)
204-
Input.Keyboard.KeyUp(modifiers[i]);
203+
{
204+
ScheduleDelayedAction(() =>
205+
{
206+
Input.Keyboard.KeyUp(keyStroke.Key);
207+
for (int i = modifiers.Length - 1; i >= 0; i--)
208+
Input.Keyboard.KeyUp(modifiers[i]);
209+
});
210+
}
211+
else
212+
{
213+
for (int i = modifiers.Length - 1; i >= 0; i--)
214+
Input.Keyboard.KeyUp(modifiers[i]);
215+
}
205216
break;
206217
}
207218
}
@@ -228,13 +239,21 @@ private static void SendKeyStrokeDirect(Keyboard.KeyStroke keyStroke, KeyAction
228239
foreach (var modifier in modifiers)
229240
SendKeyDirect(modifier, false);
230241
SendKeyDirect(keyStroke.Key, false);
231-
// Add custom delay between key-down and key-up to improve compatibility with games
232-
if (DirectInputPressDelayMs > 0)
233-
Thread.Sleep(DirectInputPressDelayMs);
242+
234243
if (EnableKeyUp)
235-
SendKeyDirect(keyStroke.Key, true);
236-
for (int i = modifiers.Length - 1; i >= 0; i--)
237-
SendKeyDirect(modifiers[i], true);
244+
{
245+
ScheduleDelayedAction(() =>
246+
{
247+
SendKeyDirect(keyStroke.Key, true);
248+
for (int i = modifiers.Length - 1; i >= 0; i--)
249+
SendKeyDirect(modifiers[i], true);
250+
});
251+
}
252+
else
253+
{
254+
for (int i = modifiers.Length - 1; i >= 0; i--)
255+
SendKeyDirect(modifiers[i], true);
256+
}
238257
break;
239258
}
240259
}
@@ -293,11 +312,38 @@ private static void SendKeyStrokeWindow(Keyboard.KeyStroke keyStroke, IntPtr hWn
293312

294313
case KeyAction.Press:
295314
PostMessage(hWnd, WM_KEYDOWN, (IntPtr)vk, lParamDown);
296-
if (DirectInputPressDelayMs > 0)
297-
Thread.Sleep(DirectInputPressDelayMs);
298315
if (EnableKeyUp)
299-
PostMessage(hWnd, WM_KEYUP, (IntPtr)vk, lParamUp);
316+
{
317+
ScheduleDelayedAction(() =>
318+
{
319+
PostMessage(hWnd, WM_KEYUP, (IntPtr)vk, lParamUp);
320+
});
321+
}
300322
break;
301323
}
302324
}
325+
326+
private static void ScheduleDelayedAction(Action action)
327+
{
328+
var delayMs = Math.Max(0, DirectInputPressDelayMs);
329+
330+
if (delayMs == 0)
331+
{
332+
action();
333+
return;
334+
}
335+
336+
_ = Task.Run(async () =>
337+
{
338+
try
339+
{
340+
await Task.Delay(delayMs).ConfigureAwait(false);
341+
action();
342+
}
343+
catch
344+
{
345+
// Best-effort delayed key-up dispatch.
346+
}
347+
});
348+
}
303349
}

0 commit comments

Comments
 (0)