fix: negotiate modified Return keyboard reporting

This commit is contained in:
2026-10-22 16:47:08 +02:00
parent acdd6dc3e9
commit 2279004e91
4 changed files with 31 additions and 2 deletions
+2
View File
@@ -73,6 +73,8 @@ Two or more checked videos launch `terebi --new-instance --queue-file '/private/
**Ctrl+Return** (`video.enqueue`) sends the same checked rows, or the hovered row when none are checked, to a running Terebi queue without replacing its current playback. The terminal must transmit the modified Return, or you can rebind the action. Enqueue always uses `terebi --enqueue --queue-file '/private/session/queue.json'`, even for one video, preserving independent per-item progress. If Terebi is not running, it starts with that queue. Plain Return still opens a new instance. These shortcuts do nothing on Miruro catalog titles or saved shows and do not submit text inputs.
Tubular requests the Kitty keyboard protocol's escape-code disambiguation for its entire terminal session and restores the previous mode on exit. Supporting terminals can then distinguish Ctrl+Return from plain Return. A terminal or multiplexer that does not support/forward this protocol may still send identical bytes for both; Tubular cannot distinguish them. In that case, configure another key, for example `[keys.video]` with `enqueue = "alt+e"`.
### Miruro browser
Choose **Miruro** at startup or use `--miruro` to start directly. Its interface is **catalog → series → episodes**, with a separate saved-show library organized by overlapping category tags, without YouTube's Search/Feed tabs or channel controls.
+2 -1
View File
@@ -128,7 +128,8 @@ The complete request is rejected on an identity already in the current queue, a
### Enqueue verification
- Tubular: `cargo fmt --all`, `cargo test --locked` (**233 passed**), `cargo build --locked` and built `--help`; Rust launcher diagnostics were clean.
- Actual YouTube and Miruro terminal interfaces: reverse-checked rows produced display-ordered enqueue manifests, cleared checks fell back to the hovered row, Ctrl/Super+Return and an F12 override worked, and plain Return still used `--new-instance --url`. Six handoffs used private `0600` manifests in `0700` session directories with distinct report destinations. The capture launcher did not run Terebi.
- Actual YouTube and Miruro terminal interfaces with injected modified-key sequences: reverse-checked rows produced display-ordered enqueue manifests, cleared checks fell back to the hovered row, Ctrl/Super+Return and an F12 override worked, and plain Return still used `--new-instance --url`. Six handoffs used private `0600` manifests in `0700` session directories with distinct report destinations. The capture launcher did not run Terebi, and injecting already-encoded modified keys did not verify terminal protocol negotiation.
- Terebi: `check-cli`, `check-queue`, `check-reporting` and `make all` passed. A regression check first failed on rebinding the original single-video identity and passed after binding it independently of appended reports.
- Headless native enqueue smoke with local video-only HLS passed: repeated delivery while paused/playing, unchanged current selection/revision, lazy mixed-provider append, natural-end advance, navigation/revisits, atomic rejection/rollback, isolated original/appended reports and empty-player startup.
- Full `make check-resolved` stopped in the pre-existing mixed-queue natural-end scenario at `Could not start Core Audio (560227702)` before reaching enqueue. No full A/V-suite pass is claimed. No packaged-GUI/LaunchServices smoke or visual-layout confirmation was performed; the app was built, not installed. Temporary terminal/server fixtures were removed.
- Modified-Return correction: a protocol-aware PTY driver reproduced Ctrl+Return opening a new instance when startup did not request disambiguation. After adding a session-scoped Kitty keyboard protocol push/pop, the same actual TUI driver observed Ctrl+Return using `--enqueue`, plain Return using `--new-instance`, and keyboard-mode restoration on exit. `cargo test --locked` remained **233 passed** and the build passed. This emulates a supporting terminal; it does not prove support in the user's terminal/multiplexer. Legacy identical Return bytes require a different binding.
+1
View File
@@ -3854,6 +3854,7 @@ fn main() -> io::Result<()> {
let config_path = config::config_path()?;
let config = config::load(&config_path)?;
ratatui::run(|terminal| {
let _keyboard = ui::KeyboardProtocol::enable()?;
if !options.miruro {
let Some(miruro) = choose_provider(terminal, &config.keys, None)? else {
return Ok(());
+26 -1
View File
@@ -2,7 +2,13 @@ use std::time::Duration;
use ratatui::{
Frame,
crossterm::{clipboard::CopyToClipboard, execute},
crossterm::{
clipboard::CopyToClipboard,
event::{
KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
},
execute,
},
layout::{Constraint, Layout, Rect},
style::{Color, Style},
text::{Line, Span},
@@ -13,6 +19,25 @@ pub const ACCENT: Style = Style::new().fg(Color::Cyan);
pub const SELECTED: Style = Style::new().fg(Color::Black).bg(Color::Cyan);
pub const SELECTION_MARKER: &str = "> ";
// Keep modified Return distinct from Return on terminals supporting the Kitty protocol.
pub struct KeyboardProtocol;
impl KeyboardProtocol {
pub fn enable() -> std::io::Result<Self> {
execute!(
std::io::stdout(),
PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES)
)?;
Ok(Self)
}
}
impl Drop for KeyboardProtocol {
fn drop(&mut self) {
let _ = execute!(std::io::stdout(), PopKeyboardEnhancementFlags);
}
}
pub fn copy_video_url(id: &str) -> String {
let result = crate::youtube::video_url(id)
.and_then(|url| execute!(std::io::stdout(), CopyToClipboard::to_clipboard_from(url)));