From 3ccbcd1a2c8e482d4b2b1df1ce391934d43043d4 Mon Sep 17 00:00:00 2001 From: jtroo Date: Wed, 9 Aug 2023 10:51:30 -0700 Subject: [PATCH] fix: precision of on-idle ticks + doc changes (#528) This commit fixes a bug where even if there are multiple ticks of the keyberon state in the processing loop, the idle time ticks would only increment by one. In addition to the bug fix, some documentation improvements are included. --- docs/config.adoc | 16 ++++++++++++---- src/kanata/mod.rs | 37 +++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/docs/config.adoc b/docs/config.adoc index d59440802..025c3a4c1 100644 --- a/docs/config.adoc +++ b/docs/config.adoc @@ -1747,8 +1747,8 @@ physical key presses and can only be activated via these actions: * `+(on-release-fakekey )+`: Activate a fake key action when releasing the key mapped to this action. * `+(on-idle-fakekey )+`: - Activate a fake key action - when the keyboard is idle for `idle time` milliseconds + Activate a fake key action when kanata has been idle + for at least `idle time` milliseconds. A fake key can be defined in a `+deffakekeys+` configuration entry. Configuring this entry is similar to `+defalias+`, but you cannot make use of aliases @@ -1762,6 +1762,14 @@ The aforementioned `++` can be one of three values: * `+release+`: Release the fake key. If it's not already pressed, this does nothing. * `+tap+`: Press and release the fake key. If it's already pressed, this only releases it. +Expanding on the `on-idle-fakekey` action some more, +the wording that "kanata" has been idle is important. +Even if the keyboard is idle, kanata may not yet be idle. +For example, if a long-running macro is playing, +or kanata is waiting for the timeout of actions such as `caps-word` or `tap-dance`, +kanata is not yet idle, and the tick count for the `` parameter +will not yet be counting even if you no longer have any keyboard keys pressed. + .Example: [source] ---- @@ -2042,14 +2050,14 @@ One case is a triple of: - keys check - action: to activate if keys check succeeds -- fallthrough|break: stop evaluating cases +- `fallthrough|break`: choose to continue vs. stop evaluating cases The default use of keys check behaves similarly to fork. For example, the keys check `(a b c)` will activate the corresponding action if any of a, b, or c are currently pressed. -The keys check also accepts the boolean operators and|or to allow more +The keys check also accepts the boolean operators `and|or` to allow more complex use cases. The order of cases matters. diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index 8acd95ad0..6e32a21b1 100644 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -419,7 +419,8 @@ impl Kanata { } /// Advance keyberon layout state and send events based on changes to its state. - fn handle_time_ticks(&mut self, tx: &Option>) -> Result<()> { + /// Returns the number of ticks that elapsed. + fn handle_time_ticks(&mut self, tx: &Option>) -> Result { const NS_IN_MS: u128 = 1_000_000; let now = time::Instant::now(); let ns_elapsed = now.duration_since(self.last_tick).as_nanos(); @@ -464,7 +465,12 @@ impl Kanata { self.check_handle_layer_change(tx); } - Ok(()) + #[cfg(feature = "perf_logging")] + log::info!("ms elapsed: {ms_elapsed}"); + // Note regarding `as` casting. It doesn't really matter if the result would truncate and + // end up being wrong. Prefer to do the cheaper operation, as compared to doing the min of + // u16::MAX and ms_elapsed. + Ok(ms_elapsed as u16) } fn handle_scrolling(&mut self) -> Result<()> { @@ -1143,6 +1149,7 @@ impl Kanata { | CustomAction::DelayOnRelease(_) | CustomAction::CancelMacroOnRelease => {} CustomAction::FakeKeyOnIdle(fkd) => { + self.ticks_since_idle = 0; self.waiting_for_idle.insert(*fkd); } } @@ -1446,6 +1453,7 @@ impl Kanata { std::thread::sleep(time::Duration::from_millis(1)); } } + let mut ms_elapsed = 0; info!("Starting kanata proper"); let err = loop { @@ -1459,7 +1467,9 @@ impl Kanata { if !is_idle { k.ticks_since_idle = 0; } else if is_idle && counting_idle_ticks { - k.ticks_since_idle = k.ticks_since_idle.saturating_add(1); + k.ticks_since_idle = k.ticks_since_idle.saturating_add(ms_elapsed); + #[cfg(feature = "perf_logging")] + log::info!("ticks since idle: {}", k.ticks_since_idle); } is_idle && !counting_idle_ticks }; @@ -1487,9 +1497,10 @@ impl Kanata { #[cfg(feature = "perf_logging")] let start = std::time::Instant::now(); - if let Err(e) = k.handle_time_ticks(&tx) { - break e; - } + match k.handle_time_ticks(&tx) { + Ok(ms) => ms_elapsed = ms, + Err(e) => break e, + }; #[cfg(feature = "perf_logging")] log::info!( @@ -1521,9 +1532,10 @@ impl Kanata { #[cfg(feature = "perf_logging")] let start = std::time::Instant::now(); - if let Err(e) = k.handle_time_ticks(&tx) { - break e; - } + match k.handle_time_ticks(&tx) { + Ok(ms) => ms_elapsed = ms, + Err(e) => break e, + }; #[cfg(feature = "perf_logging")] log::info!( @@ -1535,9 +1547,10 @@ impl Kanata { #[cfg(feature = "perf_logging")] let start = std::time::Instant::now(); - if let Err(e) = k.handle_time_ticks(&tx) { - break e; - } + match k.handle_time_ticks(&tx) { + Ok(ms) => ms_elapsed = ms, + Err(e) => break e, + }; #[cfg(feature = "perf_logging")] log::info!(