diff --git a/internal/c/libqb.cpp b/internal/c/libqb.cpp index 9f258003e..40089b21b 100644 --- a/internal/c/libqb.cpp +++ b/internal/c/libqb.cpp @@ -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 diff --git a/internal/c/qbx.cpp b/internal/c/qbx.cpp index 643231fd5..ba2991a5a 100755 --- a/internal/c/qbx.cpp +++ b/internal/c/qbx.cpp @@ -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 diff --git a/tests/compile_tests/timer/sleep_ends_early.bas b/tests/compile_tests/timer/sleep_ends_early.bas new file mode 100644 index 000000000..97183a9e1 --- /dev/null +++ b/tests/compile_tests/timer/sleep_ends_early.bas @@ -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 diff --git a/tests/compile_tests/timer/sleep_ends_early.output b/tests/compile_tests/timer/sleep_ends_early.output new file mode 100644 index 000000000..5d4a3dfd7 --- /dev/null +++ b/tests/compile_tests/timer/sleep_ends_early.output @@ -0,0 +1 @@ +Timer! diff --git a/tests/compile_tests/timer/timer_delayed_run.bas b/tests/compile_tests/timer/timer_delayed_run.bas new file mode 100644 index 000000000..5b3eb0ddb --- /dev/null +++ b/tests/compile_tests/timer/timer_delayed_run.bas @@ -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 diff --git a/tests/compile_tests/timer/timer_delayed_run.output b/tests/compile_tests/timer/timer_delayed_run.output new file mode 100644 index 000000000..9b9060b4c --- /dev/null +++ b/tests/compile_tests/timer/timer_delayed_run.output @@ -0,0 +1,2 @@ +Timer! +Timer! diff --git a/tests/compile_tests/timer/timer_first_run.bas b/tests/compile_tests/timer/timer_first_run.bas new file mode 100644 index 000000000..ddc2f66ad --- /dev/null +++ b/tests/compile_tests/timer/timer_first_run.bas @@ -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 diff --git a/tests/compile_tests/timer/timer_first_run.output b/tests/compile_tests/timer/timer_first_run.output new file mode 100644 index 000000000..9b9060b4c --- /dev/null +++ b/tests/compile_tests/timer/timer_first_run.output @@ -0,0 +1,2 @@ +Timer! +Timer! diff --git a/tests/compile_tests/timer/timer_stop.bas b/tests/compile_tests/timer/timer_stop.bas new file mode 100644 index 000000000..fab87d629 --- /dev/null +++ b/tests/compile_tests/timer/timer_stop.bas @@ -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 diff --git a/tests/compile_tests/timer/timer_stop.output b/tests/compile_tests/timer/timer_stop.output new file mode 100644 index 000000000..5d4a3dfd7 --- /dev/null +++ b/tests/compile_tests/timer/timer_stop.output @@ -0,0 +1 @@ +Timer!