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 @@ true latest x64 - 1.6.0-alpha.4 + 1.6.0-alpha.5 1.6.0.0 1.6.0.0 - 1.6.0-alpha.4 + 1.6.0-alpha.5 Console Mode Console Mode lippdev 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