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

推荐订阅源

The Cloudflare Blog
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
博客园 - 司徒正美
V
Visual Studio Blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
博客园_首页
Blog — PlanetScale
Blog — PlanetScale
博客园 - 聂微东
S
SegmentFault 最新的问题
T
The Blog of Author Tim Ferriss
D
Docker
Vercel News
Vercel News
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
爱范儿
爱范儿
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏

The Rust Programming Language Forum - Latest posts

What's everyone working on this week (21/2026)? Rust Function Call with one Param Iced + Canvas + Text: How do I create a style for canvas text "Value dropped while borrowed" as a lifetime mismatch Weird `use of moved value` behaviour Slightly surprising behavior of a while loop Clap: how to disable options after a certain positional argument How do i tell rust-analyzer what kind of bracket to use for a macro? Iterator + Borrow Checker: Work around borrowing already borrowed mutable variable Requesting data via mavlink SKILLS.md for Rust development 🧵 Stringlet UTF-8 Hack Option Niche? Iterator + Map - How do divide every element, including the last element, by the last element Why can't we store returned value of a function in a variable if one of the parameters goes out of scope My first crate :D, floop: A more convenient and less error prone replacement for loop `{ select! { .. }}` Sorting is slow because architectures are wrong — zan-sort redesigns the architecture, not the algorithm Iced Font - Create a custom monospace font to display dollar amounts Is the UnsafePinned RFC wrong about being able to return `&mut T` from `get_mut_unchecked`? Fixing Polars 0.37 compilation errors: Hashbrown 0.17 dependency conflict and decimal parsing Any plans for improving error diagnostic in Rust 2.0? How do I build completely offline? Is `&mut T -> &mut ManuallyDrop<T>` well-defined and sound? Would you use this? — fixtura, declarative fake data injection for tests Foreign trait restrictions on native types make generics hard to use Cargo Exclude Directive Compiler reasoning around a modulo counter Multiple mutable references to elements within one vector Handling non-`Send` data in a `Send` closure Review: Static Multi Pool Allocator Rmquickjs - High-level MicroQuickJS bindings for Rust
Ratatui detect arrow key press and release
@conqp Richa · 2026-04-22 · via The Rust Programming Language Forum - Latest posts

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?