Skip to content

Commit 611da42

Browse files
authored
Merge pull request #354 from switchifyapp/feat/scroll-repeat-interval-353
Separate scroll repeat interval
2 parents 883f800 + 89c3f83 commit 611da42

21 files changed

Lines changed: 631 additions & 69 deletions

src/SwitchifyPc.App/SettingsWindow.xaml

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -457,39 +457,81 @@
457457
<ColumnDefinition Width="Auto" />
458458
</Grid.ColumnDefinitions>
459459
<StackPanel>
460-
<TextBlock Text="Repeat interval" Style="{StaticResource DetailLabel}" />
460+
<TextBlock Text="Movement repeat interval" Style="{StaticResource DetailLabel}" />
461461
<TextBlock Margin="0,4,0,0"
462-
Text="Time between repeated mouse actions."
462+
Text="Time between repeated pointer movements."
463463
Style="{StaticResource MutedText}" />
464464
</StackPanel>
465465
<TextBlock Grid.Column="1"
466466
Margin="16,0,0,0"
467467
VerticalAlignment="Top"
468-
Text="{Binding MouseRepeatInterval}"
468+
Text="{Binding MouseRepeatMoveInterval}"
469469
Style="{StaticResource DetailValue}" />
470470
</Grid>
471471

472472
<UniformGrid Margin="0,14,0,0" Columns="4"
473473
IsEnabled="{Binding MouseRepeatEnabled}">
474474
<RadioButton Content="0.1 s"
475-
GroupName="MouseRepeatInterval"
476-
IsChecked="{Binding IsMouseRepeatInterval100, Mode=OneWay}"
477-
Checked="MouseRepeatInterval100_Checked"
475+
GroupName="MouseRepeatMoveInterval"
476+
IsChecked="{Binding IsMouseRepeatMoveInterval100, Mode=OneWay}"
477+
Checked="MouseRepeatMoveInterval100_Checked"
478478
Style="{StaticResource SegmentRadio}" />
479479
<RadioButton Content="0.25 s"
480-
GroupName="MouseRepeatInterval"
481-
IsChecked="{Binding IsMouseRepeatInterval250, Mode=OneWay}"
482-
Checked="MouseRepeatInterval250_Checked"
480+
GroupName="MouseRepeatMoveInterval"
481+
IsChecked="{Binding IsMouseRepeatMoveInterval250, Mode=OneWay}"
482+
Checked="MouseRepeatMoveInterval250_Checked"
483483
Style="{StaticResource SegmentRadio}" />
484484
<RadioButton Content="0.5 s"
485-
GroupName="MouseRepeatInterval"
486-
IsChecked="{Binding IsMouseRepeatInterval500, Mode=OneWay}"
487-
Checked="MouseRepeatInterval500_Checked"
485+
GroupName="MouseRepeatMoveInterval"
486+
IsChecked="{Binding IsMouseRepeatMoveInterval500, Mode=OneWay}"
487+
Checked="MouseRepeatMoveInterval500_Checked"
488488
Style="{StaticResource SegmentRadio}" />
489489
<RadioButton Content="1 s"
490-
GroupName="MouseRepeatInterval"
491-
IsChecked="{Binding IsMouseRepeatInterval1000, Mode=OneWay}"
492-
Checked="MouseRepeatInterval1000_Checked"
490+
GroupName="MouseRepeatMoveInterval"
491+
IsChecked="{Binding IsMouseRepeatMoveInterval1000, Mode=OneWay}"
492+
Checked="MouseRepeatMoveInterval1000_Checked"
493+
Style="{StaticResource SegmentRadio}" />
494+
</UniformGrid>
495+
496+
<Grid Margin="0,14,0,0">
497+
<Grid.ColumnDefinitions>
498+
<ColumnDefinition Width="*" />
499+
<ColumnDefinition Width="Auto" />
500+
</Grid.ColumnDefinitions>
501+
<StackPanel>
502+
<TextBlock Text="Scroll repeat interval" Style="{StaticResource DetailLabel}" />
503+
<TextBlock Margin="0,4,0,0"
504+
Text="Time between repeated scroll actions."
505+
Style="{StaticResource MutedText}" />
506+
</StackPanel>
507+
<TextBlock Grid.Column="1"
508+
Margin="16,0,0,0"
509+
VerticalAlignment="Top"
510+
Text="{Binding MouseRepeatScrollInterval}"
511+
Style="{StaticResource DetailValue}" />
512+
</Grid>
513+
514+
<UniformGrid Margin="0,14,0,0" Columns="4"
515+
IsEnabled="{Binding MouseRepeatEnabled}">
516+
<RadioButton Content="0.1 s"
517+
GroupName="MouseRepeatScrollInterval"
518+
IsChecked="{Binding IsMouseRepeatScrollInterval100, Mode=OneWay}"
519+
Checked="MouseRepeatScrollInterval100_Checked"
520+
Style="{StaticResource SegmentRadio}" />
521+
<RadioButton Content="0.25 s"
522+
GroupName="MouseRepeatScrollInterval"
523+
IsChecked="{Binding IsMouseRepeatScrollInterval250, Mode=OneWay}"
524+
Checked="MouseRepeatScrollInterval250_Checked"
525+
Style="{StaticResource SegmentRadio}" />
526+
<RadioButton Content="0.5 s"
527+
GroupName="MouseRepeatScrollInterval"
528+
IsChecked="{Binding IsMouseRepeatScrollInterval500, Mode=OneWay}"
529+
Checked="MouseRepeatScrollInterval500_Checked"
530+
Style="{StaticResource SegmentRadio}" />
531+
<RadioButton Content="1 s"
532+
GroupName="MouseRepeatScrollInterval"
533+
IsChecked="{Binding IsMouseRepeatScrollInterval1000, Mode=OneWay}"
534+
Checked="MouseRepeatScrollInterval1000_Checked"
493535
Style="{StaticResource SegmentRadio}" />
494536
</UniformGrid>
495537
</StackPanel>

src/SwitchifyPc.App/SettingsWindow.xaml.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,21 @@ private void MouseRepeatEnabled_Click(object sender, RoutedEventArgs e)
7171
}
7272
}
7373

74-
private void MouseRepeatInterval100_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatIntervalMs(100));
74+
private void MouseRepeatMoveInterval100_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatMoveIntervalMs(100));
7575

76-
private void MouseRepeatInterval250_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatIntervalMs(250));
76+
private void MouseRepeatMoveInterval250_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatMoveIntervalMs(250));
7777

78-
private void MouseRepeatInterval500_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatIntervalMs(500));
78+
private void MouseRepeatMoveInterval500_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatMoveIntervalMs(500));
7979

80-
private void MouseRepeatInterval1000_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatIntervalMs(1000));
80+
private void MouseRepeatMoveInterval1000_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatMoveIntervalMs(1000));
81+
82+
private void MouseRepeatScrollInterval100_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatScrollIntervalMs(100));
83+
84+
private void MouseRepeatScrollInterval250_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatScrollIntervalMs(250));
85+
86+
private void MouseRepeatScrollInterval500_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatScrollIntervalMs(500));
87+
88+
private void MouseRepeatScrollInterval1000_Checked(object sender, RoutedEventArgs e) => SaveIfReady(() => controller!.SetMouseRepeatScrollIntervalMs(1000));
8189

8290
private void SectionNav_Checked(object sender, RoutedEventArgs e)
8391
{

src/SwitchifyPc.Core/Control/ControlSession.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ private static JsonObject PointerProfileResponse(string id, PointerMovementProfi
260260
["supported"] = profile.Capabilities.MouseRepeat.Supported,
261261
["enabled"] = profile.Capabilities.MouseRepeat.Enabled,
262262
["intervalMs"] = profile.Capabilities.MouseRepeat.IntervalMs,
263+
["moveIntervalMs"] = profile.Capabilities.MouseRepeat.MoveIntervalMs,
264+
["scrollIntervalMs"] = profile.Capabilities.MouseRepeat.ScrollIntervalMs,
263265
["minIntervalMs"] = profile.Capabilities.MouseRepeat.MinIntervalMs,
264266
["maxIntervalMs"] = profile.Capabilities.MouseRepeat.MaxIntervalMs
265267
}

src/SwitchifyPc.Core/Input/MouseRepeatController.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private async Task RunAsync(string deviceId, ActiveRepeat repeat)
101101
return;
102102
}
103103

104-
await delay(settings.IntervalMs, repeat.Cancellation).ConfigureAwait(false);
104+
await delay(IntervalFor(settings, repeat.Command.RootElement), repeat.Cancellation).ConfigureAwait(false);
105105
if (repeat.Cancellation.IsCancellationRequested) return;
106106

107107
settings = settingsStore.Load();
@@ -148,6 +148,13 @@ private Task StopIfCurrentAsync(string deviceId, ActiveRepeat repeat)
148148
return Task.CompletedTask;
149149
}
150150

151+
private static int IntervalFor(MouseRepeatSettings settings, JsonElement command)
152+
{
153+
return command.GetProperty("type").GetString() == "mouse.scroll"
154+
? settings.ScrollIntervalMs
155+
: settings.MoveIntervalMs;
156+
}
157+
151158
private sealed class ActiveRepeat
152159
{
153160
private readonly CancellationTokenSource cancellation = new();

src/SwitchifyPc.Core/Input/PointerProfile.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ public sealed record Bounds(double X, double Y, double Width, double Height);
88
public sealed record DisplayInfo(Bounds Bounds, double ScaleFactor);
99
public sealed record PointerProfileInput(Point Cursor, DisplayInfo Display, int? MaxDelta = null);
1010
public sealed record RecommendedDeltas(int Small, int Medium, int Large);
11-
public sealed record MouseRepeatCapabilities(bool Supported, bool Enabled, int IntervalMs, int MinIntervalMs, int MaxIntervalMs);
11+
public sealed record MouseRepeatCapabilities(
12+
bool Supported,
13+
bool Enabled,
14+
int IntervalMs,
15+
int MoveIntervalMs,
16+
int ScrollIntervalMs,
17+
int MinIntervalMs,
18+
int MaxIntervalMs);
1219
public sealed record PointerCapabilities(bool NoAckMouseMove, IReadOnlyList<string> NoAckCommands, IReadOnlyList<string> SupportedCommands, MouseRepeatCapabilities MouseRepeat);
1320
public sealed record PointerMovementProfile(
1421
string DisplayId,
@@ -59,7 +66,9 @@ public static PointerMovementProfile Create(PointerProfileInput input)
5966
MouseRepeat: new MouseRepeatCapabilities(
6067
Supported: true,
6168
Enabled: MouseRepeatSettingsModel.Default.Enabled,
62-
IntervalMs: MouseRepeatSettingsModel.Default.IntervalMs,
69+
IntervalMs: MouseRepeatSettingsModel.Default.MoveIntervalMs,
70+
MoveIntervalMs: MouseRepeatSettingsModel.Default.MoveIntervalMs,
71+
ScrollIntervalMs: MouseRepeatSettingsModel.Default.ScrollIntervalMs,
6372
MinIntervalMs: MouseRepeatSettingsModel.MinIntervalMs,
6473
MaxIntervalMs: MouseRepeatSettingsModel.MaxIntervalMs)));
6574
}

src/SwitchifyPc.Core/Settings/MouseRepeatSettings.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace SwitchifyPc.Core.Settings;
66

7-
public sealed record MouseRepeatSettings(bool Enabled, int IntervalMs);
7+
public sealed record MouseRepeatSettings(bool Enabled, int MoveIntervalMs, int ScrollIntervalMs);
88

99
public static class MouseRepeatSettingsModel
1010
{
@@ -14,11 +14,15 @@ public static class MouseRepeatSettingsModel
1414
public const int MaxIntervalMs = 2000;
1515
public const int IntervalStepMs = 50;
1616

17-
public static readonly MouseRepeatSettings Default = new(DefaultEnabled, DefaultIntervalMs);
17+
public static readonly MouseRepeatSettings Default = new(DefaultEnabled, DefaultIntervalMs, DefaultIntervalMs);
1818

1919
public static MouseRepeatSettings Normalize(MouseRepeatSettings settings)
2020
{
21-
return settings with { IntervalMs = NormalizeInterval(settings.IntervalMs) };
21+
return settings with
22+
{
23+
MoveIntervalMs = NormalizeInterval(settings.MoveIntervalMs),
24+
ScrollIntervalMs = NormalizeInterval(settings.ScrollIntervalMs)
25+
};
2226
}
2327

2428
public static MouseRepeatSettings Normalize(JsonNode? value)
@@ -35,14 +39,28 @@ public static MouseRepeatSettings Normalize(JsonNode? value)
3539
enabled = enabledValue;
3640
}
3741

38-
int intervalMs = DefaultIntervalMs;
42+
int legacyIntervalMs = DefaultIntervalMs;
3943
if (candidate.TryGetPropertyValue("intervalMs", out JsonNode? intervalNode) &&
4044
TryGetInteger(intervalNode, out int intervalValue))
4145
{
42-
intervalMs = intervalValue;
46+
legacyIntervalMs = intervalValue;
47+
}
48+
49+
int moveIntervalMs = legacyIntervalMs;
50+
if (candidate.TryGetPropertyValue("moveIntervalMs", out JsonNode? moveIntervalNode) &&
51+
TryGetInteger(moveIntervalNode, out int moveIntervalValue))
52+
{
53+
moveIntervalMs = moveIntervalValue;
54+
}
55+
56+
int scrollIntervalMs = legacyIntervalMs;
57+
if (candidate.TryGetPropertyValue("scrollIntervalMs", out JsonNode? scrollIntervalNode) &&
58+
TryGetInteger(scrollIntervalNode, out int scrollIntervalValue))
59+
{
60+
scrollIntervalMs = scrollIntervalValue;
4361
}
4462

45-
return Normalize(new MouseRepeatSettings(enabled, intervalMs));
63+
return Normalize(new MouseRepeatSettings(enabled, moveIntervalMs, scrollIntervalMs));
4664
}
4765

4866
public static JsonObject ToJsonObject(MouseRepeatSettings settings)
@@ -51,7 +69,8 @@ public static JsonObject ToJsonObject(MouseRepeatSettings settings)
5169
return new JsonObject
5270
{
5371
["enabled"] = normalized.Enabled,
54-
["intervalMs"] = normalized.IntervalMs
72+
["moveIntervalMs"] = normalized.MoveIntervalMs,
73+
["scrollIntervalMs"] = normalized.ScrollIntervalMs
5574
};
5675
}
5776

src/SwitchifyPc.Core/Ui/SettingsController.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,16 @@ public MouseRepeatSettings SetMouseRepeatEnabled(bool enabled)
5252
return saved;
5353
}
5454

55-
public MouseRepeatSettings SetMouseRepeatIntervalMs(int intervalMs)
55+
public MouseRepeatSettings SetMouseRepeatMoveIntervalMs(int intervalMs)
5656
{
57-
MouseRepeatSettings saved = mouseRepeatSettings.Save(CurrentMouseRepeatSettings() with { IntervalMs = intervalMs });
57+
MouseRepeatSettings saved = mouseRepeatSettings.Save(CurrentMouseRepeatSettings() with { MoveIntervalMs = intervalMs });
58+
viewModel.SetMouseRepeatSettings(saved);
59+
return saved;
60+
}
61+
62+
public MouseRepeatSettings SetMouseRepeatScrollIntervalMs(int intervalMs)
63+
{
64+
MouseRepeatSettings saved = mouseRepeatSettings.Save(CurrentMouseRepeatSettings() with { ScrollIntervalMs = intervalMs });
5865
viewModel.SetMouseRepeatSettings(saved);
5966
return saved;
6067
}

0 commit comments

Comments
 (0)