First ConfigSet steps
This commit is contained in:
parent
5276dc262d
commit
64d67eba99
|
@ -4,6 +4,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <X11/Xlibint.h>
|
#include <X11/Xlibint.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
@ -13,6 +15,7 @@
|
||||||
#include <X11/extensions/record.h>
|
#include <X11/extensions/record.h>
|
||||||
#include <X11/extensions/XTest.h>
|
#include <X11/extensions/XTest.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
extern "C" { // Needed to avoid C++ compiler name mangling
|
extern "C" { // Needed to avoid C++ compiler name mangling
|
||||||
#include <xdo.h>
|
#include <xdo.h>
|
||||||
}
|
}
|
||||||
|
@ -210,4 +213,105 @@ void trigger_paste() {
|
||||||
|
|
||||||
void trigger_terminal_paste() {
|
void trigger_terminal_paste() {
|
||||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Control_L+Shift+v", 8000);
|
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Control_L+Shift+v", 8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SYSTEM MODULE
|
||||||
|
|
||||||
|
// Function taken from the wmlib tool source code
|
||||||
|
char *get_property(Display *disp, Window win,
|
||||||
|
Atom xa_prop_type, char *prop_name, unsigned long *size)
|
||||||
|
{
|
||||||
|
unsigned long ret_nitems, ret_bytes_after, tmp_size;
|
||||||
|
Atom xa_prop_name, xa_ret_type;
|
||||||
|
unsigned char *ret_prop;
|
||||||
|
int ret_format;
|
||||||
|
char *ret;
|
||||||
|
int size_in_byte;
|
||||||
|
|
||||||
|
xa_prop_name = XInternAtom(disp, prop_name, False);
|
||||||
|
|
||||||
|
if (XGetWindowProperty(disp, win, xa_prop_name, 0, 4096 / 4, False,
|
||||||
|
xa_prop_type, &xa_ret_type, &ret_format, &ret_nitems,
|
||||||
|
&ret_bytes_after, &ret_prop) != Success)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (xa_ret_type != xa_prop_type)
|
||||||
|
{
|
||||||
|
XFree(ret_prop);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(ret_format) {
|
||||||
|
case 8: size_in_byte = sizeof(char); break;
|
||||||
|
case 16: size_in_byte = sizeof(short); break;
|
||||||
|
case 32: size_in_byte = sizeof(long); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_size = size_in_byte * ret_nitems;
|
||||||
|
ret = (char*) malloc(tmp_size + 1);
|
||||||
|
memcpy(ret, ret_prop, tmp_size);
|
||||||
|
ret[tmp_size] = '\0';
|
||||||
|
|
||||||
|
if (size) *size = tmp_size;
|
||||||
|
|
||||||
|
XFree(ret_prop);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function taken from Window Management Library for Ruby
|
||||||
|
char *xwm_get_win_title(Display *disp, Window win)
|
||||||
|
{
|
||||||
|
char *wname = (char*)get_property(disp,win, XA_STRING, "WM_NAME", NULL);
|
||||||
|
char *nwname = (char*)get_property(disp,win, XInternAtom(disp,
|
||||||
|
"UTF8_STRING", False), "_NET_WM_NAME", NULL);
|
||||||
|
|
||||||
|
return nwname ? nwname : (wname ? wname : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_active_window_name(char * buffer, int32_t size) {
|
||||||
|
Display *disp = XOpenDisplay(NULL);
|
||||||
|
|
||||||
|
if (!disp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the active window
|
||||||
|
Window win;
|
||||||
|
int revert_to_return;
|
||||||
|
XGetInputFocus(disp, &win, &revert_to_return);
|
||||||
|
|
||||||
|
char * title = xwm_get_win_title(disp, win);
|
||||||
|
|
||||||
|
snprintf(buffer, size, "%s", title);
|
||||||
|
|
||||||
|
XFree(title);
|
||||||
|
|
||||||
|
XCloseDisplay(disp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t get_active_window_class(char * buffer, int32_t size) {
|
||||||
|
Display *disp = XOpenDisplay(NULL);
|
||||||
|
|
||||||
|
if (!disp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the active window
|
||||||
|
Window win;
|
||||||
|
int revert_to_return;
|
||||||
|
XGetInputFocus(disp, &win, &revert_to_return);
|
||||||
|
|
||||||
|
XClassHint hint;
|
||||||
|
|
||||||
|
if (XGetClassHint(disp, win, &hint)) {
|
||||||
|
snprintf(buffer, size, "%s", hint.res_class);
|
||||||
|
XFree(hint.res_name);
|
||||||
|
XFree(hint.res_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
XCloseDisplay(disp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
|
@ -52,4 +52,17 @@ extern "C" void trigger_paste();
|
||||||
*/
|
*/
|
||||||
extern "C" void trigger_terminal_paste();
|
extern "C" void trigger_terminal_paste();
|
||||||
|
|
||||||
|
|
||||||
|
// SYSTEM MODULE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the active windows's WM_NAME
|
||||||
|
*/
|
||||||
|
extern "C" int32_t get_active_window_name(char * buffer, int32_t size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the active windows's WM_CLASS
|
||||||
|
*/
|
||||||
|
extern "C" int32_t get_active_window_class(char * buffer, int32_t size);
|
||||||
|
|
||||||
#endif //ESPANSO_BRIDGE_H
|
#endif //ESPANSO_BRIDGE_H
|
||||||
|
|
21
src/bridge/linux.rs
Normal file
21
src/bridge/linux.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use std::os::raw::{c_void, c_char};
|
||||||
|
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
#[link(name="linuxbridge", kind="static")]
|
||||||
|
extern {
|
||||||
|
// System
|
||||||
|
pub fn get_active_window_name(buffer: *mut c_char, size: i32) -> i32;
|
||||||
|
pub fn get_active_window_class(buffer: *mut c_char, size: i32) -> i32;
|
||||||
|
|
||||||
|
// Keyboard
|
||||||
|
pub fn register_keypress_callback(s: *const c_void,
|
||||||
|
cb: extern fn(_self: *mut c_void, *const u8,
|
||||||
|
i32, i32, i32));
|
||||||
|
pub fn initialize();
|
||||||
|
pub fn eventloop();
|
||||||
|
pub fn cleanup();
|
||||||
|
pub fn send_string(string: *const c_char);
|
||||||
|
pub fn delete_string(count: i32);
|
||||||
|
pub fn trigger_paste();
|
||||||
|
pub fn trigger_terminal_paste();
|
||||||
|
}
|
8
src/bridge/mod.rs
Normal file
8
src/bridge/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub(crate) mod windows;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) mod linux;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub(crate) mod macos;
|
|
@ -67,6 +67,7 @@ impl Configs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ConfigSet {
|
pub struct ConfigSet {
|
||||||
default: Configs,
|
default: Configs,
|
||||||
specific: Vec<Configs>,
|
specific: Vec<Configs>,
|
||||||
|
@ -78,17 +79,21 @@ impl ConfigSet {
|
||||||
panic!("Invalid config directory");
|
panic!("Invalid config directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
let default_file = dir_path.join(DEFAULT_CONFIG_FILE_NAME);
|
||||||
let default = Configs::load_config(default_file);
|
let default = Configs::load_config(default_file.as_path());
|
||||||
|
|
||||||
let mut specific = Vec::new();
|
let mut specific = Vec::new();
|
||||||
|
|
||||||
for entry in fs::read_dir(dir_path)? {
|
for entry in fs::read_dir(dir_path)
|
||||||
let entry = entry?;
|
.expect("Cannot read espanso config directory!") {
|
||||||
let path = entry.path();
|
|
||||||
|
|
||||||
let config = Configs::load_config(path.as_path());
|
let entry = entry;
|
||||||
specific.push(config);
|
if let Ok(entry) = entry {
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
let config = Configs::load_config(path.as_path());
|
||||||
|
specific.push(config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigSet {
|
ConfigSet {
|
||||||
|
@ -103,7 +108,7 @@ impl ConfigSet {
|
||||||
let espanso_dir = home_dir.join(".espanso");
|
let espanso_dir = home_dir.join(".espanso");
|
||||||
|
|
||||||
// Create the espanso dir if id doesn't exist
|
// Create the espanso dir if id doesn't exist
|
||||||
let res = create_dir_all(espanso_dir);
|
let res = create_dir_all(espanso_dir.as_path());
|
||||||
|
|
||||||
if let Ok(_) = res {
|
if let Ok(_) = res {
|
||||||
let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
||||||
|
@ -120,4 +125,24 @@ impl ConfigSet {
|
||||||
|
|
||||||
panic!("Could not generate default position for config file");
|
panic!("Could not generate default position for config file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toggle_key(&self) -> &KeyModifier {
|
||||||
|
&self.default.toggle_key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_interval(&self) -> u32 {
|
||||||
|
self.default.toggle_interval
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backspace_limit(&self) -> i32 {
|
||||||
|
self.default.backspace_limit
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backend(&self) -> &BackendType {
|
||||||
|
&BackendType::Inject // TODO make dynamic based on system current active app
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn matches(&self) -> &Vec<Match> {
|
||||||
|
&self.default.matches
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::matcher::{Match, MatchReceiver};
|
use crate::matcher::{Match, MatchReceiver};
|
||||||
use crate::keyboard::KeyboardSender;
|
use crate::keyboard::KeyboardSender;
|
||||||
use crate::config::Configs;
|
use crate::config::ConfigSet;
|
||||||
use crate::config::BackendType;
|
use crate::config::BackendType;
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::clipboard::ClipboardManager;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -8,12 +8,12 @@ use std::sync::Arc;
|
||||||
pub struct Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
pub struct Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
||||||
sender: S,
|
sender: S,
|
||||||
clipboard_manager: Arc<C>,
|
clipboard_manager: Arc<C>,
|
||||||
configs: Configs,
|
config_set: ConfigSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S, C> Engine<S, C> where S: KeyboardSender, C: ClipboardManager{
|
impl <S, C> Engine<S, C> where S: KeyboardSender, C: ClipboardManager{
|
||||||
pub fn new(sender: S, clipboard_manager: Arc<C>, configs: Configs) -> Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
pub fn new(sender: S, clipboard_manager: Arc<C>, config_set: ConfigSet) -> Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
||||||
Engine{sender, clipboard_manager, configs }
|
Engine{sender, clipboard_manager, config_set }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ impl <S, C> MatchReceiver for Engine<S, C> where S: KeyboardSender, C: Clipboard
|
||||||
fn on_match(&self, m: &Match) {
|
fn on_match(&self, m: &Match) {
|
||||||
self.sender.delete_string(m.trigger.len() as i32);
|
self.sender.delete_string(m.trigger.len() as i32);
|
||||||
|
|
||||||
match self.configs.backend {
|
match self.config_set.backend() {
|
||||||
BackendType::Inject => {
|
BackendType::Inject => {
|
||||||
// Send the expected string. On linux, newlines are managed automatically
|
// Send the expected string. On linux, newlines are managed automatically
|
||||||
// while on windows and macos, we need to emulate a Enter key press.
|
// while on windows and macos, we need to emulate a Enter key press.
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::thread;
|
use std::{thread};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use crate::keyboard::{KeyEvent, KeyModifier};
|
use crate::keyboard::{KeyEvent, KeyModifier};
|
||||||
use crate::keyboard::KeyModifier::*;
|
use crate::keyboard::KeyModifier::*;
|
||||||
|
|
||||||
|
use crate::bridge::linux::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LinuxKeyboardInterceptor {
|
pub struct LinuxKeyboardInterceptor {
|
||||||
pub sender: mpsc::Sender<KeyEvent>
|
pub sender: mpsc::Sender<KeyEvent>
|
||||||
|
@ -13,7 +15,8 @@ pub struct LinuxKeyboardInterceptor {
|
||||||
impl super::KeyboardInterceptor for LinuxKeyboardInterceptor {
|
impl super::KeyboardInterceptor for LinuxKeyboardInterceptor {
|
||||||
fn initialize(&self) {
|
fn initialize(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
register_keypress_callback(self,keypress_callback);
|
let self_ptr = self as *const LinuxKeyboardInterceptor as *const c_void;
|
||||||
|
register_keypress_callback( self_ptr,keypress_callback);
|
||||||
initialize(); // TODO: check initialization return codes
|
initialize(); // TODO: check initialization return codes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,9 +63,11 @@ impl super::KeyboardSender for LinuxKeyboardSender {
|
||||||
|
|
||||||
// Native bridge code
|
// Native bridge code
|
||||||
|
|
||||||
extern fn keypress_callback(_self: *mut LinuxKeyboardInterceptor, raw_buffer: *const u8, len: i32,
|
extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32,
|
||||||
is_modifier: i32, key_code: i32) {
|
is_modifier: i32, key_code: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let _self = _self as *mut LinuxKeyboardInterceptor;
|
||||||
|
|
||||||
if is_modifier == 0 { // Char event
|
if is_modifier == 0 { // Char event
|
||||||
// Convert the received buffer to a character
|
// Convert the received buffer to a character
|
||||||
let buffer = std::slice::from_raw_parts(raw_buffer, len as usize);
|
let buffer = std::slice::from_raw_parts(raw_buffer, len as usize);
|
||||||
|
@ -87,19 +92,4 @@ extern fn keypress_callback(_self: *mut LinuxKeyboardInterceptor, raw_buffer: *c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(improper_ctypes)]
|
|
||||||
#[link(name="linuxbridge", kind="static")]
|
|
||||||
extern {
|
|
||||||
fn register_keypress_callback(s: *const LinuxKeyboardInterceptor,
|
|
||||||
cb: extern fn(_self: *mut LinuxKeyboardInterceptor, *const u8,
|
|
||||||
i32, i32, i32));
|
|
||||||
fn initialize();
|
|
||||||
fn eventloop();
|
|
||||||
fn cleanup();
|
|
||||||
fn send_string(string: *const c_char);
|
|
||||||
fn delete_string(count: i32);
|
|
||||||
fn trigger_paste();
|
|
||||||
fn trigger_terminal_paste();
|
|
||||||
}
|
}
|
33
src/main.rs
33
src/main.rs
|
@ -3,18 +3,21 @@ use crate::keyboard::KeyboardInterceptor;
|
||||||
use crate::matcher::Matcher;
|
use crate::matcher::Matcher;
|
||||||
use crate::matcher::scrolling::ScrollingMatcher;
|
use crate::matcher::scrolling::ScrollingMatcher;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::config::Configs;
|
use crate::config::{Configs, ConfigSet};
|
||||||
use crate::ui::UIManager;
|
use crate::ui::UIManager;
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::clipboard::ClipboardManager;
|
||||||
|
use crate::system::SystemManager;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
mod keyboard;
|
mod ui;
|
||||||
mod matcher;
|
mod bridge;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod config;
|
mod config;
|
||||||
mod ui;
|
mod system;
|
||||||
|
mod matcher;
|
||||||
|
mod keyboard;
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
|
|
||||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
@ -28,7 +31,7 @@ fn main() {
|
||||||
.short("c")
|
.short("c")
|
||||||
.long("config")
|
.long("config")
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("Sets a custom config file. If not specified, reads the default $HOME/.espanso file, creating it if not present.")
|
.help("Sets a custom config directory. If not specified, reads the default $HOME/.espanso/default.yaml file, creating it if not present.")
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(Arg::with_name("dump")
|
.arg(Arg::with_name("dump")
|
||||||
.long("dump")
|
.long("dump")
|
||||||
|
@ -39,23 +42,27 @@ fn main() {
|
||||||
.help("Sets the level of verbosity"))
|
.help("Sets the level of verbosity"))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let configs = match matches.value_of("config") {
|
let config_set = match matches.value_of("config") {
|
||||||
None => {Configs::load_default()},
|
None => {ConfigSet::load_default()},
|
||||||
Some(path) => {Configs::load(Path::new(path))},
|
Some(path) => {ConfigSet::load(Path::new(path))},
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches.is_present("dump") {
|
if matches.is_present("dump") {
|
||||||
println!("{:#?}", configs);
|
println!("{:#?}", config_set);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
espanso_main(configs);
|
espanso_main(config_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn espanso_main(configs: Configs) {
|
fn espanso_main(config_set: ConfigSet) {
|
||||||
let ui_manager = ui::get_uimanager();
|
let ui_manager = ui::get_uimanager();
|
||||||
ui_manager.notify("Hello guys");
|
ui_manager.notify("Hello guys");
|
||||||
|
|
||||||
|
let system_manager = system::get_manager();
|
||||||
|
println!("{}", system_manager.get_current_window_title().unwrap());
|
||||||
|
println!("{}", system_manager.get_current_window_class().unwrap());
|
||||||
|
|
||||||
let clipboard_manager = clipboard::get_manager();
|
let clipboard_manager = clipboard::get_manager();
|
||||||
let clipboard_manager_arc = Arc::new(clipboard_manager);
|
let clipboard_manager_arc = Arc::new(clipboard_manager);
|
||||||
|
|
||||||
|
@ -65,10 +72,10 @@ fn espanso_main(configs: Configs) {
|
||||||
|
|
||||||
let engine = Engine::new(sender,
|
let engine = Engine::new(sender,
|
||||||
Arc::clone(&clipboard_manager_arc),
|
Arc::clone(&clipboard_manager_arc),
|
||||||
configs.clone());
|
config_set.clone());
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let matcher = ScrollingMatcher::new(configs.clone(), engine);
|
let matcher = ScrollingMatcher::new(config_set.clone(), engine);
|
||||||
matcher.watch(rxc);
|
matcher.watch(rxc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use crate::matcher::{Match, MatchReceiver};
|
use crate::matcher::{Match, MatchReceiver};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use crate::keyboard::KeyModifier;
|
use crate::keyboard::KeyModifier;
|
||||||
use crate::config::Configs;
|
use crate::config::ConfigSet;
|
||||||
use crate::keyboard::KeyModifier::BACKSPACE;
|
use crate::keyboard::KeyModifier::BACKSPACE;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct ScrollingMatcher<'a, R> where R: MatchReceiver{
|
pub struct ScrollingMatcher<'a, R> where R: MatchReceiver{
|
||||||
configs: Configs,
|
config_set: ConfigSet,
|
||||||
receiver: R,
|
receiver: R,
|
||||||
current_set_queue: RefCell<VecDeque<Vec<MatchEntry<'a>>>>,
|
current_set_queue: RefCell<VecDeque<Vec<MatchEntry<'a>>>>,
|
||||||
toggle_press_time: RefCell<SystemTime>,
|
toggle_press_time: RefCell<SystemTime>,
|
||||||
|
@ -28,7 +28,7 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv
|
||||||
|
|
||||||
let mut current_set_queue = self.current_set_queue.borrow_mut();
|
let mut current_set_queue = self.current_set_queue.borrow_mut();
|
||||||
|
|
||||||
let new_matches: Vec<MatchEntry> = self.configs.matches.iter()
|
let new_matches: Vec<MatchEntry> = self.config_set.matches().iter()
|
||||||
.filter(|&x| x.trigger.chars().nth(0).unwrap() == c)
|
.filter(|&x| x.trigger.chars().nth(0).unwrap() == c)
|
||||||
.map(|x | MatchEntry{start: 1, _match: &x})
|
.map(|x | MatchEntry{start: 1, _match: &x})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -60,7 +60,7 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv
|
||||||
|
|
||||||
current_set_queue.push_back(combined_matches);
|
current_set_queue.push_back(combined_matches);
|
||||||
|
|
||||||
if current_set_queue.len() as i32 > (self.configs.backspace_limit + 1) {
|
if current_set_queue.len() as i32 > (self.config_set.backspace_limit() + 1) {
|
||||||
current_set_queue.pop_front();
|
current_set_queue.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,10 +73,10 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_modifier(&'a self, m: KeyModifier) {
|
fn handle_modifier(&'a self, m: KeyModifier) {
|
||||||
if m == self.configs.toggle_key {
|
if m == *self.config_set.toggle_key() {
|
||||||
let mut toggle_press_time = self.toggle_press_time.borrow_mut();
|
let mut toggle_press_time = self.toggle_press_time.borrow_mut();
|
||||||
if let Ok(elapsed) = toggle_press_time.elapsed() {
|
if let Ok(elapsed) = toggle_press_time.elapsed() {
|
||||||
if elapsed.as_millis() < self.configs.toggle_interval as u128 {
|
if elapsed.as_millis() < self.config_set.toggle_interval() as u128 {
|
||||||
let mut is_enabled = self.is_enabled.borrow_mut();
|
let mut is_enabled = self.is_enabled.borrow_mut();
|
||||||
*is_enabled = !(*is_enabled);
|
*is_enabled = !(*is_enabled);
|
||||||
|
|
||||||
|
@ -99,12 +99,12 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl <'a, R> ScrollingMatcher<'a, R> where R: MatchReceiver {
|
impl <'a, R> ScrollingMatcher<'a, R> where R: MatchReceiver {
|
||||||
pub fn new(configs: Configs, receiver: R) -> ScrollingMatcher<'a, R> {
|
pub fn new(config_set: ConfigSet, receiver: R) -> ScrollingMatcher<'a, R> {
|
||||||
let current_set_queue = RefCell::new(VecDeque::new());
|
let current_set_queue = RefCell::new(VecDeque::new());
|
||||||
let toggle_press_time = RefCell::new(SystemTime::now());
|
let toggle_press_time = RefCell::new(SystemTime::now());
|
||||||
|
|
||||||
ScrollingMatcher{
|
ScrollingMatcher{
|
||||||
configs,
|
config_set,
|
||||||
receiver,
|
receiver,
|
||||||
current_set_queue,
|
current_set_queue,
|
||||||
toggle_press_time,
|
toggle_press_time,
|
||||||
|
|
58
src/system/linux.rs
Normal file
58
src/system/linux.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
use crate::bridge::linux::{get_active_window_name, get_active_window_class};
|
||||||
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
pub struct LinuxSystemManager {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::SystemManager for LinuxSystemManager {
|
||||||
|
fn initialize(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_window_title(&self) -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
let mut buffer : [c_char; 100] = [0; 100];
|
||||||
|
let res = get_active_window_name(buffer.as_mut_ptr(), buffer.len() as i32);
|
||||||
|
|
||||||
|
if res > 0 {
|
||||||
|
let c_string = CStr::from_ptr(buffer.as_ptr());
|
||||||
|
|
||||||
|
let string = c_string.to_str();
|
||||||
|
if let Ok(string) = string {
|
||||||
|
return Some((*string).to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_window_class(&self) -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
let mut buffer : [c_char; 100] = [0; 100];
|
||||||
|
let res = get_active_window_class(buffer.as_mut_ptr(), buffer.len() as i32);
|
||||||
|
|
||||||
|
if res > 0 {
|
||||||
|
let c_string = CStr::from_ptr(buffer.as_ptr());
|
||||||
|
|
||||||
|
let string = c_string.to_str();
|
||||||
|
if let Ok(string) = string {
|
||||||
|
return Some((*string).to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_window_executable(&self) -> Option<String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinuxSystemManager {
|
||||||
|
|
||||||
|
}
|
23
src/system/mod.rs
Normal file
23
src/system/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod windows;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
mod linux;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod macos;
|
||||||
|
|
||||||
|
pub trait SystemManager {
|
||||||
|
fn initialize(&self);
|
||||||
|
fn get_current_window_title(&self) -> Option<String>;
|
||||||
|
fn get_current_window_class(&self) -> Option<String>;
|
||||||
|
fn get_current_window_executable(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LINUX IMPLEMENTATION
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn get_manager() -> impl SystemManager {
|
||||||
|
let manager = linux::LinuxSystemManager{};
|
||||||
|
manager.initialize();
|
||||||
|
manager
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user