@@ -11,6 +11,8 @@ import {
1111 ToolbarMenu ,
1212 settings ,
1313 sha256Hex ,
14+ isTv ,
15+ useRemoteNav ,
1416 type SaveState ,
1517} from ' @nes-emulator/player'
1618import { isTauri , pickRomFile , storage } from ' ./emulator/platform'
@@ -33,6 +35,23 @@ const inputLocked = computed(
3335 () => storeOpen .value || settingsOpen .value || savesOpen .value || helpOpen .value ,
3436)
3537
38+ // Android TV 遥控器:工具栏焦点导航。无模态、且(未载入或已暂停)时由工具栏接管方向键;
39+ // 游戏运行中则交还 NesScreen(方向键控制角色)。开机未载入时自动聚焦,解决"无入口"问题。
40+ const toolbarRef = ref <HTMLElement | null >(null )
41+ const toolbarNavActive = computed (
42+ () => isTv && ! inputLocked .value && (! romName .value || paused .value ),
43+ )
44+ useRemoteNav ({
45+ container: toolbarRef ,
46+ active: toolbarNavActive ,
47+ autoFocus: isTv ,
48+ priority: 0 ,
49+ })
50+ // 焦点环作用到全局(含 Teleport 到 body 的下拉菜单):给 <html> 标记 tv-nav。
51+ if (isTv && typeof document !== ' undefined' ) {
52+ document .documentElement .classList .add (' tv-nav' )
53+ }
54+
3655// 快捷键修饰键:桌面(Tauri)用 Ctrl,浏览器用 Shift(避开 Ctrl+L/N 等浏览器冲突)。
3756const modKey: ' ctrl' | ' shift' = isTauri ? ' ctrl' : ' shift'
3857const modLabel = isTauri ? ' Ctrl' : ' Shift'
@@ -133,8 +152,8 @@ function onSystemAction(action: string) {
133152 </script >
134153
135154<template >
136- <div class =" app" >
137- <header class =" toolbar" >
155+ <div class =" app" :class = " { 'tv-nav': isTv } " >
156+ <header ref = " toolbarRef " class =" toolbar" >
138157 <h1 class =" title" >NES/FC 模拟器</h1 >
139158 <div class =" spacer" />
140159 <button class =" btn" :disabled =" loading" @click =" openRom" >
@@ -180,7 +199,7 @@ function onSystemAction(action: string) {
180199 <main class =" stage" >
181200 <NesScreen
182201 ref="screen"
183- :input-locked =" inputLocked "
202+ :input-locked =" inputLocked || paused "
184203 :modifier =" modKey "
185204 :rom-key =" romKey "
186205 :rom-name =" romName "
@@ -192,6 +211,7 @@ function onSystemAction(action: string) {
192211 <footer class =" footer" >
193212 <span class =" keys" >键盘 {{ keyHint }}</span >
194213 <button class =" link-btn" @click =" helpOpen = true" >查看所有快捷键</button >
214+ <span v-if =" isTv" class =" tv-tip" >遥控器可操作菜单与基础游玩,完整体验建议连接蓝牙手柄</span >
195215 <span class =" meta" >{{ romName ?? '未载入' }} · {{ isTauri ? 'Tauri App' : '浏览器预览' }}</span >
196216 </footer >
197217 </div >
@@ -216,6 +236,20 @@ body {
216236 font-family : system-ui , -apple-system , ' Segoe UI' , sans-serif ;
217237 overflow : hidden ;
218238}
239+ /* Android TV 遥控器焦点环:仅 TV(<html>.tv-nav)启用,桌面键鼠不受影响。
240+ 补 :focus 兜底,因部分 Android WebView 对 button 不触发 :focus-visible。 */
241+ .tv-nav :focus-visible ,
242+ .tv-nav button :focus ,
243+ .tv-nav a :focus ,
244+ .tv-nav input :focus ,
245+ .tv-nav select :focus ,
246+ .tv-nav textarea :focus ,
247+ .tv-nav [tabindex ]:focus ,
248+ .tv-nav [data-nav ]:focus {
249+ outline : 3px solid #4ea1ff ;
250+ outline-offset : 2px ;
251+ border-radius : 6px ;
252+ }
219253 </style >
220254
221255<style scoped>
@@ -312,6 +346,9 @@ body {
312346 color : #777 ;
313347 margin-left : auto ;
314348}
349+ .footer .tv-tip {
350+ color : #6ab0ff ;
351+ }
315352.link-btn {
316353 border : none ;
317354 background : transparent ;
0 commit comments