Mark24
记录灵感、技术、思考
Curses非阻塞输入探索
我们以 include Curses
的例子为例,这里主要是 设置 timeout=
Sets block and non-blocking reads for the window.
If delay is negative, blocking read is used (i.e., waits indefinitely for input).
If delay is zero, then non-blocking read is used (i.e., read returns ERR if no input is waiting).
If delay is positive, then read blocks for delay milliseconds, and returns ERR if there is still no input.
负数是永远阻塞,0 是非阻塞,正数 则是非阻塞延迟,单位是毫秒。
#!/usr/bin/env ruby
require "curses"
include Curses
init_screen
noecho
stdscr.timeout = 500 # 正数等待 一定时间 unit: ms; 0 不等待; -1 阻塞
trap(0) { echo }
while (c = getch) != ?\e
if c
setpos(0, 0)
addstr("You typed #{c.chr.inspect}")
else
p c
end
sleep 0.5
end
如果我们想带上 Curses类来工作
require "curses"
Curses.init_screen
Curses.noecho
Curses.stdscr.timeout = 500
win = Curses::Window.new(Curses.lines, Curses.cols, 0, 0)
win.box(0, 0)
win.refresh
count = 0
while (c = Curses.getch) != ?\e
count += 1
win.clear
if c
win.setpos(0, 0)
win.addstr("#{count}@#{c.chr.inspect}")
else
# do nothing
end
win.refresh
sleep 1.0 / 60
end
在 Curses lib 中除了 Curses 提供的 timeout=
,还有 对 window 子类也提供了 timeout=
这样可以针对具体的 window 下的 getch 来设置。
require "curses"
Curses.init_screen
Curses.noecho
win = Curses::Window.new(Curses.lines, Curses.cols, 0, 0)
win.timeout = 500
win.box(0, 0)
win.refresh
count = 0
while (c = win.getch) != ?\e
count += 1
win.clear
if c
win.setpos(0, 0)
win.addstr("#{count}@#{c.chr.inspect}")
else
# do nothing
end
win.refresh
sleep 1.0 / 60
end
# 设置 win 的 timeout=,
# win的 getch 也在生效
一旦输入变成非阻塞模式,必须通过循环来读取。
这里设置了count,通过不同频率的count增幅不同可以观察并非同步。
二、特殊覆盖
屏幕是父,在此基础上的 win、subwin …… 他们的设置会覆盖全局设置。
这里 Curses 设置为 100ms 的非阻塞。子类window 对象的设置是 -1 阻塞方式工作。
这里最终 win 上是 阻塞设置进行工作的。
require "curses"
Curses.init_screen
Curses.noecho
Curses.stdscr.timeout = 100
win = Curses::Window.new(Curses.lines, Curses.cols, 0, 0)
win.box(0, 0)
win.timeout = -1 # 这里会和全局冲突
win.refresh
count = 0
while (c = win.getch) != ?\e
count += 1
win.clear
if c
win.setpos(0, 0)
win.addstr("#{count}@#{c.chr.inspect}")
else
# do nothing
end
win.refresh
sleep 1.0 / 60
end