First draft of working passive mode on linux
This commit is contained in:
parent
9e5a2a7c95
commit
9332899969
|
@ -307,6 +307,14 @@ void trigger_alt_shift_ins_paste() {
|
|||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Shift+Alt+Insert", 8000);
|
||||
}
|
||||
|
||||
void trigger_copy() {
|
||||
// Release the other keys, for an explanation, read the 'trigger_paste' method
|
||||
|
||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Alt", 8000);
|
||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Shift", 8000);
|
||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Control_L+c", 8000);
|
||||
}
|
||||
|
||||
// SYSTEM MODULE
|
||||
|
||||
// Function taken from the wmlib tool source code
|
||||
|
|
|
@ -92,6 +92,10 @@ extern "C" void trigger_shift_ins_paste();
|
|||
*/
|
||||
extern "C" void trigger_alt_shift_ins_paste();
|
||||
|
||||
/*
|
||||
* Trigger copy shortcut ( Pressing CTRL+C )
|
||||
*/
|
||||
extern "C" void trigger_copy();
|
||||
|
||||
// SYSTEM MODULE
|
||||
|
||||
|
|
|
@ -44,4 +44,5 @@ extern {
|
|||
pub fn trigger_terminal_paste();
|
||||
pub fn trigger_shift_ins_paste();
|
||||
pub fn trigger_alt_shift_ins_paste();
|
||||
pub fn trigger_copy();
|
||||
}
|
|
@ -53,10 +53,12 @@ fn default_use_system_agent() -> bool { true }
|
|||
fn default_config_caching_interval() -> i32 { 800 }
|
||||
fn default_word_separators() -> Vec<char> { vec![' ', ',', '.', '\r', '\n', 22u8 as char] }
|
||||
fn default_toggle_interval() -> u32 { 230 }
|
||||
fn default_toggle_key() -> KeyModifier { KeyModifier::ALT }
|
||||
fn default_preserve_clipboard() -> bool {false}
|
||||
fn default_passive_match_regex() -> String{ "(?P<name>:\\p{L}+)(/(?P<args>.*)/)?".to_owned() }
|
||||
fn default_passive_arg_delimiter() -> char { '/' }
|
||||
fn default_passive_arg_escape() -> char { '\\' }
|
||||
fn default_passive_key() -> KeyModifier { KeyModifier::OFF }
|
||||
fn default_backspace_limit() -> i32 { 3 }
|
||||
fn default_exclude_default_matches() -> bool {false}
|
||||
fn default_matches() -> Vec<Match> { Vec::new() }
|
||||
|
@ -96,7 +98,7 @@ pub struct Configs {
|
|||
#[serde(default = "default_word_separators")]
|
||||
pub word_separators: Vec<char>, // TODO: add parsing test
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_toggle_key")]
|
||||
pub toggle_key: KeyModifier,
|
||||
|
||||
#[serde(default = "default_toggle_interval")]
|
||||
|
@ -114,6 +116,9 @@ pub struct Configs {
|
|||
#[serde(default = "default_passive_arg_escape")]
|
||||
pub passive_arg_escape: char,
|
||||
|
||||
#[serde(default = "default_passive_key")]
|
||||
pub passive_key: KeyModifier,
|
||||
|
||||
#[serde(default)]
|
||||
pub paste_shortcut: PasteShortcut,
|
||||
|
||||
|
@ -156,7 +161,7 @@ impl Configs {
|
|||
|
||||
validate_field!(result, self.config_caching_interval, default_config_caching_interval());
|
||||
validate_field!(result, self.log_level, default_log_level());
|
||||
validate_field!(result, self.toggle_key, KeyModifier::default());
|
||||
validate_field!(result, self.toggle_key, default_toggle_key());
|
||||
validate_field!(result, self.toggle_interval, default_toggle_interval());
|
||||
validate_field!(result, self.backspace_limit, default_backspace_limit());
|
||||
validate_field!(result, self.ipc_server_port, default_ipc_server_port());
|
||||
|
@ -165,6 +170,7 @@ impl Configs {
|
|||
validate_field!(result, self.passive_match_regex, default_passive_match_regex());
|
||||
validate_field!(result, self.passive_arg_delimiter, default_passive_arg_delimiter());
|
||||
validate_field!(result, self.passive_arg_escape, default_passive_arg_escape());
|
||||
validate_field!(result, self.passive_key, default_passive_key());
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -231,6 +231,39 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
|
|||
|
||||
self.ui_manager.notify(message);
|
||||
}
|
||||
|
||||
fn on_passive(&self) {
|
||||
info!("Passive mode activated");
|
||||
|
||||
// Trigger a copy shortcut to transfer the content of the selection to the clipboard
|
||||
self.keyboard_manager.trigger_copy();
|
||||
|
||||
// Sleep for a while, giving time to effectively copy the text
|
||||
std::thread::sleep(std::time::Duration::from_millis(100)); // TODO: avoid hardcoding
|
||||
|
||||
// Then get the text from the clipboard and render the match output
|
||||
let clipboard = self.clipboard_manager.get_clipboard();
|
||||
|
||||
if let Some(clipboard) = clipboard {
|
||||
let config = self.config_manager.active_config();
|
||||
|
||||
let rendered = self.renderer.render_passive(&clipboard,
|
||||
&config);
|
||||
|
||||
match rendered {
|
||||
RenderResult::Text(payload) => {
|
||||
// Paste back the result in the field
|
||||
self.clipboard_manager.set_clipboard(&payload);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(100)); // TODO: avoid hardcoding
|
||||
self.keyboard_manager.trigger_paste(&config.paste_shortcut);
|
||||
},
|
||||
_ => {
|
||||
warn!("Cannot expand passive match")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, S: KeyboardManager, C: ClipboardManager,
|
||||
|
|
|
@ -66,12 +66,6 @@ pub enum KeyModifier {
|
|||
OFF,
|
||||
}
|
||||
|
||||
impl Default for KeyModifier {
|
||||
fn default() -> Self {
|
||||
KeyModifier::ALT
|
||||
}
|
||||
}
|
||||
|
||||
// Receivers
|
||||
|
||||
pub trait KeyEventReceiver {
|
||||
|
|
|
@ -81,4 +81,10 @@ impl super::KeyboardManager for LinuxKeyboardManager {
|
|||
left_arrow(count);
|
||||
}
|
||||
}
|
||||
|
||||
fn trigger_copy(&self) {
|
||||
unsafe {
|
||||
trigger_copy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ pub trait KeyboardManager {
|
|||
fn trigger_paste(&self, shortcut: &PasteShortcut);
|
||||
fn delete_string(&self, count: i32);
|
||||
fn move_cursor_left(&self, count: i32);
|
||||
fn trigger_copy(&self);
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -181,6 +181,7 @@ pub enum TriggerEntry {
|
|||
pub trait MatchReceiver {
|
||||
fn on_match(&self, m: &Match, trailing_separator: Option<char>);
|
||||
fn on_enable_update(&self, status: bool);
|
||||
fn on_passive(&self);
|
||||
}
|
||||
|
||||
pub trait Matcher : KeyEventReceiver {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
use crate::matcher::{Match, MatchReceiver, TriggerEntry};
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{RefCell, Ref};
|
||||
use crate::event::{KeyModifier, ActionEventReceiver, ActionType};
|
||||
use crate::config::ConfigManager;
|
||||
use crate::event::KeyModifier::BACKSPACE;
|
||||
|
@ -30,6 +30,7 @@ pub struct ScrollingMatcher<'a, R: MatchReceiver, M: ConfigManager<'a>> {
|
|||
receiver: &'a R,
|
||||
current_set_queue: RefCell<VecDeque<Vec<MatchEntry<'a>>>>,
|
||||
toggle_press_time: RefCell<SystemTime>,
|
||||
passive_press_time: RefCell<SystemTime>,
|
||||
is_enabled: RefCell<bool>,
|
||||
was_previous_char_word_separator: RefCell<bool>,
|
||||
}
|
||||
|
@ -45,12 +46,14 @@ impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ScrollingMatcher<'a, R, M> {
|
|||
pub fn new(config_manager: &'a M, receiver: &'a R) -> ScrollingMatcher<'a, R, M> {
|
||||
let current_set_queue = RefCell::new(VecDeque::new());
|
||||
let toggle_press_time = RefCell::new(SystemTime::now());
|
||||
let passive_press_time = RefCell::new(SystemTime::now());
|
||||
|
||||
ScrollingMatcher{
|
||||
config_manager,
|
||||
receiver,
|
||||
current_set_queue,
|
||||
toggle_press_time,
|
||||
passive_press_time,
|
||||
is_enabled: RefCell::new(true),
|
||||
was_previous_char_word_separator: RefCell::new(true),
|
||||
}
|
||||
|
@ -193,22 +196,25 @@ impl <'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMa
|
|||
fn handle_modifier(&self, m: KeyModifier) {
|
||||
let config = self.config_manager.default_config();
|
||||
|
||||
// TODO: at the moment, activating the passive key triggers the toggle key
|
||||
// study a mechanism to avoid this problem
|
||||
|
||||
if m == config.toggle_key {
|
||||
if m == KeyModifier::OFF { return }
|
||||
let mut toggle_press_time = self.toggle_press_time.borrow_mut();
|
||||
if let Ok(elapsed) = toggle_press_time.elapsed() {
|
||||
if elapsed.as_millis() < u128::from(config.toggle_interval) {
|
||||
self.toggle();
|
||||
check_interval(&self.toggle_press_time,
|
||||
u128::from(config.toggle_interval), || {
|
||||
self.toggle();
|
||||
|
||||
let is_enabled = self.is_enabled.borrow();
|
||||
let is_enabled = self.is_enabled.borrow();
|
||||
|
||||
if !*is_enabled {
|
||||
self.current_set_queue.borrow_mut().clear();
|
||||
}
|
||||
if !*is_enabled {
|
||||
self.current_set_queue.borrow_mut().clear();
|
||||
}
|
||||
}
|
||||
|
||||
(*toggle_press_time) = SystemTime::now();
|
||||
});
|
||||
}else if m == config.passive_key {
|
||||
check_interval(&self.passive_press_time,
|
||||
u128::from(config.toggle_interval), || {
|
||||
self.receiver.on_passive();
|
||||
});
|
||||
}
|
||||
|
||||
// Backspace handling, basically "rewinding history"
|
||||
|
@ -235,3 +241,14 @@ impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ActionEventReceiver for Scroll
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_interval<F>(state_var: &RefCell<SystemTime>, interval: u128, elapsed_callback: F) where F:Fn() {
|
||||
let mut press_time = state_var.borrow_mut();
|
||||
if let Ok(elapsed) = press_time.elapsed() {
|
||||
if elapsed.as_millis() < interval {
|
||||
elapsed_callback();
|
||||
}
|
||||
}
|
||||
|
||||
(*press_time) = SystemTime::now();
|
||||
}
|
Loading…
Reference in New Issue
Block a user