diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md
index c9f9a57..4a7cc71 100644
--- a/CHANGELOG.en-US.md
+++ b/CHANGELOG.en-US.md
@@ -4,6 +4,12 @@ English (US) release notes, mirroring CHANGELOG.md (Brazilian Portuguese). Befor
## [Unreleased]
+## [1.6.0-alpha.5]
+
+### Fixes
+- Console screen: read DualShock input directly over HID; overlay: navigate from the sidebar to windows, remove the cards' X button and display the ControlFS logo. (#130)
+
+
## [1.6.0-alpha.4]
### What's new
- Settings → TV: console mode turns a Google TV / Android TV on over the network and switches to the PC's HDMI input; it can also put the TV in standby on restore. (#126)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d07ad44..5074c8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ Notas em português do Brasil; a versão em inglês (Estados Unidos) fica em `CH
## [Unreleased]
+## [1.6.0-alpha.5]
+
+### Correções
+- Tela Console: leitura direta do DualShock por HID; overlay: navegação da lateral para as janelas, remoção do X dos cartões e logo do ControlFS. (#130)
+
+
## [1.6.0-alpha.4]
### Novidades
- Ajustes → TV: o modo console liga a Google TV / Android TV pela rede e troca para a entrada HDMI do PC; também pode colocá-la em espera ao restaurar. (#126)
diff --git a/docs/TESTING.md b/docs/TESTING.md
index 5ccaa57..6918d61 100644
--- a/docs/TESTING.md
+++ b/docs/TESTING.md
@@ -321,3 +321,16 @@ Pré-condições: 1.6 instalada por cima da 1.5, com a configuração da 1.5 (te
- [ ] Playnite lento para abrir (troca a janela de carregamento pela principal): o app não volta ao PC sozinho e só restaura a mesa quando o Playnite fecha. Resultado: ______
- [ ] Fechar o app no meio da sessão e abrir de novo: "Restaurar setup" traz a mesa de volta a partir do backup. Resultado: ______
- [ ] Um backup da mesa feito pela 1.5 (sessão iniciada na 1.5, app atualizado antes de restaurar) é restaurado pela 1.6. Resultado: ______
+
+## Regressão: DualShock e navegação entre painéis do menu
+
+- [ ] DualShock 4 por USB, sem DS4Windows/Steam Input: na tela Console, D-pad e analógico movem o foco; ✕ confirma, ○ volta e L1/R1 trocam abas. Resultado: ______
+- [ ] Repetir por Bluetooth e com Steam Input/DS4Windows ligado: cada toque produz uma única ação, sem movimento em repouso. Resultado: ______
+- [ ] Com um Xbox também conectado, repetir a navegação com o DualShock. Resultado: ______
+- [ ] Reconectar o DualShock com a tela Console aberta: a navegação volta a responder. Resultado: ______
+- [ ] Durante o jogo, Share + △ (Select + Y) abre o overlay; → em uma opção lateral leva ao primeiro cartão de janela e ✕ ativa a janela escolhida. Resultado: ______
+- [ ] No primeiro cartão de uma coluna, ← retorna à opção lateral de origem; ↑/↓ e ←/→ navegam pelos demais cartões, inclusive com rolagem. Resultado: ______
+- [ ] Com seletor de sessão ou confirmação de fechamento aberto, as direções ficam dentro do diálogo. Sem janelas abertas, → não perde o foco. Resultado: ______
+- [ ] Os cartões não exibem o botão X no canto. Quadrado/Delete continuam pedindo confirmação para fechar a janela selecionada. Resultado: ______
+- [ ] A logo fornecida do ControlFS aparece no painel fixo do overlay, tanto instalado quanto ausente, inclusive no aplicativo publicado. Resultado: ______
+- [ ] Com overlay aberto ou outro aplicativo em primeiro plano, a tela Console ao fundo não reage ao DualShock. Resultado: ______
diff --git a/src/ConsoleMode/Assets/OtherApps/controlfs.png b/src/ConsoleMode/Assets/OtherApps/controlfs.png
new file mode 100644
index 0000000..22bf8a3
Binary files /dev/null and b/src/ConsoleMode/Assets/OtherApps/controlfs.png differ
diff --git a/src/ConsoleMode/ConsoleMode.csproj b/src/ConsoleMode/ConsoleMode.csproj
index 3be7fbb..1be9ad6 100644
--- a/src/ConsoleMode/ConsoleMode.csproj
+++ b/src/ConsoleMode/ConsoleMode.csproj
@@ -17,10 +17,10 @@
truelatestx64
- 1.6.0-alpha.4
+ 1.6.0-alpha.51.6.0.01.6.0.0
- 1.6.0-alpha.4
+ 1.6.0-alpha.5Console ModeConsole Modelippdev
diff --git a/src/ConsoleMode/SessionMenuWindow.xaml b/src/ConsoleMode/SessionMenuWindow.xaml
index 5865272..0029b48 100644
--- a/src/ConsoleMode/SessionMenuWindow.xaml
+++ b/src/ConsoleMode/SessionMenuWindow.xaml
@@ -142,7 +142,9 @@
-
+
+
+
@@ -293,11 +295,6 @@
-
diff --git a/src/ConsoleMode/SessionMenuWindow.xaml.cs b/src/ConsoleMode/SessionMenuWindow.xaml.cs
index f74a4b3..be3ca35 100644
--- a/src/ConsoleMode/SessionMenuWindow.xaml.cs
+++ b/src/ConsoleMode/SessionMenuWindow.xaml.cs
@@ -93,6 +93,15 @@ public SessionMenuWindow(MainViewModel viewModel, ScreenRect? target)
UiSounds.Play(UiSound.Move);
return true;
}
+ // Cross into the grid explicitly; spatial focus may prefer another sidebar row.
+ if (!_editingVolume && direction == FocusNavigationDirection.Right && !ViewModel.IsSessionPickerOpen
+ && Root.XamlRoot is { } root
+ && FocusManager.GetFocusedElement(root) is DependencyObject focused
+ && IsInside(SidebarPanel, focused) && FocusFirstWindowCard())
+ {
+ UiSounds.Play(UiSound.Move);
+ return true;
+ }
if (!_editingVolume) return false;
if (direction == FocusNavigationDirection.Left) { ViewModel.ChangeVolume(-1); UiSounds.Play(UiSound.Move); }
else if (direction == FocusNavigationDirection.Right) { ViewModel.ChangeVolume(1); UiSounds.Play(UiSound.Move); }
@@ -177,6 +186,8 @@ public SessionMenuWindow(MainViewModel viewModel, ScreenRect? target)
{
ScaleFocused(e.OriginalSource, grow: true);
if (e.OriginalSource is Control focused && IsInside(SidebarPanel, focused)) _lastSidebarFocus = focused;
+ if (e.OriginalSource is FrameworkElement { DataContext: SwitchWindowItem } card)
+ card.StartBringIntoView();
};
Root.LostFocus += (_, e) => ScaleFocused(e.OriginalSource, grow: false);
// Mouse clicks sound like a confirm (the pad has its own sounds in the navigator).
@@ -448,6 +459,23 @@ private DependencyObject RegionOfFocus()
return Root;
}
+ /// Enter the windows grid even when spatial focus cannot reach it from the sidebar.
+ private bool FocusFirstWindowCard()
+ {
+ SwitcherList.UpdateLayout();
+ for (var i = 0; i < ViewModel.SwitcherWindows.Count; i++)
+ {
+ if (SwitcherList.ContainerFromIndex(i) is { } container
+ && FocusManager.FindFirstFocusableElement(container) is Control card
+ && card.Focus(FocusState.Keyboard))
+ {
+ card.StartBringIntoView();
+ return true;
+ }
+ }
+ return false;
+ }
+
/// True when the focus is on a window card with no card to its left (the first column of the grid).
private bool IsOnLeftmostCard()
{
@@ -504,12 +532,6 @@ private async void ConfirmCloseClick(object sender, RoutedEventArgs e)
private void CancelCloseClick(object sender, RoutedEventArgs e) => CancelCloseConfirmation();
- private void CloseCardClick(object sender, RoutedEventArgs e)
- {
- if (sender is FrameworkElement { DataContext: SwitchWindowItem item })
- ShowCloseConfirmation(item, ViewModel.SwitcherWindows.IndexOf(item));
- }
-
/// Keep focus on the target while the close request is pending, then move to a neighbor if it closes.
private async Task CloseAndRefocusAsync(SwitchWindowItem item, int index)
{
diff --git a/src/ConsoleMode/ViewModels/MainViewModel.OtherApps.cs b/src/ConsoleMode/ViewModels/MainViewModel.OtherApps.cs
index 29f5415..97e824d 100644
--- a/src/ConsoleMode/ViewModels/MainViewModel.OtherApps.cs
+++ b/src/ConsoleMode/ViewModels/MainViewModel.OtherApps.cs
@@ -13,9 +13,11 @@ public partial class MainViewModel
{
private ImageSource? _wakeOnLogo;
private ImageSource? _nextBoostLogo;
+ private ImageSource? _controlFsLogo;
public ImageSource? WakeOnLogo => _wakeOnLogo ??= LoadLogo("wakeon.png");
public ImageSource? NextBoostLogo => _nextBoostLogo ??= LoadLogo("nextboost.png");
+ public ImageSource? ControlFsLogo => _controlFsLogo ??= LoadLogo("controlfs.png");
/// Embedded, so the installed and portable builds need no loose files.
private static BitmapImage? LoadLogo(string file)
diff --git a/src/ConsoleMode/Views/ConsoleHomeView.xaml.cs b/src/ConsoleMode/Views/ConsoleHomeView.xaml.cs
index dedf5a1..498442e 100644
--- a/src/ConsoleMode/Views/ConsoleHomeView.xaml.cs
+++ b/src/ConsoleMode/Views/ConsoleHomeView.xaml.cs
@@ -64,7 +64,8 @@ private async Task PickBackgroundImageAsync()
private void OnLoaded(object sender, RoutedEventArgs e)
{
_navigator ??= new GamepadNavigator(DispatcherQueue, this,
- App.MainWindowInstance is { } w ? WinRT.Interop.WindowNative.GetWindowHandle(w) : 0);
+ App.MainWindowInstance is { } w ? WinRT.Interop.WindowNative.GetWindowHandle(w) : 0,
+ readSonyHid: true);
_navigator.SearchRoot = () =>
ViewModel.IsControllerTestOpen ? ControllerTestPanel
: ViewModel.IsConsoleTutorialOpen ? ConsoleTutorialPanel