With Ed's advice and some experimention of my own, I think I've sorted out the issue with SLEEP in the console not working with any timer.
Before I push any changes into the repo, I'd appreciate it if a few people with the latest development build would give these changes a test run.
Steps for testing:
1) Have the latest Dev build.
2) In internal/c, rename libqb.cpp to libqb.bak to back up the original file, if you want to.
3) Download the libqb.cpp below.
4) Paste it into internal/c.
5) Run the
purge_libqb_only.bat file so QB64 will rebuild its needed library automatically.
Now, feel free to run QB64.exe and test all sorts of things out with SLEEP in the console.
A simple test to see if it times out around the time we'd expect:
$CONSOLE:ONLY
_DEST _CONSOLE: _SOURCE _CONSOLE
PRINT "Foo"
t# = TIMER
SLEEP 2
PRINT USING "##.### seconds"; TIMER - t#
A simple test to see if it still works without a timer:
$CONSOLE:ONLY
_DEST _CONSOLE: _SOURCE _CONSOLE
PRINT "Foo"
SLEEP
The code which pertains to all this working for us, is this:
#ifdef QB64_WINDOWS
if (read_page->console){
int32 junk=0,junk2=0;
DWORD dwRet;
HANDLE hStdin = GetStdHandle (STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
if (passed){
do{
now=GetTicks();
if (now<prev)return;//value looped?
elapsed=now-prev;//elapsed time since prev
ms = ms-elapsed;
prev=now;
dwRet = WaitForSingleObject(hStdin,ms); //this should provide our pause
if (dwRet==WAIT_TIMEOUT)return; //and if we timeout without any input, we exit early.
if (dwRet==WAIT_OBJECT_0){//this says the console had input
junk=func__getconsoleinput();
if(junk==1){//this is a valid keyboard event. Let's exit SLEEP in the console.
Sleep(100);//Give the user time to remove their finger from the key, before clearing the buffer.
FlushConsoleInputBuffer(hStdin);//flush the keyboard buffer after, so we don't leave stray events to be processed (such as key up events).
return;
}else{//we had an input event such as the mouse. Ignore it and clear the buffer so we don't keep responding to mouse inputs
FlushConsoleInputBuffer(hStdin);
}
}
}while(ms>0);//as long as our timer hasn't expired, we continue to run the loop and countdown the time remaining
return; //if we get here, something odd happened. We should expire automatically with the WAIT_TIMEOUT event before this occurs.
}
do{ //ignore all console input unless it's a keydown event
junk=func__getconsoleinput();
}while(junk!=1); //only when junk = 1 do we have a keyboard event
Sleep(100); //Give the user time to remove their finger from the key, before clearing the buffer.
FlushConsoleInputBuffer(hStdin); //and flush the keyboard buffer after, so we don't leave stray events to be processed.
}
#endif
Notice how it flushes the console input buffers after we exit SLEEP -- this is intention and not a bug/glitch. If we don't clear those buffers, the KEY UP event will remain in them and carry over to the next read of our code, causing us issues.
For now, I've automatically set a delay of 1/10th of a second for someone to lift their finger off the key after pressing it down, and that seems more than sufficient from testing on my machine. If you run the code on your PC, and it instantly goes to SYSTEM instead of "PRESS <ANY KEY> TO END", at the end of the two sample codes above, speak up and I can up that delay a bit more.
_KEYCLEAR has also been fixed so that it now also clears the console input buffer for us, so IF you end up going straight to system with the console program closing as soon as you press a key, you can always try to add a manual delay and flush that buffer so it won't carry over, such as:
SLEEP
_DELAY .2 //time to lift the finger off the key we hit
_KEYCLEAR //and then clear the buffer
END //so the up key doesn't break the END event.
Test it out, report results, and if all goes well, I'll push the changes into the repo and SLEEP will now work inside the windows console with a timed event. (As well as adding functionality so that _KEYCLEAR will now work to clear the console buffer also.)