mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-09-16 15:34:03 +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;
|
DWORD dwRet;
|
||||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
FlushConsoleInputBuffer(hStdin);
|
FlushConsoleInputBuffer(hStdin);
|
||||||
if (passed) {
|
|
||||||
do {
|
do {
|
||||||
now = GetTicks();
|
uint32_t sleepms = 10;
|
||||||
if (now < prev)
|
|
||||||
return; // value looped?
|
// Check if ms is less than 10, if so sleep for that many ms to
|
||||||
elapsed = now - prev; // elapsed time since prev
|
// try to make the sleep a bit more accurate
|
||||||
ms = ms - elapsed;
|
if (passed && ms < 10 && ms > 0)
|
||||||
prev = now;
|
sleepms = ms;
|
||||||
dwRet = WaitForSingleObject(hStdin, ms); // this should provide our pause
|
|
||||||
if (dwRet == WAIT_TIMEOUT)
|
// Only sleep for a max of 10ms intervals so that we can pump the evnt() handler
|
||||||
return; // and if we timeout without any input, we exit early.
|
dwRet = WaitForSingleObject(hStdin, sleepms); // this should provide our pause
|
||||||
|
|
||||||
if (dwRet == WAIT_OBJECT_0) { // this says the console had input
|
if (dwRet == WAIT_OBJECT_0) { // this says the console had input
|
||||||
junk = func__getconsoleinput();
|
junk = func__getconsoleinput();
|
||||||
if (junk == 1) { // this is a valid keyboard event. Let's exit SLEEP in the console.
|
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);
|
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 (!passed || ms > 0); // We loop if we weren't provided a number of seconds to sleep, or if we reached the timeout
|
||||||
} 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.
|
// If we got here, then we timed out
|
||||||
FlushConsoleInputBuffer(hStdin); // and flush the keyboard buffer after, so we don't leave stray events to be processed.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2073,14 +2073,16 @@ void sub_timer(int32 i, int32 option, int32 passed) {
|
||||||
// ref: uint8 active;//0=OFF, 1=ON, 2=STOP
|
// ref: uint8 active;//0=OFF, 1=ON, 2=STOP
|
||||||
if (option == 1) { // ON
|
if (option == 1) { // ON
|
||||||
ontimer[i].active = 1;
|
ontimer[i].active = 1;
|
||||||
|
|
||||||
|
// This is necessary so that if a timer triggered while stopped we will run it now.
|
||||||
|
qbevent = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (option == 2) { // OFF
|
if (option == 2) { // OFF
|
||||||
ontimer[i].active = 0;
|
ontimer[i].active = 0;
|
||||||
if (ontimer[i].state == 1)
|
if (ontimer[i].state == 1)
|
||||||
ontimer[i].state = 0; // retract event if not in progress
|
ontimer[i].state = 0; // retract event if not in progress
|
||||||
ontimer[i].last_time =
|
ontimer[i].last_time = 0; // when ON is next used, the timer will start over
|
||||||
0; // when ON is next used, event will be triggered immediately
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (option == 3) { // STOP
|
if (option == 3) { // STOP
|
||||||
|
@ -2114,19 +2116,14 @@ void TIMERTHREAD(void *unused) {
|
||||||
if (!ontimerthread_lock) { // mutex
|
if (!ontimerthread_lock) { // mutex
|
||||||
time_now = ((double)GetTicks()) * 0.001;
|
time_now = ((double)GetTicks()) * 0.001;
|
||||||
for (i = 0; i < ontimer_nextfree; i++) {
|
for (i = 0; i < ontimer_nextfree; i++) {
|
||||||
if (ontimer[i].allocated) {
|
if (ontimer[i].allocated && ontimer[i].id && ontimer[i].active && !ontimer[i].state) {
|
||||||
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) {
|
if (!ontimer[i].last_time) {
|
||||||
ontimer[i].last_time = time_now;
|
ontimer[i].last_time = time_now;
|
||||||
} else {
|
} else if (time_now - ontimer[i].last_time > ontimer[i].seconds) {
|
||||||
// keep measured time for accurate
|
// keep measured time for accurate
|
||||||
// number of calls overall
|
// number of calls overall
|
||||||
ontimer[i].last_time +=
|
ontimer[i].last_time += ontimer[i].seconds;
|
||||||
ontimer[i].seconds;
|
|
||||||
// if difference between actual time and
|
// if difference between actual time and
|
||||||
// measured time is beyond 'seconds' set
|
// measured time is beyond 'seconds' set
|
||||||
// measured to actual
|
// measured to actual
|
||||||
|
@ -2136,12 +2133,8 @@ void TIMERTHREAD(void *unused) {
|
||||||
ontimer[i].last_time = time_now;
|
ontimer[i].last_time = time_now;
|
||||||
ontimer[i].state = 1;
|
ontimer[i].state = 1;
|
||||||
qbevent = 1;
|
qbevent = 1;
|
||||||
}
|
|
||||||
} // time check
|
} // time check
|
||||||
} // state==0
|
}
|
||||||
} // active
|
|
||||||
} // id
|
|
||||||
} // allocated
|
|
||||||
if (ontimerthread_lock == 1)
|
if (ontimerthread_lock == 1)
|
||||||
goto quick_lock;
|
goto quick_lock;
|
||||||
} // i
|
} // 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