Skip to content

Commit

Permalink
Implement more reliable foreground swap
Browse files Browse the repository at this point in the history
  • Loading branch information
hymccord committed Feb 12, 2023
1 parent 1321479 commit f5e6e4c
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 94 deletions.
5 changes: 1 addition & 4 deletions ReadySetTarkov/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using ReadySetTarkov.Settings;

using Serilog;
using Serilog.Events;

Expand Down Expand Up @@ -62,7 +60,6 @@ private void Exiting()
}

_exitHandled = true;
_host.Services.GetRequiredService<ISettingsProvider>().Save();
}

private void InstallExceptionHandlers()
Expand All @@ -86,7 +83,7 @@ private async void LogUnhandledExceptionAsync(Exception ex, string sources)
#pragma warning restore VSTHRD100, VSTHRD200
{
#if DEBUG
await _icon!.ShowBalloonTipAsync("ReadySetTarkove fatal error", sources, Hardcodet.Wpf.TaskbarNotification.BalloonIcon.Error);
await _icon!.ShowBalloonTipAsync("ReadySetTarkov fatal error", sources, Hardcodet.Wpf.TaskbarNotification.BalloonIcon.Error);
await Task.Delay(5000);
await _icon.CloseBalloonTipAsync();
#endif
Expand Down
50 changes: 32 additions & 18 deletions ReadySetTarkov/MainContextMenu.xaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
<ContextMenu x:Class="ReadySetTarkov.MainContextMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ReadySetTarkov"
d:DataContext="{d:DesignInstance Type=local:TrayViewModel}"
mc:Ignorable="d">
<MenuItem Header="Flash Taskbar" IsCheckable="True" IsChecked="{Binding FlashTaskbar}" />
<MenuItem Header="Bring Window to Foreground" IsChecked="{Binding SetTopMost}"
ItemsSource="{Binding TimeLeftOptions}">
<ContextMenu
x:Class="ReadySetTarkov.MainContextMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ReadySetTarkov"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance Type=local:TrayViewModel}"
mc:Ignorable="d">
<MenuItem
Header="Flash Taskbar"
IsCheckable="True"
IsChecked="{Binding FlashTaskbar}" />
<MenuItem
Header="Bring Window to Foreground"
ItemsSource="{Binding TimeLeftOptions}">
<MenuItem.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding Header}" IsChecked="{Binding IsChecked, Mode=TwoWay}" GroupName="TimeLeft" />
<RadioButton
Content="{Binding Header}"
GroupName="TimeLeft"
IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</DataTemplate>
</MenuItem.ItemTemplate>
<MenuItem.ItemContainerStyle>
Expand All @@ -22,12 +30,18 @@
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="Sounds">
<MenuItem Header="Match Starting" IsCheckable="True" IsChecked="{Binding MatchStart}" />
<MenuItem Header="Matchmaking Aborted" IsCheckable="True" IsChecked="{Binding MatchAbort}" />
<MenuItem
Header="Match Starting"
IsCheckable="True"
IsChecked="{Binding MatchStart}" />
<MenuItem
Header="Matchmaking Aborted"
IsCheckable="True"
IsChecked="{Binding MatchAbort}" />
</MenuItem>
<Separator/>
<Separator />
<MenuItem Header="{Binding Status}" />
<Separator/>
<MenuItem Header="Reset" Command="{Binding ResetCommand}" />
<MenuItem Header="Exit" Command="{Binding ExitCommand}" />
<Separator />
<MenuItem Command="{Binding ResetCommand}" Header="Reset" />
<MenuItem Command="{Binding ExitCommand}" Header="Exit" />
</ContextMenu>
5 changes: 5 additions & 0 deletions ReadySetTarkov/MainContextMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
public partial class MainContextMenu
{
public MainContextMenu() => InitializeComponent();

private void MenuItem_Click(object sender, System.Windows.RoutedEventArgs e)
{

}
}
10 changes: 8 additions & 2 deletions ReadySetTarkov/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ QueryFullProcessImageName
OpenProcess

// User32
AttachThreadInput
GetCurrentThreadId
GetForegroundWindow
SetForegroundWindow
GetWindowLong
Expand All @@ -13,10 +15,14 @@ SetFocus
SetActiveWindow
GetClassName
FlashWindow
ShowWindow
ShowWindowAsync
FindWindow
IsWindow
IsIconic
keybd_event
GetWindowThreadProcessId
SystemParametersInfo
AllowSetForegroundWindow
LockSetForegroundWindow

SET_WINDOW_POS_FLAGS
SET_WINDOW_POS_FLAGS
12 changes: 12 additions & 0 deletions ReadySetTarkov/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"ReadySetTarkov": {
"commandName": "Project"
},
"Desktop": {
"commandName": "Executable",
"executablePath": "C:\\Users\\Hank\\Desktop\\ReadySetTarkov\\ReadySetTarkov.exe",
"workingDirectory": "C:\\Users\\Hank\\Desktop\\ReadySetTarkov"
}
}
}
22 changes: 12 additions & 10 deletions ReadySetTarkov/ReadySetTarkov.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<UseWPF>true</UseWPF>
Expand All @@ -20,17 +20,19 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0-preview3" />
<PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.0.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
<PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.1.0" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.0.64" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.619-beta" PrivateAssets="all" ExcludeAssets="compile" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.5.22" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.188-beta" PrivateAssets="all" ExcludeAssets="compile">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog" Version="2.12.1-dev-01635" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.IO.Abstractions" Version="16.1.26" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00947" />
<PackageReference Include="System.IO.Abstractions" Version="19.1.1" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion ReadySetTarkov/ReadySetTarkovHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public static IHostBuilder AddServices(this IHostBuilder hostBuilder)
_ = services.AddTransient<INativeMethods, NativeMethods>();
_ = services.AddTransient<IKernel32, Kernel32>();
_ = services.AddTransient<IUser32, User32>();
_ = services.AddTransient<ISystemParametersInfo, SystemParameters>();
_ = services.AddTransient<IWindowForegrounding, WindowForegrounding>();

// Tarkov Log Watchers
_ = services.AddSingleton<ILogFileHandlerProvider, ApplicationLogFileHandlerProvider>();
Expand All @@ -66,7 +68,7 @@ public static IHostBuilder AddServices(this IHostBuilder hostBuilder)

public static LoggerConfiguration MinimumLevelFromConfiguration(this LoggerConfiguration builder, IConfiguration config)
{
foreach ((string key, string value) in config.AsEnumerable())
foreach ((string key, string? value) in config.AsEnumerable())
{
int idx = key.LastIndexOf(':');
string? eventName = key[(idx + 1)..];
Expand Down
17 changes: 10 additions & 7 deletions ReadySetTarkov/Services/ShutdownHandler.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.Threading;

using ReadySetTarkov.Settings;

namespace ReadySetTarkov.Services;
internal class ShutdownHandler : IHostedService
{
private readonly ISettingsProvider _settingsProvider;
private readonly JoinableTaskFactory _joinableTaskFactory;

public ShutdownHandler(IHostApplicationLifetime hostApplicationLifetime, JoinableTaskFactory joinableTaskFactory)
public ShutdownHandler(
IHostApplicationLifetime hostApplicationLifetime,
ISettingsProvider settingsProvider,
JoinableTaskFactory joinableTaskFactory)
{
_joinableTaskFactory = joinableTaskFactory;

_settingsProvider = settingsProvider;
hostApplicationLifetime.ApplicationStopping.Register(static (c) => _ = (c as ShutdownHandler)!.ShutdownAppAsync(), this);
}

Expand All @@ -26,6 +28,7 @@ public ShutdownHandler(IHostApplicationLifetime hostApplicationLifetime, Joinabl

private async Task ShutdownAppAsync()
{
_settingsProvider.Save();
await _joinableTaskFactory.SwitchToMainThreadAsync();

Application.Current.Shutdown();
Expand Down
3 changes: 1 addition & 2 deletions ReadySetTarkov/Settings/ReadySetTarkovSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
public class ReadySetTarkovSettings
{
public bool FlashTaskbar { get; set; } = true;
public bool SetTopMost { get; set; } = true;
public int WithSecondsLeft { get; set; } = 0;
public int WithSecondsLeft { get; set; } = 3;
public SoundSettings Sounds { get; } = new SoundSettings();
}

Expand Down
13 changes: 5 additions & 8 deletions ReadySetTarkov/Tarkov/GameEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,19 @@ private async void GameStartingEventHandler(object? sender, EventArgs e)
player.Play();
}

if (_settingsProvider.Settings.SetTopMost && _settingsProvider.Settings.WithSecondsLeft > 0)
if (_settingsProvider.Settings.WithSecondsLeft > 0)
{
// Going to assume 20 seconds, there's no log way to get the amount of time remaining.
await Task.Delay((20 * 1000) - (_settingsProvider.Settings.WithSecondsLeft * 1000))
.ContinueWith(t =>
_nativeMethods.BringTarkovToForeground(),
TaskScheduler.Default
);
await Task.Delay((20 * 1000) - (_settingsProvider.Settings.WithSecondsLeft * 1000));
await _nativeMethods.BringTarkovToForegroundAsync();
}
}

private void GameStartedEventHandler(object? sender, EventArgs e)
{
if (_settingsProvider.Settings.SetTopMost && _settingsProvider.Settings.WithSecondsLeft == 0)
if (_settingsProvider.Settings.WithSecondsLeft == 0)
{
_nativeMethods.BringTarkovToForeground();
_ = _nativeMethods.BringTarkovToForegroundAsync();
}
}

Expand Down
24 changes: 12 additions & 12 deletions ReadySetTarkov/TrayViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

namespace ReadySetTarkov;

[ObservableObject]
public partial class TrayViewModel : ITray
public partial class TrayViewModel : ObservableObject, ITray
{
private readonly ISettingsProvider _settingsProvider;
private readonly Lazy<ICoreService> _coreService;
Expand All @@ -26,6 +25,7 @@ public TrayViewModel(ISettingsProvider settingsProvider, Lazy<ICoreService> core
_hostApplicationLifetime = hostApplicationLifetime;
TimeLeftOptions = new ObservableCollection<TimeLeftOption>
{
new TimeLeftOption(settingsProvider, -1),
new TimeLeftOption(settingsProvider, 20),
new TimeLeftOption(settingsProvider, 10),
new TimeLeftOption(settingsProvider, 5),
Expand All @@ -46,11 +46,7 @@ public string CurrentIcon

public bool Visible { get; set; }

public bool SetTopMost
{
get => _settingsProvider.Settings.SetTopMost;
set => _settingsProvider.Settings.SetTopMost = value;
}
public bool SetTopMost => _settingsProvider.Settings.WithSecondsLeft >= 0;

public bool FlashTaskbar
{
Expand Down Expand Up @@ -79,14 +75,13 @@ public string Status

public void SetStatus(string text) => Status = text;

[ICommand]
[RelayCommand]
private void Reset() => _ = _coreService.Value.ResetAsync();

[ICommand]
[RelayCommand]
private void Exit() => _hostApplicationLifetime.StopApplication();

[ObservableObject]
public partial class TimeLeftOption
public partial class TimeLeftOption : ObservableObject
{
private readonly ISettingsProvider _settingsProvider;

Expand All @@ -95,6 +90,11 @@ public TimeLeftOption(ISettingsProvider settingsProvider, int value)
_settingsProvider = settingsProvider;
Header = $"{value}s left";
Value = value;

if (value < 0)
{
Header += " (disabled)";
}
}

public string Header { get; }
Expand All @@ -111,7 +111,7 @@ public bool IsChecked
}
}

[ICommand]
[RelayCommand]
private void SetTimeLeft() => IsChecked = !IsChecked;
}
}
6 changes: 4 additions & 2 deletions ReadySetTarkov/Utility/INativeMethods.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
namespace ReadySetTarkov.Utility;
using System.Threading.Tasks;

namespace ReadySetTarkov.Utility;

public interface INativeMethods
{
void BringTarkovToForeground();
Task BringTarkovToForegroundAsync();
void FlashTarkov();
string GetProcessFilename(uint processId);
uint GetTarkovProcId();
Expand Down
Loading

0 comments on commit f5e6e4c

Please sign in to comment.