implement stricter and more consistent timeouts.
- stricter timeouts: Instead of adding an entire millisecond, use a list of timeouts that are supposed to be handled on the same tick. This reduces the delay between target tick and actual tick, especially for many timeouts issued to the same tick, i.e. combos. - consistent timeouts: Timeouts are now guaranteed to be handled in the order they were issued. Timer rollover is handled properly. caveat / change to the interface: the returned `timeout_key` is a tuple of the target timeout tick and the index of the timeout at that tick.
This commit is contained in:
parent
d4e72b98c9
commit
07a485b04d
@ -3,6 +3,7 @@ from supervisor import ticks_ms
|
|||||||
from kmk.consts import KMK_RELEASE, UnicodeMode
|
from kmk.consts import KMK_RELEASE, UnicodeMode
|
||||||
from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes
|
from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes
|
||||||
from kmk.keys import KC
|
from kmk.keys import KC
|
||||||
|
from kmk.kmktime import ticks_add, ticks_diff
|
||||||
from kmk.matrix import MatrixScanner, intify_coordinate
|
from kmk.matrix import MatrixScanner, intify_coordinate
|
||||||
|
|
||||||
|
|
||||||
@ -210,17 +211,22 @@ class KMKKeyboard:
|
|||||||
# We allow passing False as an implicit "run this on the next process timeouts cycle"
|
# We allow passing False as an implicit "run this on the next process timeouts cycle"
|
||||||
timeout_key = ticks_ms()
|
timeout_key = ticks_ms()
|
||||||
else:
|
else:
|
||||||
timeout_key = ticks_ms() + after_ticks
|
timeout_key = ticks_add(ticks_ms(), after_ticks)
|
||||||
|
|
||||||
while timeout_key in self._timeouts:
|
if timeout_key not in self._timeouts:
|
||||||
timeout_key += 1
|
self._timeouts[timeout_key] = []
|
||||||
|
|
||||||
self._timeouts[timeout_key] = callback
|
idx = len(self._timeouts[timeout_key])
|
||||||
return timeout_key
|
self._timeouts[timeout_key].append(callback)
|
||||||
|
|
||||||
|
return (timeout_key, idx)
|
||||||
|
|
||||||
def cancel_timeout(self, timeout_key):
|
def cancel_timeout(self, timeout_key):
|
||||||
if timeout_key in self._timeouts:
|
try:
|
||||||
del self._timeouts[timeout_key]
|
self._timeouts[timeout_key[0]][timeout_key[1]] = None
|
||||||
|
except (KeyError, IndexError):
|
||||||
|
if self.debug_enabled:
|
||||||
|
print(f'no such timeout: {timeout_key}')
|
||||||
|
|
||||||
def _process_timeouts(self):
|
def _process_timeouts(self):
|
||||||
if not self._timeouts:
|
if not self._timeouts:
|
||||||
@ -228,14 +234,20 @@ class KMKKeyboard:
|
|||||||
|
|
||||||
current_time = ticks_ms()
|
current_time = ticks_ms()
|
||||||
|
|
||||||
# cast this to a tuple to ensure that if a callback itself sets
|
# Copy to a temporary list to allow sorting and ensure that if a
|
||||||
# timeouts, we do not handle them on the current cycle
|
# callback itself sets timeouts, we do not handle them on the current
|
||||||
timeouts = tuple(self._timeouts.items())
|
# cycle.
|
||||||
|
timeouts = []
|
||||||
|
for k, v in self._timeouts.items():
|
||||||
|
if ticks_diff(k, current_time) <= 0:
|
||||||
|
timeouts.append((k, v))
|
||||||
|
|
||||||
for k, v in timeouts:
|
timeouts.sort(key=lambda k: k[0])
|
||||||
if k <= current_time:
|
for k, callbacks in timeouts:
|
||||||
v()
|
del self._timeouts[k]
|
||||||
self.cancel_timeout(k)
|
for callback in callbacks:
|
||||||
|
if callback:
|
||||||
|
callback()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ def ticks_diff(new, start):
|
|||||||
return diff
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def ticks_add(ticks, delta):
|
||||||
|
return (ticks + delta) % _TICKS_PERIOD
|
||||||
|
|
||||||
|
|
||||||
def check_deadline(new, start, ms):
|
def check_deadline(new, start, ms):
|
||||||
return ticks_diff(new, start) < ms
|
return ticks_diff(new, start) < ms
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user