I'm fairly new to ruby and wanted to write some example programs in
ruby using ncurses-wrapper-library. That is, in fact, really simple
and works well.
But now I have a problem: I want ncurses to draw some things on the
screen and update it every second - until a key is pressed. I'm trying
to do it as follows (short example):
stop = nil
Thread.new do
until stop
Ncurses.printw("foo") # just an example...
Ncurses.refresh
sleep 1
end
Ncurses.endwin
end
Ncurses.getch
stop = 1
But I suppose Ncurses.getch blocks any other ncurses-functions from
writing anything on the window... so - what to do?
I just want to run the thread continuously until one key is pressed...
What other possibilities do I have?
You can just select on STDIN, or use the 'io/wait' module to check for
its status:
require 'io/wait'
require 'ncurses'
begin
Ncurses.initscr; Ncurses.cbreak; Ncurses.noecho; Ncurses.nonl
Ncurses.stdscr.addstr("Press a key to continue...")
Ncurses.stdscr.refresh
while not STDIN.ready?
Ncurses.stdscr.addstr('.')
Ncurses.stdscr.refresh
sleep 1
end
Ncurses.stdscr.getch
ensure
Ncurses.echo; Ncurses.nocbreak; Ncurses.nl; Ncurses.endwin
end
But now I have a problem: I want ncurses to draw some things on the
screen and update it every second - until a key is pressed. I'm trying
to do it as follows (short example):
stop = nil
Thread.new do
until stop
Ncurses.printw("foo") # just an example...
Ncurses.refresh
sleep 1
end
Ncurses.endwin
end
Ncurses.getch
stop = 1
But I suppose Ncurses.getch blocks any other ncurses-functions from
writing anything on the window... so - what to do?
I just want to run the thread continuously until one key is pressed...
What other possibilities do I have?
Ncurses.getch blocks not only other ncurses-functions. It blocks the complete ruby interpreter, all threads.
This has to change, obviously, and it will change before the 1.0 release of ncurses-ruby. In the meantime, you can work around the limitation in the way Lennon suggested [ruby-talk:109697].
Even when Ncurses.getch is fixed, you can not expect to call Ncurses functions concurrently from several threads and get the desired results.
Ncurses shares this limitation with most other UI libraries. They are basically state machines, i.e. order of commands matters. Your application is responsible for serializing Ncurses calls, not the ncurses wrapper.
>I just want to run the thread continuously until one key is pressed...
>What other possibilities do I have?
Ncurses.getch blocks not only other ncurses-functions. It blocks the
complete ruby interpreter, all threads.
This has to change, obviously, and it will change before the 1.0 release
of ncurses-ruby. In the meantime, you can work around the limitation in
the way Lennon suggested [ruby-talk:109697].
Raggle uses this approach, and it does have at least one caveat:
terminal resize events (and possibly mouse events as well, although I
believe those are still broken in Ncurses-Ruby) are not handled
properly.
That said, here's the code from Raggle:
timeout = $config['input_select_timeout'] # defaults to 0.2
$done = false
until $done
# handle keyboard input
r = select [$stdin], nil, nil, timeout
if r && r.size > 0
c = Ncurses::getch
$config['keys'][c].call($wins[$a_win],c) \
if $config['keys'].has_key? c
end