fix(engine): prevent events from stacking up when the search bar is open. Fix #781

This commit is contained in:
Federico Terzi 2021-10-16 11:19:26 +02:00
parent a257cf96e5
commit 70bff10fd5
6 changed files with 89 additions and 34 deletions

View File

@ -85,6 +85,14 @@ pub struct DiscardPreviousEvent {
pub minimum_source_id: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DiscardBetweenEvent {
// All Events with a source_id between start_id (included) and end_id (excluded)
// will be discarded
pub start_id: u32,
pub end_id: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SecureInputEnabledEvent {
pub app_name: String,

View File

@ -71,6 +71,7 @@ pub enum EventType {
ImageResolved(internal::ImageResolvedEvent),
MatchInjected,
DiscardPrevious(internal::DiscardPreviousEvent),
DiscardBetween(internal::DiscardBetweenEvent),
Undo(internal::UndoEvent),
Disabled,

View File

@ -25,11 +25,11 @@ use super::{
cause::CauseCompensateMiddleware,
cursor_hint::CursorHintMiddleware,
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider},
discard::EventsDiscardMiddleware,
markdown::MarkdownMiddleware,
match_select::MatchSelectMiddleware,
matcher::MatcherMiddleware,
multiplex::MultiplexMiddleware,
past_discard::PastEventsDiscardMiddleware,
render::RenderMiddleware,
},
DisableOptions, EnabledStatusProvider, MatchFilter, MatchInfoProvider, MatchProvider,
@ -73,14 +73,18 @@ impl<'a> DefaultProcessor<'a> {
Self {
event_queue: VecDeque::new(),
middleware: vec![
Box::new(PastEventsDiscardMiddleware::new()),
Box::new(EventsDiscardMiddleware::new()),
Box::new(DisableMiddleware::new(disable_options)),
Box::new(IconStatusMiddleware::new()),
Box::new(MatcherMiddleware::new(matchers, matcher_options_provider)),
Box::new(SuppressMiddleware::new(enabled_status_provider)),
Box::new(ContextMenuMiddleware::new()),
Box::new(HotKeyMiddleware::new()),
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
Box::new(MatchSelectMiddleware::new(
match_filter,
match_selector,
event_sequence_provider,
)),
Box::new(CauseCompensateMiddleware::new()),
Box::new(MultiplexMiddleware::new(multiplexer)),
Box::new(RenderMiddleware::new(renderer)),

View File

@ -24,42 +24,54 @@ use log::trace;
use super::super::Middleware;
use crate::event::{Event, EventType, SourceId};
/// This middleware discards all events that have a source_id smaller than its
/// configured threshold. This useful to discard past events that might have
/// been stuck in the event queue for too long.
pub struct PastEventsDiscardMiddleware {
source_id_threshold: RefCell<SourceId>,
/// This middleware discards all events that have a source_id between
/// the given maximum and minimum.
/// This useful to discard past events that might have been stuck in the
/// event queue for too long, or events generated while the search bar was open.
pub struct EventsDiscardMiddleware {
min_id_threshold: RefCell<SourceId>,
max_id_threshold: RefCell<SourceId>,
}
impl PastEventsDiscardMiddleware {
impl EventsDiscardMiddleware {
pub fn new() -> Self {
Self {
source_id_threshold: RefCell::new(0),
min_id_threshold: RefCell::new(0),
max_id_threshold: RefCell::new(0),
}
}
}
impl Middleware for PastEventsDiscardMiddleware {
impl Middleware for EventsDiscardMiddleware {
fn name(&self) -> &'static str {
"past_discard"
"discard"
}
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
let mut source_id_threshold = self.source_id_threshold.borrow_mut();
let mut min_id_threshold = self.min_id_threshold.borrow_mut();
let mut max_id_threshold = self.max_id_threshold.borrow_mut();
// Filter out previous events
if event.source_id < *source_id_threshold {
if event.source_id < *max_id_threshold && event.source_id >= *min_id_threshold {
trace!("discarding previous event: {:?}", event);
return Event::caused_by(event.source_id, EventType::NOOP);
}
// Update the minimum threshold
// Update the thresholds
if let EventType::DiscardPrevious(m_event) = &event.etype {
trace!(
"updating minimum source id threshold for events to: {}",
"updating discard max_id_threshold threshold for events to: {}",
m_event.minimum_source_id
);
*source_id_threshold = m_event.minimum_source_id;
*max_id_threshold = m_event.minimum_source_id;
} else if let EventType::DiscardBetween(m_event) = &event.etype {
trace!(
"updating discard thresholds for events to: max={} min={}",
m_event.end_id,
m_event.start_id
);
*max_id_threshold = m_event.end_id;
*min_id_threshold = m_event.start_id;
}
event

View File

@ -20,7 +20,13 @@
use log::{debug, error};
use super::super::Middleware;
use crate::event::{internal::MatchSelectedEvent, Event, EventType};
use crate::{
event::{
internal::{DiscardBetweenEvent, MatchSelectedEvent},
Event, EventType,
},
process::EventSequenceProvider,
};
pub trait MatchFilter {
fn filter_active(&self, matches_ids: &[i32]) -> Vec<i32>;
@ -33,13 +39,19 @@ pub trait MatchSelector {
pub struct MatchSelectMiddleware<'a> {
match_filter: &'a dyn MatchFilter,
match_selector: &'a dyn MatchSelector,
event_sequence_provider: &'a dyn EventSequenceProvider,
}
impl<'a> MatchSelectMiddleware<'a> {
pub fn new(match_filter: &'a dyn MatchFilter, match_selector: &'a dyn MatchSelector) -> Self {
pub fn new(
match_filter: &'a dyn MatchFilter,
match_selector: &'a dyn MatchSelector,
event_sequence_provider: &'a dyn EventSequenceProvider,
) -> Self {
Self {
match_filter,
match_selector,
event_sequence_provider,
}
}
}
@ -49,7 +61,7 @@ impl<'a> Middleware for MatchSelectMiddleware<'a> {
"match_select"
}
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
if let EventType::MatchesDetected(m_event) = event.etype {
let matches_ids: Vec<i32> = m_event.matches.iter().map(|m| m.id).collect();
@ -75,22 +87,40 @@ impl<'a> Middleware for MatchSelectMiddleware<'a> {
}
}
_ => {
let start_event_id = self.event_sequence_provider.get_next_id();
// Multiple matches, we need to ask the user which one to use
if let Some(selected_id) = self.match_selector.select(&valid_ids, m_event.is_search) {
let m = m_event.matches.into_iter().find(|m| m.id == selected_id);
if let Some(m) = m {
Event::caused_by(
event.source_id,
EventType::MatchSelected(MatchSelectedEvent { chosen: m }),
)
let next_event =
if let Some(selected_id) = self.match_selector.select(&valid_ids, m_event.is_search) {
let m = m_event.matches.into_iter().find(|m| m.id == selected_id);
if let Some(m) = m {
Event::caused_by(
event.source_id,
EventType::MatchSelected(MatchSelectedEvent { chosen: m }),
)
} else {
error!("MatchSelectMiddleware could not find the correspondent match");
Event::caused_by(event.source_id, EventType::NOOP)
}
} else {
error!("MatchSelectMiddleware could not find the correspondent match");
debug!("MatchSelectMiddleware did not receive any match selection");
Event::caused_by(event.source_id, EventType::NOOP)
}
} else {
debug!("MatchSelectMiddleware did not receive any match selection");
Event::caused_by(event.source_id, EventType::NOOP)
}
};
let end_event_id = self.event_sequence_provider.get_next_id();
// We want to prevent espanso from "stacking up" events while the search bar is open,
// therefore we filter out all events that were generated while the search bar was open.
// See also: https://github.com/federico-terzi/espanso/issues/781
dispatch(Event::caused_by(
event.source_id,
EventType::DiscardBetween(DiscardBetweenEvent {
start_id: start_event_id,
end_id: end_event_id,
}),
));
next_event
}
};
}

View File

@ -23,6 +23,7 @@ pub mod context_menu;
pub mod cursor_hint;
pub mod delay_modifiers;
pub mod disable;
pub mod discard;
pub mod exit;
pub mod hotkey;
pub mod icon_status;
@ -31,7 +32,6 @@ pub mod markdown;
pub mod match_select;
pub mod matcher;
pub mod multiplex;
pub mod past_discard;
pub mod render;
pub mod search;
pub mod suppress;