From 1bd42653e98e77bf656a6a70cff754600266d522 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Tue, 7 Jan 2025 16:35:59 +0100 Subject: [PATCH 1/3] Implement theme switcher and fix some bugs --- .../DataContexts/MainWindowDataContext.cs | 5 ++- src/InvLock/MainWindow.xaml | 31 ++++++++++++++----- src/InvLock/Settings.cs | 27 ++++++++++++++++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/InvLock/DataContexts/MainWindowDataContext.cs b/src/InvLock/DataContexts/MainWindowDataContext.cs index 65e5860..136f959 100644 --- a/src/InvLock/DataContexts/MainWindowDataContext.cs +++ b/src/InvLock/DataContexts/MainWindowDataContext.cs @@ -1,9 +1,8 @@ -using System.ComponentModel; -using System.Reflection; +using System.Reflection; namespace InvLock.DataContexts; -internal class MainWindowDataContext : INotifyPropertyChanged +internal class MainWindowDataContext { #if DEBUG public string Title => $"{App.AppName} - Dev {AppVersion}"; diff --git a/src/InvLock/MainWindow.xaml b/src/InvLock/MainWindow.xaml index e2b90ba..b547b02 100644 --- a/src/InvLock/MainWindow.xaml +++ b/src/InvLock/MainWindow.xaml @@ -76,7 +76,7 @@ - + @@ -129,7 +129,26 @@ - + + + + + + + + + + + + + + + + + + + + @@ -140,13 +159,9 @@ - - + + - - - - diff --git a/src/InvLock/Settings.cs b/src/InvLock/Settings.cs index 33a03ee..33bc1d8 100644 --- a/src/InvLock/Settings.cs +++ b/src/InvLock/Settings.cs @@ -3,6 +3,8 @@ using System.Runtime.CompilerServices; using System.Text.Json; +using Wpf.Ui.Appearance; + namespace InvLock; public class Settings : INotifyPropertyChanged @@ -12,6 +14,7 @@ public class Settings : INotifyPropertyChanged private static readonly string settingsPath = Path.Combine(App.ApplicationDataPath, "settings.json"); private bool hideWindows = false; private string lockText = "Lock Screen Active"; + private string theme = "Windows default"; private string unlockText = "Lock Screen Inactive"; @@ -45,6 +48,30 @@ public string UnlockText } } + public string Theme + { + get => theme; + set + { + theme = value; + + if (value == "Windows default") + { + ApplicationThemeManager.ApplySystemTheme(); + } + else if (value == "Light") + { + ApplicationThemeManager.Apply(ApplicationTheme.Light); + } + else if (value == "Dark") + { + ApplicationThemeManager.Apply(ApplicationTheme.Dark); + } + + OnPropertyChanged(); + } + } + public static Settings Load() { if (File.Exists(settingsPath)) From 1898148462f6277a828f19169b0f0a2f3d7ab21c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Mon, 20 Jan 2025 23:33:58 +0100 Subject: [PATCH 2/3] Make shortcuts customizable --- .../DataContexts/MainWindowDataContext.cs | 44 +++++++- src/InvLock/InvLock.csproj | 1 + src/InvLock/LockWindow.xaml | 4 +- src/InvLock/LockWindow.xaml.cs | 101 +++++++++++++++--- src/InvLock/MainWindow.xaml | 31 ++++-- src/InvLock/MainWindow.xaml.cs | 3 +- src/InvLock/Settings.cs | 58 +++++++++- 7 files changed, 215 insertions(+), 27 deletions(-) diff --git a/src/InvLock/DataContexts/MainWindowDataContext.cs b/src/InvLock/DataContexts/MainWindowDataContext.cs index 136f959..93c1d3d 100644 --- a/src/InvLock/DataContexts/MainWindowDataContext.cs +++ b/src/InvLock/DataContexts/MainWindowDataContext.cs @@ -1,8 +1,12 @@ -using System.Reflection; +using CommunityToolkit.Mvvm.Input; + +using SharpHook.Native; + +using System.Reflection; namespace InvLock.DataContexts; -internal class MainWindowDataContext +internal partial class MainWindowDataContext(Func lockWindowAccessor) { #if DEBUG public string Title => $"{App.AppName} - Dev {AppVersion}"; @@ -18,4 +22,40 @@ internal class MainWindowDataContext public string AppVersion => Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "Unknown"; public Settings Settings { get; } = Settings.Load(); + + [RelayCommand] + public async Task RecordLockShortcut() + { + LockWindow? lockWindow = lockWindowAccessor(); + + if (lockWindow is null) + { + return; + } + + HashSet? lockShortcut = await lockWindow.RecordShortcut(); + + if (lockShortcut is not null) + { + Settings.LockShortcut = lockShortcut; + } + } + + [RelayCommand] + public async Task RecordUnlockShortcut() + { + LockWindow? lockWindow = lockWindowAccessor(); + + if (lockWindow is null) + { + return; + } + + HashSet? unlockShortcut = await lockWindow.RecordShortcut(); + + if (unlockShortcut is not null) + { + Settings.UnlockShortcut = unlockShortcut; + } + } } \ No newline at end of file diff --git a/src/InvLock/InvLock.csproj b/src/InvLock/InvLock.csproj index f523019..8e16378 100644 --- a/src/InvLock/InvLock.csproj +++ b/src/InvLock/InvLock.csproj @@ -15,6 +15,7 @@ + diff --git a/src/InvLock/LockWindow.xaml b/src/InvLock/LockWindow.xaml index 2a8ae6c..8f230ac 100644 --- a/src/InvLock/LockWindow.xaml +++ b/src/InvLock/LockWindow.xaml @@ -17,5 +17,7 @@ ShowInTaskbar="False" Title="MainWindow" Height="Auto" Width="Auto"> - + + + \ No newline at end of file diff --git a/src/InvLock/LockWindow.xaml.cs b/src/InvLock/LockWindow.xaml.cs index ce1ea40..02c9615 100644 --- a/src/InvLock/LockWindow.xaml.cs +++ b/src/InvLock/LockWindow.xaml.cs @@ -3,6 +3,7 @@ using SharpHook; using SharpHook.Native; +using System.Diagnostics; using System.Windows; using System.Windows.Interop; using System.Windows.Media; @@ -59,6 +60,59 @@ public LockWindow(Settings settings) _ = Task.Run(hook.Run); } + public async Task?> RecordShortcut() + { + HashSet keys = []; + + hook.KeyPressed -= Hook_KeyPressed; + hook.KeyPressed += Record; + + textBlock.Text = "Press a key combination to record a shortcut"; + textBlock.Stroke = Brushes.White; + textBlock.Opacity = 1; + + // Wait for the user to press the enter key + await Task.Run(async () => + { + while (!keys.Contains(KeyCode.VcEnter) && !keys.Contains(KeyCode.VcEscape)) + { + await Task.Delay(100); + } + }); + + hook.KeyPressed -= Record; + hook.KeyPressed += Hook_KeyPressed; + + textBlock.Opacity = 0; + + if (keys.Contains(KeyCode.VcEscape) || keys.Count <= 1) + { + textBlock.Text = "Shortcut Recording Cancelled"; + textBlock.Stroke = (Brush)FindResource("PaletteRedBrush"); + Animation(); + + return null; + } + + textBlock.Text = "Shortcut Recorded"; + textBlock.Stroke = (Brush)FindResource("PaletteGreenBrush"); + Animation(); + + _ = keys.Remove(KeyCode.VcEnter); + + return keys; + + void Record(object? sender, KeyboardHookEventArgs e) + { + e.SuppressEvent = true; + _ = keys.Add(e.Data.KeyCode); + Debug.WriteLine(string.Join(" + ", keys.Select(key => key.ToString()))); + _ = Dispatcher.Invoke(() => textBlock.Text = string.Join(" + ", keys.Select(key => key.ToString()[2..])) + + Environment.NewLine + + "Press ENTER to save or ESCAPE to cancel"); + } + } + private void ActivateLockScreen() { if (settings.HideWindows) @@ -82,8 +136,30 @@ private void ActivateLockScreen() private void DeactivateLockScreen() { - isOpen = false; - Dispatcher.Invoke(Close); + if (settings.UseWindowsLockScreen) + { + isOpen = false; + + Dispatcher.Invoke(Close); + } + else + { + Dispatcher.Invoke(() => + { + if (settings.HideWindows) + { + RestoreWindows(); + } + + textBlock.Text = settings.UnlockText; + textBlock.Stroke = (Brush)FindResource("PaletteGreenBrush"); + + Animation(); + + isOpen = true; + suppressInput = false; + }); + } } private void Hook_KeyPressed(object? sender, KeyboardHookEventArgs e) @@ -97,16 +173,13 @@ private void Hook_KeyPressed(object? sender, KeyboardHookEventArgs e) } _ = pressedKeys[e.Data.KeyCode] = DateTime.UtcNow; - if (pressedKeys.ContainsKey(KeyCode.VcL) && pressedKeys.ContainsKey(KeyCode.VcLeftShift) && pressedKeys.ContainsKey(KeyCode.VcLeftControl) && pressedKeys.Count == 3) + if (pressedKeys.All(kvp => settings.UnlockShortcut.Contains(kvp.Key)) && suppressInput && pressedKeys.Count == settings.UnlockShortcut.Count) { - if (suppressInput) - { - DeactivateLockScreen(); - } - else - { - ActivateLockScreen(); - } + DeactivateLockScreen(); + } + else if (pressedKeys.All(kvp => settings.LockShortcut.Contains(kvp.Key)) && !suppressInput && pressedKeys.Count == settings.LockShortcut.Count) + { + ActivateLockScreen(); } e.SuppressEvent = suppressInput; @@ -171,7 +244,11 @@ private void RestoreWindows() private void Animation() { - Storyboard storyboard = new Storyboard(); + Storyboard storyboard = new Storyboard + { + FillBehavior = FillBehavior.Stop + }; + TimeSpan duration = TimeSpan.FromMilliseconds(500); DoubleAnimation fadeInAnimation = new DoubleAnimation() diff --git a/src/InvLock/MainWindow.xaml b/src/InvLock/MainWindow.xaml index b547b02..6ff43a4 100644 --- a/src/InvLock/MainWindow.xaml +++ b/src/InvLock/MainWindow.xaml @@ -56,10 +56,6 @@ It is designed to be lightweight and easy to use. If you have any issues or feature requests, please report them on GitHub. - - - To lock and unlock your screen, press - WIN + SHIFT + L @@ -90,6 +86,13 @@ + + + + + + + @@ -97,6 +100,13 @@ + + + + + + + @@ -104,6 +114,13 @@ + + + + + + + @@ -131,7 +148,7 @@ - + @@ -147,7 +164,7 @@ - + @@ -160,7 +177,7 @@ - + diff --git a/src/InvLock/MainWindow.xaml.cs b/src/InvLock/MainWindow.xaml.cs index 4bc68f3..926f921 100644 --- a/src/InvLock/MainWindow.xaml.cs +++ b/src/InvLock/MainWindow.xaml.cs @@ -12,12 +12,13 @@ namespace InvLock; /// public partial class MainWindow : FluentWindow { - private readonly MainWindowDataContext mainWindowDataContext = new MainWindowDataContext(); + private readonly MainWindowDataContext mainWindowDataContext; private LockWindow? lockWindow; private bool blockWindowClosing = true; public MainWindow() { + mainWindowDataContext = new MainWindowDataContext(() => lockWindow); DataContext = mainWindowDataContext; InitializeComponent(); diff --git a/src/InvLock/Settings.cs b/src/InvLock/Settings.cs index 33bc1d8..24c960e 100644 --- a/src/InvLock/Settings.cs +++ b/src/InvLock/Settings.cs @@ -1,7 +1,10 @@ -using System.ComponentModel; +using SharpHook.Native; + +using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Text.Json; +using System.Text.Json.Serialization; using Wpf.Ui.Appearance; @@ -12,9 +15,12 @@ public class Settings : INotifyPropertyChanged public event PropertyChangedEventHandler? PropertyChanged; private static readonly string settingsPath = Path.Combine(App.ApplicationDataPath, "settings.json"); + private bool useWindowsLockScreen = true; private bool hideWindows = false; private string lockText = "Lock Screen Active"; private string theme = "Windows default"; + private HashSet lockShortcut = [KeyCode.VcLeftControl, KeyCode.VcLeftShift, KeyCode.VcL]; + private HashSet unlockShortcut = [KeyCode.VcLeftControl, KeyCode.VcLeftShift, KeyCode.VcL]; private string unlockText = "Lock Screen Inactive"; @@ -28,6 +34,16 @@ public bool HideWindows } } + public bool UseWindowsLockScreen + { + get => useWindowsLockScreen; + set + { + useWindowsLockScreen = value; + OnPropertyChanged(); + } + } + public string LockText { get => lockText; @@ -38,6 +54,20 @@ public string LockText } } + public HashSet LockShortcut + { + get => lockShortcut; + set + { + lockShortcut = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(LockShortcutText)); + } + } + + [JsonIgnore] + public string LockShortcutText => string.Join(" + ", LockShortcut.Select(key => key.ToString()[2..])); + public string UnlockText { get => unlockText; @@ -48,6 +78,20 @@ public string UnlockText } } + public HashSet UnlockShortcut + { + get => unlockShortcut; + set + { + unlockShortcut = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(UnlockShortcutText)); + } + } + + [JsonIgnore] + public string UnlockShortcutText => string.Join(" + ", UnlockShortcut.Select(key => key.ToString()[2..])); + public string Theme { get => theme; @@ -76,10 +120,16 @@ public static Settings Load() { if (File.Exists(settingsPath)) { - string json = File.ReadAllText(settingsPath); - return JsonSerializer.Deserialize(json) ?? new Settings(); + try + { + string json = File.ReadAllText(settingsPath); + return JsonSerializer.Deserialize(json) ?? new Settings(); + } + catch (JsonException) + { + return new Settings(); + } } - return new Settings(); } From 24149dabef57ec83876b45bd3ea4b4a94518903c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Tue, 21 Jan 2025 01:03:00 +0100 Subject: [PATCH 3/3] Fix lock bug when restoring windows --- src/InvLock/LockWindow.xaml.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/InvLock/LockWindow.xaml.cs b/src/InvLock/LockWindow.xaml.cs index 02c9615..67c4750 100644 --- a/src/InvLock/LockWindow.xaml.cs +++ b/src/InvLock/LockWindow.xaml.cs @@ -146,18 +146,19 @@ private void DeactivateLockScreen() { Dispatcher.Invoke(() => { + suppressInput = false; + if (settings.HideWindows) { RestoreWindows(); } + isOpen = true; + textBlock.Text = settings.UnlockText; textBlock.Stroke = (Brush)FindResource("PaletteGreenBrush"); Animation(); - - isOpen = true; - suppressInput = false; }); } }