net 8 upgrade and xbox gamebar widget
68
.github/workflows/build_performance_overlay.yaml
vendored
|
|
@ -1,3 +1,5 @@
|
|||
name: build-performance-overlay
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
|
|
@ -6,6 +8,8 @@ on:
|
|||
- "PerformanceOverlay/**"
|
||||
- "CommonHelpers/**"
|
||||
- "ExternalHelpers/**"
|
||||
- "XboxGameBarWidget/**"
|
||||
- "scripts/install_gamebar_widget.ps1"
|
||||
- "VERSION"
|
||||
pull_request:
|
||||
paths:
|
||||
|
|
@ -13,14 +17,17 @@ on:
|
|||
- "PerformanceOverlay/**"
|
||||
- "CommonHelpers/**"
|
||||
- "ExternalHelpers/**"
|
||||
- "XboxGameBarWidget/**"
|
||||
- "scripts/install_gamebar_widget.ps1"
|
||||
- "VERSION"
|
||||
|
||||
env:
|
||||
DOTNET_VERSION: "6.0.x"
|
||||
DOTNET_VERSION: "8.0.x"
|
||||
APP_NAME: PerformanceOverlay
|
||||
WIDGET_NAME: SteamDeckToolsGameBarWidget
|
||||
|
||||
jobs:
|
||||
build-performance-overlay:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -30,27 +37,80 @@ jobs:
|
|||
with:
|
||||
dotnet-version: ${{ env.DOTNET_VERSION }}
|
||||
|
||||
- name: Set RELEASE_VERSION
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Set versions
|
||||
shell: pwsh
|
||||
run: |
|
||||
$majorVersion = (Get-Content VERSION -Raw).Trim()
|
||||
$releaseVersion = "$majorVersion.${{ github.run_number }}"
|
||||
"RELEASE_VERSION=$releaseVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
$segments = @($majorVersion.Split('.') | Where-Object { $_ -ne '' })
|
||||
switch ($segments.Count) {
|
||||
0 { $widgetVersion = "1.0.${{ github.run_number }}.0" }
|
||||
1 { $widgetVersion = "$($segments[0]).0.${{ github.run_number }}.0" }
|
||||
2 { $widgetVersion = "$($segments[0]).$($segments[1]).${{ github.run_number }}.0" }
|
||||
default { $widgetVersion = "$($segments[0]).$($segments[1]).$($segments[2]).${{ github.run_number }}" }
|
||||
}
|
||||
"WIDGET_PACKAGE_VERSION=$widgetVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: Restore PerformanceOverlay dependencies
|
||||
run: dotnet restore PerformanceOverlay/PerformanceOverlay.csproj
|
||||
|
||||
- name: Build PerformanceOverlay
|
||||
run: dotnet build PerformanceOverlay/PerformanceOverlay.csproj --configuration Release --output "${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}/" "/property:Version=${{ env.RELEASE_VERSION }}" "/property:ExtraDefineConstants=PRODUCTION_BUILD"
|
||||
|
||||
- name: Create zip artifact
|
||||
- name: Create PerformanceOverlay zip artifact
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path "${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}\*" -DestinationPath "${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}.zip"
|
||||
|
||||
- name: Build Game Bar widget package
|
||||
shell: pwsh
|
||||
run: |
|
||||
$manifestPath = "XboxGameBarWidget/Package.appxmanifest"
|
||||
$manifestContent = Get-Content $manifestPath -Raw
|
||||
$manifestContent = [regex]::Replace(
|
||||
$manifestContent,
|
||||
'(<Identity\s+Name="SteamDeckToolsGameBarWidget"\s+Publisher="CN=SteamDeckTools"\s+Version=")[^"]+(")',
|
||||
{
|
||||
param($match)
|
||||
$match.Groups[1].Value + "${{ env.WIDGET_PACKAGE_VERSION }}" + $match.Groups[2].Value
|
||||
}
|
||||
)
|
||||
Set-Content -Path $manifestPath -Value $manifestContent -Encoding UTF8
|
||||
|
||||
$widgetPackageDir = Join-Path $PWD "${{ env.WIDGET_NAME }}-${{ env.RELEASE_VERSION }}"
|
||||
New-Item -ItemType Directory -Path $widgetPackageDir -Force | Out-Null
|
||||
|
||||
msbuild XboxGameBarWidget\SteamDeckToolsGameBarWidget.csproj `
|
||||
/restore `
|
||||
/p:Configuration=Release `
|
||||
/p:Platform=x64 `
|
||||
/p:AppxBundle=Never `
|
||||
/p:UapAppxPackageBuildMode=SideloadOnly `
|
||||
/p:AppxPackageDir="$widgetPackageDir\\" `
|
||||
/p:AppxPackageSigningEnabled=false
|
||||
|
||||
Copy-Item scripts\install_gamebar_widget.ps1 (Join-Path $widgetPackageDir "install_gamebar_widget.ps1") -Force
|
||||
|
||||
- name: Create Game Bar widget zip artifact
|
||||
shell: pwsh
|
||||
run: |
|
||||
Compress-Archive -Path "${{ env.WIDGET_NAME }}-${{ env.RELEASE_VERSION }}\*" -DestinationPath "${{ env.WIDGET_NAME }}-${{ env.RELEASE_VERSION }}.zip"
|
||||
|
||||
- name: Upload PerformanceOverlay zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}.zip
|
||||
path: ${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}.zip
|
||||
retention-days: 14
|
||||
|
||||
- name: Upload Game Bar widget zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.WIDGET_NAME }}-${{ env.RELEASE_VERSION }}.zip
|
||||
path: ${{ env.WIDGET_NAME }}-${{ env.RELEASE_VERSION }}.zip
|
||||
retention-days: 14
|
||||
|
|
|
|||
3
.gitignore
vendored
|
|
@ -5,7 +5,10 @@ obj/
|
|||
build-Release/
|
||||
build-Debug/
|
||||
.vscode/
|
||||
out/
|
||||
scripts/Redist/
|
||||
SteamDeckTools_Setup*.exe
|
||||
GameProfiles/
|
||||
ControllerProfiles/
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
|
||||
<Exec Command="git describe --long --always --dirty --exclude=* --abbrev=8" ConsoleToMSBuild="True" IgnoreExitCode="True">
|
||||
<Exec Command="git describe --long --always --dirty --abbrev=8" ConsoleToMSBuild="True" IgnoreExitCode="True" IgnoreStandardErrorWarningFormat="true">
|
||||
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
|
||||
</Exec>
|
||||
</Target>
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@
|
|||
}
|
||||
private void SetRampRate(byte rampRate)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(rampRate);
|
||||
byte[] data = new byte[] { rampRate };
|
||||
inpOut?.WriteMemory(FRPR, data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||
<PackageReference Include="System.Management" Version="8.0.0" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
332
PerformanceOverlay/OverlayCommandLine.cs
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
using CommonHelpers;
|
||||
|
||||
namespace PerformanceOverlay
|
||||
{
|
||||
internal enum OverlayControlResult
|
||||
{
|
||||
NotACommand,
|
||||
HandledAndExit,
|
||||
ContinueStartup
|
||||
}
|
||||
|
||||
internal enum OverlayControlCommandType
|
||||
{
|
||||
SetMode,
|
||||
CycleMode,
|
||||
ToggleVisibility,
|
||||
Show,
|
||||
Hide
|
||||
}
|
||||
|
||||
internal readonly struct OverlayControlCommand
|
||||
{
|
||||
public OverlayControlCommandType CommandType { get; }
|
||||
public OverlayMode Mode { get; }
|
||||
|
||||
private OverlayControlCommand(OverlayControlCommandType commandType, OverlayMode mode = OverlayMode.FPS)
|
||||
{
|
||||
CommandType = commandType;
|
||||
Mode = mode;
|
||||
}
|
||||
|
||||
public static OverlayControlCommand SetMode(OverlayMode mode)
|
||||
{
|
||||
return new OverlayControlCommand(OverlayControlCommandType.SetMode, mode);
|
||||
}
|
||||
|
||||
public static OverlayControlCommand CycleMode()
|
||||
{
|
||||
return new OverlayControlCommand(OverlayControlCommandType.CycleMode);
|
||||
}
|
||||
|
||||
public static OverlayControlCommand ToggleVisibility()
|
||||
{
|
||||
return new OverlayControlCommand(OverlayControlCommandType.ToggleVisibility);
|
||||
}
|
||||
|
||||
public static OverlayControlCommand Show()
|
||||
{
|
||||
return new OverlayControlCommand(OverlayControlCommandType.Show);
|
||||
}
|
||||
|
||||
public static OverlayControlCommand Hide()
|
||||
{
|
||||
return new OverlayControlCommand(OverlayControlCommandType.Hide);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class OverlayCommandLine
|
||||
{
|
||||
internal const string ProtocolScheme = "steamdecktools-performanceoverlay";
|
||||
private const string RunOnceMutexName = "Global\\PerformanceOverlay";
|
||||
|
||||
public static OverlayControlResult HandleArgs(string[] args)
|
||||
{
|
||||
if (!TryParseCommand(args, out var command))
|
||||
return OverlayControlResult.NotACommand;
|
||||
|
||||
if (TryDispatchToRunningInstance(command))
|
||||
return OverlayControlResult.HandledAndExit;
|
||||
|
||||
// Avoid run-once fatal dialog if an existing instance is present but IPC failed.
|
||||
if (IsPerformanceOverlayInstanceRunning())
|
||||
return OverlayControlResult.HandledAndExit;
|
||||
|
||||
ApplyLocally(command);
|
||||
return OverlayControlResult.ContinueStartup;
|
||||
}
|
||||
|
||||
private static bool TryParseCommand(string[] args, out OverlayControlCommand command)
|
||||
{
|
||||
command = default;
|
||||
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (TryParseUriCommand(arg, out command))
|
||||
return true;
|
||||
}
|
||||
|
||||
return TryParseSwitchCommand(args, out command);
|
||||
}
|
||||
|
||||
private static bool TryParseUriCommand(string arg, out OverlayControlCommand command)
|
||||
{
|
||||
command = default;
|
||||
|
||||
if (!Uri.TryCreate(arg, UriKind.Absolute, out var uri))
|
||||
return false;
|
||||
|
||||
if (!uri.Scheme.Equals(ProtocolScheme, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
var segments = new List<string>();
|
||||
if (!String.IsNullOrWhiteSpace(uri.Host))
|
||||
segments.Add(uri.Host);
|
||||
|
||||
segments.AddRange(
|
||||
uri.AbsolutePath
|
||||
.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
);
|
||||
|
||||
if (segments.Count == 0)
|
||||
return false;
|
||||
|
||||
var head = segments[0];
|
||||
if (head.Equals("cycle", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.CycleMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (head.Equals("toggle", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.ToggleVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (head.Equals("show", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.Show();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (head.Equals("hide", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.Hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((head.Equals("mode", StringComparison.OrdinalIgnoreCase) || head.Equals("set", StringComparison.OrdinalIgnoreCase))
|
||||
&& segments.Count > 1
|
||||
&& TryParseMode(segments[1], out var uriMode))
|
||||
{
|
||||
command = OverlayControlCommand.SetMode(uriMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseSwitchCommand(string[] args, out OverlayControlCommand command)
|
||||
{
|
||||
command = default;
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
var arg = args[i];
|
||||
if (arg.Equals("--cycle", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.CycleMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arg.Equals("--toggle", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.ToggleVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arg.Equals("--show", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.Show();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arg.Equals("--hide", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
command = OverlayControlCommand.Hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("--mode=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var modeArg = arg["--mode=".Length..];
|
||||
if (TryParseMode(modeArg, out var inlineMode))
|
||||
{
|
||||
command = OverlayControlCommand.SetMode(inlineMode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.Equals("--mode", StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length && TryParseMode(args[i + 1], out var nextMode))
|
||||
{
|
||||
command = OverlayControlCommand.SetMode(nextMode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseMode(string value, out OverlayMode mode)
|
||||
{
|
||||
if (Enum.TryParse<OverlayMode>(value, true, out mode))
|
||||
return true;
|
||||
|
||||
var normalized = value.Trim().Replace("-", "").Replace("_", "").ToLowerInvariant();
|
||||
switch (normalized)
|
||||
{
|
||||
case "fpsbattery":
|
||||
case "fpswithbattery":
|
||||
mode = OverlayMode.FPSWithBattery;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryDispatchToRunningInstance(OverlayControlCommand command)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var sharedData = SharedData<OverlayModeSetting>.OpenExisting();
|
||||
if (!sharedData.GetValue(out var value))
|
||||
value = sharedData.NewValue();
|
||||
|
||||
ApplyToSharedState(ref value, command);
|
||||
return sharedData.SetValue(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.TraceLine("OverlayCommandLine: IPC dispatch failed: {0}", ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyToSharedState(ref OverlayModeSetting value, OverlayControlCommand command)
|
||||
{
|
||||
switch (command.CommandType)
|
||||
{
|
||||
case OverlayControlCommandType.SetMode:
|
||||
value.Desired = command.Mode;
|
||||
value.DesiredEnabled = OverlayEnabled.Yes;
|
||||
return;
|
||||
case OverlayControlCommandType.CycleMode:
|
||||
value.Desired = NextMode(CurrentMode(value));
|
||||
value.DesiredEnabled = OverlayEnabled.Yes;
|
||||
return;
|
||||
case OverlayControlCommandType.ToggleVisibility:
|
||||
value.DesiredEnabled = CurrentEnabled(value) == OverlayEnabled.Yes ? OverlayEnabled.No : OverlayEnabled.Yes;
|
||||
return;
|
||||
case OverlayControlCommandType.Show:
|
||||
value.DesiredEnabled = OverlayEnabled.Yes;
|
||||
return;
|
||||
case OverlayControlCommandType.Hide:
|
||||
value.DesiredEnabled = OverlayEnabled.No;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static OverlayMode CurrentMode(OverlayModeSetting value)
|
||||
{
|
||||
if (Enum.IsDefined<OverlayMode>(value.Current))
|
||||
return value.Current;
|
||||
if (Enum.IsDefined<OverlayMode>(value.Desired))
|
||||
return value.Desired;
|
||||
return Settings.Default.OSDMode;
|
||||
}
|
||||
|
||||
private static OverlayEnabled CurrentEnabled(OverlayModeSetting value)
|
||||
{
|
||||
if (Enum.IsDefined<OverlayEnabled>(value.CurrentEnabled))
|
||||
return value.CurrentEnabled;
|
||||
if (Enum.IsDefined<OverlayEnabled>(value.DesiredEnabled))
|
||||
return value.DesiredEnabled;
|
||||
return Settings.Default.ShowOSD ? OverlayEnabled.Yes : OverlayEnabled.No;
|
||||
}
|
||||
|
||||
private static void ApplyLocally(OverlayControlCommand command)
|
||||
{
|
||||
switch (command.CommandType)
|
||||
{
|
||||
case OverlayControlCommandType.SetMode:
|
||||
Settings.Default.OSDMode = command.Mode;
|
||||
Settings.Default.ShowOSD = true;
|
||||
return;
|
||||
case OverlayControlCommandType.CycleMode:
|
||||
Settings.Default.OSDMode = NextMode(Settings.Default.OSDMode);
|
||||
Settings.Default.ShowOSD = true;
|
||||
return;
|
||||
case OverlayControlCommandType.ToggleVisibility:
|
||||
Settings.Default.ShowOSD = !Settings.Default.ShowOSD;
|
||||
return;
|
||||
case OverlayControlCommandType.Show:
|
||||
Settings.Default.ShowOSD = true;
|
||||
return;
|
||||
case OverlayControlCommandType.Hide:
|
||||
Settings.Default.ShowOSD = false;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static OverlayMode NextMode(OverlayMode current)
|
||||
{
|
||||
var values = Enum.GetValues<OverlayMode>();
|
||||
var currentIndex = Array.IndexOf(values, current);
|
||||
if (currentIndex < 0)
|
||||
currentIndex = 0;
|
||||
|
||||
return values[(currentIndex + 1) % values.Length];
|
||||
}
|
||||
|
||||
private static bool IsPerformanceOverlayInstanceRunning()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var mutex = Mutex.OpenExisting(RunOnceMutexName);
|
||||
return true;
|
||||
}
|
||||
catch (WaitHandleCannotBeOpenedException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using CommonHelpers;
|
||||
using RTSSSharedMemoryNET;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace PerformanceOverlay
|
||||
{
|
||||
|
|
@ -11,6 +10,12 @@ namespace PerformanceOverlay
|
|||
{
|
||||
Instance.WithSentry(() =>
|
||||
{
|
||||
UriProtocolRegistration.EnsureRegistered();
|
||||
|
||||
var commandResult = OverlayCommandLine.HandleArgs(Environment.GetCommandLineArgs().Skip(1).ToArray());
|
||||
if (commandResult == OverlayControlResult.HandledAndExit)
|
||||
return;
|
||||
|
||||
ApplicationConfiguration.Initialize();
|
||||
|
||||
using (var controller = new Controller())
|
||||
|
|
@ -20,4 +25,4 @@ namespace PerformanceOverlay
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
PerformanceOverlay/UriProtocolRegistration.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using CommonHelpers;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace PerformanceOverlay
|
||||
{
|
||||
internal static class UriProtocolRegistration
|
||||
{
|
||||
private const string ProtocolKey = @"Software\Classes\steamdecktools-performanceoverlay";
|
||||
|
||||
public static void EnsureRegistered()
|
||||
{
|
||||
try
|
||||
{
|
||||
var exePath = Environment.ProcessPath;
|
||||
if (String.IsNullOrWhiteSpace(exePath))
|
||||
return;
|
||||
|
||||
using var protocol = Registry.CurrentUser.CreateSubKey(ProtocolKey);
|
||||
if (protocol is null)
|
||||
return;
|
||||
|
||||
protocol.SetValue("", "URL:Steam Deck Tools Performance Overlay");
|
||||
protocol.SetValue("URL Protocol", "");
|
||||
|
||||
using var icon = protocol.CreateSubKey("DefaultIcon");
|
||||
icon?.SetValue("", "\"" + exePath + "\",0");
|
||||
|
||||
using var command = protocol.CreateSubKey(@"shell\open\command");
|
||||
command?.SetValue("", "\"" + exePath + "\" \"%1\"");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.TraceLine("UriProtocolRegistration: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
README.md
|
|
@ -4,13 +4,14 @@ This repository is a personal fork of Steam Deck Tools, customized for my ROG Al
|
|||
|
||||
## Scope
|
||||
|
||||
This fork is focused on `PerformanceOverlay` only.
|
||||
This fork is focused on `PerformanceOverlay` and companion tooling around it (including a Game Bar widget).
|
||||
|
||||
Included projects:
|
||||
|
||||
- `PerformanceOverlay`
|
||||
- `CommonHelpers`
|
||||
- `ExternalHelpers`
|
||||
- `XboxGameBarWidget`
|
||||
|
||||
The other original applications are intentionally not part of active development in this fork.
|
||||
|
||||
|
|
@ -21,9 +22,44 @@ dotnet restore PerformanceOverlay/PerformanceOverlay.csproj
|
|||
dotnet build PerformanceOverlay/PerformanceOverlay.csproj --configuration Release
|
||||
```
|
||||
|
||||
This fork now targets `.NET 8` for desktop projects.
|
||||
|
||||
## CI
|
||||
|
||||
GitHub Actions is configured to build only `PerformanceOverlay` and publish a ZIP artifact.
|
||||
GitHub Actions builds and publishes:
|
||||
|
||||
- `PerformanceOverlay-<version>.zip`
|
||||
- `SteamDeckToolsGameBarWidget-<version>.zip` (includes MSIX package + install script)
|
||||
|
||||
## Xbox Game Bar widget (Windows 11)
|
||||
|
||||
The widget appears in Xbox Game Bar (`Win+G`) as **Performance Overlay Control** and lets you:
|
||||
|
||||
- Switch directly to `FPS`, `FPSWithBattery`, `Battery`, `Minimal`, `Detail`, `Full`
|
||||
- `Cycle`, `Show`, `Hide`, or `Toggle` the overlay
|
||||
|
||||
The widget sends URI commands to `PerformanceOverlay` via:
|
||||
|
||||
- `steamdecktools-performanceoverlay://mode/<name>`
|
||||
- `steamdecktools-performanceoverlay://cycle`
|
||||
- `steamdecktools-performanceoverlay://show`
|
||||
- `steamdecktools-performanceoverlay://hide`
|
||||
- `steamdecktools-performanceoverlay://toggle`
|
||||
|
||||
Run `PerformanceOverlay` once after extracting it so it can register the URI protocol in `HKCU`.
|
||||
|
||||
## Install widget package (PowerShell)
|
||||
|
||||
After downloading the `SteamDeckToolsGameBarWidget-<version>.zip` artifact:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File scripts/install_gamebar_widget.ps1 -PackagePath "C:\path\to\SteamDeckToolsGameBarWidget-<version>.zip"
|
||||
```
|
||||
|
||||
Use `-ForceReinstall` to remove an existing widget package before reinstalling.
|
||||
|
||||
If Windows blocks unsigned package installation, enable Developer Mode:
|
||||
`Settings > Privacy & security > For developers > Developer Mode`.
|
||||
|
||||
## Install latest GitHub build artifact (PowerShell)
|
||||
|
||||
|
|
@ -114,4 +150,4 @@ Steam Deck Tools is not affiliated with Valve, Steam, or any of their partners.
|
|||
|
||||
[Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA)](http://creativecommons.org/licenses/by-nc-sa/4.0/).
|
||||
|
||||
Free for personal use. Contact me in other cases (`ayufan@ayufan.eu`).
|
||||
Free for personal use. Contact me in other cases (`ayufan@ayufan.eu`).
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonHelpers", "CommonHelp
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalHelpers", "ExternalHelpers\ExternalHelpers.csproj", "{A3FD29A4-844F-42B1-80C5-0301BD053AC0}"
|
||||
EndProject
|
||||
Project("{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A}") = "SteamDeckToolsGameBarWidget", "XboxGameBarWidget\SteamDeckToolsGameBarWidget.csproj", "{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -55,6 +57,18 @@ Global
|
|||
{A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|x64.Build.0 = Debug|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Debug|x86.Build.0 = Debug|x86
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|Any CPU.Build.0 = Release|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|x64.ActiveCfg = Release|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|x64.Build.0 = Release|x64
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|x86.ActiveCfg = Release|x86
|
||||
{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
5
XboxGameBarWidget/App.xaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<Application
|
||||
x:Class="SteamDeckToolsGameBarWidget.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SteamDeckToolsGameBarWidget" />
|
||||
93
XboxGameBarWidget/App.xaml.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using Microsoft.Gaming.XboxGameBar;
|
||||
using System;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace SteamDeckToolsGameBarWidget
|
||||
{
|
||||
sealed partial class App : Application
|
||||
{
|
||||
private XboxGameBarWidget widget = null;
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
protected override void OnActivated(IActivatedEventArgs args)
|
||||
{
|
||||
XboxGameBarWidgetActivatedEventArgs widgetArgs = null;
|
||||
|
||||
if (args.Kind == ActivationKind.Protocol)
|
||||
{
|
||||
var protocolArgs = args as IProtocolActivatedEventArgs;
|
||||
if (protocolArgs != null && protocolArgs.Uri.Scheme.Equals("ms-gamebarwidget", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
widgetArgs = args as XboxGameBarWidgetActivatedEventArgs;
|
||||
}
|
||||
}
|
||||
|
||||
if (widgetArgs == null)
|
||||
return;
|
||||
|
||||
if (widgetArgs.IsLaunchActivation)
|
||||
{
|
||||
var rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
Window.Current.Content = rootFrame;
|
||||
|
||||
widget = new XboxGameBarWidget(
|
||||
widgetArgs,
|
||||
Window.Current.CoreWindow,
|
||||
rootFrame
|
||||
);
|
||||
|
||||
rootFrame.Navigate(typeof(WidgetPage));
|
||||
Window.Current.Closed += WidgetWindow_Closed;
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
var rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
if (rootFrame == null)
|
||||
{
|
||||
rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (!e.PrelaunchActivated)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void WidgetWindow_Closed(object sender, Windows.UI.Core.CoreWindowEventArgs e)
|
||||
{
|
||||
widget = null;
|
||||
Window.Current.Closed -= WidgetWindow_Closed;
|
||||
}
|
||||
|
||||
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
widget = null;
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
XboxGameBarWidget/Assets/LargeTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
XboxGameBarWidget/Assets/SmallTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
XboxGameBarWidget/Assets/SplashScreen.scale-100.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
XboxGameBarWidget/Assets/Square150x150Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
XboxGameBarWidget/Assets/Square44x44Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
BIN
XboxGameBarWidget/Assets/StoreLogo.scale-100.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
XboxGameBarWidget/Assets/Wide310x150Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 8 KiB |
16
XboxGameBarWidget/MainPage.xaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<Page
|
||||
x:Class="SteamDeckToolsGameBarWidget.MainPage"
|
||||
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="using:SteamDeckToolsGameBarWidget"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Padding="16">
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="Open Xbox Game Bar (Win+G), then add 'Performance Overlay Control' from the widget list." />
|
||||
</Grid>
|
||||
</Page>
|
||||
12
XboxGameBarWidget/MainPage.xaml.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SteamDeckToolsGameBarWidget
|
||||
{
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
112
XboxGameBarWidget/Package.appxmanifest
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
IgnorableNamespaces="uap uap3 mp">
|
||||
|
||||
<Identity
|
||||
Name="SteamDeckToolsGameBarWidget"
|
||||
Publisher="CN=SteamDeckTools"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="5b2bd271-f8d5-43d8-8fe8-56c4f57c44ee" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Steam Deck Tools Game Bar Widget</DisplayName>
|
||||
<PublisherDisplayName>SteamDeckTools</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.26100.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application
|
||||
Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="SteamDeckToolsGameBarWidget.App">
|
||||
<uap:VisualElements
|
||||
DisplayName="Steam Deck Tools Game Bar Widget"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||
Description="Control Steam Deck Tools PerformanceOverlay modes from Xbox Game Bar."
|
||||
BackgroundColor="transparent">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square71x71Logo="Assets\SmallTile.png" Square310x310Logo="Assets\LargeTile.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension
|
||||
Name="microsoft.gameBarUIExtension"
|
||||
Id="PerformanceOverlayControl"
|
||||
DisplayName="Performance Overlay Control"
|
||||
Description="Quickly switch PerformanceOverlay views."
|
||||
PublicFolder="GameBar">
|
||||
<uap3:Properties>
|
||||
<GameBarWidget Type="Standard">
|
||||
<HomeMenuVisible>true</HomeMenuVisible>
|
||||
<PinningSupported>true</PinningSupported>
|
||||
<Window>
|
||||
<Size>
|
||||
<Height>330</Height>
|
||||
<Width>420</Width>
|
||||
<MinHeight>240</MinHeight>
|
||||
<MinWidth>320</MinWidth>
|
||||
<MaxHeight>500</MaxHeight>
|
||||
<MaxWidth>700</MaxWidth>
|
||||
</Size>
|
||||
<ResizeSupported>
|
||||
<Horizontal>true</Horizontal>
|
||||
<Vertical>true</Vertical>
|
||||
</ResizeSupported>
|
||||
</Window>
|
||||
</GameBarWidget>
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Extensions>
|
||||
<!-- Required for Game Bar metadata-based marshaling interfaces. -->
|
||||
<Extension Category="windows.activatableClass.proxyStub">
|
||||
<ProxyStub ClassId="00000355-0000-0000-C000-000000000046">
|
||||
<Path>Microsoft.Gaming.XboxGameBar.winmd</Path>
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarAppTargetHost" InterfaceId="38CDC43C-0A0E-4B3B-BBD3-A581AE220D53" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarAppTargetInfo" InterfaceId="D7689E93-5587-47D1-A42E-78D16B2FA807" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarActivityHost" InterfaceId="2B113C9B-E370-49B2-A20B-83E0F5737577" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarHotkeyManagerHost" InterfaceId="F6225A53-B34C-4833-9511-AA377B43316F" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetAuthHost" InterfaceId="DC263529-B12F-469E-BB35-B94069F5B15A" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetControlHost" InterfaceId="C309CAC7-8435-4082-8F37-784523747047" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetForegroundWorkerHost" InterfaceId="DDB52B57-FA83-420C-AFDE-6FA556E18B83" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetForegroundWorkerPrivate" InterfaceId="42BACDFC-BB28-4E71-99B4-24C034C7B7E0" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarNavigationKeyCombo" InterfaceId="5EEA3DBF-09BB-42A5-B491-CF561E33C172" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetActivatedEventArgsPrivate" InterfaceId="782535A7-9407-4572-BFCB-316B4086F102" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost" InterfaceId="5D12BC93-212B-4B9F-9091-76B73BF56525" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost2" InterfaceId="28717C8B-D8E8-47A8-AF47-A1D5263BAE9B" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost3" InterfaceId="3F5A3F12-C1E4-4942-B80D-3117BC948E29" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost4" InterfaceId="FA696D9E-2501-4B01-B26F-4BB85344740F" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost5" InterfaceId="A6C878CC-2B08-4B94-B1C3-222C6A913F3C" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetHost6" InterfaceId="CE6F0D73-C44F-4BBD-9652-A0FC52C37A34" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetNotificationHost" InterfaceId="6F68D392-E4A9-46F7-A024-5275BC2FE7BA" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetNotificationPrivate" InterfaceId="C94C8DC8-C8B5-4560-AF6E-A588B558213A" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetPrivate" InterfaceId="22ABA97F-FB0F-4439-9BDD-2C67B2D5AA8F" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetPrivate2" InterfaceId="B2F7DB8C-7540-48DA-9B46-4E60CE0D9DEB" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetPrivate3" InterfaceId="4FB89FB6-7CB8-489D-8408-2269E6C733A1" />
|
||||
<Interface Name="Microsoft.Gaming.XboxGameBar.Private.IXboxGameBarWidgetPrivate4" InterfaceId="5638D65A-3733-48CC-90E5-984688D62786" />
|
||||
</ProxyStub>
|
||||
</Extension>
|
||||
</Extensions>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
14
XboxGameBarWidget/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("SteamDeckToolsGameBarWidget")]
|
||||
[assembly: AssemblyDescription("Xbox Game Bar widget controls for Steam Deck Tools PerformanceOverlay.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SteamDeckToolsGameBarWidget")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2026")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
||||
5
XboxGameBarWidget/Properties/Default.rd.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
</Application>
|
||||
</Directives>
|
||||
159
XboxGameBarWidget/SteamDeckToolsGameBarWidget.csproj
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{4E1DE235-5D8B-4ED9-B4AE-2D6B3E5C4E6A}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SteamDeckToolsGameBarWidget</RootNamespace>
|
||||
<AssemblyName>SteamDeckToolsGameBarWidget</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.22621.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<AppxPackageSigningEnabled>False</AppxPackageSigningEnabled>
|
||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
|
||||
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||
<AppxBundle>Never</AppxBundle>
|
||||
<AppxBundlePlatforms>x64|arm64</AppxBundlePlatforms>
|
||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
|
||||
<OutputPath>bin\ARM64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetPage.xaml.cs">
|
||||
<DependentUpon>WidgetPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\LargeTile.scale-100.png" />
|
||||
<Content Include="Assets\SmallTile.scale-100.png" />
|
||||
<Content Include="Assets\SplashScreen.scale-100.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-100.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-100.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.scale-100.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-100.png" />
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WidgetPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Gaming.XboxGameBar">
|
||||
<Version>7.2.240903001</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.2.9</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<XboxGameBar-Platform Condition="'$(Platform)' == 'x86'">win32</XboxGameBar-Platform>
|
||||
<XboxGameBar-Platform Condition="'$(Platform)' != 'x86'">$(Platform)</XboxGameBar-Platform>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
</Project>
|
||||
68
XboxGameBarWidget/WidgetPage.xaml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<Page
|
||||
x:Class="SteamDeckToolsGameBarWidget.WidgetPage"
|
||||
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="using:SteamDeckToolsGameBarWidget"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="#15181F">
|
||||
<StackPanel Margin="12">
|
||||
<TextBlock
|
||||
Margin="0,0,0,8"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="White"
|
||||
Text="Performance Overlay" />
|
||||
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="0" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/fps">FPS</Button>
|
||||
<Button Grid.Row="0" Grid.Column="1" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/fpswithbattery">FPS + Battery</Button>
|
||||
<Button Grid.Row="0" Grid.Column="2" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/battery">Battery</Button>
|
||||
|
||||
<Button Grid.Row="1" Grid.Column="0" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/minimal">Minimal</Button>
|
||||
<Button Grid.Row="1" Grid.Column="1" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/detail">Detail</Button>
|
||||
<Button Grid.Row="1" Grid.Column="2" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/full">Full</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://show">Show</Button>
|
||||
<Button Grid.Column="1" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://hide">Hide</Button>
|
||||
<Button Grid.Column="2" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://toggle">Toggle</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://cycle">Cycle</Button>
|
||||
<Button Grid.Column="1" Margin="2" Click="CommandButton_Click" Tag="steamdecktools-performanceoverlay://mode/fps">Quick Reset</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
x:Name="StatusText"
|
||||
Foreground="#B7C7D6"
|
||||
Text="Requires PerformanceOverlay running at least once to register the URI protocol."
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
42
XboxGameBarWidget/WidgetPage.xaml.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SteamDeckToolsGameBarWidget
|
||||
{
|
||||
public sealed partial class WidgetPage : Page
|
||||
{
|
||||
public WidgetPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void CommandButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var button = sender as Button;
|
||||
if (button == null || !(button.Tag is string))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var targetUri = (string)button.Tag;
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(targetUri, UriKind.Absolute, out uri))
|
||||
{
|
||||
StatusText.Text = "Invalid command URI.";
|
||||
return;
|
||||
}
|
||||
|
||||
bool launched = await Launcher.LaunchUriAsync(uri);
|
||||
StatusText.Text = launched
|
||||
? "Sent command: " + button.Content
|
||||
: "Unable to launch command URI. Start PerformanceOverlay first.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText.Text = "Failed to send command: " + ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,27 @@ It currently registers two global hotkeys:
|
|||
- **Shift+F11** - enable performance overlay
|
||||
- **Alt+Shift+F11** - cycle to next performance overlay (and enable it)
|
||||
|
||||
It also supports command URIs (used by the Xbox Game Bar widget in this fork):
|
||||
|
||||
- `steamdecktools-performanceoverlay://mode/fps`
|
||||
- `steamdecktools-performanceoverlay://mode/fpswithbattery`
|
||||
- `steamdecktools-performanceoverlay://mode/battery`
|
||||
- `steamdecktools-performanceoverlay://mode/minimal`
|
||||
- `steamdecktools-performanceoverlay://mode/detail`
|
||||
- `steamdecktools-performanceoverlay://mode/full`
|
||||
- `steamdecktools-performanceoverlay://cycle`
|
||||
- `steamdecktools-performanceoverlay://show`
|
||||
- `steamdecktools-performanceoverlay://hide`
|
||||
- `steamdecktools-performanceoverlay://toggle`
|
||||
|
||||
Equivalent command-line switches are available:
|
||||
|
||||
- `--mode <fps|fpswithbattery|battery|minimal|detail|full>`
|
||||
- `--cycle`
|
||||
- `--show`
|
||||
- `--hide`
|
||||
- `--toggle`
|
||||
|
||||
There are 5 modes of presentation:
|
||||
|
||||
## 1. FPS
|
||||
|
|
|
|||
|
|
@ -30,5 +30,5 @@ if ($lastVer) {
|
|||
}
|
||||
echo "nextVer: $nextVer"
|
||||
|
||||
dotnet --list-sdks -or winget install Microsoft.DotNet.SDK.6
|
||||
dotnet --list-sdks -or winget install Microsoft.DotNet.SDK.8
|
||||
dotnet build PerformanceOverlay/PerformanceOverlay.csproj --configuration "$configuration" "/property:Version=$nextVer" --output "$path"
|
||||
|
|
|
|||
66
scripts/install_gamebar_widget.ps1
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$PackagePath,
|
||||
|
||||
[switch]$ForceReinstall
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $PackagePath)) {
|
||||
throw "PackagePath not found: $PackagePath"
|
||||
}
|
||||
|
||||
$tempExtractDir = $null
|
||||
|
||||
try {
|
||||
$packageItem = Get-Item -LiteralPath $PackagePath
|
||||
if (-not $packageItem.PSIsContainer -and $packageItem.Extension -eq ".zip") {
|
||||
$tempExtractDir = Join-Path ([System.IO.Path]::GetTempPath()) ("sdt-widget-install-" + [System.Guid]::NewGuid().ToString("N"))
|
||||
New-Item -ItemType Directory -Path $tempExtractDir -Force | Out-Null
|
||||
Expand-Archive -Path $packageItem.FullName -DestinationPath $tempExtractDir -Force
|
||||
$packageItem = Get-Item -LiteralPath $tempExtractDir
|
||||
}
|
||||
|
||||
if ($packageItem.PSIsContainer) {
|
||||
$packageItem = Get-ChildItem -LiteralPath $packageItem.FullName -Recurse -File |
|
||||
Where-Object { $_.Extension -in ".msix", ".appx", ".msixbundle", ".appxbundle" } |
|
||||
Sort-Object LastWriteTime -Descending |
|
||||
Select-Object -First 1
|
||||
}
|
||||
|
||||
if (-not $packageItem) {
|
||||
throw "No .msix/.appx package was found under '$PackagePath'."
|
||||
}
|
||||
|
||||
$identityName = "SteamDeckToolsGameBarWidget"
|
||||
$installedPackage = Get-AppxPackage -Name $identityName -ErrorAction SilentlyContinue
|
||||
|
||||
if ($ForceReinstall -and $installedPackage) {
|
||||
Write-Host "Removing existing package: $($installedPackage.PackageFullName)"
|
||||
Remove-AppxPackage -Package $installedPackage.PackageFullName
|
||||
}
|
||||
|
||||
Write-Host "Installing package: $($packageItem.FullName)"
|
||||
|
||||
try {
|
||||
Add-AppxPackage `
|
||||
-Path $packageItem.FullName `
|
||||
-ForceUpdateFromAnyVersion `
|
||||
-ForceApplicationShutdown `
|
||||
-AllowUnsigned
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "Install failed. If this is an unsigned package, enable Developer Mode in Windows:"
|
||||
Write-Host "Settings > Privacy & security > For developers > Developer Mode"
|
||||
throw
|
||||
}
|
||||
|
||||
Write-Host "Installed. Open Xbox Game Bar (Win+G), click Widget Menu, then add 'Performance Overlay Control'."
|
||||
}
|
||||
finally {
|
||||
if ($tempExtractDir -and (Test-Path -LiteralPath $tempExtractDir)) {
|
||||
Remove-Item -LiteralPath $tempExtractDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@ cd "%~dp0\.."
|
|||
:retry
|
||||
|
||||
taskkill /F /IM "%2.exe"
|
||||
del %2\bin\Debug\net6.0-windows\%2.exe
|
||||
del %2\bin\Debug\net8.0-windows\%2.exe
|
||||
|
||||
dotnet build %2\%2.csproj
|
||||
%2\bin\Debug\net6.0-windows\%2.exe
|
||||
%2\bin\Debug\net8.0-windows\%2.exe
|
||||
|
||||
timeout /t 3
|
||||
goto retry
|
||||
|
|
|
|||