#42 Problem with win32\\pdckbd()

closed-fixed
None
5
2007-04-01
2005-09-28
Anonymous
No

I found this problem while trying to implement a Ctrl/C
handler while using PDCurses. Before the call to initscr
(), the handler trapped the Ctrl/C correctly. However,
after the initscr() call, the handler no longer recieved
CTRL_C_EVENT notifications (or, if using signal(), no
SIGINT events, which appear to be handled almost
identically). I traced this to the SetConsoleMode() call
in PDC_reset_prog_mode(), which effectively clears the
ENABLE_PROCESSED_INPUT bit, thereby causing
Ctrl/C's to be reported through the input buffer (as 0x03)
rather than passed to my handler.

I thought I might be clever, and added my own
SetConsoleMode() call after the initscr() re-enable the
Ctrl/C handling, but wasn't entirely successful. (I'll
paste my test code below). My handler was called
successfully, but for some reason, refresh() no longer
painted the screen until after the next input was read
from curses. I thought this odd, and a little disruptive to
my app, as I was trying to handle the Ctrl/C events
gracefully.

By tracing through a refresh() call and also a call to
wgetch(stdscr), I was able to identify the problem as a
slight discrepancy in the handling of KEY_EVENTs
between PDC_get_bios_key() and GetInterestingEvent()
(used by PDC_check_bios_key(), which is called
(eventually) from refresh() to put off updating the screen
if keyboard input is pending).

PDC_get_bios_key() essentially ignores any presses of
the Ctrl key by itself. It uses win32_kbhit() (which
returns to TRUE if the Ctrl key is pressed) to read Crtl
key press events, but PDC_get_bios_key() will not
return if Ctrl is pressed alone, i.e. it doesn't "count".

PDC_check_bios_key() also uses win32_kbhit(), but
returns its return value directly to the caller. Therefore,
PDC_check_bios_key() returns TRUE, even when a key
not recognized as significant by PDC_get_bios_key() is
pressed. Which leads to the GetInterestingEvent()
funciton used by win32_kbhit().

There is section in GetInterestingEvent() that process
Shift, Ctrl, and Alt key presses (key-down events). It
correctly saves and return key-up events if SP-
>return_key_modifiers is TRUE. But, all key-down
events should be ignored, SP->return_key_modifiers
true or not. As is, the code returns FALSE (ignores the
key down event) is SP->return_key_modifiers is
FALSE, but returns ip->Event.KeyEvent.wRepeatCount
if it is TRUE. The relevant portion of the code is below.
I've added my own comments using C++ style //:

if (ip->Event.KeyEvent.bKeyDown == FALSE)
{
/* key up */
// Key up events for Shift/Ctrl/Alt that match the last key-
down event, and we want to report key modifiers as keys
if ((ip->Event.KeyEvent.wVirtualKeyCode == 16
|| ip->Event.KeyEvent.wVirtualKeyCode == 17
|| ip->Event.KeyEvent.wVirtualKeyCode == 18)
&& ip->Event.KeyEvent.wVirtualKeyCode ==
save_press
&& SP->return_key_modifiers)
#ifdef PDCDEBUG
ptr = "KEYUP WANTED";
#else
// Will set and return numKeys below
;
#endif
else
{
#ifdef PDCDEBUG
ptr = "KEYUP IGNORED";
#endif
break; /* throw away KeyUp
events */
}
}
else
{
// This is what I changed for my own app
#if 0 /* *** Mismatched functionality with
PDC_get_bios_key() - MDH *** */
// This was the original code. It stored the virtual key
code in save_press for Shift/Ctrl/Alt if we want key
modifiers reported as keys, and then ignored the event
// But, even if we don't want to report key modifiers, we
still need to ignore Shift/Ctrl/Alt key presses.
if ((ip->Event.KeyEvent.wVirtualKeyCode == 16
|| ip->Event.KeyEvent.wVirtualKeyCode == 17
|| ip->Event.KeyEvent.wVirtualKeyCode == 18)
&& SP->return_key_modifiers)
{
#else
// This separates the Shift/Ctrl/Alt test
if (ip->Event.KeyEvent.wVirtualKeyCode == 16
|| ip->Event.KeyEvent.wVirtualKeyCode == 17
|| ip->Event.KeyEvent.wVirtualKeyCode == 18)
{
// And then checks for key modifier reporting separately
if (SP->return_key_modifiers)
#endif
// This now is bound to the key modifier check above
save_press = ip-
>Event.KeyEvent.wVirtualKeyCode;
#ifdef PDCDEBUG
ptr = "KEYDOWN SAVED";
#endif
// And this happens for all Shift/Ctrl/Alt presses
break; /* throw away key press */
}
}
save_press = 0;
if (ip->Event.KeyEvent.uChar.AsciiChar == 0 &&
(MapVirtualKey(ip-
>Event.KeyEvent.wVirtualKeyCode,2) & 0x80000000))
{
#ifdef PDCDEBUG
ptr = "DIACRITIC IGNORED";
#endif
break; /* Diacritic characters, ignore
them */
}
#ifdef PDCDEBUG
ptr = "KEY WANTED";
#endif
// If we didn't break out anywhere above, we get the
repeat count here and report it as an "interesting" event
numKeys = ip->Event.KeyEvent.wRepeatCount;
break;

Sorry for being long winded. Hope this makes sense to
somebody.

Michael Houle
houle@plh.af.mil

Original test code below:

#include <stdio.h>
#include <windows.h>
#include <signal.h>

#include "curses.h"

#define sleep(x) Sleep((x) * 1000)

int c = 0;

BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
{
switch(dwCtrlType) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
c = 1;
return(TRUE);
default:
return(FALSE);
}
}

void CtrlC(int sig)
{
c = 2;
return;
}

void main(int argc, char *argv[])
{
HANDLE hConIn;
DWORD dwConsoleMode;
int i;

/*
* Reversing the next to lines, thus changing the
install order of the two
* handler routines, shows that signal() is
implemented in the same manner
* as SetConsoleCrtlHandler().
*/
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
signal(SIGINT, CtrlC);

hConIn = GetStdHandle(STD_INPUT_HANDLE);

GetConsoleMode(hConIn, &dwConsoleMode);

/* Give the tester a chance to press Ctrl/C before initscr
() */
for(i = 0; i < 10; i++) {
if(c != 0) {
printf("Ctrl/C set %d\n", c);
return;
}
printf("%d...\n", i);
sleep(1);
}

initscr();

/* Re-enable processed input for Ctrl/C handling */
GetConsoleMode(hConIn, &dwConsoleMode);
SetConsoleMode(hConIn, dwConsoleMode |
ENABLE_PROCESSED_INPUT);

for(i = 0; i < 10; i++) {
if(c != 0) {
printw("Ctrl/C set %d\n", c);
refresh();
/*
* Uncomment the following line to trace into the
PDC_get_bios_key()
* routine and see a different behavoir than
GetInterestingEvent().
*/
// if(c == 2) wgetch(stdscr);
return;
}
printw("%d...\n", i);
refresh();
sleep(1);
}
}

Discussion

  • William McBrine

    William McBrine - 2005-12-12

    Logged In: YES
    user_id=27933

    Thanks for the detailed report. I believe Mark's new Win32
    keyboard code (in CVS) resolves your issue (per the test
    program), but the changes are much more extensive. Please
    check it and let me know.

     
  • William McBrine

    William McBrine - 2005-12-12
    • assigned_to: nobody --> rexx
    • status: open --> pending-fixed
     
  • William McBrine

    William McBrine - 2007-04-01
    • summary: Problem with win32\pdckbd() --> Problem with win32\pdckbd()
    • status: pending-fixed --> closed-fixed
     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks