Changed the way Notifications work since they are fired as background processes

This commit is contained in:
2026-03-30 11:03:24 -07:00
parent c723a75756
commit 9e9804b1b1
4 changed files with 172 additions and 183 deletions

View File

@@ -92,88 +92,19 @@ try {
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] Replay file confirmed: $($savedFile.FullName) ($fileSizeMB MB)"
# --- Notify user that the replay was saved ---
$notifyScript = {
param($fileName, $fileSizeMB, $contactNumber)
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Drawing
$hBitmap = [System.Drawing.SystemIcons]::Shield.ToBitmap().GetHbitmap()
$wpfImage = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap(
$hBitmap, [IntPtr]::Zero, [System.Windows.Int32Rect]::Empty,
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
[System.Runtime.InteropServices.Marshal]::DeleteObject($hBitmap)
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="IT Screen Recorder" Height="260" Width="440"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
Topmost="True" ShowInTaskbar="False">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,14">
<Image x:Name="ImgHeader" Width="32" Height="32" Margin="0,0,10,0" VerticalAlignment="Center"/>
<TextBlock Text="Replay Saved Successfully" FontSize="16" FontWeight="SemiBold" FontFamily="Segoe UI" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock x:Name="TxtBody" Grid.Row="1" TextWrapping="Wrap" FontSize="12" FontFamily="Segoe UI" LineHeight="22"/>
<TextBlock x:Name="TxtContact" Grid.Row="2" FontSize="11" FontFamily="Segoe UI" Foreground="#555" HorizontalAlignment="Center" Margin="0,12,0,16"/>
<Button x:Name="BtnOK" Grid.Row="3" Width="100" HorizontalAlignment="Center" IsDefault="True"/>
</Grid>
</Window>
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfImage
$txtContact.Text = "Questions? Contact IT at $contactNumber"
$txtBody.Inlines.Add("Your replay has been saved ($fileSizeMB MB):`n")
$bold1 = New-Object System.Windows.Documents.Run($fileName)
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add("`n`nIT can retrieve this file if needed for a support case.")
$script:tick = 30
$btnOK.Content = "OK (30)"
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds(1)
$timer.Add_Tick({
$script:tick--
$btnOK.Content = "OK ($script:tick)"
if ($script:tick -le 0) {
$timer.Stop()
$window.Close()
}
})
$timer.Start()
$btnOK.Add_Click({ $timer.Stop(); $window.Close() })
$window.ShowDialog() | Out-Null
}
$notifyRunspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$notifyRunspace.ApartmentState = [System.Threading.ApartmentState]::STA
$notifyRunspace.Open()
$notifyPS = [System.Management.Automation.PowerShell]::Create()
$notifyPS.Runspace = $notifyRunspace
$notifyPS.AddScript($notifyScript) | Out-Null
$notifyPS.AddArgument($savedFile.Name) | Out-Null
$notifyPS.AddArgument($fileSizeMB) | Out-Null
$notifyPS.AddArgument($config.ITContactNumber) | Out-Null
$notifyPS.Invoke()
$notifyPS.Dispose()
$notifyRunspace.Close()
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] User notification dismissed."
$notifyScript = Join-Path $PSScriptRoot 'Show-Notification.ps1'
Start-Process -FilePath 'powershell.exe' -ArgumentList @(
'-STA'
'-ExecutionPolicy', 'Bypass'
'-NonInteractive'
'-WindowStyle', 'Hidden'
'-File', $notifyScript
'-Type', 'ReplaySaved'
'-ContactNumber', $config.ITContactNumber
'-FileName', $savedFile.Name
'-FileSizeMB', $fileSizeMB
) -WindowStyle Hidden
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] User notification launched."
return $true
}

View File

@@ -0,0 +1,141 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Shows a WPF notification popup for the OBS Replay Buffer tool.
Must be launched via Start-Process with powershell.exe -STA.
.PARAMETER Type
'BufferStarted' — shown at logon when the replay buffer is active.
'ReplaySaved' — shown after a successful replay save.
#>
param(
[Parameter(Mandatory)]
[ValidateSet('BufferStarted', 'ReplaySaved')]
[string]$Type,
[string]$ContactNumber = '',
[int]$BufferMinutes = 0,
[string]$FileName = '',
[double]$FileSizeMB = 0
)
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Drawing
$hBitmap = [System.Drawing.SystemIcons]::Shield.ToBitmap().GetHbitmap()
$wpfImage = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap(
$hBitmap, [IntPtr]::Zero, [System.Windows.Int32Rect]::Empty,
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
[System.Runtime.InteropServices.Marshal]::DeleteObject($hBitmap)
if ($Type -eq 'BufferStarted') {
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="IT Screen Recorder" Height="320" Width="440"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
Topmost="True" ShowInTaskbar="False">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,14">
<Image x:Name="ImgHeader" Width="32" Height="32" Margin="0,0,10,0" VerticalAlignment="Center"/>
<TextBlock Text="Screen Recording is Active" FontSize="16" FontWeight="SemiBold" FontFamily="Segoe UI" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock x:Name="TxtBody" Grid.Row="1" TextWrapping="Wrap" FontSize="12" FontFamily="Segoe UI" LineHeight="22"/>
<Border Grid.Row="2" Background="#F0F0F0" CornerRadius="4" Padding="10,8" Margin="0,12,0,12">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Image x:Name="ImgTray" Width="22" Height="22" Margin="0,0,8,0"/>
<TextBlock Text="Look for this icon in your system tray" FontSize="11" FontFamily="Segoe UI" VerticalAlignment="Center" Foreground="#555"/>
</StackPanel>
</Border>
<TextBlock x:Name="TxtContact" Grid.Row="3" FontSize="11" FontFamily="Segoe UI" Foreground="#555" HorizontalAlignment="Center" Margin="0,0,0,16"/>
<Button x:Name="BtnOK" Grid.Row="4" Width="100" HorizontalAlignment="Center" IsDefault="True"/>
</Grid>
</Window>
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$imgTray = $window.FindName('ImgTray')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfImage
$imgTray.Source = $wpfImage
$txtContact.Text = "Questions? Contact IT at $ContactNumber"
$txtBody.Inlines.Add("Your screen is being recorded into a rolling $BufferMinutes-minute replay buffer. Nothing is saved until you request it.`n`nTo save a clip, ")
$bold1 = New-Object System.Windows.Documents.Run('right-click the shield icon')
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add(' in your system tray (bottom-right of your screen) and select ')
$bold2 = New-Object System.Windows.Documents.Run('Save Replay')
$bold2.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold2)
$txtBody.Inlines.Add('.')
} else {
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="IT Screen Recorder" Height="260" Width="440"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
Topmost="True" ShowInTaskbar="False">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,14">
<Image x:Name="ImgHeader" Width="32" Height="32" Margin="0,0,10,0" VerticalAlignment="Center"/>
<TextBlock Text="Replay Saved Successfully" FontSize="16" FontWeight="SemiBold" FontFamily="Segoe UI" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock x:Name="TxtBody" Grid.Row="1" TextWrapping="Wrap" FontSize="12" FontFamily="Segoe UI" LineHeight="22"/>
<TextBlock x:Name="TxtContact" Grid.Row="2" FontSize="11" FontFamily="Segoe UI" Foreground="#555" HorizontalAlignment="Center" Margin="0,12,0,16"/>
<Button x:Name="BtnOK" Grid.Row="3" Width="100" HorizontalAlignment="Center" IsDefault="True"/>
</Grid>
</Window>
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfImage
$txtContact.Text = "Questions? Contact IT at $ContactNumber"
$txtBody.Inlines.Add("Your replay has been saved ($FileSizeMB MB):`n")
$bold1 = New-Object System.Windows.Documents.Run($FileName)
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add("`n`nIT can retrieve this file if needed for a support case.")
}
# Countdown timer — auto-dismisses after 30 seconds
$script:tick = 30
$btnOK.Content = "OK (30)"
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds(1)
$timer.Add_Tick({
$script:tick--
$btnOK.Content = "OK ($script:tick)"
if ($script:tick -le 0) {
$timer.Stop()
$window.Close()
}
})
$timer.Start()
$btnOK.Add_Click({ $timer.Stop(); $window.Close() })
$window.ShowDialog() | Out-Null

View File

@@ -239,104 +239,19 @@ while (-not $rbStarted) {
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] Replay Buffer confirmed started."
# --- Notify user that the replay buffer is active ---
# Runs in a dedicated STA runspace because WPF requires STA apartment state
$notifyScript = {
param($contactNumber, $bufferMinutes)
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Drawing
# Convert the Shield system icon (same one used by the tray) to a WPF BitmapSource
$hBitmap = [System.Drawing.SystemIcons]::Shield.ToBitmap().GetHbitmap()
$wpfImage = [System.Windows.Interop.Imaging]::CreateBitmapSourceFromHBitmap(
$hBitmap, [IntPtr]::Zero, [System.Windows.Int32Rect]::Empty,
[System.Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions()
)
[System.Runtime.InteropServices.Marshal]::DeleteObject($hBitmap)
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="IT Screen Recorder" Height="320" Width="440"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
Topmost="True" ShowInTaskbar="False">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,14">
<Image x:Name="ImgHeader" Width="32" Height="32" Margin="0,0,10,0" VerticalAlignment="Center"/>
<TextBlock Text="Screen Recording is Active" FontSize="16" FontWeight="SemiBold" FontFamily="Segoe UI" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock x:Name="TxtBody" Grid.Row="1" TextWrapping="Wrap" FontSize="12" FontFamily="Segoe UI" LineHeight="22"/>
<Border Grid.Row="2" Background="#F0F0F0" CornerRadius="4" Padding="10,8" Margin="0,12,0,12">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Image x:Name="ImgTray" Width="22" Height="22" Margin="0,0,8,0"/>
<TextBlock Text="Look for this icon in your system tray" FontSize="11" FontFamily="Segoe UI" VerticalAlignment="Center" Foreground="#555"/>
</StackPanel>
</Border>
<TextBlock x:Name="TxtContact" Grid.Row="3" FontSize="11" FontFamily="Segoe UI" Foreground="#555" HorizontalAlignment="Center" Margin="0,0,0,16"/>
<Button x:Name="BtnOK" Grid.Row="4" Width="100" HorizontalAlignment="Center" IsDefault="True"/>
</Grid>
</Window>
"@
$window = [System.Windows.Markup.XamlReader]::Load([System.Xml.XmlNodeReader]::new($xaml))
$imgHeader = $window.FindName('ImgHeader')
$imgTray = $window.FindName('ImgTray')
$txtBody = $window.FindName('TxtBody')
$txtContact = $window.FindName('TxtContact')
$btnOK = $window.FindName('BtnOK')
$imgHeader.Source = $wpfImage
$imgTray.Source = $wpfImage
$txtContact.Text = "Questions? Contact IT at $contactNumber"
# Build body text with inline bold runs
$txtBody.Inlines.Add("Your screen is being recorded into a rolling $bufferMinutes-minute replay buffer. Nothing is saved until you request it.`n`nTo save a clip, ")
$bold1 = New-Object System.Windows.Documents.Run('right-click the shield icon')
$bold1.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold1)
$txtBody.Inlines.Add(' in your system tray (bottom-right of your screen) and select ')
$bold2 = New-Object System.Windows.Documents.Run('Save Replay')
$bold2.FontWeight = [System.Windows.FontWeights]::Bold
$txtBody.Inlines.Add($bold2)
$txtBody.Inlines.Add('.')
# Countdown timer — auto-dismisses after 30 seconds
$script:tick = 30
$btnOK.Content = "OK (30)"
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds(1)
$timer.Add_Tick({
$script:tick--
$btnOK.Content = "OK ($script:tick)"
if ($script:tick -le 0) {
$timer.Stop()
$window.Close()
}
})
$timer.Start()
$btnOK.Add_Click({ $timer.Stop(); $window.Close() })
$window.ShowDialog() | Out-Null
}
$notifyRunspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$notifyRunspace.ApartmentState = [System.Threading.ApartmentState]::STA
$notifyRunspace.Open()
$notifyPS = [System.Management.Automation.PowerShell]::Create()
$notifyPS.Runspace = $notifyRunspace
$notifyPS.AddScript($notifyScript) | Out-Null
$notifyPS.AddArgument($config.ITContactNumber) | Out-Null
$notifyPS.AddArgument([math]::Round($config.BufferSeconds / 60)) | Out-Null
$notifyPS.Invoke()
$notifyPS.Dispose()
$notifyRunspace.Close()
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] User notification dismissed."
$notifyScript = Join-Path $PSScriptRoot 'Show-Notification.ps1'
$bufferMinutes = [math]::Round($config.BufferSeconds / 60)
Start-Process -FilePath 'powershell.exe' -ArgumentList @(
'-STA'
'-ExecutionPolicy', 'Bypass'
'-NonInteractive'
'-WindowStyle', 'Hidden'
'-File', $notifyScript
'-Type', 'BufferStarted'
'-ContactNumber', $config.ITContactNumber
'-BufferMinutes', $bufferMinutes
) -WindowStyle Hidden
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] User notification launched."
# --- Launch tray icon as a separate background process ---
$trayScript = Join-Path $PSScriptRoot 'Show-ReplayTray.ps1'