The halfdelay() input option is broken in PDCurses -- wgetch() is always
either fully blocking or nonblocking. The problem is in pdcurses/getch.c,
in the wgetch() function, after a low-level keyboard read is attempted:
/* keyboard read leaves value in "key", then: */
if (w->_nodelay)
{
/*
* if nodelay and no char, return ERR
*/
if (key == -1)
return( ERR );
else if ( ! SP->echo ) {
if ( ! (w->_flags & _PAD) ) {
if ( is_wintouched(w) )
wrefresh(w);
}
else
{
if (SP->delaytenths)
{
if (waitingtenths == 0 && key == (-1))
return(ERR);
if (key == (-1))
{
waitingtenths--;
napms(10);
continue;
}
}
}
The trouble is that the low-level keyboard read function itself depends on
the status of w->_nodelay. When it's true, obviously the "SP->delaytenths"
section will never be reached; but also, when false, the return value in
"key" will never be -1, so although the delay section is reached, it has
no function. The remedy is simply to swap around the conditions: test
SP->delaytenths first, then w->_nodelay. Note that, for halfdelay() to
work then, the window must first be set to nodelay(); since this depends
on a specific window, while halfdelay() is global, I haven't included this
in the patch.
That fixed, there's another problem: nocbreak() does not reset the value
set by halfdelay(), as it's supposed to. This is tricky, because if you
look at nocbreak() in pdcurses/inopts.c, it appears to be resetting it;
but this function is only used in the XCurses port. For the rest,
nocbreak() is defined in curses.h:
# define nocbreak() (SP->cbreak = FALSE)
I just changed this to:
# define nocbreak() (SP->cbreak = FALSE, SP->delaytenths = 0)
Finally, the pause routine napms() works in Win32 and OS/2 (though the
pause seems overlong in OS/2), but not in DOS, with DJGPP or Turbo C++;
on those platforms it returns immediately. In the case of DJGPP, I found
the explanation in the info page for usleep(), the function PDCurses uses
to implement napms() there:
Note that, since `usleep' calls `clock' internally, and the latter has
a 55-msec granularity, any argument less than 55msec will result in a
pause of random length between 0 and 55 msec. Any argument less than
11msec (more precisely, less than 11264 microseconds), will always
result in zero-length pause (because `clock' multiplies the timer count
by 5).
PDCurses is calling usleep() with a 10ms parameter, so there's no pause. I
haven't attempted to fix this yet. And I haven't yet figured out why the
Turbo C++ routine (based on delay() from TC's dos.h) isn't working.
Patches for the first two problems attached.
--
William McBrine <[EMAIL PROTECTED]>
*** pdcurses/getch.c.old Wed Jan 10 03:27:01 2001
--- pdcurses/getch.c Sun Mar 3 06:44:06 2002
***************
*** 259,289 ****
key = (-1);
#endif
! if (w->_nodelay)
{
! /*
! * if nodelay and no char, return ERR
! */
! if (key == -1)
! return( ERR );
! else if ( ! SP->echo ) {
! if ( ! (w->_flags & _PAD) ) {
! if ( is_wintouched(w) )
! wrefresh(w);
! }
}
}
else
{
! if (SP->delaytenths)
{
! if (waitingtenths == 0 && key == (-1))
! return(ERR);
! if (key == (-1))
! {
! waitingtenths--;
! napms(10);
! continue;
}
}
}
--- 259,289 ----
key = (-1);
#endif
! if (SP->delaytenths)
{
! if (waitingtenths == 0 && key == (-1))
! return(ERR);
! if (key == (-1))
! {
! waitingtenths--;
! napms(10);
! continue;
}
}
else
{
! if (w->_nodelay)
{
! /*
! * if nodelay and no char, return ERR
! */
! if (key == -1)
! return( ERR );
! else if ( ! SP->echo ) {
! if ( ! (w->_flags & _PAD) ) {
! if ( is_wintouched(w) )
! wrefresh(w);
! }
}
}
}
*** curses.h.old Tue Oct 16 07:03:15 2001
--- curses.h Sun Mar 3 06:47:05 2002
***************
*** 2070,2076 ****
#define wstandout(w) wattrset(w, A_STANDOUT)
#if !defined(UNIX) && !defined(XCURSES)
! # define nocbreak() (SP->cbreak = FALSE)
# define cbreak() (SP->cbreak = TRUE)
# define nocrmode() (SP->cbreak = FALSE)
# define crmode() (SP->cbreak = TRUE)
--- 2070,2076 ----
#define wstandout(w) wattrset(w, A_STANDOUT)
#if !defined(UNIX) && !defined(XCURSES)
! # define nocbreak() (SP->cbreak = FALSE, SP->delaytenths = 0)
# define cbreak() (SP->cbreak = TRUE)
# define nocrmode() (SP->cbreak = FALSE)
# define crmode() (SP->cbreak = TRUE)