1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-25 16:15:53 +00:00

Merge pull request #295 from mkilgore/fix-timer-first-run

Fix timers at program start, TIMER STOP, and Sleep with console
This commit is contained in:
Matt Kilgore 2023-02-12 22:08:55 -05:00 committed by GitHub
commit 47639507ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 128 additions and 54 deletions

View file

@ -20093,36 +20093,53 @@ void sub_sleep(int32 seconds, int32 passed) {
DWORD dwRet;
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdin);
if (passed) {
do {
do {
uint32_t sleepms = 10;
// Check if ms is less than 10, if so sleep for that many ms to
// try to make the sleep a bit more accurate
if (passed && ms < 10 && ms > 0)
sleepms = ms;
// Only sleep for a max of 10ms intervals so that we can pump the evnt() handler
dwRet = WaitForSingleObject(hStdin, sleepms); // this should provide our pause
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);
}
}
// Handle periodic events (timers and some other things)
evnt(0);
// evnt() may trigger us to end sleep early
if (sleep_break)
return;
if (stop_program)
return;
// We only update the ms count if we were provided a max number of
// seconds to sleep
if (passed) {
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.
}
} while (!passed || ms > 0); // We loop if we weren't provided a number of seconds to sleep, or if we reached the timeout
// If we got here, then we timed out
return;
}
#endif

View file

@ -2073,14 +2073,16 @@ void sub_timer(int32 i, int32 option, int32 passed) {
// ref: uint8 active;//0=OFF, 1=ON, 2=STOP
if (option == 1) { // ON
ontimer[i].active = 1;
// This is necessary so that if a timer triggered while stopped we will run it now.
qbevent = 1;
return;
}
if (option == 2) { // OFF
ontimer[i].active = 0;
if (ontimer[i].state == 1)
ontimer[i].state = 0; // retract event if not in progress
ontimer[i].last_time =
0; // when ON is next used, event will be triggered immediately
ontimer[i].last_time = 0; // when ON is next used, the timer will start over
return;
}
if (option == 3) { // STOP
@ -2114,34 +2116,25 @@ void TIMERTHREAD(void *unused) {
if (!ontimerthread_lock) { // mutex
time_now = ((double)GetTicks()) * 0.001;
for (i = 0; i < ontimer_nextfree; i++) {
if (ontimer[i].allocated) {
if (ontimer[i].id) {
if (ontimer[i].active) {
if (!ontimer[i].state) {
if (time_now - ontimer[i].last_time >
ontimer[i].seconds) {
if (!ontimer[i].last_time) {
ontimer[i].last_time = time_now;
} else {
// keep measured time for accurate
// number of calls overall
ontimer[i].last_time +=
ontimer[i].seconds;
// if difference between actual time and
// measured time is beyond 'seconds' set
// measured to actual
if (fabs(time_now -
ontimer[i].last_time) >=
ontimer[i].seconds)
ontimer[i].last_time = time_now;
ontimer[i].state = 1;
qbevent = 1;
}
} // time check
} // state==0
} // active
} // id
} // allocated
if (ontimer[i].allocated && ontimer[i].id && ontimer[i].active && !ontimer[i].state) {
if (!ontimer[i].last_time) {
ontimer[i].last_time = time_now;
} else if (time_now - ontimer[i].last_time > ontimer[i].seconds) {
// keep measured time for accurate
// number of calls overall
ontimer[i].last_time += ontimer[i].seconds;
// if difference between actual time and
// measured time is beyond 'seconds' set
// measured to actual
if (fabs(time_now -
ontimer[i].last_time) >=
ontimer[i].seconds)
ontimer[i].last_time = time_now;
ontimer[i].state = 1;
qbevent = 1;
} // time check
}
if (ontimerthread_lock == 1)
goto quick_lock;
} // i

View file

@ -0,0 +1,13 @@
$Console:Only
On Timer(2) GoSub timerhand
Timer On
' The timer triggering should end sleep early, so it only triggers once
Sleep 10
System
timerhand:
Print "Timer!"
return

View file

@ -0,0 +1 @@
Timer!

View file

@ -0,0 +1,15 @@
$Console:Only
On Timer(2) GoSub timerhand
' This first delay should not matter
_Delay 3
Timer On
' The timer should be triggered twice
_Delay 5
System
timerhand:
Print "Timer!"
return

View file

@ -0,0 +1,2 @@
Timer!
Timer!

View file

@ -0,0 +1,12 @@
$Console:Only
On Timer(2) GoSub timerhand
Timer On
' Timer should be triggered twice
_Delay 5
System
timerhand:
Print "Timer!"
return

View file

@ -0,0 +1,2 @@
Timer!
Timer!

View file

@ -0,0 +1,18 @@
$Console:Only
On Timer(2) GoSub timerhand
Timer On
Timer Stop
' Timer will not trigger when stopped
Sleep 3
' Timer should trigger immediately when started as two seconds have elapsed
' while it was stopped
Timer On
Timer Off 'Shouldn't matter, timer triggers as soon as Timer On runs
System
timerhand:
Print "Timer!"
return

View file

@ -0,0 +1 @@
Timer!