fix(core): fix misbehaving backspace handling
This commit is contained in:
parent
518f0f8376
commit
f4f841f58a
|
@ -21,7 +21,14 @@ use log::trace;
|
||||||
use std::{cell::RefCell, collections::VecDeque};
|
use std::{cell::RefCell, collections::VecDeque};
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{event::{Event, keyboard::{Key, Status}, matches::{DetectedMatch, MatchesDetectedEvent}}, process::{Matcher, MatcherEvent}};
|
use crate::engine::{
|
||||||
|
event::{
|
||||||
|
keyboard::{Key, Status},
|
||||||
|
matches::{DetectedMatch, MatchesDetectedEvent},
|
||||||
|
Event,
|
||||||
|
},
|
||||||
|
process::{Matcher, MatcherEvent},
|
||||||
|
};
|
||||||
|
|
||||||
const MAX_HISTORY: usize = 3; // TODO: get as parameter
|
const MAX_HISTORY: usize = 3; // TODO: get as parameter
|
||||||
|
|
||||||
|
@ -42,59 +49,63 @@ impl<'a, State> MatchMiddleware<'a, State> {
|
||||||
|
|
||||||
impl<'a, State> Middleware for MatchMiddleware<'a, State> {
|
impl<'a, State> Middleware for MatchMiddleware<'a, State> {
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
let mut matcher_states = self.matcher_states.borrow_mut();
|
if is_event_of_interest(&event) {
|
||||||
let prev_states = if !matcher_states.is_empty() {
|
let mut matcher_states = self.matcher_states.borrow_mut();
|
||||||
matcher_states.get(matcher_states.len() - 1)
|
let prev_states = if !matcher_states.is_empty() {
|
||||||
} else {
|
matcher_states.get(matcher_states.len() - 1)
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if let Event::Keyboard(keyboard_event) = &event {
|
if let Event::Keyboard(keyboard_event) = &event {
|
||||||
// Backspace handling
|
// Backspace handling
|
||||||
if keyboard_event.key == Key::Backspace {
|
if keyboard_event.key == Key::Backspace {
|
||||||
trace!("popping the last matcher state");
|
trace!("popping the last matcher state");
|
||||||
matcher_states.pop_back();
|
matcher_states.pop_back();
|
||||||
return event;
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some keys (such as the arrow keys) prevent espanso from building
|
||||||
|
// an accurate key buffer, so we need to invalidate it.
|
||||||
|
if is_invalidating_key(&keyboard_event.key) {
|
||||||
|
trace!("invalidating event detected, clearing matching state");
|
||||||
|
matcher_states.clear();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some keys (such as the arrow keys) prevent espanso from building
|
// TODO: test if the matcher detects a word match when the states are cleared (probably not :( )
|
||||||
// an accurate key buffer, so we need to invalidate it.
|
|
||||||
if is_invalidating_key(&keyboard_event.key) {
|
|
||||||
matcher_states.clear();
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test if the matcher detects a word match when the states are cleared (probably not :( )
|
let mut all_results = Vec::new();
|
||||||
|
|
||||||
let mut all_results = Vec::new();
|
if let Some(matcher_event) = convert_to_matcher_event(&event) {
|
||||||
|
let mut new_states = Vec::new();
|
||||||
|
for (i, matcher) in self.matchers.iter().enumerate() {
|
||||||
|
let prev_state = prev_states.and_then(|states| states.get(i));
|
||||||
|
|
||||||
if let Some(matcher_event) = convert_to_matcher_event(&event) {
|
let (state, results) = matcher.process(prev_state, &matcher_event);
|
||||||
let mut new_states = Vec::new();
|
all_results.extend(results);
|
||||||
for (i, matcher) in self.matchers.iter().enumerate() {
|
|
||||||
let prev_state = prev_states.and_then(|states| states.get(i));
|
|
||||||
|
|
||||||
let (state, results) = matcher.process(prev_state, &matcher_event);
|
new_states.push(state);
|
||||||
all_results.extend(results);
|
}
|
||||||
|
|
||||||
new_states.push(state);
|
matcher_states.push_back(new_states);
|
||||||
}
|
if matcher_states.len() > MAX_HISTORY {
|
||||||
|
matcher_states.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
matcher_states.push_back(new_states);
|
if !all_results.is_empty() {
|
||||||
if matcher_states.len() > MAX_HISTORY {
|
return Event::MatchesDetected(MatchesDetectedEvent {
|
||||||
matcher_states.pop_front();
|
matches: all_results
|
||||||
}
|
.into_iter()
|
||||||
|
.map(|result| DetectedMatch {
|
||||||
if !all_results.is_empty() {
|
id: result.id,
|
||||||
return Event::MatchesDetected(MatchesDetectedEvent {
|
trigger: result.trigger,
|
||||||
matches: all_results.into_iter().map(|result | {
|
args: result.args,
|
||||||
DetectedMatch {
|
})
|
||||||
id: result.id,
|
.collect(),
|
||||||
trigger: result.trigger,
|
});
|
||||||
args: result.args,
|
}
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +113,24 @@ impl<'a, State> Middleware for MatchMiddleware<'a, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_event_of_interest(event: &Event) -> bool {
|
||||||
|
if let Event::Keyboard(keyboard_event) = &event {
|
||||||
|
if keyboard_event.status == Status::Pressed {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle mouse
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn convert_to_matcher_event(event: &Event) -> Option<MatcherEvent> {
|
fn convert_to_matcher_event(event: &Event) -> Option<MatcherEvent> {
|
||||||
if let Event::Keyboard(keyboard_event) = event {
|
if let Event::Keyboard(keyboard_event) = event {
|
||||||
if keyboard_event.status == Status::Pressed {
|
return Some(MatcherEvent::Key {
|
||||||
return Some(MatcherEvent::Key {
|
key: keyboard_event.key.clone(),
|
||||||
key: keyboard_event.key.clone(),
|
chars: keyboard_event.value.clone(),
|
||||||
chars: keyboard_event.value.clone(),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: mouse event should act as separator
|
// TODO: mouse event should act as separator
|
||||||
|
@ -132,4 +153,4 @@ fn is_invalidating_key(key: &Key) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test
|
// TODO: test
|
||||||
|
|
Loading…
Reference in New Issue
Block a user