Skip to content

Commit fe058cd

Browse files
committed
add configuration file
add InputDelay
1 parent 74a77ed commit fe058cd

File tree

6 files changed

+90
-17
lines changed

6 files changed

+90
-17
lines changed

WinSyncScroll/Enums/OptionSections.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace WinSyncScroll.Enums;
2+
3+
public enum OptionSections
4+
{
5+
General,
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace WinSyncScroll.Models;
4+
5+
public class GeneralOptions
6+
{
7+
[Required]
8+
public required bool IsStrictProcessIdCheckEnabled { get; set; }
9+
10+
[Required]
11+
[Range(0, 500)]
12+
public required int InputDelay { get; set; }
13+
}

WinSyncScroll/Utils/ContainerConfigurationUtils.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
1-
using Microsoft.Extensions.DependencyInjection;
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Logging;
34
using NLog.Extensions.Logging;
5+
using WinSyncScroll.Enums;
6+
using WinSyncScroll.Models;
47
using WinSyncScroll.Services;
58
using WinSyncScroll.ViewModels;
69

710
namespace WinSyncScroll.Utils;
811

912
public static class ContainerConfigurationUtils
1013
{
11-
private static IServiceCollection ConfigureServices(this IServiceCollection services)
14+
private static IConfigurationRoot GetConfigurationRoot()
1215
{
16+
var configurationBuilder = new ConfigurationBuilder()
17+
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
18+
var configurationRoot = configurationBuilder.Build();
19+
return configurationRoot;
20+
}
21+
22+
private static IServiceCollection ConfigureServices(
23+
this IServiceCollection services,
24+
IConfigurationRoot configurationRoot)
25+
{
26+
services
27+
.AddOptions<GeneralOptions>()
28+
.Bind(configurationRoot.GetSection(nameof(OptionSections.General)))
29+
.ValidateDataAnnotations()
30+
.ValidateOnStart();
31+
1332
return services
1433
/* Logging */
1534
.AddSingleton<ILoggerFactory>(_ =>
@@ -30,8 +49,10 @@ private static IServiceCollection ConfigureServices(this IServiceCollection serv
3049

3150
public static IServiceProvider CreateServiceProvider()
3251
{
52+
var configurationRoot = GetConfigurationRoot();
53+
3354
return new ServiceCollection()
34-
.ConfigureServices()
55+
.ConfigureServices(configurationRoot)
3556
.BuildServiceProvider();
3657
}
3758
}

WinSyncScroll/ViewModels/MainViewModel.cs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Windows.Win32.UI.WindowsAndMessaging;
1111
using CommunityToolkit.Mvvm.Input;
1212
using Microsoft.Extensions.Logging;
13+
using Microsoft.Extensions.Options;
1314
using PropertyChanged.SourceGenerator;
1415
using WinSyncScroll.Enums;
1516
using WinSyncScroll.Extensions;
@@ -24,6 +25,7 @@ namespace WinSyncScroll.ViewModels;
2425
public sealed partial class MainViewModel : IDisposable
2526
{
2627
private readonly ILogger<MainViewModel> _logger;
28+
private readonly IOptions<GeneralOptions> _options;
2729
private readonly WinApiService _winApiService;
2830
private readonly MouseHook _mouseHook;
2931

@@ -79,12 +81,16 @@ public sealed partial class MainViewModel : IDisposable
7981
private int _smCxScreen;
8082
private int _smCyScreen;
8183

84+
private static readonly int SizeOfInput = Marshal.SizeOf(typeof(INPUT));
85+
8286
public MainViewModel(
8387
ILogger<MainViewModel> logger,
88+
IOptions<GeneralOptions> options,
8489
WinApiService winApiService,
8590
MouseHook mouseHook)
8691
{
8792
_logger = logger;
93+
_options = options;
8894
_winApiService = winApiService;
8995
_mouseHook = mouseHook;
9096

@@ -166,9 +172,16 @@ private static Point CalculateCenterOfWindow(WindowRect rect)
166172
rect.Top + ((rect.Bottom - rect.Top) / 2));
167173
}
168174

169-
// protection is disabled because MS Word reports a different process ID for the window
170-
[SuppressMessage("Performance", "CA1802:Use literals where appropriate", Justification = "This is an option")]
171-
private static readonly bool IsStrictProcessIdCheckEnabled = false;
175+
private void LogSendInput(INPUT[] inputs)
176+
{
177+
_logger.LogTrace("Sending input to target window: {NewLine}{Inputs}",
178+
Environment.NewLine,
179+
string.Join(
180+
Environment.NewLine,
181+
inputs.Select((item, index) =>
182+
$"{index.ToStringInvariant()}: {item.ToLogString()}"))
183+
);
184+
}
172185

173186
private async Task RunMouseEventProcessingLoopAsync(
174187
Channel<MouseMessageInfo> channel,
@@ -224,7 +237,7 @@ private async Task RunMouseEventProcessingLoopAsync(
224237
continue;
225238
}
226239

227-
if (IsStrictProcessIdCheckEnabled)
240+
if (_options.Value.IsStrictProcessIdCheckEnabled)
228241
{
229242
var actualSourceWindowHwnd = PInvoke.WindowFromPoint(new Point(sourceEventX, sourceEventY));
230243
var (_, actualSourceProcessId, _) = PInvoke.GetWindowThreadProcessId(actualSourceWindowHwnd);
@@ -250,7 +263,7 @@ private async Task RunMouseEventProcessingLoopAsync(
250263
targetY = centerOfTarget.Y;
251264
}
252265

253-
if (IsStrictProcessIdCheckEnabled)
266+
if (_options.Value.IsStrictProcessIdCheckEnabled)
254267
{
255268
var actualTargetWindowHwnd = PInvoke.WindowFromPoint(new Point(targetX, targetY));
256269
var (_, actualTargetWindowProcessId, _) = PInvoke.GetWindowThreadProcessId(actualTargetWindowHwnd);
@@ -285,18 +298,23 @@ private async Task RunMouseEventProcessingLoopAsync(
285298
var inputMoveToSource = CreateMoveInput(sourceAbsoluteX, sourceAbsoluteY);
286299

287300
var inputs = new[] { inputMoveToTarget, inputScrollTarget, inputMoveToSource };
288-
var sizeOfInput = Marshal.SizeOf(typeof(INPUT));
289301

290302
_mouseHook.SetPreventRealScrollEvents();
291303

292-
_logger.LogTrace("Sending input to target window: {NewLine}{Inputs}",
293-
Environment.NewLine,
294-
string.Join(
295-
Environment.NewLine,
296-
inputs.Select((item, index) =>
297-
$"{index.ToStringInvariant()}: {item.ToLogString()}"))
298-
);
299-
PInvoke.SendInput(inputs.AsSpan(), sizeOfInput);
304+
LogSendInput(inputs);
305+
306+
if (_options.Value.InputDelay == 0)
307+
{
308+
PInvoke.SendInput(inputs.AsSpan(), SizeOfInput);
309+
}
310+
else
311+
{
312+
PInvoke.SendInput(inputs.AsSpan().Slice(0, 1), SizeOfInput);
313+
await Task.Delay(_options.Value.InputDelay, cancellationToken);
314+
PInvoke.SendInput(inputs.AsSpan().Slice(1, 1), SizeOfInput);
315+
await Task.Delay(_options.Value.InputDelay, cancellationToken);
316+
PInvoke.SendInput(inputs.AsSpan().Slice(2, 1), SizeOfInput);
317+
}
300318
}
301319
catch (Exception e)
302320
{

WinSyncScroll/WinSyncScroll.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,13 @@
4444
<PrivateAssets>all</PrivateAssets>
4545
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4646
</PackageReference>
47+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
48+
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
49+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
4750
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
4851
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
52+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
53+
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="8.0.0" />
4954
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
5055
<PrivateAssets>all</PrivateAssets>
5156
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -95,6 +100,10 @@
95100
<Resource Include="Resources\Icon\app_icon.ico" />
96101
<None Remove="Resources\Icon\app_icon_64.png" />
97102
<Resource Include="Resources\Icon\app_icon_64.png" />
103+
<None Remove="appsettings.json" />
104+
<Content Include="appsettings.json">
105+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
106+
</Content>
98107
</ItemGroup>
99108

100109
</Project>

WinSyncScroll/appsettings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"General": {
3+
"IsStrictProcessIdCheckEnabled": false,
4+
"InputDelay": 0
5+
}
6+
}

0 commit comments

Comments
 (0)