fix: keep initial playback focus off the titlebar pin
Restore the playback window as first responder after initial setup and after file/YouTube dialogs return. Keep native control focus indicators and Tab navigation unchanged. Verified hidden native window focus, both dialog cancellations, explicit control focus, Tab navigation, P shortcut, app build, and compact-window checks.
This commit is contained in:
@@ -53,6 +53,8 @@ Drag the compact video to move the window; on release, each axis snaps independe
|
|||||||
|
|
||||||
Single-key shortcuts apply only to the playback window and do not intercept text editing, file-picker input, or Command/Control/Option combinations. Held toggle keys do not repeatedly toggle; held `J`/`L` continue seeking and held `,`/`.` continue stepping. `C` captions remains unbound.
|
Single-key shortcuts apply only to the playback window and do not intercept text editing, file-picker input, or Command/Control/Option combinations. Held toggle keys do not repeatedly toggle; held `J`/`L` continue seeking and held `,`/`.` continue stepping. `C` captions remains unbound.
|
||||||
|
|
||||||
|
Initial window setup and returning from the file/YouTube dialogs leave keyboard focus on playback rather than automatically highlighting the titlebar pin. Tab navigation and native focus indicators remain available when choosing controls explicitly.
|
||||||
|
|
||||||
Frame stepping uses decoded presentation timestamps, not an average-FPS time offset, including variable-frame-rate video and reordered B-frames. Steps start from the displayed frame, stop at the first/last frame, and keep the timeline paused. Consecutive same-direction repeats share one counted queue entry without skipping frames or reordering seeks/direction changes. The last presented image remains visible during decoder preroll and queued steps; the progress thumb follows each authoritative stepped position. Opening/closing media still clears the old image. Audio-only files disable stepping; normal playback resumes with audio synchronized to the selected frame.
|
Frame stepping uses decoded presentation timestamps, not an average-FPS time offset, including variable-frame-rate video and reordered B-frames. Steps start from the displayed frame, stop at the first/last frame, and keep the timeline paused. Consecutive same-direction repeats share one counted queue entry without skipping frames or reordering seeks/direction changes. The last presented image remains visible during decoder preroll and queued steps; the progress thumb follows each authoritative stepped position. Opening/closing media still clears the old image. Audio-only files disable stepping; normal playback resumes with audio synchronized to the selected frame.
|
||||||
|
|
||||||
- Existing shortcuts remain: **⌘O** opens files, **←/→** seeks five seconds, **↑/↓** adjusts volume by five percent, **⌃⌘F** toggles fullscreen, and **Esc** leaves fullscreen. Double-clicking normal-mode video also toggles fullscreen.
|
- Existing shortcuts remain: **⌘O** opens files, **←/→** seeks five seconds, **↑/↓** adjusts volume by five percent, **⌃⌘F** toggles fullscreen, and **Esc** leaves fullscreen. Double-clicking normal-mode video also toggles fullscreen.
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
|
|
||||||
func openPanel() {
|
func openPanel() {
|
||||||
guard canOpen else { return }
|
guard canOpen else { return }
|
||||||
|
defer { window?.makeFirstResponder(nil) }
|
||||||
revealControls()
|
revealControls()
|
||||||
let panel = NSOpenPanel()
|
let panel = NSOpenPanel()
|
||||||
panel.canChooseFiles = true
|
panel.canChooseFiles = true
|
||||||
@@ -97,6 +98,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
|
|
||||||
func openYouTubePanel() {
|
func openYouTubePanel() {
|
||||||
guard canOpen else { return }
|
guard canOpen else { return }
|
||||||
|
defer { window?.makeFirstResponder(nil) }
|
||||||
revealControls()
|
revealControls()
|
||||||
let alert = NSAlert()
|
let alert = NSAlert()
|
||||||
alert.messageText = "Open YouTube Video"
|
alert.messageText = "Open YouTube Video"
|
||||||
@@ -1030,6 +1032,7 @@ private struct WindowChrome: NSViewRepresentable {
|
|||||||
guard let self, let window else { return }
|
guard let self, let window else { return }
|
||||||
self.model.attachWindow(window)
|
self.model.attachWindow(window)
|
||||||
self.updateButtons()
|
self.updateButtons()
|
||||||
|
window.makeFirstResponder(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user