You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中使用Crossterm检测按键释放事件(基于Tokio)

如何在Tokio+Crossterm项目中检测按键释放事件

你当前的代码无法检测按键释放事件,主要有两个核心问题:一是未启用终端的raw模式(默认模式下终端不会向程序发送释放事件),二是事件匹配方式不够精准。以下是修正后的实现方案:

关键修改点

  1. 启用Raw模式:只有在raw模式下,终端才会传递按键释放事件,退出时需恢复终端正常模式,避免影响后续终端操作。
  2. 精准匹配事件:不要直接构造KeyEvent进行全值对比(可能存在修饰键、重复标记等字段差异),而是先解构事件,再检查按键类型和释放状态。

修正后的代码

use crossterm::{
    event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
    terminal::{disable_raw_mode, enable_raw_mode},
};
use tokio::time::{Delay, Duration};
use futures::{future::select, StreamExt};

async fn print_events() {
    // 启用raw模式以捕获按键释放事件
    if let Err(e) = enable_raw_mode() {
        eprintln!("启用raw模式失败: {:?}", e);
        return;
    }

    let mut reader = EventStream::new();

    loop {
        let mut delay = Delay::new(Duration::from_millis(1_000)).fuse();
        let mut event = reader.next().fuse();

        select! {
            _ = delay => { println!(".\r"); },
            maybe_event = event => {
                match maybe_event {
                    Some(Ok(event)) => {
                        println!("Event::{:?}\r", event);

                        // 解构事件,检查是否为按键释放事件
                        if let Event::Key(key_event) = event {
                            if key_event.kind == KeyEventKind::Release {
                                match key_event.code {
                                    KeyCode::Char('c') => {
                                        println!("c键已释放! 光标位置: {:?}\r", position());
                                    }
                                    KeyCode::Esc => {
                                        // 检测到Esc释放时退出循环
                                        break;
                                    }
                                    _ => {}
                                }
                            }
                        }
                    }
                    Some(Err(e)) => println!("错误: {:?}\r", e),
                    None => break,
                }
            }
        };
    }

    // 退出前恢复终端正常模式
    let _ = disable_raw_mode();
}

// 示例光标位置函数,替换为你实际的实现
fn position() -> (u16, u16) {
    (0, 0)
}

补充说明

  • Raw模式启用后,终端会禁用行缓冲、自动回显等默认行为,确保程序能实时接收所有按键事件(包括按下和释放)。
  • 通过key_event.kind明确区分事件类型(释放/按下),再匹配具体按键,避免了全值对比带来的匹配失败问题。

内容的提问来源于stack exchange,提问作者Mithrandir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:25:25