如何用Ruby在终端捕获鼠标事件?
解决Ruby终端鼠标事件读取问题
你的代码存在两个核心问题:终端默认的规范模式会缓冲输入并回显,且STDIN默认处于阻塞状态,导致read_nonblock无法捕获鼠标事件数据。以下是修复方案:
关键修改点
- 将终端切换为原始模式:关闭输入缓冲与回显,让鼠标事件直接传递到程序,而非显示在终端界面。
- 设置STDIN为非阻塞模式:适配
read_nonblock的调用要求。 - 使用
IO.select等待输入:避免空循环占用CPU资源。
修复后的代码
begin # 启用终端原始模式,关闭缓冲与回显 IO.console.raw! # 将STDIN设置为非阻塞模式 STDIN.nonblock = true # 启用鼠标按下/释放事件报告,可追加1002启用移动事件报告 print "\e[?1003h\e[?1002h" loop do # 等待STDIN有可读数据,超时1秒避免死循环 if IO.select([STDIN], nil, nil, 1) begin input = STDIN.read_nonblock(1024) puts "捕获到输入: #{input.inspect}" rescue IO::EAGAINWaitReadable # 无数据时跳过,继续循环 end end end ensure # 关闭鼠标事件报告 print "\e[?1003l\e[?1002l" # 恢复终端为规范模式 IO.console.cooked! # 恢复STDIN为阻塞模式 STDIN.nonblock = false end
说明
- 原始模式:
IO.console.raw!禁用终端的行缓冲、回显和特殊字符处理,让鼠标转义序列直接被程序读取,不会在终端显示。 - 非阻塞STDIN:
STDIN.nonblock = true让read_nonblock在无数据时抛出异常而非阻塞,配合IO.select可高效等待输入。 - 鼠标事件参数:
\e[?1002h用于启用鼠标移动时的事件报告,若仅需捕获按下/释放动作,保留1003即可。 - 终端状态恢复:
ensure块必须恢复终端模式,否则退出程序后终端会出现输入不显示、无法正常换行等异常。
测试时移动或点击鼠标,程序会输出捕获到的鼠标转义序列,不会再出现终端直接显示序列却读不到数据的情况。
内容的提问来源于stack exchange,提问作者Scoobie
相关产品推荐
相关产品推荐

