diff --git a/src/AutoCursorLock.App/AutoCursorLockException.cs b/src/AutoCursorLock.App/AutoCursorLockException.cs
index 8a4eb58..5998994 100644
--- a/src/AutoCursorLock.App/AutoCursorLockException.cs
+++ b/src/AutoCursorLock.App/AutoCursorLockException.cs
@@ -18,9 +18,4 @@ public AutoCursorLockException(string message)
: base(message)
{
}
-
- public AutoCursorLockException(string message, Exception innerException)
- : base(message, innerException)
- {
- }
}
diff --git a/src/AutoCursorLock.App/Models/ProcessListItem.cs b/src/AutoCursorLock.App/Models/ProcessListItem.cs
index 85432a6..e281c8e 100644
--- a/src/AutoCursorLock.App/Models/ProcessListItem.cs
+++ b/src/AutoCursorLock.App/Models/ProcessListItem.cs
@@ -19,13 +19,15 @@ public record ProcessListItem
/// The path of the proceess' executable.
/// The type of app lock.
/// The margin around the window for the app lock.
+ /// The interval in milliseconds before reapplying the lock while the window is in focus.
/// The icon image of the process.
- public ProcessListItem(string name, string? path, AppLockType appLockType, AppLockMargin? margin, BitmapSource? icon)
+ public ProcessListItem(string name, string? path, AppLockType appLockType, AppLockMargin? margin, int reapplyLockInterval, BitmapSource? icon)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Path = path;
AppLockType = appLockType;
Margin = margin ?? new AppLockMargin(0, 0, 0, 0);
+ ReapplyLockInterval = reapplyLockInterval;
Icon = icon;
}
@@ -49,6 +51,15 @@ public ProcessListItem(string name, string? path, AppLockType appLockType, AppLo
///
public AppLockMargin Margin { get; init; }
+ ///
+ /// Gets the interval in milliseconds before reapplying the lock while the window is in focus.
+ ///
+ ///
+ /// A value of 0 disables reapplying the lock.
+ /// The lock will only be applied once, when the window is first focused.
+ ///
+ public int ReapplyLockInterval { get; init; }
+
///
/// Gets the icon image of the process.
///
diff --git a/src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs b/src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs
index aff3bce..b1efa98 100644
--- a/src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs
+++ b/src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs
@@ -29,7 +29,7 @@ public static ProcessListItem FromPath(string path)
.FirstOrDefault()
?? throw new AutoCursorLockException($"Could not find process for path: {path}");
- return FromAppLockSettings(new AppLockSettingsModel(process.ProcessName, path, AppLockType.Window, Margin: default));
+ return FromAppLockSettings(new AppLockSettingsModel(process.ProcessName, path, AppLockType.Window, Margin: default, ReapplyLockInterval: default));
}
///
@@ -52,7 +52,7 @@ public static ProcessListItem FromAppLockSettings(AppLockSettingsModel appLockSe
bitmapIcon = new BitmapImage(new Uri("pack://application:,,,/media/question-mark.png", UriKind.Absolute));
}
- return new ProcessListItem(appLockSettings.Name, appLockSettings.Path, appLockSettings.Type, appLockSettings.Margin, bitmapIcon);
+ return new ProcessListItem(appLockSettings.Name, appLockSettings.Path, appLockSettings.Type, appLockSettings.Margin, appLockSettings.ReapplyLockInterval, bitmapIcon);
}
///
@@ -66,7 +66,8 @@ public static AppLockSettingsModel ToModel(this ProcessListItem processListItem)
processListItem.Name,
processListItem.Path,
processListItem.AppLockType,
- processListItem.Margin
+ processListItem.Margin,
+ processListItem.ReapplyLockInterval
);
}
diff --git a/src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml b/src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml
index 14d03e6..7cffc5b 100644
--- a/src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml
+++ b/src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml
@@ -5,17 +5,18 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AutoCursorLock.App.Views"
mc:Ignorable="d"
- Title="App Lock Settings" Height="300" Width="600">
-
+ Title="App Lock Settings" Height="400" Width="600">
+
+
-
+
@@ -46,7 +47,8 @@
SelectedItem="{Binding AppLockSettings.AppLockType}" />
+ Grid.Row="1"
+ Margin="5">
Left-side margin
+ Grid.Row="2"
+ Margin="5">
Top-side margin
+ Grid.Row="3"
+ Margin="5">
Right-side margin
+ Grid.Row="4"
+ Margin="5">
Bottom-side margin
+
+
+ Lock re-apply interval.
+ The interval in milliseconds the cursor lock should be re-applied as long as the application is in focus.
+ Use this for applications that clear the cursor lock.
+
+
+ Set to 0 to disable the re-application. This means the cursor lock will only be applied once, right after the application is focused.
+
+
+ Small values may cause performance issues.
+ Large values may cause the cursor to be unlocked for a short period of time.
+ 10-100 milliseconds seems to be a good range for most applications.
+
+
+
+
diff --git a/src/AutoCursorLock.App/Views/MainWindow.xaml.cs b/src/AutoCursorLock.App/Views/MainWindow.xaml.cs
index 02f888b..92a68b1 100644
--- a/src/AutoCursorLock.App/Views/MainWindow.xaml.cs
+++ b/src/AutoCursorLock.App/Views/MainWindow.xaml.cs
@@ -9,6 +9,7 @@ namespace AutoCursorLock.App.Views;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@@ -29,7 +30,8 @@ public partial class MainWindow : Window, INotifyPropertyChanged
private readonly SaveUserSettingsOperation saveUserSettingsOperation;
private readonly ILogger logger;
- private ApplicationEventSource applicationEventSource;
+ private readonly ApplicationEventSource applicationEventSource;
+ private readonly object activeProcessLock = new ();
private bool globalLockEnabled = true;
private bool applicationLockEnabled = false;
@@ -140,21 +142,29 @@ public ProcessListItem? ActiveProcess
{
get
{
- return this.activeProcess;
+ lock (this.activeProcessLock)
+ {
+ return this.activeProcess;
+ }
}
set
{
- this.activeProcess = value;
- ApplicationLockEnabled = value != null;
- NotifyPropertyChanged(nameof(ActiveProcess));
+ lock (this.activeProcessLock)
+ {
+ this.activeProcess = value;
+ ApplicationLockEnabled = value != null;
+ NotifyPropertyChanged(nameof(ActiveProcess));
+ }
}
}
private IntPtr Hwnd => this.windowInteropHelper.Handle;
+ private Timer? ReapplyTimer { get; set; }
+
///
- /// Gets the list of enabled processes.
+ /// Runs when the Window handle is available.
///
/// Event args.
protected override void OnSourceInitialized(EventArgs e)
@@ -198,25 +208,35 @@ private void OnApplicationChanged(object? sender, ApplicationEventArgs e)
ActiveProcess = UserSettings.EnabledProcesses.FirstOrDefault(x => x.Name == e.ProcessName);
+ // dispose previous timer
+ ReapplyTimer?.Dispose();
+
+ // set up new timer if needed
+ if (ActiveProcess is not null && ActiveProcess.ReapplyLockInterval != 0)
+ {
+ ReapplyTimer = new Timer(_ => AdjustLock(e.Handle), null, ActiveProcess.ReapplyLockInterval, ActiveProcess.ReapplyLockInterval);
+ }
+
AdjustLock(e.Handle);
}
private void AdjustLock(IntPtr hwnd)
{
- if (GlobalLockEnabled && ActiveProcess is not null)
+ var activeProcess = ActiveProcess;
+ if (GlobalLockEnabled && activeProcess is not null)
{
- this.logger.LogInformation("Locking cursor to {ProcessName} {AppLockType}", ActiveProcess.Name, ActiveProcess.AppLockType);
+ this.logger.LogInformation("Locking cursor to {ProcessName} {AppLockType}", activeProcess.Name, activeProcess.AppLockType);
- var border = ActiveProcess.AppLockType switch
+ var border = activeProcess.AppLockType switch
{
AppLockType.Window => ApplicationHandler.GetApplicationBorders(hwnd),
AppLockType.Monitor => ApplicationHandler.GetMonitorBorders(hwnd),
_ => throw new NotImplementedException("Invalid AppLockType")
};
- if (ActiveProcess.Margin is not null)
+ if (activeProcess.Margin is not null)
{
- border = border.ApplyMargin(ActiveProcess.Margin);
+ border = border.ApplyMargin(activeProcess.Margin);
}
if (!MouseHandler.LockCursorToBorder(border))
@@ -328,7 +348,6 @@ private void RefreshButton_Click(object sender, RoutedEventArgs e)
this.logger.LogError(ex2, "Failed to create process list item for process: {ProcessName}", p.ProcessName);
}
}
-
}
}
diff --git a/src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs b/src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs
index a20b021..04de8d9 100644
--- a/src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs
+++ b/src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs
@@ -10,11 +10,13 @@ namespace AutoCursorLock.Sdk.Models;
/// The path to the application.
/// The type of app lock to use.
/// The margin around the window for the app lock.
+/// The interval in milliseconds before reapplying the lock while the window is in focus.
public record AppLockSettingsModel(
string Name,
string? Path,
AppLockType Type,
- AppLockMargin? Margin
+ AppLockMargin? Margin,
+ int ReapplyLockInterval
)
{
///
@@ -25,6 +27,6 @@ public record AppLockSettingsModel(
/// The model.
public static AppLockSettingsModel FromNameAndPath(string name, string? path)
{
- return new AppLockSettingsModel(name, path, AppLockType.Window, new AppLockMargin(0, 0, 0, 0));
+ return new AppLockSettingsModel(name, path, AppLockType.Window, new AppLockMargin(0, 0, 0, 0), ReapplyLockInterval: default);
}
}
diff --git a/src/AutoCursorLock.Sdk/Models/HotKeyModel.cs b/src/AutoCursorLock.Sdk/Models/HotKeyModel.cs
index 07d999b..76f8a58 100644
--- a/src/AutoCursorLock.Sdk/Models/HotKeyModel.cs
+++ b/src/AutoCursorLock.Sdk/Models/HotKeyModel.cs
@@ -11,13 +11,13 @@ namespace AutoCursorLock.Sdk.Models;
public record HotKeyModel
{
///
- /// THe modifiers for the hot key.
+ /// Gets the modifiers for the hot key.
///
[JsonRequired]
required public ModifierKey[] Modifiers { get; init; }
///
- /// The virtual key code for the hot key.
+ /// Gets the virtual key code for the hot key.
///
[JsonRequired]
required public int VirtualKey { get; init; }