feat(core): add source_id parameter to events and introduce past events discarding mechanism
This commit is contained in:
parent
7db39f4c74
commit
302a45aa88
|
@ -53,7 +53,7 @@ pub fn initialize_and_spawn(
|
||||||
|
|
||||||
let modulo_manager = ui::modulo::ModuloManager::new();
|
let modulo_manager = ui::modulo::ModuloManager::new();
|
||||||
|
|
||||||
let (detect_source, modifier_state_store) =
|
let (detect_source, modifier_state_store, sequencer) =
|
||||||
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
||||||
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![&detect_source];
|
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![&detect_source];
|
||||||
let funnel = crate::engine::funnel::default(&sources);
|
let funnel = crate::engine::funnel::default(&sources);
|
||||||
|
@ -108,6 +108,7 @@ pub fn initialize_and_spawn(
|
||||||
&renderer_adapter,
|
&renderer_adapter,
|
||||||
&match_cache,
|
&match_cache,
|
||||||
&modifier_state_store,
|
&modifier_state_store,
|
||||||
|
&sequencer,
|
||||||
);
|
);
|
||||||
|
|
||||||
let event_injector =
|
let event_injector =
|
||||||
|
|
|
@ -17,11 +17,9 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use espanso_config::matches::{Match, MatchEffect};
|
use espanso_config::matches::{Match, MatchEffect};
|
||||||
|
|
||||||
use crate::engine::{event::{Event, internal::DetectedMatch, internal::RenderingRequestedEvent}, process::Multiplexer};
|
use crate::engine::{event::{EventType, internal::DetectedMatch, internal::RenderingRequestedEvent}, process::Multiplexer};
|
||||||
|
|
||||||
pub trait MatchProvider<'a> {
|
pub trait MatchProvider<'a> {
|
||||||
fn get(&self, match_id: i32) -> Option<&'a Match>;
|
fn get(&self, match_id: i32) -> Option<&'a Match>;
|
||||||
|
@ -38,11 +36,11 @@ impl<'a> MultiplexAdapter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Multiplexer for MultiplexAdapter<'a> {
|
impl<'a> Multiplexer for MultiplexAdapter<'a> {
|
||||||
fn convert(&self, detected_match: DetectedMatch) -> Option<Event> {
|
fn convert(&self, detected_match: DetectedMatch) -> Option<EventType> {
|
||||||
let m = self.provider.get(detected_match.id)?;
|
let m = self.provider.get(detected_match.id)?;
|
||||||
|
|
||||||
match &m.effect {
|
match &m.effect {
|
||||||
MatchEffect::Text(_) => Some(Event::RenderingRequested(RenderingRequestedEvent {
|
MatchEffect::Text(_) => Some(EventType::RenderingRequested(RenderingRequestedEvent {
|
||||||
match_id: detected_match.id,
|
match_id: detected_match.id,
|
||||||
trigger: detected_match.trigger,
|
trigger: detected_match.trigger,
|
||||||
left_separator: detected_match.left_separator,
|
left_separator: detected_match.left_separator,
|
||||||
|
|
|
@ -18,18 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
use espanso_detect::{event::InputEvent};
|
use espanso_detect::event::InputEvent;
|
||||||
|
|
||||||
use crate::engine::{
|
use crate::engine::{event::{Event, EventType, SourceId, input::{Key, KeyboardEvent, MouseButton, MouseEvent, Status, Variant}}, funnel};
|
||||||
event::{
|
|
||||||
input::{Key, KeyboardEvent, MouseButton, MouseEvent, Status, Variant},
|
|
||||||
Event,
|
|
||||||
},
|
|
||||||
funnel
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct DetectSource {
|
pub struct DetectSource {
|
||||||
pub receiver: Receiver<InputEvent>,
|
pub receiver: Receiver<(InputEvent, SourceId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> funnel::Source<'a> for DetectSource {
|
impl<'a> funnel::Source<'a> for DetectSource {
|
||||||
|
@ -38,20 +32,26 @@ impl<'a> funnel::Source<'a> for DetectSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, op: SelectedOperation) -> Event {
|
fn receive(&self, op: SelectedOperation) -> Event {
|
||||||
let input_event = op
|
let (input_event, source_id) = op
|
||||||
.recv(&self.receiver)
|
.recv(&self.receiver)
|
||||||
.expect("unable to select data from DetectSource receiver");
|
.expect("unable to select data from DetectSource receiver");
|
||||||
match input_event {
|
match input_event {
|
||||||
InputEvent::Keyboard(keyboard_event) => Event::Keyboard(KeyboardEvent {
|
InputEvent::Keyboard(keyboard_event) => Event {
|
||||||
|
source_id,
|
||||||
|
etype: EventType::Keyboard(KeyboardEvent {
|
||||||
key: keyboard_event.key.into(),
|
key: keyboard_event.key.into(),
|
||||||
value: keyboard_event.value,
|
value: keyboard_event.value,
|
||||||
status: keyboard_event.status.into(),
|
status: keyboard_event.status.into(),
|
||||||
variant: keyboard_event.variant.map(|variant| variant.into()),
|
variant: keyboard_event.variant.map(|variant| variant.into()),
|
||||||
}),
|
}),
|
||||||
InputEvent::Mouse(mouse_event) => Event::Mouse(MouseEvent {
|
},
|
||||||
|
InputEvent::Mouse(mouse_event) => Event {
|
||||||
|
source_id,
|
||||||
|
etype: EventType::Mouse(MouseEvent {
|
||||||
status: mouse_event.status.into(),
|
status: mouse_event.status.into(),
|
||||||
button: mouse_event.button.into(),
|
button: mouse_event.button.into(),
|
||||||
}),
|
}),
|
||||||
|
},
|
||||||
InputEvent::HotKey(_) => todo!(), // TODO
|
InputEvent::HotKey(_) => todo!(), // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,19 +24,22 @@ use thiserror::Error;
|
||||||
|
|
||||||
use detect::DetectSource;
|
use detect::DetectSource;
|
||||||
|
|
||||||
use self::modifier::{Modifier, ModifierStateStore};
|
use self::{modifier::{Modifier, ModifierStateStore}, sequencer::Sequencer};
|
||||||
|
|
||||||
pub mod detect;
|
pub mod detect;
|
||||||
pub mod modifier;
|
pub mod modifier;
|
||||||
|
pub mod sequencer;
|
||||||
|
|
||||||
// TODO: pass options
|
// TODO: pass options
|
||||||
pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore)> {
|
pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore, Sequencer)> {
|
||||||
let (sender, receiver) = crossbeam::channel::unbounded();
|
let (sender, receiver) = crossbeam::channel::unbounded();
|
||||||
let (init_tx, init_rx) = crossbeam::channel::unbounded();
|
let (init_tx, init_rx) = crossbeam::channel::unbounded();
|
||||||
|
|
||||||
let modifier_state_store = ModifierStateStore::new();
|
let modifier_state_store = ModifierStateStore::new();
|
||||||
|
let sequencer = Sequencer::new();
|
||||||
|
|
||||||
let state_store_clone = modifier_state_store.clone();
|
let state_store_clone = modifier_state_store.clone();
|
||||||
|
let sequencer_clone = sequencer.clone();
|
||||||
if let Err(error) = std::thread::Builder::new()
|
if let Err(error) = std::thread::Builder::new()
|
||||||
.name("detect thread".to_string())
|
.name("detect thread".to_string())
|
||||||
.spawn(
|
.spawn(
|
||||||
|
@ -58,8 +61,11 @@ pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore)> {
|
||||||
state_store_clone.update_state(modifier, is_pressed);
|
state_store_clone.update_state(modifier, is_pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a monotonically increasing id for the current event
|
||||||
|
let source_id = sequencer_clone.next_id();
|
||||||
|
|
||||||
sender
|
sender
|
||||||
.send(event)
|
.send((event, source_id))
|
||||||
.expect("unable to send to the source channel");
|
.expect("unable to send to the source channel");
|
||||||
}))
|
}))
|
||||||
.expect("detect eventloop crashed");
|
.expect("detect eventloop crashed");
|
||||||
|
@ -86,7 +92,7 @@ pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore)> {
|
||||||
return Err(DetectSourceError::InitFailed.into());
|
return Err(DetectSourceError::InitFailed.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((DetectSource { receiver }, modifier_state_store))
|
Ok((DetectSource { receiver }, modifier_state_store, sequencer))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|
48
espanso/src/cli/worker/engine/source/sequencer.rs
Normal file
48
espanso/src/cli/worker/engine/source/sequencer.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicU32, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::engine::{event::SourceId, process::EventSequenceProvider};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Sequencer {
|
||||||
|
current_id: Arc<AtomicU32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sequencer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
current_id: Arc::new(AtomicU32::new(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_id(&self) -> SourceId {
|
||||||
|
self.current_id.fetch_add(1, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventSequenceProvider for Sequencer {
|
||||||
|
fn get_next_id(&self) -> SourceId {
|
||||||
|
self.next_id()
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::engine::event::EventType;
|
||||||
|
|
||||||
use super::super::{Event, Executor, KeyInjector};
|
use super::super::{Event, Executor, KeyInjector};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
|
@ -32,7 +34,7 @@ impl<'a> KeyInjectExecutor<'a> {
|
||||||
|
|
||||||
impl<'a> Executor for KeyInjectExecutor<'a> {
|
impl<'a> Executor for KeyInjectExecutor<'a> {
|
||||||
fn execute(&self, event: &Event) -> bool {
|
fn execute(&self, event: &Event) -> bool {
|
||||||
if let Event::KeySequenceInject(inject_event) = event {
|
if let EventType::KeySequenceInject(inject_event) = &event.etype {
|
||||||
if let Err(error) = self.injector.inject_sequence(&inject_event.keys) {
|
if let Err(error) = self.injector.inject_sequence(&inject_event.keys) {
|
||||||
error!("key injector reported an error: {}", error);
|
error!("key injector reported an error: {}", error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use super::super::{Event, Executor};
|
use super::super::{Event, Executor};
|
||||||
use crate::engine::event::effect::TextInjectMode;
|
use crate::engine::event::{EventType, effect::TextInjectMode};
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
|
|
||||||
pub trait TextInjector {
|
pub trait TextInjector {
|
||||||
|
@ -63,7 +63,7 @@ impl<'a> TextInjectExecutor<'a> {
|
||||||
|
|
||||||
impl<'a> Executor for TextInjectExecutor<'a> {
|
impl<'a> Executor for TextInjectExecutor<'a> {
|
||||||
fn execute(&self, event: &Event) -> bool {
|
fn execute(&self, event: &Event) -> bool {
|
||||||
if let Event::TextInject(inject_event) = event {
|
if let EventType::TextInject(inject_event) = &event.etype {
|
||||||
let active_mode = self.mode_provider.active_mode();
|
let active_mode = self.mode_provider.active_mode();
|
||||||
|
|
||||||
let injector = if let Some(force_mode) = &inject_event.force_mode {
|
let injector = if let Some(force_mode) = &inject_event.force_mode {
|
||||||
|
|
|
@ -57,3 +57,9 @@ pub struct RenderedEvent {
|
||||||
pub match_id: i32,
|
pub match_id: i32,
|
||||||
pub body: String,
|
pub body: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct DiscardPreviousEvent {
|
||||||
|
// All Events with a source_id smaller than this one will be discarded
|
||||||
|
pub minimum_source_id: u32,
|
||||||
|
}
|
|
@ -21,8 +21,30 @@ pub mod input;
|
||||||
pub mod effect;
|
pub mod effect;
|
||||||
pub mod internal;
|
pub mod internal;
|
||||||
|
|
||||||
|
pub type SourceId = u32;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Event {
|
pub struct Event {
|
||||||
|
// The source id is a unique, monothonically increasing number
|
||||||
|
// that is given to each event by the source and is propagated
|
||||||
|
// to all consequential events.
|
||||||
|
// For example, if a keyboard event with source_id = 5 generates
|
||||||
|
// a detected match event, this event will have source_id = 5
|
||||||
|
pub source_id: SourceId,
|
||||||
|
pub etype: EventType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
pub fn caused_by(cause_id: SourceId, event_type: EventType) -> Event {
|
||||||
|
Event {
|
||||||
|
source_id: cause_id,
|
||||||
|
etype: event_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum EventType {
|
||||||
NOOP,
|
NOOP,
|
||||||
ProcessingError(String),
|
ProcessingError(String),
|
||||||
|
|
||||||
|
@ -39,6 +61,7 @@ pub enum Event {
|
||||||
RenderingRequested(internal::RenderingRequestedEvent),
|
RenderingRequested(internal::RenderingRequestedEvent),
|
||||||
Rendered(internal::RenderedEvent),
|
Rendered(internal::RenderedEvent),
|
||||||
MatchInjected,
|
MatchInjected,
|
||||||
|
DiscardPrevious(internal::DiscardPreviousEvent),
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
TriggerCompensation(effect::TriggerCompensationEvent),
|
TriggerCompensation(effect::TriggerCompensationEvent),
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use log::{debug, trace};
|
use log::{debug};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
dispatch::Dispatcher,
|
dispatch::Dispatcher,
|
||||||
event::Event,
|
event::{Event},
|
||||||
process::Processor,
|
process::Processor,
|
||||||
funnel::{Funnel, FunnelResult},
|
funnel::{Funnel, FunnelResult},
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use super::{Event, MatchFilter, MatchInfoProvider, MatchSelector, Matcher, Middleware, Multiplexer, Processor, Renderer, middleware::{
|
use super::{MatchFilter, MatchInfoProvider, MatchSelector, Matcher, Middleware, Multiplexer, Processor, Renderer, middleware::{
|
||||||
match_select::MatchSelectMiddleware, matcher::MatcherMiddleware, multiplex::MultiplexMiddleware,
|
match_select::MatchSelectMiddleware, matcher::MatcherMiddleware, multiplex::MultiplexMiddleware,
|
||||||
render::RenderMiddleware, action::ActionMiddleware, cursor_hint::CursorHintMiddleware, cause::CauseCompensateMiddleware,
|
render::RenderMiddleware, action::{ActionMiddleware, EventSequenceProvider}, cursor_hint::CursorHintMiddleware, cause::CauseCompensateMiddleware,
|
||||||
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider},
|
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider},
|
||||||
|
past_discard::PastEventsDiscardMiddleware,
|
||||||
}};
|
}};
|
||||||
|
use crate::engine::event::{Event, EventType};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct DefaultProcessor<'a> {
|
pub struct DefaultProcessor<'a> {
|
||||||
|
@ -40,17 +42,19 @@ impl<'a> DefaultProcessor<'a> {
|
||||||
renderer: &'a dyn Renderer<'a>,
|
renderer: &'a dyn Renderer<'a>,
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
match_info_provider: &'a dyn MatchInfoProvider,
|
||||||
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
||||||
|
event_sequence_provider: &'a dyn EventSequenceProvider,
|
||||||
) -> DefaultProcessor<'a> {
|
) -> DefaultProcessor<'a> {
|
||||||
Self {
|
Self {
|
||||||
event_queue: VecDeque::new(),
|
event_queue: VecDeque::new(),
|
||||||
middleware: vec![
|
middleware: vec![
|
||||||
|
Box::new(PastEventsDiscardMiddleware::new()),
|
||||||
Box::new(MatcherMiddleware::new(matchers)),
|
Box::new(MatcherMiddleware::new(matchers)),
|
||||||
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
||||||
Box::new(CauseCompensateMiddleware::new()),
|
Box::new(CauseCompensateMiddleware::new()),
|
||||||
Box::new(MultiplexMiddleware::new(multiplexer)),
|
Box::new(MultiplexMiddleware::new(multiplexer)),
|
||||||
Box::new(RenderMiddleware::new(renderer)),
|
Box::new(RenderMiddleware::new(renderer)),
|
||||||
Box::new(CursorHintMiddleware::new()),
|
Box::new(CursorHintMiddleware::new()),
|
||||||
Box::new(ActionMiddleware::new(match_info_provider)),
|
Box::new(ActionMiddleware::new(match_info_provider, event_sequence_provider)),
|
||||||
Box::new(DelayForModifierReleaseMiddleware::new(modifier_status_provider)),
|
Box::new(DelayForModifierReleaseMiddleware::new(modifier_status_provider)),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -73,6 +77,11 @@ impl<'a> DefaultProcessor<'a> {
|
||||||
current_event = middleware.next(current_event, &mut dispatch);
|
current_event = middleware.next(current_event, &mut dispatch);
|
||||||
|
|
||||||
trace!("middleware '{}' produced event: {:?}", middleware.name(), current_event);
|
trace!("middleware '{}' produced event: {:?}", middleware.name(), current_event);
|
||||||
|
|
||||||
|
if let EventType::NOOP = current_event.etype {
|
||||||
|
trace!("interrupting chain as the event is NOOP");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(event) = current_queue.pop_back() {
|
while let Some(event) = current_queue.pop_back() {
|
||||||
|
|
|
@ -18,26 +18,34 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{
|
use crate::engine::event::{
|
||||||
event::{
|
effect::{KeySequenceInjectRequest, TextInjectMode, TextInjectRequest},
|
||||||
input::{Key},
|
input::Key,
|
||||||
effect::{TextInjectMode, TextInjectRequest, KeySequenceInjectRequest},
|
internal::DiscardPreviousEvent,
|
||||||
Event,
|
Event, EventType,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait MatchInfoProvider {
|
pub trait MatchInfoProvider {
|
||||||
fn get_force_mode(&self, match_id: i32) -> Option<TextInjectMode>;
|
fn get_force_mode(&self, match_id: i32) -> Option<TextInjectMode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait EventSequenceProvider {
|
||||||
|
fn get_next_id(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActionMiddleware<'a> {
|
pub struct ActionMiddleware<'a> {
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
match_info_provider: &'a dyn MatchInfoProvider,
|
||||||
|
event_sequence_provider: &'a dyn EventSequenceProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ActionMiddleware<'a> {
|
impl<'a> ActionMiddleware<'a> {
|
||||||
pub fn new(match_info_provider: &'a dyn MatchInfoProvider) -> Self {
|
pub fn new(
|
||||||
|
match_info_provider: &'a dyn MatchInfoProvider,
|
||||||
|
event_sequence_provider: &'a dyn EventSequenceProvider,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
match_info_provider,
|
match_info_provider,
|
||||||
|
event_sequence_provider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,23 +56,42 @@ impl<'a> Middleware for ActionMiddleware<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
||||||
match &event {
|
match &event.etype {
|
||||||
Event::Rendered(m_event) => {
|
EventType::Rendered(m_event) => {
|
||||||
dispatch(Event::MatchInjected);
|
dispatch(Event::caused_by(event.source_id, EventType::MatchInjected));
|
||||||
|
dispatch(Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::DiscardPrevious(DiscardPreviousEvent {
|
||||||
|
minimum_source_id: self.event_sequence_provider.get_next_id(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
Event::TextInject(TextInjectRequest {
|
Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::TextInject(TextInjectRequest {
|
||||||
text: m_event.body.clone(),
|
text: m_event.body.clone(),
|
||||||
force_mode: self.match_info_provider.get_force_mode(m_event.match_id),
|
force_mode: self.match_info_provider.get_force_mode(m_event.match_id),
|
||||||
})
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Event::CursorHintCompensation(m_event) => {
|
EventType::CursorHintCompensation(m_event) => {
|
||||||
Event::KeySequenceInject(KeySequenceInjectRequest {
|
dispatch(Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::DiscardPrevious(DiscardPreviousEvent {
|
||||||
|
minimum_source_id: self.event_sequence_provider.get_next_id(),
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::KeySequenceInject(KeySequenceInjectRequest {
|
||||||
keys: (0..m_event.cursor_hint_back_count)
|
keys: (0..m_event.cursor_hint_back_count)
|
||||||
.map(|_| Key::ArrowLeft)
|
.map(|_| Key::ArrowLeft)
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Event::TriggerCompensation(m_event) => {
|
EventType::TriggerCompensation(m_event) => {
|
||||||
let mut backspace_count = m_event.trigger.chars().count();
|
let mut backspace_count = m_event.trigger.chars().count();
|
||||||
|
|
||||||
// We want to preserve the left separator if present
|
// We want to preserve the left separator if present
|
||||||
|
@ -72,9 +99,12 @@ impl<'a> Middleware for ActionMiddleware<'a> {
|
||||||
backspace_count -= left_separator.chars().count();
|
backspace_count -= left_separator.chars().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::KeySequenceInject(KeySequenceInjectRequest {
|
Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::KeySequenceInject(KeySequenceInjectRequest {
|
||||||
keys: (0..backspace_count).map(|_| Key::Backspace).collect(),
|
keys: (0..backspace_count).map(|_| Key::Backspace).collect(),
|
||||||
})
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => event,
|
_ => event,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{
|
use crate::engine::{event::{Event, EventType, effect::TriggerCompensationEvent, internal::CauseCompensatedMatchEvent}};
|
||||||
event::{
|
|
||||||
effect::TriggerCompensationEvent,
|
|
||||||
internal::CauseCompensatedMatchEvent,
|
|
||||||
Event,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct CauseCompensateMiddleware {}
|
pub struct CauseCompensateMiddleware {}
|
||||||
|
|
||||||
|
@ -36,22 +30,22 @@ impl CauseCompensateMiddleware {
|
||||||
|
|
||||||
impl Middleware for CauseCompensateMiddleware {
|
impl Middleware for CauseCompensateMiddleware {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"cause_compensate"
|
"discard"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
||||||
if let Event::MatchSelected(m_event) = &event {
|
if let EventType::MatchSelected(m_event) = &event.etype {
|
||||||
let compensated_event =
|
let compensated_event =
|
||||||
Event::CauseCompensatedMatch(CauseCompensatedMatchEvent { m: m_event.chosen.clone() });
|
Event::caused_by(event.source_id, EventType::CauseCompensatedMatch(CauseCompensatedMatchEvent { m: m_event.chosen.clone() }));
|
||||||
|
|
||||||
if let Some(trigger) = &m_event.chosen.trigger {
|
if let Some(trigger) = &m_event.chosen.trigger {
|
||||||
dispatch(compensated_event);
|
dispatch(compensated_event);
|
||||||
|
|
||||||
// Before the event, place a trigger compensation
|
// Before the event, place a trigger compensation
|
||||||
return Event::TriggerCompensation(TriggerCompensationEvent {
|
return Event::caused_by(event.source_id, EventType::TriggerCompensation(TriggerCompensationEvent {
|
||||||
trigger: trigger.clone(),
|
trigger: trigger.clone(),
|
||||||
left_separator: m_event.chosen.left_separator.clone(),
|
left_separator: m_event.chosen.left_separator.clone(),
|
||||||
});
|
}));
|
||||||
} else {
|
} else {
|
||||||
return compensated_event;
|
return compensated_event;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{event::{Event, effect::CursorHintCompensationEvent, internal::RenderedEvent}};
|
use crate::engine::{event::{Event, EventType, effect::CursorHintCompensationEvent, internal::RenderedEvent}};
|
||||||
|
|
||||||
pub struct CursorHintMiddleware {}
|
pub struct CursorHintMiddleware {}
|
||||||
|
|
||||||
|
@ -34,20 +34,20 @@ impl Middleware for CursorHintMiddleware {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
||||||
if let Event::Rendered(m_event) = event {
|
if let EventType::Rendered(m_event) = event.etype {
|
||||||
let (body, cursor_hint_back_count) = process_cursor_hint(m_event.body);
|
let (body, cursor_hint_back_count) = process_cursor_hint(m_event.body);
|
||||||
|
|
||||||
if let Some(cursor_hint_back_count) = cursor_hint_back_count {
|
if let Some(cursor_hint_back_count) = cursor_hint_back_count {
|
||||||
dispatch(Event::CursorHintCompensation(CursorHintCompensationEvent {
|
dispatch(Event::caused_by(event.source_id, EventType::CursorHintCompensation(CursorHintCompensationEvent {
|
||||||
cursor_hint_back_count,
|
cursor_hint_back_count,
|
||||||
}))
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alter the rendered event to remove the cursor hint from the body
|
// Alter the rendered event to remove the cursor hint from the body
|
||||||
return Event::Rendered(RenderedEvent {
|
return Event::caused_by(event.source_id, EventType::Rendered(RenderedEvent {
|
||||||
body,
|
body,
|
||||||
..m_event
|
..m_event
|
||||||
})
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
event
|
event
|
||||||
|
|
|
@ -26,9 +26,7 @@ use std::{
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::event::{
|
use crate::engine::event::{Event, EventType};
|
||||||
Event,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: pass through config
|
// TODO: pass through config
|
||||||
const MODIFIER_DELAY_TIMEOUT: Duration = Duration::from_secs(3);
|
const MODIFIER_DELAY_TIMEOUT: Duration = Duration::from_secs(3);
|
||||||
|
@ -55,7 +53,7 @@ impl <'a> Middleware for DelayForModifierReleaseMiddleware<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
if is_injection_event(&event) {
|
if is_injection_event(&event.etype) {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
while self.provider.is_any_modifier_pressed() {
|
while self.provider.is_any_modifier_pressed() {
|
||||||
if Instant::now().duration_since(start) > MODIFIER_DELAY_TIMEOUT {
|
if Instant::now().duration_since(start) > MODIFIER_DELAY_TIMEOUT {
|
||||||
|
@ -71,12 +69,12 @@ impl <'a> Middleware for DelayForModifierReleaseMiddleware<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_injection_event(event: &Event) -> bool {
|
fn is_injection_event(event_type: &EventType) -> bool {
|
||||||
match event {
|
match event_type {
|
||||||
Event::TriggerCompensation(_) => true,
|
EventType::TriggerCompensation(_) => true,
|
||||||
Event::CursorHintCompensation(_) => true,
|
EventType::CursorHintCompensation(_) => true,
|
||||||
Event::KeySequenceInject(_) => true,
|
EventType::KeySequenceInject(_) => true,
|
||||||
Event::TextInject(_) => true,
|
EventType::TextInject(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,7 @@
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{
|
use crate::engine::{event::{Event, EventType, internal::{MatchSelectedEvent}}, process::{MatchFilter, MatchSelector}};
|
||||||
event::{
|
|
||||||
internal::{MatchSelectedEvent},
|
|
||||||
Event,
|
|
||||||
},
|
|
||||||
process::{MatchFilter, MatchSelector},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct MatchSelectMiddleware<'a> {
|
pub struct MatchSelectMiddleware<'a> {
|
||||||
match_filter: &'a dyn MatchFilter,
|
match_filter: &'a dyn MatchFilter,
|
||||||
|
@ -48,14 +42,14 @@ impl<'a> Middleware for MatchSelectMiddleware<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
if let Event::MatchesDetected(m_event) = event {
|
if let EventType::MatchesDetected(m_event) = event.etype {
|
||||||
let matches_ids: Vec<i32> = m_event.matches.iter().map(|m| m.id).collect();
|
let matches_ids: Vec<i32> = m_event.matches.iter().map(|m| m.id).collect();
|
||||||
|
|
||||||
// Find the matches that are actually valid in the current context
|
// Find the matches that are actually valid in the current context
|
||||||
let valid_ids = self.match_filter.filter_active(&matches_ids);
|
let valid_ids = self.match_filter.filter_active(&matches_ids);
|
||||||
|
|
||||||
return match valid_ids.len() {
|
return match valid_ids.len() {
|
||||||
0 => Event::NOOP, // No valid matches, consume the event
|
0 => Event::caused_by(event.source_id, EventType::NOOP), // No valid matches, consume the event
|
||||||
1 => {
|
1 => {
|
||||||
// Only one match, no need to show a selection dialog
|
// Only one match, no need to show a selection dialog
|
||||||
let m = m_event
|
let m = m_event
|
||||||
|
@ -63,10 +57,10 @@ impl<'a> Middleware for MatchSelectMiddleware<'a> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|m| m.id == *valid_ids.first().unwrap());
|
.find(|m| m.id == *valid_ids.first().unwrap());
|
||||||
if let Some(m) = m {
|
if let Some(m) = m {
|
||||||
Event::MatchSelected(MatchSelectedEvent { chosen: m })
|
Event::caused_by(event.source_id, EventType::MatchSelected(MatchSelectedEvent { chosen: m }))
|
||||||
} else {
|
} else {
|
||||||
error!("MatchSelectMiddleware could not find the correspondent match");
|
error!("MatchSelectMiddleware could not find the correspondent match");
|
||||||
Event::NOOP
|
Event::caused_by(event.source_id, EventType::NOOP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -77,14 +71,14 @@ impl<'a> Middleware for MatchSelectMiddleware<'a> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|m| m.id == selected_id);
|
.find(|m| m.id == selected_id);
|
||||||
if let Some(m) = m {
|
if let Some(m) = m {
|
||||||
Event::MatchSelected(MatchSelectedEvent { chosen: m })
|
Event::caused_by(event.source_id, EventType::MatchSelected(MatchSelectedEvent { chosen: m }))
|
||||||
} else {
|
} else {
|
||||||
error!("MatchSelectMiddleware could not find the correspondent match");
|
error!("MatchSelectMiddleware could not find the correspondent match");
|
||||||
Event::NOOP
|
Event::caused_by(event.source_id, EventType::NOOP)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("MatchSelectMiddleware did not receive any match selection");
|
debug!("MatchSelectMiddleware did not receive any match selection");
|
||||||
Event::NOOP
|
Event::caused_by(event.source_id, EventType::NOOP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::engine::{
|
||||||
event::{
|
event::{
|
||||||
input::{Key, Status},
|
input::{Key, Status},
|
||||||
internal::{DetectedMatch, MatchesDetectedEvent},
|
internal::{DetectedMatch, MatchesDetectedEvent},
|
||||||
Event,
|
Event, EventType,
|
||||||
},
|
},
|
||||||
process::{Matcher, MatcherEvent},
|
process::{Matcher, MatcherEvent},
|
||||||
};
|
};
|
||||||
|
@ -53,7 +53,7 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
if is_event_of_interest(&event) {
|
if is_event_of_interest(&event.etype) {
|
||||||
let mut matcher_states = self.matcher_states.borrow_mut();
|
let mut matcher_states = self.matcher_states.borrow_mut();
|
||||||
let prev_states = if !matcher_states.is_empty() {
|
let prev_states = if !matcher_states.is_empty() {
|
||||||
matcher_states.get(matcher_states.len() - 1)
|
matcher_states.get(matcher_states.len() - 1)
|
||||||
|
@ -61,7 +61,7 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Event::Keyboard(keyboard_event) = &event {
|
if let EventType::Keyboard(keyboard_event) = &event.etype {
|
||||||
// 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");
|
||||||
|
@ -80,7 +80,7 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
|
|
||||||
let mut all_results = Vec::new();
|
let mut all_results = Vec::new();
|
||||||
|
|
||||||
if let Some(matcher_event) = convert_to_matcher_event(&event) {
|
if let Some(matcher_event) = convert_to_matcher_event(&event.etype) {
|
||||||
let mut new_states = Vec::new();
|
let mut new_states = Vec::new();
|
||||||
for (i, matcher) in self.matchers.iter().enumerate() {
|
for (i, matcher) in self.matchers.iter().enumerate() {
|
||||||
let prev_state = prev_states.and_then(|states| states.get(i));
|
let prev_state = prev_states.and_then(|states| states.get(i));
|
||||||
|
@ -97,7 +97,9 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !all_results.is_empty() {
|
if !all_results.is_empty() {
|
||||||
return Event::MatchesDetected(MatchesDetectedEvent {
|
return Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::MatchesDetected(MatchesDetectedEvent {
|
||||||
matches: all_results
|
matches: all_results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|result| DetectedMatch {
|
.map(|result| DetectedMatch {
|
||||||
|
@ -108,7 +110,8 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
args: result.args,
|
args: result.args,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,9 +120,9 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_event_of_interest(event: &Event) -> bool {
|
fn is_event_of_interest(event_type: &EventType) -> bool {
|
||||||
match event {
|
match event_type {
|
||||||
Event::Keyboard(keyboard_event) => {
|
EventType::Keyboard(keyboard_event) => {
|
||||||
if keyboard_event.status != Status::Pressed {
|
if keyboard_event.status != Status::Pressed {
|
||||||
// Skip non-press events
|
// Skip non-press events
|
||||||
false
|
false
|
||||||
|
@ -133,24 +136,24 @@ fn is_event_of_interest(event: &Event) -> bool {
|
||||||
Key::NumLock => false,
|
Key::NumLock => false,
|
||||||
Key::Control => false,
|
Key::Control => false,
|
||||||
|
|
||||||
_ => true
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Event::Mouse(mouse_event) => mouse_event.status == Status::Pressed,
|
EventType::Mouse(mouse_event) => mouse_event.status == Status::Pressed,
|
||||||
Event::MatchInjected => true,
|
EventType::MatchInjected => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_matcher_event(event: &Event) -> Option<MatcherEvent> {
|
fn convert_to_matcher_event(event_type: &EventType) -> Option<MatcherEvent> {
|
||||||
match event {
|
match event_type {
|
||||||
Event::Keyboard(keyboard_event) => Some(MatcherEvent::Key {
|
EventType::Keyboard(keyboard_event) => Some(MatcherEvent::Key {
|
||||||
key: keyboard_event.key.clone(),
|
key: keyboard_event.key.clone(),
|
||||||
chars: keyboard_event.value.clone(),
|
chars: keyboard_event.value.clone(),
|
||||||
}),
|
}),
|
||||||
Event::Mouse(_) => Some(MatcherEvent::VirtualSeparator),
|
EventType::Mouse(_) => Some(MatcherEvent::VirtualSeparator),
|
||||||
Event::MatchInjected => Some(MatcherEvent::VirtualSeparator),
|
EventType::MatchInjected => Some(MatcherEvent::VirtualSeparator),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,5 @@ pub mod delay_modifiers;
|
||||||
pub mod match_select;
|
pub mod match_select;
|
||||||
pub mod matcher;
|
pub mod matcher;
|
||||||
pub mod multiplex;
|
pub mod multiplex;
|
||||||
|
pub mod past_discard;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
|
|
@ -17,10 +17,13 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use log::{error};
|
use log::error;
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{event::Event, process::Multiplexer};
|
use crate::engine::{
|
||||||
|
event::{Event, EventType},
|
||||||
|
process::Multiplexer,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct MultiplexMiddleware<'a> {
|
pub struct MultiplexMiddleware<'a> {
|
||||||
multiplexer: &'a dyn Multiplexer,
|
multiplexer: &'a dyn Multiplexer,
|
||||||
|
@ -38,14 +41,14 @@ impl<'a> Middleware for MultiplexMiddleware<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
if let Event::CauseCompensatedMatch(m_event) = event {
|
if let EventType::CauseCompensatedMatch(m_event) = event.etype {
|
||||||
return match self.multiplexer.convert(m_event.m) {
|
return match self.multiplexer.convert(m_event.m) {
|
||||||
Some(event) => event,
|
Some(new_event) => Event::caused_by(event.source_id, new_event),
|
||||||
None => {
|
None => {
|
||||||
error!("match multiplexing failed");
|
error!("match multiplexing failed");
|
||||||
Event::NOOP
|
Event::caused_by(event.source_id, EventType::NOOP)
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
event
|
event
|
||||||
|
|
66
espanso/src/engine/process/middleware/past_discard.rs
Normal file
66
espanso/src/engine/process/middleware/past_discard.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 Federico Terzi
|
||||||
|
*
|
||||||
|
* espanso is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* espanso is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
|
use super::super::Middleware;
|
||||||
|
use crate::engine::{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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PastEventsDiscardMiddleware {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
source_id_threshold: RefCell::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Middleware for PastEventsDiscardMiddleware {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"past_discard"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
|
let mut source_id_threshold = self.source_id_threshold.borrow_mut();
|
||||||
|
|
||||||
|
// Filter out previous events
|
||||||
|
if event.source_id < *source_id_threshold {
|
||||||
|
trace!("discarding previous event: {:?}", event);
|
||||||
|
return Event::caused_by(event.source_id, EventType::NOOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the minimum threshold
|
||||||
|
if let EventType::DiscardPrevious(m_event) = &event.etype {
|
||||||
|
trace!("updating minimum source id threshold for events to: {}", m_event.minimum_source_id);
|
||||||
|
*source_id_threshold = m_event.minimum_source_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
|
@ -22,9 +22,8 @@ use log::error;
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
event::{
|
event::{
|
||||||
effect::{CursorHintCompensationEvent, TriggerCompensationEvent},
|
|
||||||
internal::RenderedEvent,
|
internal::RenderedEvent,
|
||||||
Event,
|
Event, EventType,
|
||||||
},
|
},
|
||||||
process::{Renderer, RendererError},
|
process::{Renderer, RendererError},
|
||||||
};
|
};
|
||||||
|
@ -45,8 +44,12 @@ impl<'a> Middleware for RenderMiddleware<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
||||||
if let Event::RenderingRequested(m_event) = event {
|
if let EventType::RenderingRequested(m_event) = event.etype {
|
||||||
match self.renderer.render(m_event.match_id, m_event.trigger.as_deref(), m_event.trigger_args) {
|
match self.renderer.render(
|
||||||
|
m_event.match_id,
|
||||||
|
m_event.trigger.as_deref(),
|
||||||
|
m_event.trigger_args,
|
||||||
|
) {
|
||||||
Ok(body) => {
|
Ok(body) => {
|
||||||
let body = if let Some(right_separator) = m_event.right_separator {
|
let body = if let Some(right_separator) = m_event.right_separator {
|
||||||
format!("{}{}", body, right_separator)
|
format!("{}{}", body, right_separator)
|
||||||
|
@ -54,20 +57,21 @@ impl<'a> Middleware for RenderMiddleware<'a> {
|
||||||
body
|
body
|
||||||
};
|
};
|
||||||
|
|
||||||
return Event::Rendered(RenderedEvent {
|
return Event::caused_by(
|
||||||
|
event.source_id,
|
||||||
|
EventType::Rendered(RenderedEvent {
|
||||||
match_id: m_event.match_id,
|
match_id: m_event.match_id,
|
||||||
body,
|
body,
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => match err.downcast_ref::<RendererError>() {
|
||||||
match err.downcast_ref::<RendererError>() {
|
Some(RendererError::Aborted) => return Event::caused_by(event.source_id, EventType::NOOP),
|
||||||
Some(RendererError::Aborted) => return Event::NOOP,
|
|
||||||
_ => {
|
_ => {
|
||||||
error!("error during rendering: {}", err);
|
error!("error during rendering: {}", err);
|
||||||
return Event::ProcessingError("An error has occurred during rendering, please examine the logs or contact support.".to_string());
|
return Event::caused_by(event.source_id, EventType::ProcessingError("An error has occurred during rendering, please examine the logs or contact support.".to_string()));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::{Event, event::{input::Key, internal::DetectedMatch}};
|
use super::{Event, event::{EventType, input::Key, internal::DetectedMatch}};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -73,7 +73,7 @@ pub trait Multiplexer {
|
||||||
fn convert(
|
fn convert(
|
||||||
&self,
|
&self,
|
||||||
m: DetectedMatch,
|
m: DetectedMatch,
|
||||||
) -> Option<Event>;
|
) -> Option<EventType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer<'a> {
|
pub trait Renderer<'a> {
|
||||||
|
@ -92,7 +92,7 @@ pub enum RendererError {
|
||||||
Aborted,
|
Aborted,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use middleware::action::MatchInfoProvider;
|
pub use middleware::action::{MatchInfoProvider, EventSequenceProvider};
|
||||||
pub use middleware::delay_modifiers::ModifierStatusProvider;
|
pub use middleware::delay_modifiers::ModifierStatusProvider;
|
||||||
|
|
||||||
pub fn default<'a, MatcherState>(
|
pub fn default<'a, MatcherState>(
|
||||||
|
@ -103,6 +103,7 @@ pub fn default<'a, MatcherState>(
|
||||||
renderer: &'a dyn Renderer<'a>,
|
renderer: &'a dyn Renderer<'a>,
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
match_info_provider: &'a dyn MatchInfoProvider,
|
||||||
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
||||||
|
event_sequence_provider: &'a dyn EventSequenceProvider,
|
||||||
) -> impl Processor + 'a {
|
) -> impl Processor + 'a {
|
||||||
default::DefaultProcessor::new(
|
default::DefaultProcessor::new(
|
||||||
matchers,
|
matchers,
|
||||||
|
@ -112,5 +113,6 @@ pub fn default<'a, MatcherState>(
|
||||||
renderer,
|
renderer,
|
||||||
match_info_provider,
|
match_info_provider,
|
||||||
modifier_status_provider,
|
modifier_status_provider,
|
||||||
|
event_sequence_provider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user