perlmeditation
strredwolf
<p>If many monks here know, there's been a bit of a problem with the Curses module. It's not that it's good, it's more like it's not well documented -- in terms of "I'm new to Curses/NCurses! What do I do?!?" </P>
<P>Now, I hear a ton of monks say "For the love of Larry, 'perldoc Curses'!!!" To those heathens, read the doc and tell me how to actually use it. <I>You can't. It only describes that it's a wrapper around Curses/NCurses!</I></P>
<P>Then another ton say "'man curses', you fool!" to which I smack them upside the head, because <I>the Curses module attempts to make things saner than just the C library!</I>.</P>
<P><I>Unfortunately, something has been lost in the translation.</I> For instance, take the getch() routine. In C, it returns an integer ranging from -1 (ERR) to at least 511 (for special keys such as up, down, left, right, home, end, etc). In Perl, -1 and anything over 255 are returned as that integer; <I>everything else is returned as a character!</I> I had to dig through the source code to find that quirk out!</P>
<P>And thus, after two nights of wracking my brain and raging against the machine, I have this lovely example done on the way to create a replacement to Sirc's ssfe C screen handler.</P>
<p>
<readmore>
<code>#!/usr/bin/perl
use Curses;
use IO::Select;
# Subs
sub send_line {
my $sl=shift;
$top->addstr($sl."\n");
$top->refresh;
}
sub handle_keyboard {
my $ch=$bottom->getch();
if($ch<0) {
$leavenow++; return;
}
my $c=ord $ch;
if($ch>255) {
;
} elsif($c<32 || $c==127) {
if($c==127) {
$line=~s/.$//;
$bottom->erase;
$bottom->addstr(0,0,$line);
} elsif($c==10 || $c==13) {
send_line($line);
$line='';
$bottom->erase;
}
} else {
$line.=$ch;
$bottom->addch($ch);
}
my $len=length($line);
$bottom->move(int($len/80),($len % 80));
$bottom->refresh();
}
# MAIN
my $sel=IO::Select->new();
$sel->add(\*STDIN);
$root=new Curses;
cbreak();
noecho();
start_color();
init_pair(1,COLOR_WHITE,COLOR_BLACK);
init_pair(2,COLOR_BLACK,COLOR_WHITE);
$root->erase;
$top=$root->subwin(20,80,0,0);
$top->scrollok(1);
$top->leaveok(1);
$top->attron(COLOR_PAIR(1));
$top->refresh;
$top->addstr(0,0,"Startup");
$top->refresh;
$status=$root->subwin(1,80,20,0);
$status->leaveok(1);
$status->attron(COLOR_PAIR(2));
$status->addstr(0,0," " x 80);
$status->refresh;
$bottom=$root->subwin(3,80,21,0);
$bottom->leaveok(0);
$bottom->attron(COLOR_PAIR(1));
$bottom->keypad(1);
$bottom->move(0,0);
$bottom->refresh;
my $leavenow=0;
my @ready;
my $line='';
while(@ready=$sel->can_read) {
my $fh;
# $top->addstr("test"); $top->refresh;
foreach $fh (@ready) {
if($fh == \*STDIN) { # Keyboard.
# $top->addstr("key! "); $top->refresh;
handle_keyboard;
}
}
# $top->addstr($leavenow); $top->refresh;
# last if($leavenow);
}
endwin;
exit 0;
</code>
</readmore>
</p>
<p>The gist of this example is this: I'm accepting basic input (BS/DEL works), and on the ENTER key send the bottom buffer up to the top.</P>
<P>You'll note that I don't use POE. I looked at POE, and it looked rather complicated for what I was trying to do. I was also looking at AnyEvent as well, but for something to hack together, a good old IO::Select loop felt much more comfortable.</p>
<p>I'll clean this up a bit and comment it up more in future posts. </P>
<div class="pmsig"><div class="pmsig-13922">
<I>Information doesn't want to be free. It wants to be <b>feline</b>.</I>
</div></div>