feat(core): wire up injectors

This commit is contained in:
Federico Terzi 2021-04-11 19:19:52 +02:00
parent 4af4a434a3
commit 518f0f8376
20 changed files with 243 additions and 35 deletions

View File

@ -0,0 +1,84 @@
/*
* 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 espanso_inject::Injector;
use crate::engine::dispatch::KeyInjector;
pub struct KeyInjectorAdapter<'a> {
injector: &'a dyn Injector,
}
impl<'a> KeyInjectorAdapter<'a> {
pub fn new(injector: &'a dyn Injector) -> Self {
Self { injector }
}
}
impl<'a> KeyInjector for KeyInjectorAdapter<'a> {
fn inject_sequence(&self, keys: &[crate::engine::event::keyboard::Key]) -> anyhow::Result<()> {
let converted_keys: Vec<_> = keys.iter().map(convert_to_inject_key).collect();
self.injector.send_keys(&converted_keys, Default::default()) // TODO: handle options
}
}
fn convert_to_inject_key(key: &crate::engine::event::keyboard::Key) -> espanso_inject::keys::Key {
match key {
crate::engine::event::keyboard::Key::Alt => espanso_inject::keys::Key::Alt,
crate::engine::event::keyboard::Key::CapsLock => espanso_inject::keys::Key::CapsLock,
crate::engine::event::keyboard::Key::Control => espanso_inject::keys::Key::Control,
crate::engine::event::keyboard::Key::Meta => espanso_inject::keys::Key::Meta,
crate::engine::event::keyboard::Key::NumLock => espanso_inject::keys::Key::NumLock,
crate::engine::event::keyboard::Key::Shift => espanso_inject::keys::Key::Shift,
crate::engine::event::keyboard::Key::Enter => espanso_inject::keys::Key::Enter,
crate::engine::event::keyboard::Key::Tab => espanso_inject::keys::Key::Tab,
crate::engine::event::keyboard::Key::Space => espanso_inject::keys::Key::Space,
crate::engine::event::keyboard::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown,
crate::engine::event::keyboard::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft,
crate::engine::event::keyboard::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight,
crate::engine::event::keyboard::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp,
crate::engine::event::keyboard::Key::End => espanso_inject::keys::Key::End,
crate::engine::event::keyboard::Key::Home => espanso_inject::keys::Key::Home,
crate::engine::event::keyboard::Key::PageDown => espanso_inject::keys::Key::PageDown,
crate::engine::event::keyboard::Key::PageUp => espanso_inject::keys::Key::PageUp,
crate::engine::event::keyboard::Key::Escape => espanso_inject::keys::Key::Escape,
crate::engine::event::keyboard::Key::Backspace => espanso_inject::keys::Key::Backspace,
crate::engine::event::keyboard::Key::F1 => espanso_inject::keys::Key::F1,
crate::engine::event::keyboard::Key::F2 => espanso_inject::keys::Key::F2,
crate::engine::event::keyboard::Key::F3 => espanso_inject::keys::Key::F3,
crate::engine::event::keyboard::Key::F4 => espanso_inject::keys::Key::F4,
crate::engine::event::keyboard::Key::F5 => espanso_inject::keys::Key::F5,
crate::engine::event::keyboard::Key::F6 => espanso_inject::keys::Key::F6,
crate::engine::event::keyboard::Key::F7 => espanso_inject::keys::Key::F7,
crate::engine::event::keyboard::Key::F8 => espanso_inject::keys::Key::F8,
crate::engine::event::keyboard::Key::F9 => espanso_inject::keys::Key::F9,
crate::engine::event::keyboard::Key::F10 => espanso_inject::keys::Key::F10,
crate::engine::event::keyboard::Key::F11 => espanso_inject::keys::Key::F11,
crate::engine::event::keyboard::Key::F12 => espanso_inject::keys::Key::F12,
crate::engine::event::keyboard::Key::F13 => espanso_inject::keys::Key::F13,
crate::engine::event::keyboard::Key::F14 => espanso_inject::keys::Key::F14,
crate::engine::event::keyboard::Key::F15 => espanso_inject::keys::Key::F15,
crate::engine::event::keyboard::Key::F16 => espanso_inject::keys::Key::F16,
crate::engine::event::keyboard::Key::F17 => espanso_inject::keys::Key::F17,
crate::engine::event::keyboard::Key::F18 => espanso_inject::keys::Key::F18,
crate::engine::event::keyboard::Key::F19 => espanso_inject::keys::Key::F19,
crate::engine::event::keyboard::Key::F20 => espanso_inject::keys::Key::F20,
crate::engine::event::keyboard::Key::Other(raw) => espanso_inject::keys::Key::Raw(*raw),
}
}

View File

@ -17,4 +17,5 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod text_injector;
pub mod text_injector;
pub mod key_injector;

View File

@ -17,21 +17,25 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use espanso_inject::Injector;
use crate::engine::dispatch::TextInjector;
pub struct TextInjectorAdapter {}
pub struct TextInjectorAdapter<'a> {
injector: &'a dyn Injector,
}
impl TextInjectorAdapter {
pub fn new() -> Self {
Self {}
impl <'a> TextInjectorAdapter<'a> {
pub fn new(injector: &'a dyn Injector) -> Self {
Self {
injector
}
}
}
impl TextInjector for TextInjectorAdapter {
fn inject(&self, text: &str) -> anyhow::Result<()> {
// TODO: implement
println!("INJECT: {}", text);
Ok(())
impl <'a> TextInjector for TextInjectorAdapter<'a> {
fn inject_text(&self, text: &str) -> anyhow::Result<()> {
// TODO: handle injection options
self.injector.send_string(text, Default::default())
}
}

View File

@ -63,8 +63,11 @@ fn worker_main(args: CliModuleArgs) {
let mut processor = process::default(&matchers, &config_manager, &selector, &multiplexer, &renderer_adapter);
let text_injector = engine::executor::text_injector::TextInjectorAdapter::new();
let dispatcher = dispatch::default(&text_injector);
let injector = espanso_inject::get_injector(Default::default()).expect("failed to initialize injector module"); // TODO: handle the options
let text_injector = engine::executor::text_injector::TextInjectorAdapter::new(&*injector);
let key_injector = engine::executor::key_injector::KeyInjectorAdapter::new(&*injector);
let dispatcher = dispatch::default(&text_injector, &key_injector);
let mut engine = Engine::new(&funnel, &mut processor, &dispatcher);
engine.run();

View File

@ -17,7 +17,7 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use super::{Dispatcher, Executor, TextInjector};
use super::{Dispatcher, Executor, KeyInjector, TextInjector};
use super::Event;
pub struct DefaultDispatcher<'a> {
@ -25,10 +25,11 @@ pub struct DefaultDispatcher<'a> {
}
impl <'a> DefaultDispatcher<'a> {
pub fn new(text_injector: &'a dyn TextInjector) -> Self {
pub fn new(text_injector: &'a dyn TextInjector, key_injector: &'a dyn KeyInjector) -> Self {
Self {
executors: vec![
Box::new(super::executor::text_inject::TextInjectExecutor::new(text_injector)),
Box::new(super::executor::key_inject::KeyInjectExecutor::new(key_injector)),
]
}
}

View File

@ -0,0 +1,44 @@
/*
* 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 super::super::{Event, Executor, KeyInjector};
use log::error;
pub struct KeyInjectExecutor<'a> {
injector: &'a dyn KeyInjector,
}
impl<'a> KeyInjectExecutor<'a> {
pub fn new(injector: &'a dyn KeyInjector) -> Self {
Self { injector }
}
}
impl<'a> Executor for KeyInjectExecutor<'a> {
fn execute(&self, event: &Event) -> bool {
if let Event::KeySequenceInject(inject_event) = event {
if let Err(error) = self.injector.inject_sequence(&inject_event.keys) {
error!("key injector reported an error: {}", error);
}
return true;
}
false
}
}

View File

@ -17,4 +17,5 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod text_inject;
pub mod text_inject;
pub mod key_inject;

View File

@ -18,7 +18,7 @@
*/
use super::super::{Event, Executor, TextInjector};
use crate::engine::event::inject::TextInjectMode;
use crate::engine::event::text::TextInjectMode;
use log::error;
pub struct TextInjectExecutor<'a> {
@ -35,7 +35,7 @@ impl<'a> Executor for TextInjectExecutor<'a> {
fn execute(&self, event: &Event) -> bool {
if let Event::TextInject(inject_event) = event {
if let Some(TextInjectMode::Keys) = inject_event.force_mode {
if let Err(error) = self.injector.inject(&inject_event.text) {
if let Err(error) = self.injector.inject_text(&inject_event.text) {
error!("text injector reported an error: {:?}", error);
}
return true;

View File

@ -18,7 +18,7 @@
*/
use anyhow::Result;
use super::Event;
use super::{Event, event::keyboard::Key};
mod executor;
mod default;
@ -32,11 +32,16 @@ pub trait Dispatcher {
}
pub trait TextInjector {
fn inject(&self, text: &str) -> Result<()>;
fn inject_text(&self, text: &str) -> Result<()>;
}
pub fn default<'a>(text_injector: &'a dyn TextInjector) -> impl Dispatcher + 'a {
pub trait KeyInjector {
fn inject_sequence(&self, keys: &[Key]) -> Result<()>;
}
pub fn default<'a>(text_injector: &'a dyn TextInjector, key_injector: &'a dyn KeyInjector) -> impl Dispatcher + 'a {
default::DefaultDispatcher::new(
text_injector,
key_injector,
)
}

View File

@ -37,6 +37,11 @@ pub struct KeyboardEvent {
pub variant: Option<Variant>,
}
#[derive(Debug)]
pub struct KeySequenceInjectRequest {
pub keys: Vec<Key>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Key {
// Modifiers

View File

@ -18,7 +18,7 @@
*/
pub mod keyboard;
pub mod inject;
pub mod text;
pub mod matches;
pub mod render;
@ -38,5 +38,6 @@ pub enum Event {
Rendered(render::RenderedEvent),
// Effects
TextInject(inject::TextInjectRequest),
KeySequenceInject(keyboard::KeySequenceInjectRequest),
TextInject(text::TextInjectRequest),
}

View File

@ -19,7 +19,6 @@
#[derive(Debug)]
pub struct TextInjectRequest {
pub delete_count: i32,
pub text: String,
pub force_mode: Option<TextInjectMode>,
}
@ -28,4 +27,5 @@ pub struct TextInjectRequest {
pub enum TextInjectMode {
Keys,
Clipboard,
}
}

View File

@ -22,7 +22,7 @@ use log::trace;
use super::{
middleware::{
match_select::MatchSelectMiddleware, matcher::MatchMiddleware, multiplex::MultiplexMiddleware,
render::RenderMiddleware,
render::RenderMiddleware, action::ActionMiddleware,
},
Event, MatchFilter, MatchSelector, Matcher, Middleware, Multiplexer, Processor, Renderer,
};
@ -48,6 +48,7 @@ impl<'a> DefaultProcessor<'a> {
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
Box::new(MultiplexMiddleware::new(multiplexer)),
Box::new(RenderMiddleware::new(renderer)),
Box::new(ActionMiddleware::new()),
],
}
}
@ -57,7 +58,7 @@ impl<'a> DefaultProcessor<'a> {
let mut current_event = event;
let mut current_queue = VecDeque::new();
let dispatch = |event: Event| {
let mut dispatch = |event: Event| {
trace!("dispatched event: {:?}", event);
current_queue.push_front(event);
};
@ -65,7 +66,7 @@ impl<'a> DefaultProcessor<'a> {
for middleware in self.middleware.iter() {
trace!("middleware received event: {:?}", current_event);
current_event = middleware.next(current_event, &dispatch);
current_event = middleware.next(current_event, &mut dispatch);
trace!("middleware produced event: {:?}", current_event);
}

View File

@ -0,0 +1,57 @@
/*
* 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 log::{debug, error};
use super::super::Middleware;
use crate::engine::{event::{Event, keyboard::{Key, KeySequenceInjectRequest}, matches::MatchSelectedEvent, text::{TextInjectMode, TextInjectRequest}}, process::{MatchFilter, MatchSelector, Multiplexer}};
pub struct ActionMiddleware {
}
impl ActionMiddleware {
pub fn new() -> Self {
Self {}
}
}
impl Middleware for ActionMiddleware {
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
if let Event::Rendered(m_event) = &event {
let delete_count = m_event.trigger.len();
let delete_sequence: Vec<_> = (0..delete_count).map(|_| Key::Backspace).collect();
dispatch(Event::TextInject(TextInjectRequest {
text: m_event.body.clone(),
force_mode: Some(TextInjectMode::Keys), // TODO: determine this one dynamically
}));
// This is executed before the dispatched event
return Event::KeySequenceInject(KeySequenceInjectRequest {
keys: delete_sequence
})
}
// TODO: handle images
event
}
}
// TODO: test

View File

@ -43,7 +43,7 @@ impl<'a> MatchSelectMiddleware<'a> {
}
impl<'a> Middleware for MatchSelectMiddleware<'a> {
fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
if let Event::MatchesDetected(m_event) = event {
let matches_ids: Vec<i32> = m_event.matches.iter().map(|m| m.id).collect();

View File

@ -41,7 +41,7 @@ impl<'a, State> MatchMiddleware<'a, State> {
}
impl<'a, State> Middleware for MatchMiddleware<'a, State> {
fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
let mut matcher_states = self.matcher_states.borrow_mut();
let prev_states = if !matcher_states.is_empty() {
matcher_states.get(matcher_states.len() - 1)

View File

@ -17,6 +17,7 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod action;
pub mod render;
pub mod matcher;
pub mod multiplex;

View File

@ -20,7 +20,7 @@
use log::{debug, error};
use super::super::Middleware;
use crate::engine::{event::{Event, inject::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent}, process::{MatchFilter, MatchSelector, Multiplexer}};
use crate::engine::{event::{Event, text::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent}, process::{MatchFilter, MatchSelector, Multiplexer}};
pub struct MultiplexMiddleware<'a> {
multiplexer: &'a dyn Multiplexer,
@ -33,7 +33,7 @@ impl<'a> MultiplexMiddleware<'a> {
}
impl<'a> Middleware for MultiplexMiddleware<'a> {
fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
if let Event::MatchSelected(m_event) = event {
return match self.multiplexer.convert(m_event.chosen.id, m_event.chosen.trigger, m_event.chosen.args) {
Some(event) => event,

View File

@ -20,7 +20,7 @@
use log::{debug, error};
use super::super::Middleware;
use crate::engine::{event::{Event, inject::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent, render::RenderedEvent}, process::{MatchFilter, MatchSelector, Renderer, RendererError}};
use crate::engine::{event::{Event, text::{TextInjectRequest, TextInjectMode}, matches::MatchSelectedEvent, render::RenderedEvent}, process::{MatchFilter, MatchSelector, Renderer, RendererError}};
pub struct RenderMiddleware<'a> {
renderer: &'a dyn Renderer<'a>,
@ -33,7 +33,7 @@ impl<'a> RenderMiddleware<'a> {
}
impl<'a> Middleware for RenderMiddleware<'a> {
fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
if let Event::RenderingRequested(m_event) = event {
match self.renderer.render(m_event.match_id, m_event.trigger_args) {
Ok(body) => {

View File

@ -26,7 +26,7 @@ mod default;
mod middleware;
pub trait Middleware {
fn next(&self, event: Event, dispatch: &dyn FnMut(Event)) -> Event;
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event;
}
pub trait Processor {