-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(repeat): check event code itself for repeat output (#986)
This commit fixes key repeat in Linux TTY and Windows when a key on the base layer is transparent, OR process-unmapped-keys is enabled and the key is unmapped. This functionality was broken in commit 089853a which changed how layers worked by removing the duplicated base-version and while-held-version of layers, for the benefit of reduced memory consumption.
- Loading branch information
Showing
4 changed files
with
234 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use super::*; | ||
|
||
impl Kanata { | ||
/// This compares the active keys in the keyberon layout against the potential key outputs for | ||
/// corresponding physical key in the configuration. If any of keyberon active keys match any | ||
/// potential physical key output, write the repeat event to the OS. | ||
pub(super) fn handle_repeat(&mut self, event: &KeyEvent) -> Result<()> { | ||
let ret = self.handle_repeat_actual(event); | ||
// The cur_keys Vec is re-used for processing, for efficiency reasons to avoid allocation. | ||
// Unlike prev_keys which has useful info for the next call to handle_time_ticks, cur_keys | ||
// can be reused and cleared — it just needs to be empty for the next handle_time_ticks | ||
// call. | ||
self.cur_keys.clear(); | ||
ret | ||
} | ||
|
||
pub(super) fn handle_repeat_actual(&mut self, event: &KeyEvent) -> Result<()> { | ||
if self.sequence_state.is_some() { | ||
// While in sequence mode, don't send key repeats. I can't imagine it's a helpful use | ||
// case for someone trying to type in a sequence that they want to rely on key repeats | ||
// to finish a sequence. I suppose one might want to do repeat in order to try and | ||
// cancel an input sequence... I'll wait for a user created issue to deal with this. | ||
return Ok(()); | ||
} | ||
self.cur_keys.extend(self.layout.bm().keycodes()); | ||
self.overrides | ||
.override_keys(&mut self.cur_keys, &mut self.override_states); | ||
|
||
// Prioritize checking the active layer in case a layer-while-held is active. | ||
let active_held_layers = self.layout.bm().trans_resolution_layer_order(); | ||
let mut held_layer_active = false; | ||
for layer in active_held_layers { | ||
held_layer_active = true; | ||
if let Some(outputs_for_key) = self.key_outputs[usize::from(layer)].get(&event.code) { | ||
log::debug!("key outs for active layer-while-held: {outputs_for_key:?};"); | ||
for osc in outputs_for_key.iter().rev().copied() { | ||
let kc = osc.into(); | ||
if self.cur_keys.contains(&kc) | ||
|| self.unshifted_keys.contains(&kc) | ||
|| self.unmodded_keys.contains(&kc) | ||
{ | ||
log::debug!("repeat {:?}", KeyCode::from(osc)); | ||
if let Err(e) = write_key(&mut self.kbd_out, osc, KeyValue::Repeat) { | ||
bail!("could not write key {e:?}") | ||
} | ||
return Ok(()); | ||
} | ||
} | ||
} | ||
} | ||
if held_layer_active { | ||
log::debug!("empty layer-while-held outputs, probably transparent"); | ||
} | ||
|
||
if let Some(outputs_for_key) = | ||
self.key_outputs[self.layout.bm().default_layer].get(&event.code) | ||
{ | ||
// Try matching a key on the default layer. | ||
// | ||
// This code executes in two cases: | ||
// 1. current layer is the default layer | ||
// 2. current layer is layer-while-held but did not find a match in the code above, e.g. a | ||
// transparent key was pressed. | ||
log::debug!("key outs for default layer: {outputs_for_key:?};"); | ||
for osc in outputs_for_key.iter().rev().copied() { | ||
let kc = osc.into(); | ||
if self.cur_keys.contains(&kc) | ||
|| self.unshifted_keys.contains(&kc) | ||
|| self.unmodded_keys.contains(&kc) | ||
{ | ||
log::debug!("repeat {:?}", KeyCode::from(osc)); | ||
if let Err(e) = write_key(&mut self.kbd_out, osc, KeyValue::Repeat) { | ||
bail!("could not write key {e:?}") | ||
} | ||
return Ok(()); | ||
} | ||
} | ||
} | ||
|
||
// Reached here and have not exited yet. | ||
// Check the standard key output itself because default layer might also be transparent | ||
// and have delegated to defsrc handling. | ||
log::debug!("checking defsrc output"); | ||
let kc = event.code.into(); | ||
if self.cur_keys.contains(&kc) | ||
|| self.unshifted_keys.contains(&kc) | ||
|| self.unmodded_keys.contains(&kc) | ||
{ | ||
if let Err(e) = write_key(&mut self.kbd_out, event.code, KeyValue::Repeat) { | ||
bail!("could not write key {e:?}"); | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
use super::*; | ||
|
||
#[test] | ||
fn repeat_standard() { | ||
let result = simulate( | ||
" | ||
(defsrc a) | ||
(deflayer base b) | ||
", | ||
" | ||
d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"out:↓B\nt:10ms\nout:↓B\nt:10ms\nout:↓B\nt:10ms\nout:↑B", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_layer_while_held() { | ||
let result = simulate( | ||
" | ||
(defsrc a b) | ||
(deflayer base a (layer-while-held held)) | ||
(deflayer held c b) | ||
", | ||
" | ||
d:b t:10 r:b t:10 d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"t:20ms\nout:↓C\nt:10ms\nout:↓C\nt:10ms\nout:↓C\nt:10ms\nout:↑C", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_layer_switch() { | ||
let result = simulate( | ||
" | ||
(defsrc a b) | ||
(deflayer base a (layer-switch swtc)) | ||
(deflayer swtc d b) | ||
", | ||
" | ||
d:b t:10 r:b t:10 d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"t:20ms\nout:↓D\nt:10ms\nout:↓D\nt:10ms\nout:↓D\nt:10ms\nout:↑D", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_layer_held_trans() { | ||
let result = simulate( | ||
" | ||
(defsrc a b) | ||
(deflayer base e (layer-while-held held)) | ||
(deflayer held _ b) | ||
", | ||
" | ||
d:b t:10 r:b t:10 d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"t:20ms\nout:↓E\nt:10ms\nout:↓E\nt:10ms\nout:↓E\nt:10ms\nout:↑E", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_many_layer_held_trans() { | ||
let result = simulate( | ||
" | ||
(defsrc a b c d e) | ||
(deflayer base e (layer-while-held held1) _ _ _) | ||
(deflayer held1 f b (layer-while-held held2) _ _) | ||
(deflayer held2 _ _ _ (layer-while-held held3) _) | ||
(deflayer held3 _ _ _ _ (layer-while-held held4)) | ||
(deflayer held4 _ _ _ _ _) | ||
", | ||
" | ||
d:b t:10 r:b t:10 | ||
d:c t:10 r:c t:10 | ||
d:d t:10 r:d t:10 | ||
d:e t:10 r:e t:10 | ||
d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"t:80ms\nout:↓F\nt:10ms\nout:↓F\nt:10ms\nout:↓F\nt:10ms\nout:↑F", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_base_layer_trans() { | ||
let result = simulate( | ||
" | ||
(defsrc a) | ||
(deflayer base _) | ||
", | ||
" | ||
d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
", | ||
); | ||
assert_eq!( | ||
"out:↓A\nt:10ms\nout:↓A\nt:10ms\nout:↓A\nt:10ms\nout:↑A", | ||
result | ||
); | ||
} | ||
|
||
#[test] | ||
fn repeat_delegate_to_base_layer_trans() { | ||
let result = simulate( | ||
" | ||
(defcfg delegate-to-first-layer yes) | ||
(defsrc a c b) | ||
(deflayer base e _ (layer-switch swtc)) | ||
(deflayer swtc _ _ _) | ||
", | ||
" | ||
d:b t:10 r:b t:10 | ||
d:a t:10 r:a t:10 r:a t:10 u:a t:10 r:a | ||
d:c t:10 r:c t:10 r:c t:10 u:c t:10 r:c | ||
", | ||
); | ||
assert_eq!( | ||
"t:20ms\nout:↓E\nt:10ms\nout:↓E\nt:10ms\nout:↓E\nt:10ms\nout:↑E\n\ | ||
t:10ms\nout:↓C\nt:10ms\nout:↓C\nt:10ms\nout:↓C\nt:10ms\nout:↑C", | ||
result | ||
); | ||
} |