Improve Ctrl+C handling with dual detection method

Implemented both keyboard event and signal detection for Ctrl+C:
1. Check for Ctrl+C as keyboard event (KeyModifiers::CONTROL + 'c')
2. Check for SIGINT signal via tokio::signal::unix

This ensures Ctrl+C works reliably in both raw terminal mode and
through signal handling.

Exit options: Ctrl+C, 'q', or ESC

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-09 06:41:07 +01:00
parent 097fca6ed3
commit 5a707df725

View File

@@ -2,7 +2,7 @@ use crate::animation::{easing::EasingFunction, effects::Effect, timeline::Timeli
use crate::color::{apply, ColorEngine}; use crate::color::{apply, ColorEngine};
use crate::utils::{ansi, ascii::AsciiArt, terminal::TerminalManager}; use crate::utils::{ansi, ascii::AsciiArt, terminal::TerminalManager};
use anyhow::Result; use anyhow::Result;
use crossterm::event::{self, Event, KeyCode}; use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use std::time::Duration; use std::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
@@ -36,28 +36,29 @@ impl<'a> Renderer<'a> {
let mut timeline = Timeline::new(self.timeline.duration_ms(), self.timeline.fps()); let mut timeline = Timeline::new(self.timeline.duration_ms(), self.timeline.fps());
timeline.start(); timeline.start();
// Setup Ctrl+C handler using a channel // Setup Ctrl+C handler
let (tx, mut rx) = tokio::sync::mpsc::channel::<()>(1); let mut sigint = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt())?;
tokio::spawn(async move {
let _ = tokio::signal::ctrl_c().await;
let _ = tx.send(()).await;
});
loop { loop {
let frame_start = std::time::Instant::now(); let frame_start = std::time::Instant::now();
// Check for keyboard input (q or ESC to exit) // Check for keyboard input (Ctrl+C, q, or ESC to exit)
if event::poll(Duration::from_millis(0))? { if event::poll(Duration::from_millis(0))? {
if let Event::Key(key) = event::read()? { if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') || key.code == KeyCode::Esc { match key.code {
break; KeyCode::Char('q') | KeyCode::Esc => break,
KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => break,
_ => {}
} }
} }
} }
// Check for Ctrl+C signal // Also check for SIGINT
if rx.try_recv().is_ok() { tokio::select! {
break; _ = sigint.recv() => {
break;
}
_ = tokio::time::sleep(Duration::from_millis(0)) => {}
} }
// Calculate progress with easing // Calculate progress with easing