mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-09-07 15:20:18 +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:
commit
47639507ff
10 changed files with 128 additions and 54 deletions
|
@ -20093,17 +20093,18 @@ void sub_sleep(int32 seconds, int32 passed) {
|
|||
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.
|
||||
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.
|
||||
|
@ -20115,14 +20116,30 @@ void sub_sleep(int32 seconds, int32 passed) {
|
|||
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.
|
||||
|
||||
// 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;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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,19 +2116,14 @@ 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].allocated && ontimer[i].id && ontimer[i].active && !ontimer[i].state) {
|
||||
if (!ontimer[i].last_time) {
|
||||
ontimer[i].last_time = time_now;
|
||||
} else {
|
||||
} 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;
|
||||
ontimer[i].last_time += ontimer[i].seconds;
|
||||
|
||||
// if difference between actual time and
|
||||
// measured time is beyond 'seconds' set
|
||||
// measured to actual
|
||||
|
@ -2136,12 +2133,8 @@ void TIMERTHREAD(void *unused) {
|
|||
ontimer[i].last_time = time_now;
|
||||
ontimer[i].state = 1;
|
||||
qbevent = 1;
|
||||
}
|
||||
} // time check
|
||||
} // state==0
|
||||
} // active
|
||||
} // id
|
||||
} // allocated
|
||||
}
|
||||
if (ontimerthread_lock == 1)
|
||||
goto quick_lock;
|
||||
} // i
|
||||
|
|
13
tests/compile_tests/timer/sleep_ends_early.bas
Normal file
13
tests/compile_tests/timer/sleep_ends_early.bas
Normal 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
|
1
tests/compile_tests/timer/sleep_ends_early.output
Normal file
1
tests/compile_tests/timer/sleep_ends_early.output
Normal file
|
@ -0,0 +1 @@
|
|||
Timer!
|
15
tests/compile_tests/timer/timer_delayed_run.bas
Normal file
15
tests/compile_tests/timer/timer_delayed_run.bas
Normal 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
|
2
tests/compile_tests/timer/timer_delayed_run.output
Normal file
2
tests/compile_tests/timer/timer_delayed_run.output
Normal file
|
@ -0,0 +1,2 @@
|
|||
Timer!
|
||||
Timer!
|
12
tests/compile_tests/timer/timer_first_run.bas
Normal file
12
tests/compile_tests/timer/timer_first_run.bas
Normal 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
|
2
tests/compile_tests/timer/timer_first_run.output
Normal file
2
tests/compile_tests/timer/timer_first_run.output
Normal file
|
@ -0,0 +1,2 @@
|
|||
Timer!
|
||||
Timer!
|
18
tests/compile_tests/timer/timer_stop.bas
Normal file
18
tests/compile_tests/timer/timer_stop.bas
Normal 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
|
1
tests/compile_tests/timer/timer_stop.output
Normal file
1
tests/compile_tests/timer/timer_stop.output
Normal file
|
@ -0,0 +1 @@
|
|||
Timer!
|
Loading…
Reference in a new issue