Merge pull request #13 from atomsk-0/controllerSupport

Added basic controller navigation support
This commit is contained in:
Dexrn ZacAttack
2025-03-04 05:38:29 -08:00
committed by GitHub
5 changed files with 191 additions and 32 deletions

View File

@@ -8,7 +8,7 @@
mc:Ignorable="d"
Margin="10, 10, 10, 10"
>
<Button Width="320" Height="180" Padding="0" Name="startButton" CornerRadius="5, 5, 0, 0" BorderThickness="0" Background="{ThemeResource SystemControlAltLowAcrylicElementBrush}" >
<Button Width="320" Height="180" Padding="0" x:Name="startButton" CornerRadius="5, 5, 0, 0" BorderThickness="0" Background="{ThemeResource SystemControlAltLowAcrylicElementBrush}" >
<Image x:Name="appLogo"/>
</Button>
<Expander CornerRadius="0, 0, 5, 5" Width="320" Name="infoExpander" Background="{ThemeResource DesktopAcrylicTransparentBrush}">

View File

@@ -26,6 +26,8 @@ namespace WinDurango.UI.Controls
private string _Publisher;
private string _Version;
private Uri _Logo;
private AppListEntry appListEntry;
private async void HandleUnregister(object sender, SplitButtonClickEventArgs e)
{
@@ -200,19 +202,19 @@ namespace WinDurango.UI.Controls
catch
{
Logger.WriteWarning($"Could not get the applist entries of \"{_Name}\"");
}
AppListEntry firstAppListEntry = appListEntries?.FirstOrDefault() ?? null;
}
appListEntry = appListEntries?.FirstOrDefault() ?? null;
if (firstAppListEntry == null)
if (appListEntry == null)
Logger.WriteWarning($"Could not get the applist entry of \"{_Name}\"");
if (String.IsNullOrEmpty(ss) || !File.Exists(ss))
{
try
{
if (firstAppListEntry != null)
if (appListEntry != null)
{
RandomAccessStreamReference logoStream = firstAppListEntry.DisplayInfo.GetLogo(new Size(320, 180));
RandomAccessStreamReference logoStream = appListEntry.DisplayInfo.GetLogo(new Size(320, 180));
BitmapImage logoImage = new();
using IRandomAccessStream stream = logoStream.OpenReadAsync().GetAwaiter().GetResult();
logoImage.SetSource(stream);
@@ -275,24 +277,28 @@ namespace WinDurango.UI.Controls
rcFlyout.ShowAt(sender as FrameworkElement, e.GetPosition(sender as UIElement));
};
startButton.Tapped += async (s, e) =>
startButton.Tapped += (_, _) => StartApp();
}
public async void StartApp()
{
if (_package.Status.LicenseIssue)
{
if (_package.Status.LicenseIssue)
{
Logger.WriteError($"Could not launch {_Name} due to licensing issue.");
_ = new NoticeDialog($"There is a licensing issue... Do you own this package?", $"Could not launch {_Name}").ShowAsync();
return;
}
Logger.WriteError($"Could not launch {_Name} due to licensing issue.");
_ = new NoticeDialog($"There is a licensing issue... Do you own this package?", $"Could not launch {_Name}").ShowAsync();
return;
}
if (firstAppListEntry == null)
{
_ = new NoticeDialog($"Could not get the applist entry of \"{_Name}\"", $"Could not launch {_Name}").ShowAsync();
return;
}
Logger.WriteInformation($"Launching {_Name}");
if (await firstAppListEntry.LaunchAsync() == false)
_ = new NoticeDialog($"Failed to launch \"{_Name}\"!", $"Could not launch {_Name}").ShowAsync();
};
if (appListEntry == null)
{
_ = new NoticeDialog($"Could not get the applist entry of \"{_Name}\"", $"Could not launch {_Name}").ShowAsync();
return;
}
Logger.WriteInformation($"Launching {_Name}");
if (await appListEntry.LaunchAsync() == false)
_ = new NoticeDialog($"Failed to launch \"{_Name}\"!", $"Could not launch {_Name}").ShowAsync();
}
}
}

View File

@@ -102,9 +102,18 @@ namespace WinDurango.UI
if (String.IsNullOrEmpty(FSHelper.FindFileOnPath("vcruntime140d.dll")))
missing.Add("Microsoft Visual C++ Redistributable", null);
var devNotice = new NoticeDialog($"This UI is very early in development, and mainly developed by a C# learner... There WILL be bugs, and some things will NOT work...\n\nDevelopers, check Readme.md in the repo for the todolist.", "Important");
await devNotice.ShowAsync();
if (App.Settings.Settings.ShowDevNotice)
{
var devNotice = new NoticeDialog("This UI is very early in development, and mainly developed by a C# learner... There WILL be bugs, and some things will NOT work...\n\nDevelopers, check Readme.md in the repo for the todolist.", "Important");
await devNotice.ShowAsync();
// We only show this notification once from now on
Settings.Set("ShowDevNotice", false);
Settings.Save();
}
if (missing.Count != 0)
{
// todo: properly provide download link

View File

@@ -8,6 +8,8 @@ using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.Foundation;
using Windows.Gaming.Input;
using Windows.Management.Deployment;
using Windows.Storage;
using Windows.Storage.Pickers;
@@ -21,6 +23,12 @@ namespace WinDurango.UI.Pages
{
public sealed partial class AppsListPage : Page
{
private Gamepad gamepad;
private int currentIndex;
private Point currentPoint = new(0, 0);
private bool inputProcessed = true;
private long lastInput;
public async Task InitAppListAsync()
{
appList.Children.Clear();
@@ -138,14 +146,148 @@ namespace WinDurango.UI.Pages
InitializeComponent();
_ = InitAppListAsync();
// All this is useless now basically... because InitAppListAsync now runs asynchronously (not blocking the ui thread)
/*
Stopwatch PlatinumWatch = new Stopwatch();
Logger.WriteDebug("Initializing AppsListPage...");
PlatinumWatch.Start();
PlatinumWatch.Stop();
Logger.WriteDebug("Initialized AppsListPage in {0:D2}:{1:D2}:{2:D2}.{3:D3}", (int)PlatinumWatch.Elapsed.TotalHours, (int)PlatinumWatch.Elapsed.TotalMinutes, (int)PlatinumWatch.Elapsed.TotalSeconds, (int)PlatinumWatch.Elapsed.TotalMilliseconds);
*/
Loaded += OnAppListPage_Loaded;
}
private void OnAppListPage_Loaded(object sender, RoutedEventArgs e)
{
Gamepad.GamepadAdded += onGamepadAdded;
Gamepad.GamepadRemoved += OnGamepadRemoved;
}
private void OnGamepadRemoved(object sender, Gamepad e)
{
gamepad = null;
}
private void onGamepadAdded(object sender, Gamepad e)
{
gamepad = e;
ListenGamepadInput();
this.DispatcherQueue.TryEnqueue(() =>
{
if (appList.Children.Count > 0)
{
appList.Children[currentIndex].Focus(FocusState.Keyboard);
}
});
}
private async void ListenGamepadInput()
{
while (gamepad != null)
{
GamepadReading gamepadInput = gamepad.GetCurrentReading();
bool moveRight = gamepadInput.LeftThumbstickX > 0.5 || (gamepadInput.Buttons & GamepadButtons.DPadRight) != 0;
bool moveLeft = gamepadInput.LeftThumbstickX < -0.5 || (gamepadInput.Buttons & GamepadButtons.DPadLeft) != 0;
bool moveUp = gamepadInput.LeftThumbstickY > 0.5 || (gamepadInput.Buttons & GamepadButtons.DPadUp) != 0;
bool moveDown = gamepadInput.LeftThumbstickY < -0.5 || (gamepadInput.Buttons & GamepadButtons.DPadDown) != 0;
bool actionClicked = (gamepadInput.Buttons & GamepadButtons.A) != 0;
if (actionClicked && inputProcessed)
{
inputProcessed = false;
this.DispatcherQueue.TryEnqueue(() =>
{
var appTile = appList.Children[currentIndex] as AppTile;
appTile.StartApp();
inputProcessed = true;
});
}
if ((moveRight || moveLeft || moveUp || moveDown) && inputProcessed)
{
inputProcessed = false;
if (moveRight) this.DispatcherQueue.TryEnqueue(() => MoveFocus(1, 0));
else if (moveLeft) this.DispatcherQueue.TryEnqueue(() => MoveFocus(-1, 0));
else if (moveUp) this.DispatcherQueue.TryEnqueue(() => MoveFocus(0, -1));
else if (moveDown) this.DispatcherQueue.TryEnqueue(() => MoveFocus(0, 1));
}
await Task.Delay(100);
}
}
private void MoveFocus(int xOffset, int yOffset)
{
bool firstInput = lastInput == 0;
if (lastInput > DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - 200)
{
inputProcessed = true;
return;
}
lastInput = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
if (appList.Children.Count == 0)
{
inputProcessed = true;
return;
}
// We only set focus first to the index 0 if ShowDevNotice was shown before as it cancels the initial focus done in Load event
if (firstInput && App.Settings.Settings.ShowDevNotice)
{
appList.Children[0].Focus(FocusState.Keyboard);
inputProcessed = true;
return;
}
int columns = GetColumnCount();
int rows = appList.Children.Count / columns;
int newX = (int)(currentPoint.X + xOffset);
int newY = (int)(currentPoint.Y + yOffset);
newX = Math.Clamp(newX, 0, columns - 1);
newY = Math.Clamp(newY, 0, rows - 1);
if (newX != currentPoint.X || newY != currentPoint.Y)
{
currentPoint = new Point(newX, newY);
currentIndex = newY * columns + newX;
if (currentIndex < appList.Children.Count)
{
appList.Children[currentIndex].Focus(FocusState.Keyboard);
}
}
inputProcessed = true;
}
// We need do this our self as WrapPanel doesn't have internal field or function to get current column amount
private int GetColumnCount()
{
if (appList.Children.Count == 0) return 1;
FrameworkElement firstItem = appList.Children[0] as FrameworkElement;
if (firstItem == null) return 1;
double firstItemTop = firstItem.TransformToVisual(appList).TransformPoint(new Point(0, 0)).Y;
int columnCount = 1;
for (int i = 1; i < appList.Children.Count; i++)
{
var item = appList.Children[i] as FrameworkElement;
if (item == null)
continue;
double itemTop = item.TransformToVisual(appList).TransformPoint(new Point(0, 0)).Y;
if (Math.Abs(itemTop - firstItemTop) < 1)
{
columnCount++;
}
else
{
break;
}
}
return columnCount;
}
private void SearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)

View File

@@ -32,6 +32,8 @@ public class UiConfigData
public string DownloadedWdVer { get; set; } = String.Empty;
public PatchSource DownloadSource { get; set; } = PatchSource.Release;
public bool ShowDevNotice { get; set; } = true;
}
// TODO: fix type init exception