diff --git a/LockIn/Assets/Helldivers2.ico b/LockIn/Assets/Helldivers2.ico new file mode 100644 index 0000000..094da38 Binary files /dev/null and b/LockIn/Assets/Helldivers2.ico differ diff --git a/LockIn/LockIn.csproj b/LockIn/LockIn.csproj index fa63612..155e445 100644 --- a/LockIn/LockIn.csproj +++ b/LockIn/LockIn.csproj @@ -2,7 +2,7 @@ WinExe - net9.0-windows + net9.0-windows enable enable true @@ -22,9 +22,8 @@ - - PreserveNewest - + + diff --git a/LockIn/MainWindow.xaml b/LockIn/MainWindow.xaml index 80942ab..d1d1a42 100644 --- a/LockIn/MainWindow.xaml +++ b/LockIn/MainWindow.xaml @@ -3,12 +3,15 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:local="clr-namespace:LockIn" xmlns:vm="clr-namespace:LockIn.ViewModels" + xmlns:controls="clr-namespace:LockIn.UserControls" mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=vm:MainWindowViewModel, IsDesignTimeCreatable=True}" - Title="Lock In" Height="300" Width="300"> - + Title="Lock In" Height="275" Width="300" + WindowStartupLocation="CenterScreen" + Icon="./Assets/Helldivers2.ico"> + + @@ -17,24 +20,71 @@ + Margin="10,5,0,0"> + + + + + + + + + - + + + + + + + + + + + + + - - + + + + + + + + + + + + + + - + VerticalAlignment="Top" + controls:TypewriterTextBlock.TextToAnimate="{Binding LockInText}"> + + + + + + + + + + + + + diff --git a/LockIn/Themes.xaml b/LockIn/Themes.xaml index ffdb7db..57dd5da 100644 --- a/LockIn/Themes.xaml +++ b/LockIn/Themes.xaml @@ -1,18 +1,9 @@  - - - - - + - - - + + + /Assets/#FS Sinclair Regular.otf \ No newline at end of file diff --git a/LockIn/UserControls/TypewriterTextBlock.xaml b/LockIn/UserControls/TypewriterTextBlock.xaml new file mode 100644 index 0000000..31b0e7c --- /dev/null +++ b/LockIn/UserControls/TypewriterTextBlock.xaml @@ -0,0 +1,8 @@ + + diff --git a/LockIn/UserControls/TypewriterTextBlock.xaml.cs b/LockIn/UserControls/TypewriterTextBlock.xaml.cs new file mode 100644 index 0000000..c1774e9 --- /dev/null +++ b/LockIn/UserControls/TypewriterTextBlock.xaml.cs @@ -0,0 +1,69 @@ +using System.Text; +using System.Windows; +using System.Windows.Controls; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace LockIn.UserControls; + +[ObservableObject] +public partial class TypewriterTextBlock : TextBlock +{ + private CancellationTokenSource _cts = new CancellationTokenSource(); + public static readonly DependencyProperty TimePerCharacterProperty = DependencyProperty.RegisterAttached("TimePerCharacter", typeof(TimeSpan), typeof(TypewriterTextBlock), new PropertyMetadata(TimeSpan.FromMilliseconds(100))); + public static readonly DependencyProperty TextToAnimateProperty = DependencyProperty.RegisterAttached("TextToAnimate", typeof(string), typeof(TypewriterTextBlock), new PropertyMetadata(string.Empty, OnTextChanged)); + + public static void SetTimePerCharacter(DependencyObject element, TimeSpan value) + { + element.SetValue(TimePerCharacterProperty, value); + } + + public static TimeSpan GetTimePerCharacter(DependencyObject element) + { + return (TimeSpan)element.GetValue(TimePerCharacterProperty); + } + + public static void SetTextToAnimate(DependencyObject element, string value) + { + element.SetValue(TextToAnimateProperty, value); + } + + public static string GetTextToAnimate(DependencyObject element, string value) + { + return (string)element.GetValue(TextToAnimateProperty); + } + + public TypewriterTextBlock() + { + + } + + private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if(d is not TypewriterTextBlock textBlock) return; + if (e.NewValue == e.OldValue) return; + textBlock._cts.Cancel(); + textBlock._cts.Dispose(); + textBlock._cts = new CancellationTokenSource(); + _ = textBlock.AnimateText(e.NewValue.ToString() ?? string.Empty, textBlock._cts.Token); + } + + private async Task AnimateText(string textToAnimate, CancellationToken ct = default) + { + if(ct.IsCancellationRequested) return; + TimeSpan timePerCharacter = (TimeSpan)GetValue(TimePerCharacterProperty); + StringBuilder bob = new(textToAnimate.Length); + try + { + foreach (char c in textToAnimate) + { + if (ct.IsCancellationRequested) return; + bob.Append(c); + Text = bob.ToString(); + await Task.Delay(timePerCharacter, ct); + } + } + catch (OperationCanceledException) + { + } + } +} \ No newline at end of file diff --git a/LockIn/ViewModels/MainWindowViewModel.cs b/LockIn/ViewModels/MainWindowViewModel.cs index 0ebb5d6..9d574f9 100644 --- a/LockIn/ViewModels/MainWindowViewModel.cs +++ b/LockIn/ViewModels/MainWindowViewModel.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Diagnostics; +using System.Text; using System.Windows; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -46,22 +47,26 @@ private void QuitApplication(object sender, ExitEventArgs e) private void UpdateLabel() { + string textToSet = string.Empty; if (!IsLockEnabled) { - StatusText = "Disabled"; + textToSet = "Disabled"; _gameProcess = null; - return; - } - - if (_gameProcess == null || _gameProcess.HasExited) - { - StatusText = "Looking for game..."; - _threadSignaller.Set(); } else { - StatusText = "Enabled"; + if (_gameProcess == null || _gameProcess.HasExited) + { + textToSet = "Looking for game..."; + _threadSignaller.Set(); + } + else + { + textToSet = "Enabled"; + } } + + StatusText = textToSet; } private void ThreadFindGame() @@ -71,7 +76,11 @@ private void ThreadFindGame() while (_threadSignaller.WaitOne()) { if (_applicationExitTokenSource.Token.IsCancellationRequested) return; - Process[] processes = Process.GetProcessesByName("helldivers2"); + string processToFind = "helldivers2"; +#if DEBUG + processToFind = "notepad"; +#endif + Process[] processes = Process.GetProcessesByName(processToFind); if (processes.Length > 0) { _gameProcess = processes.First(); @@ -122,13 +131,6 @@ private void GameExit(object? sender, EventArgs e) partial void OnIsLockEnabledChanged(bool value) { LockInText = value ? "Unlock" : "Lock In"; - } - - protected override void OnPropertyChanged(PropertyChangedEventArgs e) - { - base.OnPropertyChanged(e); - - if(e.PropertyName != nameof(IsLockEnabled)) return; Natives.ClipCursor(IntPtr.Zero); UpdateLabel(); }