惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MongoDB | Blog
MongoDB | Blog
B
Blog
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed
博客园 - Franky
V
V2EX
IT之家
IT之家
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
J
Java Code Geeks
F
Fortinet All Blogs
I
InfoQ
云风的 BLOG
云风的 BLOG
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
Microsoft Security Blog
Microsoft Security Blog

The Rust Programming Language Forum - Latest topics

Beginner building a Rust backend framework (AI-assisted) — feedback appreciated C++ to Rust -- Exceptions Re-exporting a trait with a custom derive_macro Gold linker is deprecated Why is using PhantomData valid in this case? Code review for Static Pool Allocator Looking for a pool based allocator Why is this legal? What does it mean for Rustc to run "out of TLS keys"? Using async/await internally with no internal runtime, but exposing a nonblocking poll API — is this a reasonable design? Testing functions that use randomness `cargo-path`: improve coding agents&#39; ability to find Rust documentation Rust task runners Lifetime weird case Windows - USB device not detected A random rustc-ice-[...].txt file appeared Develop rust where the environment is setup in a docker Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 20 bytes, but got alloc238 which is only 1 byte from the end of the allocation Unbug 0.5 - Runtime debug assertions Is there a tiny error in section 6.2 Reference types? Lifetime woes implementing ratatui::Widget for a reference Rusqlite + Chrono: How do I simplify code to obtain chrono datetime value From OOP to Rust – struggling with code organization and data structure design Way to avoid a self-referential struct Rust RF and audio resources/communities Whyhttp - HTTP mocks that fail where the bug actually is Using tokio channel permits in a tower service Arc::increment_strong_count design question (cross-post) `&T`, `&mut T`, `Pin<&mut T>` and `&Cell<T>`: Ways of Borrowing a `T` Feedback about post in medium
Ratatui detect arrow key press and release
@conqp Richa · 2026-04-22 · via The Rust Programming Language Forum - Latest topics

I am new to ratatui and want to implement a console-based controller for a USB nerf missile launcher. I can capture the key press events of the arrow key, but releasing the key is not being detected as an event. I.e. only ever the key press event fires.

//! TUI controller for the USB missile launcher.

use std::io;

use crossterm::event;
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
use log::{debug, error, info};
use ratatui::prelude::*;
use ratatui::symbols::border;
use ratatui::widgets::{Block, Paragraph};
use ratatui::{DefaultTerminal, Frame};

fn main() -> io::Result<()> {
    env_logger::init();
    ratatui::run(|terminal| App::new().run(terminal))
}

#[derive(Debug)]
struct App {
    exit: bool,
}

impl App {
    /// Crate a new application.
    #[must_use]
    pub const fn new() -> Self {
        Self { exit: false }
    }

    /// Run the application's main loop until the user quits.
    ///
    /// # Errors
    ///
    /// Returns an [`io::Error`] if any I/O error occurs.
    pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
        while !self.exit {
            terminal.draw(|frame| self.draw(frame))?;
            self.handle_events()?;
        }
        Ok(())
    }

    fn draw(&self, frame: &mut Frame<'_>) {
        frame.render_widget(self, frame.area());
    }

    fn handle_events(&mut self) -> io::Result<()> {
        if let Event::Key(key_event) = event::read()? {
            self.handle_key_event(key_event);
        };

        Ok(())
    }

    const fn exit(&mut self) {
        self.exit = true;
    }

    fn handle_key_event(&mut self, key_event: KeyEvent) {
        info!("Key event: {:?}", key_event);
        match key_event.kind {
            KeyEventKind::Press => match key_event.code {
                KeyCode::Esc => self.exit(),
                KeyCode::Left | KeyCode::Right | KeyCode::Up | KeyCode::Down | KeyCode::Enter => {
                    println!("KEY PRESSED: {key_event:?}")
                }
                other => debug!("Unsupported key pressed: {other:?}"),
            },
            KeyEventKind::Release => match key_event.code {
                KeyCode::Left | KeyCode::Right | KeyCode::Up | KeyCode::Down | KeyCode::Enter => {
                    println!("KEY RELEASED: {key_event:?}");
                }
                other => debug!("Unsupported key released: {other:?}"),
            },
            KeyEventKind::Repeat => debug!("Unsupported key repeat: {key_event:?}"),
        }
    }
}

impl Widget for &App {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title = Line::from(" Counter App Tutorial ".bold());
        let instructions = Line::from(vec![
            " Decrement ".into(),
            "<Left>".blue().bold(),
            " Increment ".into(),
            "<Right>".blue().bold(),
            " Quit ".into(),
            "<Q> ".blue().bold(),
        ]);
        let block = Block::bordered()
            .title(title.centered())
            .title_bottom(instructions.centered())
            .border_set(border::THICK);

        Paragraph::new("Foobar")
            .centered()
            .block(block)
            .render(area, buf);
    }
}
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Decrement <Left> Increment <Right> Quit <Q> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛KEY PRESSED: KeyEvent { code: Up, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                                                                        KEY PRESSED: KeyEvent { code: Left, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
              KEY PRESSED: KeyEvent { code: Down, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                                                                                        KEY PRESSED: KeyEvent { code: Right, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                               KEY PRESSED: KeyEvent { code: Up, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                                                                                                       KEY PRESSED: KeyEvent { code: Left, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                             KEY PRESSED: KeyEvent { code: Down, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                                                                                                                       KEY PRESSED: KeyEvent { code: Right, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                              KEY PRESSED: KeyEvent { code: Up, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }
                                                                                                                                                                      KEY PRESSED: KeyEvent { code: Left, modifiers: KeyModifiers(0x0), kind: Press, state: KeyEventState(0x0) }

How can I differentiate between key down and key release events?