Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 0 additions & 5 deletions src/AutoCursorLock.App/AutoCursorLockException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,4 @@ public AutoCursorLockException(string message)
: base(message)
{
}

public AutoCursorLockException(string message, Exception innerException)
: base(message, innerException)
{
}
}
13 changes: 12 additions & 1 deletion src/AutoCursorLock.App/Models/ProcessListItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ public record ProcessListItem
/// <param name="path">The path of the proceess' executable.</param>
/// <param name="appLockType">The type of app lock.</param>
/// <param name="margin">The margin around the window for the app lock.</param>
/// <param name="reapplyLockInterval">The interval in milliseconds before reapplying the lock while the window is in focus.</param>
/// <param name="icon">The icon image of the process.</param>
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;
}

Expand All @@ -49,6 +51,15 @@ public ProcessListItem(string name, string? path, AppLockType appLockType, AppLo
/// </summary>
public AppLockMargin Margin { get; init; }

/// <summary>
/// Gets the interval in milliseconds before reapplying the lock while the window is in focus.
/// </summary>
/// <remarks>
/// A value of 0 disables reapplying the lock.
/// The lock will only be applied once, when the window is first focused.
/// </remarks>
public int ReapplyLockInterval { get; init; }

/// <summary>
/// Gets the icon image of the process.
/// </summary>
Expand Down
7 changes: 4 additions & 3 deletions src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

/// <summary>
Expand All @@ -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);
}

/// <summary>
Expand All @@ -66,7 +66,8 @@ public static AppLockSettingsModel ToModel(this ProcessListItem processListItem)
processListItem.Name,
processListItem.Path,
processListItem.AppLockType,
processListItem.Margin
processListItem.Margin,
processListItem.ReapplyLockInterval
);
}

Expand Down
45 changes: 38 additions & 7 deletions src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<Grid x:Name="mainGrid">
Title="App Lock Settings" Height="400" Width="600">
<Grid x:Name="mainGrid" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Margin="5">
Expand Down Expand Up @@ -46,7 +47,8 @@
SelectedItem="{Binding AppLockSettings.AppLockType}" />
<TextBlock
Grid.Column="0"
Grid.Row="1">
Grid.Row="1"
Margin="5">
Left-side margin
</TextBlock>
<TextBox
Expand All @@ -57,7 +59,8 @@
Text="{Binding AppLockSettings.Margin.Left}" />
<TextBlock
Grid.Column="0"
Grid.Row="2">
Grid.Row="2"
Margin="5">
Top-side margin
</TextBlock>
<TextBox
Expand All @@ -68,7 +71,8 @@
Text="{Binding AppLockSettings.Margin.Top}" />
<TextBlock
Grid.Column="0"
Grid.Row="3">
Grid.Row="3"
Margin="5">
Right-side margin
</TextBlock>
<TextBox
Expand All @@ -79,7 +83,8 @@
Text="{Binding AppLockSettings.Margin.Right}" />
<TextBlock
Grid.Column="0"
Grid.Row="4">
Grid.Row="4"
Margin="5">
Bottom-side margin
</TextBlock>
<TextBox
Expand All @@ -88,5 +93,31 @@
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.Margin.Bottom}" />
<StackPanel
Orientation="Vertical"
Grid.Column="0"
Grid.Row="5"
Margin="5">
<TextBlock TextWrapping="Wrap">
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.
</TextBlock>
<TextBlock TextWrapping="Wrap" Margin="0,5,0,0">
Set to 0 to disable the re-application. This means the cursor lock will only be applied once, right after the application is focused.
</TextBlock>
<TextBlock TextWrapping="Wrap" Margin="0,5,0,0">
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.
</TextBlock>

</StackPanel>
<TextBox
Grid.Column="1"
Grid.Row="5"
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.ReapplyLockInterval}" />
</Grid>
</Window>
43 changes: 31 additions & 12 deletions src/AutoCursorLock.App/Views/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,7 +30,8 @@ public partial class MainWindow : Window, INotifyPropertyChanged
private readonly SaveUserSettingsOperation saveUserSettingsOperation;
private readonly ILogger<MainWindow> logger;

private ApplicationEventSource applicationEventSource;
private readonly ApplicationEventSource applicationEventSource;
private readonly object activeProcessLock = new ();

private bool globalLockEnabled = true;
private bool applicationLockEnabled = false;
Expand Down Expand Up @@ -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; }

/// <summary>
/// Gets the list of enabled processes.
/// Runs when the Window handle is available.
/// </summary>
/// <param name="e">Event args.</param>
protected override void OnSourceInitialized(EventArgs e)
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
}
}

}
}

Expand Down
6 changes: 4 additions & 2 deletions src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ namespace AutoCursorLock.Sdk.Models;
/// <param name="Path">The path to the application.</param>
/// <param name="Type">The type of app lock to use.</param>
/// <param name="Margin">The margin around the window for the app lock.</param>
/// <param name="ReapplyLockInterval">The interval in milliseconds before reapplying the lock while the window is in focus.</param>
public record AppLockSettingsModel(
string Name,
string? Path,
AppLockType Type,
AppLockMargin? Margin
AppLockMargin? Margin,
int ReapplyLockInterval
)
{
/// <summary>
Expand All @@ -25,6 +27,6 @@ public record AppLockSettingsModel(
/// <returns>The model.</returns>
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);
}
}
4 changes: 2 additions & 2 deletions src/AutoCursorLock.Sdk/Models/HotKeyModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ namespace AutoCursorLock.Sdk.Models;
public record HotKeyModel
{
/// <summary>
/// THe modifiers for the hot key.
/// Gets the modifiers for the hot key.
/// </summary>
[JsonRequired]
required public ModifierKey[] Modifiers { get; init; }

/// <summary>
/// The virtual key code for the hot key.
/// Gets the virtual key code for the hot key.
/// </summary>
[JsonRequired]
required public int VirtualKey { get; init; }
Expand Down
Loading