Format Rust code using rustfmt
This commit is contained in:
parent
94c7af7709
commit
91624c0ce0
6 changed files with 989 additions and 421 deletions
|
@ -1,9 +1,9 @@
|
|||
use crate::udev_monitor::{Client, Environment, Server};
|
||||
use crate::Config;
|
||||
use crate::udev_monitor::{Client, Server, Environment};
|
||||
use serde_json;
|
||||
use swayipc_async::Connection;
|
||||
use std::process::{Command, Stdio};
|
||||
use x11rb::protocol::xproto::{get_property, get_input_focus, Atom, AtomEnum};
|
||||
use swayipc_async::Connection;
|
||||
use x11rb::protocol::xproto::{get_input_focus, get_property, Atom, AtomEnum};
|
||||
|
||||
pub async fn get_active_window(environment: &Environment, config: &Vec<Config>) -> Client {
|
||||
match &environment.server {
|
||||
|
@ -11,10 +11,19 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
|
|||
let server_str = server.as_str();
|
||||
match server_str {
|
||||
"Hyprland" => {
|
||||
let query = Command::new("hyprctl").args(["activewindow", "-j"]).output().unwrap();
|
||||
if let Ok(reply) = serde_json::from_str::<serde_json::Value>(std::str::from_utf8(query.stdout.as_slice()).unwrap()) {
|
||||
let active_window = Client::Class(reply["class"].to_string().replace("\"", ""));
|
||||
if let Some(_) = config.iter().find(|&x| x.associations.client == active_window) {
|
||||
let query = Command::new("hyprctl")
|
||||
.args(["activewindow", "-j"])
|
||||
.output()
|
||||
.unwrap();
|
||||
if let Ok(reply) = serde_json::from_str::<serde_json::Value>(
|
||||
std::str::from_utf8(query.stdout.as_slice()).unwrap(),
|
||||
) {
|
||||
let active_window =
|
||||
Client::Class(reply["class"].to_string().replace("\"", ""));
|
||||
if let Some(_) = config
|
||||
.iter()
|
||||
.find(|&x| x.associations.client == active_window)
|
||||
{
|
||||
active_window
|
||||
} else {
|
||||
Client::Default
|
||||
|
@ -22,33 +31,37 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
|
|||
} else {
|
||||
Client::Default
|
||||
}
|
||||
},
|
||||
}
|
||||
"sway" => {
|
||||
let mut connection = Connection::new().await.unwrap();
|
||||
let active_window = match connection.get_tree().await.unwrap().find_focused(|window| window.focused) {
|
||||
Some(window) => {
|
||||
match window.app_id {
|
||||
Some(id) => Client::Class(id),
|
||||
None => Client::Class(window.window_properties.unwrap().class.unwrap())
|
||||
}
|
||||
let active_window = match connection
|
||||
.get_tree()
|
||||
.await
|
||||
.unwrap()
|
||||
.find_focused(|window| window.focused)
|
||||
{
|
||||
Some(window) => match window.app_id {
|
||||
Some(id) => Client::Class(id),
|
||||
None => Client::Class(window.window_properties.unwrap().class.unwrap()),
|
||||
},
|
||||
None => Client::Default
|
||||
None => Client::Default,
|
||||
};
|
||||
if let Some(_) = config.iter().find(|&x| x.associations.client == active_window) {
|
||||
if let Some(_) = config
|
||||
.iter()
|
||||
.find(|&x| x.associations.client == active_window)
|
||||
{
|
||||
active_window
|
||||
} else {
|
||||
Client::Default
|
||||
}
|
||||
},
|
||||
}
|
||||
"KDE" => {
|
||||
let (user, running_as_root) =
|
||||
if let Ok(sudo_user) = environment.sudo_user.clone() {
|
||||
(Option::Some(sudo_user), true)
|
||||
}
|
||||
else if let Ok(user) = environment.user.clone() {
|
||||
} else if let Ok(user) = environment.user.clone() {
|
||||
(Option::Some(user), false)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
(Option::None, false)
|
||||
};
|
||||
let active_window = {
|
||||
|
@ -60,7 +73,12 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
|
|||
.arg("kdotool getactivewindow getwindowclassname")
|
||||
.output()
|
||||
.unwrap();
|
||||
Client::Class(std::str::from_utf8(output.stdout.as_slice()).unwrap().trim().to_string())
|
||||
Client::Class(
|
||||
std::str::from_utf8(output.stdout.as_slice())
|
||||
.unwrap()
|
||||
.trim()
|
||||
.to_string(),
|
||||
)
|
||||
} else {
|
||||
let output = Command::new("sh")
|
||||
.arg("-c")
|
||||
|
@ -68,46 +86,69 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
|
|||
.stderr(Stdio::null())
|
||||
.output()
|
||||
.unwrap();
|
||||
Client::Class(std::str::from_utf8(output.stdout.as_slice()).unwrap().trim().to_string())
|
||||
Client::Class(
|
||||
std::str::from_utf8(output.stdout.as_slice())
|
||||
.unwrap()
|
||||
.trim()
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Client::Default
|
||||
}
|
||||
};
|
||||
if let Some(_) = config.iter().find(|&x| x.associations.client == active_window) {
|
||||
if let Some(_) = config
|
||||
.iter()
|
||||
.find(|&x| x.associations.client == active_window)
|
||||
{
|
||||
active_window
|
||||
} else {
|
||||
Client::Default
|
||||
}
|
||||
},
|
||||
}
|
||||
"x11" => {
|
||||
let connection = x11rb::connect(None).unwrap().0;
|
||||
let focused_window = get_input_focus(&connection)
|
||||
.unwrap().reply().unwrap().focus;
|
||||
let (wm_class, string): (Atom, Atom) = (AtomEnum::WM_CLASS.into(), AtomEnum::STRING.into());
|
||||
let class = get_property(&connection, false, focused_window, wm_class, string, 0, u32::MAX)
|
||||
.unwrap().reply().unwrap().value;
|
||||
let focused_window =
|
||||
get_input_focus(&connection).unwrap().reply().unwrap().focus;
|
||||
let (wm_class, string): (Atom, Atom) =
|
||||
(AtomEnum::WM_CLASS.into(), AtomEnum::STRING.into());
|
||||
let class = get_property(
|
||||
&connection,
|
||||
false,
|
||||
focused_window,
|
||||
wm_class,
|
||||
string,
|
||||
0,
|
||||
u32::MAX,
|
||||
)
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.value;
|
||||
if let Some(middle) = class.iter().position(|&byte| byte == 0) {
|
||||
let class = class.split_at(middle).1;
|
||||
let mut class = &class[1..];
|
||||
if class.last() == Some(&0) {
|
||||
class = &class[..class.len() -1];
|
||||
class = &class[..class.len() - 1];
|
||||
}
|
||||
let active_window = Client::Class(std::str::from_utf8(class).unwrap().to_string());
|
||||
if let Some(_) = config.iter().find(|&x| x.associations.client == active_window) {
|
||||
active_window
|
||||
let active_window =
|
||||
Client::Class(std::str::from_utf8(class).unwrap().to_string());
|
||||
if let Some(_) = config
|
||||
.iter()
|
||||
.find(|&x| x.associations.client == active_window)
|
||||
{
|
||||
active_window
|
||||
} else {
|
||||
Client::Default
|
||||
}
|
||||
} else {
|
||||
Client::Default
|
||||
}
|
||||
},
|
||||
_ => Client::Default
|
||||
}
|
||||
_ => Client::Default,
|
||||
}
|
||||
},
|
||||
}
|
||||
Server::Unsupported => Client::Default,
|
||||
Server::Failed => Client::Default,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
110
src/config.rs
110
src/config.rs
|
@ -1,8 +1,7 @@
|
|||
use std::{collections::HashMap, str::FromStr};
|
||||
use crate::udev_monitor::Client;
|
||||
use evdev::Key;
|
||||
use serde;
|
||||
use crate::udev_monitor::Client;
|
||||
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
||||
pub enum Event {
|
||||
|
@ -31,7 +30,7 @@ pub enum Axis {
|
|||
BTN_TL2,
|
||||
BTN_TR2,
|
||||
ABS_WHEEL_CW,
|
||||
ABS_WHEEL_CCW
|
||||
ABS_WHEEL_CCW,
|
||||
}
|
||||
|
||||
impl FromStr for Axis {
|
||||
|
@ -92,10 +91,13 @@ pub struct RawConfig {
|
|||
|
||||
impl RawConfig {
|
||||
fn new_from_file(file: &str) -> Self {
|
||||
println!("Parsing config file:\n{:?}\n", file.rsplit_once("/").unwrap().1);
|
||||
println!(
|
||||
"Parsing config file:\n{:?}\n",
|
||||
file.rsplit_once("/").unwrap().1
|
||||
);
|
||||
let file_content: String = std::fs::read_to_string(file).unwrap();
|
||||
let raw_config: RawConfig = toml::from_str(&file_content)
|
||||
.expect("Couldn't parse config file.");
|
||||
let raw_config: RawConfig =
|
||||
toml::from_str(&file_content).expect("Couldn't parse config file.");
|
||||
let remap = raw_config.remap;
|
||||
let commands = raw_config.commands;
|
||||
let settings = raw_config.settings;
|
||||
|
@ -162,8 +164,10 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap<String, String>
|
|||
all: Vec::new(),
|
||||
};
|
||||
let custom_modifiers: Vec<Event> = parse_modifiers(&settings, "CUSTOM_MODIFIERS");
|
||||
let lstick_activation_modifiers: Vec<Event> = parse_modifiers(&settings, "LSTICK_ACTIVATION_MODIFIERS");
|
||||
let rstick_activation_modifiers: Vec<Event> = parse_modifiers(&settings, "RSTICK_ACTIVATION_MODIFIERS");
|
||||
let lstick_activation_modifiers: Vec<Event> =
|
||||
parse_modifiers(&settings, "LSTICK_ACTIVATION_MODIFIERS");
|
||||
let rstick_activation_modifiers: Vec<Event> =
|
||||
parse_modifiers(&settings, "RSTICK_ACTIVATION_MODIFIERS");
|
||||
|
||||
mapped_modifiers.custom.extend(custom_modifiers);
|
||||
mapped_modifiers.custom.extend(lstick_activation_modifiers);
|
||||
|
@ -192,30 +196,54 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap<String, String>
|
|||
}
|
||||
if let Ok(event) = Axis::from_str(event) {
|
||||
if !bindings.remap.contains_key(&Event::Axis(event)) {
|
||||
bindings.remap.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.remap
|
||||
.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.remap.get_mut(&Event::Axis(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.remap
|
||||
.get_mut(&Event::Axis(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
} else if let Ok(event) = Key::from_str(event) {
|
||||
if !bindings.remap.contains_key(&Event::Key(event)) {
|
||||
bindings.remap.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.remap
|
||||
.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.remap.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.remap
|
||||
.get_mut(&Event::Key(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let modifiers: Vec<Event> = Vec::new();
|
||||
if let Ok(event) = Axis::from_str(input.as_str()) {
|
||||
if !bindings.remap.contains_key(&Event::Axis(event)) {
|
||||
bindings.remap.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.remap
|
||||
.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.remap.get_mut(&Event::Axis(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.remap
|
||||
.get_mut(&Event::Axis(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
} else if let Ok(event) = Key::from_str(input.as_str()) {
|
||||
if !bindings.remap.contains_key(&Event::Key(event)) {
|
||||
bindings.remap.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.remap
|
||||
.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.remap.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.remap
|
||||
.get_mut(&Event::Key(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,39 +269,64 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap<String, String>
|
|||
}
|
||||
if let Ok(event) = Axis::from_str(event) {
|
||||
if !bindings.commands.contains_key(&Event::Axis(event)) {
|
||||
bindings.commands.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.commands
|
||||
.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.commands.get_mut(&Event::Axis(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.commands
|
||||
.get_mut(&Event::Axis(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
} else if let Ok(event) = Key::from_str(event) {
|
||||
if !bindings.commands.contains_key(&Event::Key(event)) {
|
||||
bindings.commands.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.commands
|
||||
.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.commands.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.commands
|
||||
.get_mut(&Event::Key(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let modifiers: Vec<Event> = Vec::new();
|
||||
if let Ok(event) = Axis::from_str(input.as_str()) {
|
||||
if !bindings.commands.contains_key(&Event::Axis(event)) {
|
||||
bindings.commands.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.commands
|
||||
.insert(Event::Axis(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.commands.get_mut(&Event::Axis(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.commands
|
||||
.get_mut(&Event::Axis(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
} else if let Ok(event) = Key::from_str(input.as_str()) {
|
||||
if !bindings.commands.contains_key(&Event::Key(event)) {
|
||||
bindings.commands.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
bindings
|
||||
.commands
|
||||
.insert(Event::Key(event), HashMap::from([(modifiers, output)]));
|
||||
} else {
|
||||
bindings.commands.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output);
|
||||
bindings
|
||||
.commands
|
||||
.get_mut(&Event::Key(event))
|
||||
.unwrap()
|
||||
.insert(modifiers, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mapped_modifiers.custom.sort();
|
||||
mapped_modifiers.custom.dedup();
|
||||
mapped_modifiers.all.extend(mapped_modifiers.default.clone());
|
||||
mapped_modifiers
|
||||
.all
|
||||
.extend(mapped_modifiers.default.clone());
|
||||
mapped_modifiers.all.extend(mapped_modifiers.custom.clone());
|
||||
mapped_modifiers.all.sort();
|
||||
mapped_modifiers.all.dedup();
|
||||
|
@ -296,8 +349,7 @@ pub fn parse_modifiers(settings: &HashMap<String, String>, parameter: &str) -> V
|
|||
}
|
||||
}
|
||||
custom_modifiers
|
||||
},
|
||||
}
|
||||
None => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
29
src/main.rs
29
src/main.rs
|
@ -1,15 +1,14 @@
|
|||
mod active_client;
|
||||
mod config;
|
||||
mod virtual_devices;
|
||||
mod event_reader;
|
||||
mod udev_monitor;
|
||||
mod active_client;
|
||||
mod virtual_devices;
|
||||
|
||||
use crate::udev_monitor::*;
|
||||
use config::Config;
|
||||
use std::env;
|
||||
use tokio;
|
||||
use config::Config;
|
||||
use tokio::task::JoinHandle;
|
||||
use crate::udev_monitor::*;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -23,20 +22,21 @@ async fn main() {
|
|||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
let user_home = match env::var("HOME") {
|
||||
Ok(user_home) if user_home == "/root".to_string() => {
|
||||
match env::var("SUDO_USER") {
|
||||
Ok(sudo_user) => format!("/home/{}", sudo_user),
|
||||
_ => user_home,
|
||||
}
|
||||
Ok(user_home) if user_home == "/root".to_string() => match env::var("SUDO_USER") {
|
||||
Ok(sudo_user) => format!("/home/{}", sudo_user),
|
||||
_ => user_home,
|
||||
},
|
||||
Ok(user_home) => user_home,
|
||||
_ => "/root".to_string(),
|
||||
};
|
||||
let default_config_path = format!("{}/.config/makima", user_home);
|
||||
println!("\nMAKIMA_CONFIG environment variable is not set, defaulting to {:?}.\n", default_config_path);
|
||||
println!(
|
||||
"\nMAKIMA_CONFIG environment variable is not set, defaulting to {:?}.\n",
|
||||
default_config_path
|
||||
);
|
||||
match std::fs::read_dir(default_config_path) {
|
||||
Ok(dir) => dir,
|
||||
_ => {
|
||||
|
@ -44,14 +44,15 @@ async fn main() {
|
|||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
let mut config_files: Vec<Config> = Vec::new();
|
||||
for file in config_path {
|
||||
let filename: String = file.as_ref().unwrap().file_name().into_string().unwrap();
|
||||
if filename.ends_with(".toml") && !filename.starts_with(".") {
|
||||
let name: String = filename.split(".toml").collect::<Vec<&str>>()[0].to_string();
|
||||
let config_file: Config = Config::new_from_file(file.unwrap().path().to_str().unwrap(), name);
|
||||
let config_file: Config =
|
||||
Config::new_from_file(file.unwrap().path().to_str().unwrap(), name);
|
||||
config_files.push(config_file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use std::{sync::Arc, path::Path, process::Command, env};
|
||||
use crate::config::{Associations, Event};
|
||||
use crate::event_reader::EventReader;
|
||||
use crate::Config;
|
||||
use evdev::{Device, EventStream};
|
||||
use std::{env, path::Path, process::Command, sync::Arc};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio_stream::StreamExt;
|
||||
use evdev::{Device, EventStream};
|
||||
use crate::Config;
|
||||
use crate::config::{Event, Associations};
|
||||
use crate::event_reader::EventReader;
|
||||
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
|
||||
pub enum Client {
|
||||
|
@ -32,11 +31,15 @@ pub struct Environment {
|
|||
pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<JoinHandle<()>>) {
|
||||
let environment = set_environment();
|
||||
launch_tasks(&config_files, &mut tasks, environment.clone());
|
||||
let mut monitor = tokio_udev::AsyncMonitorSocket::new (
|
||||
tokio_udev::MonitorBuilder::new().unwrap()
|
||||
.match_subsystem(std::ffi::OsStr::new("input")).unwrap()
|
||||
.listen().unwrap()
|
||||
).unwrap();
|
||||
let mut monitor = tokio_udev::AsyncMonitorSocket::new(
|
||||
tokio_udev::MonitorBuilder::new()
|
||||
.unwrap()
|
||||
.match_subsystem(std::ffi::OsStr::new("input"))
|
||||
.unwrap()
|
||||
.listen()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
while let Some(Ok(event)) = monitor.next().await {
|
||||
if is_mapped(&event.device(), &config_files) {
|
||||
println!("---------------------\n\nReinitializing...\n");
|
||||
|
@ -49,15 +52,27 @@ pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<Joi
|
|||
}
|
||||
}
|
||||
|
||||
pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>, environment: Environment) {
|
||||
pub fn launch_tasks(
|
||||
config_files: &Vec<Config>,
|
||||
tasks: &mut Vec<JoinHandle<()>>,
|
||||
environment: Environment,
|
||||
) {
|
||||
let modifiers: Arc<Mutex<Vec<Event>>> = Arc::new(Mutex::new(Default::default()));
|
||||
let modifier_was_activated: Arc<Mutex<bool>> = Arc::new(Mutex::new(true));
|
||||
let user_has_access = match Command::new("groups").output() {
|
||||
Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("input") => {
|
||||
Ok(groups)
|
||||
if std::str::from_utf8(&groups.stdout.as_slice())
|
||||
.unwrap()
|
||||
.contains("input") =>
|
||||
{
|
||||
println!("Evdev permissions available.\nScanning for event devices with a matching config file...\n");
|
||||
true
|
||||
},
|
||||
Ok(groups) if std::str::from_utf8(&groups.stdout.as_slice()).unwrap().contains("root") => {
|
||||
}
|
||||
Ok(groups)
|
||||
if std::str::from_utf8(&groups.stdout.as_slice())
|
||||
.unwrap()
|
||||
.contains("root") =>
|
||||
{
|
||||
println!("Root permissions available.\nScanning for event devices with a matching config file...\n");
|
||||
true
|
||||
}
|
||||
|
@ -65,11 +80,13 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>,
|
|||
println!("Warning: user has no access to event devices, Makima might not be able to detect all connected devices.\n\
|
||||
Note: Run Makima with 'sudo -E makima' or as a system service. Refer to the docs for more info. Continuing...\n");
|
||||
false
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Warning: unable to determine if user has access to event devices. Continuing...\n");
|
||||
println!(
|
||||
"Warning: unable to determine if user has access to event devices. Continuing...\n"
|
||||
);
|
||||
false
|
||||
},
|
||||
}
|
||||
};
|
||||
let devices: evdev::EnumerateDevices = evdev::enumerate();
|
||||
let mut devices_found = 0;
|
||||
|
@ -79,7 +96,7 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>,
|
|||
let split_config_name = config.name.split("::").collect::<Vec<&str>>();
|
||||
let associated_device_name = split_config_name[0];
|
||||
if associated_device_name == device.1.name().unwrap().replace("/", "") {
|
||||
let (window_class, layout) = match split_config_name.len() {
|
||||
let (window_class, layout) = match split_config_name.len() {
|
||||
1 => (Client::Default, 0),
|
||||
2 => {
|
||||
if let Ok(layout) = split_config_name[1].parse::<u16>() {
|
||||
|
@ -87,7 +104,7 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>,
|
|||
} else {
|
||||
(Client::Class(split_config_name[1].to_string()), 0)
|
||||
}
|
||||
},
|
||||
}
|
||||
3 => {
|
||||
if let Ok(layout) = split_config_name[1].parse::<u16>() {
|
||||
(Client::Class(split_config_name[2].to_string()), layout)
|
||||
|
@ -97,24 +114,37 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>,
|
|||
println!("Warning: unable to parse layout number in {}, treating it as default.", config.name);
|
||||
(Client::Default, 0)
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
println!("Warning: too many arguments in config file name {}, treating it as default.", config.name);
|
||||
(Client::Default, 0)
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
config.associations.client = window_class;
|
||||
config.associations.layout = layout;
|
||||
config_list.push(config.clone());
|
||||
};
|
||||
}
|
||||
if config_list.len() > 0 && !config_list.iter().any(|x| x.associations == Associations::default()) {
|
||||
if config_list.len() > 0
|
||||
&& !config_list
|
||||
.iter()
|
||||
.any(|x| x.associations == Associations::default())
|
||||
{
|
||||
config_list.push(Config::new_empty(device.1.name().unwrap().replace("/", "")));
|
||||
}
|
||||
let event_device = device.0.as_path().to_str().unwrap().to_string();
|
||||
if config_list.len() != 0 {
|
||||
let stream = Arc::new(Mutex::new(get_event_stream(Path::new(&event_device), config_list.clone())));
|
||||
let reader = EventReader::new(config_list.clone(), stream, modifiers.clone(), modifier_was_activated.clone(), environment.clone());
|
||||
let stream = Arc::new(Mutex::new(get_event_stream(
|
||||
Path::new(&event_device),
|
||||
config_list.clone(),
|
||||
)));
|
||||
let reader = EventReader::new(
|
||||
config_list.clone(),
|
||||
stream,
|
||||
modifiers.clone(),
|
||||
modifier_was_activated.clone(),
|
||||
environment.clone(),
|
||||
);
|
||||
tasks.push(tokio::spawn(start_reader(reader)));
|
||||
devices_found += 1
|
||||
}
|
||||
|
@ -133,24 +163,38 @@ pub async fn start_reader(reader: EventReader) {
|
|||
fn set_environment() -> Environment {
|
||||
match env::var("DBUS_SESSION_BUS_ADDRESS") {
|
||||
Ok(_) => {
|
||||
let command = Command::new("sh").arg("-c").arg("systemctl --user show-environment").output().unwrap();
|
||||
let vars = std::str::from_utf8(command.stdout.as_slice()).unwrap().split("\n").collect::<Vec<&str>>();
|
||||
let command = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("systemctl --user show-environment")
|
||||
.output()
|
||||
.unwrap();
|
||||
let vars = std::str::from_utf8(command.stdout.as_slice())
|
||||
.unwrap()
|
||||
.split("\n")
|
||||
.collect::<Vec<&str>>();
|
||||
for var in vars {
|
||||
if let Some((variable, value)) = var.split_once("=") {
|
||||
if let Err(env::VarError::NotPresent) = env::var(variable) {
|
||||
env::set_var(variable, value);
|
||||
if let Err(env::VarError::NotPresent) = env::var(variable) {
|
||||
env::set_var(variable, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_) => {
|
||||
let uid = Command::new("sh").arg("-c").arg("id -u").output().unwrap();
|
||||
let uid_number = std::str::from_utf8(uid.stdout.as_slice()).unwrap().trim();
|
||||
if uid_number != "0" {
|
||||
let bus_address = format!("unix:path=/run/user/{}/bus", uid_number);
|
||||
env::set_var("DBUS_SESSION_BUS_ADDRESS", bus_address);
|
||||
let command = Command::new("sh").arg("-c").arg("systemctl --user show-environment").output().unwrap();
|
||||
let vars = std::str::from_utf8(command.stdout.as_slice()).unwrap().split("\n").collect::<Vec<&str>>();
|
||||
let command = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("systemctl --user show-environment")
|
||||
.output()
|
||||
.unwrap();
|
||||
let vars = std::str::from_utf8(command.stdout.as_slice())
|
||||
.unwrap()
|
||||
.split("\n")
|
||||
.collect::<Vec<&str>>();
|
||||
for var in vars {
|
||||
if let Some((variable, value)) = var.split_once("=") {
|
||||
if let Err(env::VarError::NotPresent) = env::var(variable) {
|
||||
|
@ -166,21 +210,33 @@ fn set_environment() -> Environment {
|
|||
println!("Warning: unable to inherit user environment.\n\
|
||||
Launch Makima with 'sudo -E makima' or make sure that your systemd unit is running with the 'User=<username>' parameter.\n");
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
if let (Err(env::VarError::NotPresent), Ok(_)) = (env::var("XDG_SESSION_TYPE"), env::var("WAYLAND_DISPLAY")) {
|
||||
if let (Err(env::VarError::NotPresent), Ok(_)) =
|
||||
(env::var("XDG_SESSION_TYPE"), env::var("WAYLAND_DISPLAY"))
|
||||
{
|
||||
env::set_var("XDG_SESSION_TYPE", "wayland")
|
||||
}
|
||||
|
||||
let supported_compositors = vec!["Hyprland", "sway", "KDE"].into_iter().map(|str| String::from(str)).collect::<Vec<String>>();
|
||||
let supported_compositors = vec!["Hyprland", "sway", "KDE"]
|
||||
.into_iter()
|
||||
.map(|str| String::from(str))
|
||||
.collect::<Vec<String>>();
|
||||
let (x11, wayland) = (String::from("x11"), String::from("wayland"));
|
||||
let server: Server = match (env::var("XDG_SESSION_TYPE"), env::var("XDG_CURRENT_DESKTOP")) {
|
||||
(Ok(session), Ok(desktop)) if session == wayland && supported_compositors.contains(&desktop) => {
|
||||
let server: Server = match (
|
||||
env::var("XDG_SESSION_TYPE"),
|
||||
env::var("XDG_CURRENT_DESKTOP"),
|
||||
) {
|
||||
(Ok(session), Ok(desktop))
|
||||
if session == wayland && supported_compositors.contains(&desktop) =>
|
||||
{
|
||||
let server = 'a: {
|
||||
if desktop == String::from("KDE") {
|
||||
if let Err(_) = Command::new("kdotool").output() {
|
||||
println!("Running on KDE but kdotool doesn't seem to be installed.\n\
|
||||
Won't be able to change bindings according to the active window.\n");
|
||||
println!(
|
||||
"Running on KDE but kdotool doesn't seem to be installed.\n\
|
||||
Won't be able to change bindings according to the active window.\n"
|
||||
);
|
||||
break 'a Server::Unsupported;
|
||||
}
|
||||
}
|
||||
|
@ -188,28 +244,28 @@ fn set_environment() -> Environment {
|
|||
Server::Connected(desktop)
|
||||
};
|
||||
server
|
||||
},
|
||||
}
|
||||
(Ok(session), Ok(desktop)) if session == wayland => {
|
||||
println!("Warning: unsupported compositor: {}, won't be able to change bindings according to the active window.\n\
|
||||
Currently supported desktops: Hyprland, Sway, Plasma/KWin, X11.\n", desktop);
|
||||
Server::Unsupported
|
||||
},
|
||||
}
|
||||
(Ok(session), _) if session == x11 => {
|
||||
println!("Running on X11, per application bindings enabled.");
|
||||
Server::Connected(session)
|
||||
},
|
||||
}
|
||||
(Ok(session), Err(_)) if session == wayland => {
|
||||
println!("Warning: unable to retrieve the current desktop based on XDG_CURRENT_DESKTOP env var.\n\
|
||||
Won't be able to change bindings according to the active window.\n");
|
||||
Server::Unsupported
|
||||
},
|
||||
}
|
||||
(Err(_), _) => {
|
||||
println!("Warning: unable to retrieve the session type based on XDG_SESSION_TYPE or WAYLAND_DISPLAY env vars.\n\
|
||||
Is your Wayland compositor or X server running?\n\
|
||||
Exiting Makima.");
|
||||
std::process::exit(0);
|
||||
},
|
||||
_ => Server::Failed
|
||||
}
|
||||
_ => Server::Failed,
|
||||
};
|
||||
|
||||
Environment {
|
||||
|
@ -221,16 +277,26 @@ fn set_environment() -> Environment {
|
|||
|
||||
pub fn get_event_stream(path: &Path, config: Vec<Config>) -> EventStream {
|
||||
let mut device: Device = Device::open(path).expect("Couldn't open device path.");
|
||||
match config.iter().find(|&x| x.associations == Associations::default()).unwrap().settings.get("GRAB_DEVICE") {
|
||||
match config
|
||||
.iter()
|
||||
.find(|&x| x.associations == Associations::default())
|
||||
.unwrap()
|
||||
.settings
|
||||
.get("GRAB_DEVICE")
|
||||
{
|
||||
Some(value) => {
|
||||
if value == &true.to_string() {
|
||||
device.grab().expect("Unable to grab device. Is another instance of Makima running?")
|
||||
device
|
||||
.grab()
|
||||
.expect("Unable to grab device. Is another instance of Makima running?")
|
||||
}
|
||||
}
|
||||
None => device.grab().expect("Unable to grab device. Is another instance of Makima running?")
|
||||
None => device
|
||||
.grab()
|
||||
.expect("Unable to grab device. Is another instance of Makima running?"),
|
||||
}
|
||||
let stream: EventStream = device.into_event_stream().unwrap();
|
||||
return stream
|
||||
return stream;
|
||||
}
|
||||
|
||||
pub fn is_mapped(udev_device: &tokio_udev::Device, config_files: &Vec<Config>) -> bool {
|
||||
|
@ -239,15 +305,17 @@ pub fn is_mapped(udev_device: &tokio_udev::Device, config_files: &Vec<Config>) -
|
|||
let evdev_devices: evdev::EnumerateDevices = evdev::enumerate();
|
||||
for evdev_device in evdev_devices {
|
||||
for config in config_files {
|
||||
if config.name.contains(&evdev_device.1.name().unwrap().to_string())
|
||||
&& devnode.to_path_buf() == evdev_device.0 {
|
||||
return true
|
||||
if config
|
||||
.name
|
||||
.contains(&evdev_device.1.name().unwrap().to_string())
|
||||
&& devnode.to_path_buf() == evdev_device.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return false
|
||||
_ => return false,
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use evdev::{Key, uinput::{VirtualDevice, VirtualDeviceBuilder}};
|
||||
|
||||
use evdev::{
|
||||
uinput::{VirtualDevice, VirtualDeviceBuilder},
|
||||
Key,
|
||||
};
|
||||
|
||||
pub struct VirtualDevices {
|
||||
pub keys: VirtualDevice,
|
||||
|
@ -9,9 +11,13 @@ pub struct VirtualDevices {
|
|||
impl VirtualDevices {
|
||||
pub fn new() -> Self {
|
||||
let mut key_capabilities = evdev::AttributeSet::new();
|
||||
for i in 1..334 {key_capabilities.insert(Key(i));};
|
||||
for i in 1..334 {
|
||||
key_capabilities.insert(Key(i));
|
||||
}
|
||||
let mut axis_capabilities = evdev::AttributeSet::new();
|
||||
for i in 0..13 {axis_capabilities.insert(evdev::RelativeAxisType(i));};
|
||||
for i in 0..13 {
|
||||
axis_capabilities.insert(evdev::RelativeAxisType(i));
|
||||
}
|
||||
let keys_builder = VirtualDeviceBuilder::new()
|
||||
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
|
||||
.name("Makima Virtual Keyboard/Mouse")
|
||||
|
@ -28,4 +34,3 @@ impl VirtualDevices {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue