Format Rust code using rustfmt

This commit is contained in:
github-actions[bot] 2024-06-09 12:05:12 +00:00 committed by eljamm
parent 94c7af7709
commit 91624c0ce0
6 changed files with 989 additions and 421 deletions

View file

@ -1,9 +1,9 @@
use crate::udev_monitor::{Client, Environment, Server};
use crate::Config; use crate::Config;
use crate::udev_monitor::{Client, Server, Environment};
use serde_json; use serde_json;
use swayipc_async::Connection;
use std::process::{Command, Stdio}; 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 { pub async fn get_active_window(environment: &Environment, config: &Vec<Config>) -> Client {
match &environment.server { match &environment.server {
@ -11,10 +11,19 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
let server_str = server.as_str(); let server_str = server.as_str();
match server_str { match server_str {
"Hyprland" => { "Hyprland" => {
let query = Command::new("hyprctl").args(["activewindow", "-j"]).output().unwrap(); let query = Command::new("hyprctl")
if let Ok(reply) = serde_json::from_str::<serde_json::Value>(std::str::from_utf8(query.stdout.as_slice()).unwrap()) { .args(["activewindow", "-j"])
let active_window = Client::Class(reply["class"].to_string().replace("\"", "")); .output()
if let Some(_) = config.iter().find(|&x| x.associations.client == active_window) { .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 active_window
} else { } else {
Client::Default Client::Default
@ -22,33 +31,37 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
} else { } else {
Client::Default Client::Default
} }
}, }
"sway" => { "sway" => {
let mut connection = Connection::new().await.unwrap(); let mut connection = Connection::new().await.unwrap();
let active_window = match connection.get_tree().await.unwrap().find_focused(|window| window.focused) { let active_window = match connection
Some(window) => { .get_tree()
match window.app_id { .await
.unwrap()
.find_focused(|window| window.focused)
{
Some(window) => match window.app_id {
Some(id) => Client::Class(id), Some(id) => Client::Class(id),
None => Client::Class(window.window_properties.unwrap().class.unwrap()) 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 active_window
} else { } else {
Client::Default Client::Default
} }
}, }
"KDE" => { "KDE" => {
let (user, running_as_root) = let (user, running_as_root) =
if let Ok(sudo_user) = environment.sudo_user.clone() { if let Ok(sudo_user) = environment.sudo_user.clone() {
(Option::Some(sudo_user), true) (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) (Option::Some(user), false)
} } else {
else {
(Option::None, false) (Option::None, false)
}; };
let active_window = { let active_window = {
@ -60,7 +73,12 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
.arg("kdotool getactivewindow getwindowclassname") .arg("kdotool getactivewindow getwindowclassname")
.output() .output()
.unwrap(); .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 { } else {
let output = Command::new("sh") let output = Command::new("sh")
.arg("-c") .arg("-c")
@ -68,33 +86,57 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
.stderr(Stdio::null()) .stderr(Stdio::null())
.output() .output()
.unwrap(); .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 { } else {
Client::Default 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 active_window
} else { } else {
Client::Default Client::Default
} }
}, }
"x11" => { "x11" => {
let connection = x11rb::connect(None).unwrap().0; let connection = x11rb::connect(None).unwrap().0;
let focused_window = get_input_focus(&connection) let focused_window =
.unwrap().reply().unwrap().focus; get_input_focus(&connection).unwrap().reply().unwrap().focus;
let (wm_class, string): (Atom, Atom) = (AtomEnum::WM_CLASS.into(), AtomEnum::STRING.into()); let (wm_class, string): (Atom, Atom) =
let class = get_property(&connection, false, focused_window, wm_class, string, 0, u32::MAX) (AtomEnum::WM_CLASS.into(), AtomEnum::STRING.into());
.unwrap().reply().unwrap().value; 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) { if let Some(middle) = class.iter().position(|&byte| byte == 0) {
let class = class.split_at(middle).1; let class = class.split_at(middle).1;
let mut class = &class[1..]; let mut class = &class[1..];
if class.last() == Some(&0) { 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()); let active_window =
if let Some(_) = config.iter().find(|&x| x.associations.client == 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 active_window
} else { } else {
Client::Default Client::Default
@ -102,12 +144,11 @@ pub async fn get_active_window(environment: &Environment, config: &Vec<Config>)
} else { } else {
Client::Default Client::Default
} }
},
_ => Client::Default
} }
}, _ => Client::Default,
}
}
Server::Unsupported => Client::Default, Server::Unsupported => Client::Default,
Server::Failed => Client::Default, Server::Failed => Client::Default,
} }
} }

View file

@ -1,8 +1,7 @@
use std::{collections::HashMap, str::FromStr}; use crate::udev_monitor::Client;
use evdev::Key; use evdev::Key;
use serde; use serde;
use crate::udev_monitor::Client; use std::{collections::HashMap, str::FromStr};
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
pub enum Event { pub enum Event {
@ -31,7 +30,7 @@ pub enum Axis {
BTN_TL2, BTN_TL2,
BTN_TR2, BTN_TR2,
ABS_WHEEL_CW, ABS_WHEEL_CW,
ABS_WHEEL_CCW ABS_WHEEL_CCW,
} }
impl FromStr for Axis { impl FromStr for Axis {
@ -92,10 +91,13 @@ pub struct RawConfig {
impl RawConfig { impl RawConfig {
fn new_from_file(file: &str) -> Self { 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 file_content: String = std::fs::read_to_string(file).unwrap();
let raw_config: RawConfig = toml::from_str(&file_content) let raw_config: RawConfig =
.expect("Couldn't parse config file."); toml::from_str(&file_content).expect("Couldn't parse config file.");
let remap = raw_config.remap; let remap = raw_config.remap;
let commands = raw_config.commands; let commands = raw_config.commands;
let settings = raw_config.settings; let settings = raw_config.settings;
@ -162,8 +164,10 @@ fn parse_raw_config(raw_config: RawConfig) -> (Bindings, HashMap<String, String>
all: Vec::new(), all: Vec::new(),
}; };
let custom_modifiers: Vec<Event> = parse_modifiers(&settings, "CUSTOM_MODIFIERS"); let custom_modifiers: Vec<Event> = parse_modifiers(&settings, "CUSTOM_MODIFIERS");
let lstick_activation_modifiers: Vec<Event> = parse_modifiers(&settings, "LSTICK_ACTIVATION_MODIFIERS"); let lstick_activation_modifiers: Vec<Event> =
let rstick_activation_modifiers: Vec<Event> = parse_modifiers(&settings, "RSTICK_ACTIVATION_MODIFIERS"); 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(custom_modifiers);
mapped_modifiers.custom.extend(lstick_activation_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 let Ok(event) = Axis::from_str(event) {
if !bindings.remap.contains_key(&Event::Axis(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 { } 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) { } else if let Ok(event) = Key::from_str(event) {
if !bindings.remap.contains_key(&Event::Key(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 { } else {
bindings.remap.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output); bindings
.remap
.get_mut(&Event::Key(event))
.unwrap()
.insert(modifiers, output);
} }
} }
} else { } else {
let modifiers: Vec<Event> = Vec::new(); let modifiers: Vec<Event> = Vec::new();
if let Ok(event) = Axis::from_str(input.as_str()) { if let Ok(event) = Axis::from_str(input.as_str()) {
if !bindings.remap.contains_key(&Event::Axis(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 { } 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()) { } else if let Ok(event) = Key::from_str(input.as_str()) {
if !bindings.remap.contains_key(&Event::Key(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 { } 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 let Ok(event) = Axis::from_str(event) {
if !bindings.commands.contains_key(&Event::Axis(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 { } 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) { } else if let Ok(event) = Key::from_str(event) {
if !bindings.commands.contains_key(&Event::Key(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 { } else {
bindings.commands.get_mut(&Event::Key(event)).unwrap().insert(modifiers, output); bindings
.commands
.get_mut(&Event::Key(event))
.unwrap()
.insert(modifiers, output);
} }
} }
} else { } else {
let modifiers: Vec<Event> = Vec::new(); let modifiers: Vec<Event> = Vec::new();
if let Ok(event) = Axis::from_str(input.as_str()) { if let Ok(event) = Axis::from_str(input.as_str()) {
if !bindings.commands.contains_key(&Event::Axis(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 { } 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()) { } else if let Ok(event) = Key::from_str(input.as_str()) {
if !bindings.commands.contains_key(&Event::Key(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 { } 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.sort();
mapped_modifiers.custom.dedup(); 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.extend(mapped_modifiers.custom.clone());
mapped_modifiers.all.sort(); mapped_modifiers.all.sort();
mapped_modifiers.all.dedup(); mapped_modifiers.all.dedup();
@ -296,8 +349,7 @@ pub fn parse_modifiers(settings: &HashMap<String, String>, parameter: &str) -> V
} }
} }
custom_modifiers custom_modifiers
}, }
None => Vec::new(), None => Vec::new(),
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,14 @@
mod active_client;
mod config; mod config;
mod virtual_devices;
mod event_reader; mod event_reader;
mod udev_monitor; mod udev_monitor;
mod active_client; mod virtual_devices;
use crate::udev_monitor::*;
use config::Config;
use std::env; use std::env;
use tokio; use tokio;
use config::Config;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use crate::udev_monitor::*;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -23,20 +22,21 @@ async fn main() {
std::process::exit(0); std::process::exit(0);
} }
} }
}, }
Err(_) => { Err(_) => {
let user_home = match env::var("HOME") { let user_home = match env::var("HOME") {
Ok(user_home) if user_home == "/root".to_string() => { Ok(user_home) if user_home == "/root".to_string() => match env::var("SUDO_USER") {
match env::var("SUDO_USER") {
Ok(sudo_user) => format!("/home/{}", sudo_user), Ok(sudo_user) => format!("/home/{}", sudo_user),
_ => user_home, _ => user_home,
}
}, },
Ok(user_home) => user_home, Ok(user_home) => user_home,
_ => "/root".to_string(), _ => "/root".to_string(),
}; };
let default_config_path = format!("{}/.config/makima", user_home); 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) { match std::fs::read_dir(default_config_path) {
Ok(dir) => dir, Ok(dir) => dir,
_ => { _ => {
@ -44,14 +44,15 @@ async fn main() {
std::process::exit(0); std::process::exit(0);
} }
} }
}, }
}; };
let mut config_files: Vec<Config> = Vec::new(); let mut config_files: Vec<Config> = Vec::new();
for file in config_path { for file in config_path {
let filename: String = file.as_ref().unwrap().file_name().into_string().unwrap(); let filename: String = file.as_ref().unwrap().file_name().into_string().unwrap();
if filename.ends_with(".toml") && !filename.starts_with(".") { if filename.ends_with(".toml") && !filename.starts_with(".") {
let name: String = filename.split(".toml").collect::<Vec<&str>>()[0].to_string(); 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); config_files.push(config_file);
} }
} }

View 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::sync::Mutex;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio_stream::StreamExt; 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)] #[derive(Debug, Default, Eq, PartialEq, Hash, Clone)]
pub enum Client { pub enum Client {
@ -33,10 +32,14 @@ pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<Joi
let environment = set_environment(); let environment = set_environment();
launch_tasks(&config_files, &mut tasks, environment.clone()); launch_tasks(&config_files, &mut tasks, environment.clone());
let mut monitor = tokio_udev::AsyncMonitorSocket::new( let mut monitor = tokio_udev::AsyncMonitorSocket::new(
tokio_udev::MonitorBuilder::new().unwrap() tokio_udev::MonitorBuilder::new()
.match_subsystem(std::ffi::OsStr::new("input")).unwrap() .unwrap()
.listen().unwrap() .match_subsystem(std::ffi::OsStr::new("input"))
).unwrap(); .unwrap()
.listen()
.unwrap(),
)
.unwrap();
while let Some(Ok(event)) = monitor.next().await { while let Some(Ok(event)) = monitor.next().await {
if is_mapped(&event.device(), &config_files) { if is_mapped(&event.device(), &config_files) {
println!("---------------------\n\nReinitializing...\n"); 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 modifiers: Arc<Mutex<Vec<Event>>> = Arc::new(Mutex::new(Default::default()));
let modifier_was_activated: Arc<Mutex<bool>> = Arc::new(Mutex::new(true)); let modifier_was_activated: Arc<Mutex<bool>> = Arc::new(Mutex::new(true));
let user_has_access = match Command::new("groups").output() { 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"); println!("Evdev permissions available.\nScanning for event devices with a matching config file...\n");
true 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"); println!("Root permissions available.\nScanning for event devices with a matching config file...\n");
true 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\ 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"); Note: Run Makima with 'sudo -E makima' or as a system service. Refer to the docs for more info. Continuing...\n");
false false
}, }
Err(_) => { 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 false
}, }
}; };
let devices: evdev::EnumerateDevices = evdev::enumerate(); let devices: evdev::EnumerateDevices = evdev::enumerate();
let mut devices_found = 0; let mut devices_found = 0;
@ -87,7 +104,7 @@ pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>,
} else { } else {
(Client::Class(split_config_name[1].to_string()), 0) (Client::Class(split_config_name[1].to_string()), 0)
} }
}, }
3 => { 3 => {
if let Ok(layout) = split_config_name[1].parse::<u16>() { if let Ok(layout) = split_config_name[1].parse::<u16>() {
(Client::Class(split_config_name[2].to_string()), layout) (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); println!("Warning: unable to parse layout number in {}, treating it as default.", config.name);
(Client::Default, 0) (Client::Default, 0)
} }
}, }
_ => { _ => {
println!("Warning: too many arguments in config file name {}, treating it as default.", config.name); println!("Warning: too many arguments in config file name {}, treating it as default.", config.name);
(Client::Default, 0) (Client::Default, 0)
}, }
}; };
config.associations.client = window_class; config.associations.client = window_class;
config.associations.layout = layout; config.associations.layout = layout;
config_list.push(config.clone()); 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("/", ""))); config_list.push(Config::new_empty(device.1.name().unwrap().replace("/", "")));
} }
let event_device = device.0.as_path().to_str().unwrap().to_string(); let event_device = device.0.as_path().to_str().unwrap().to_string();
if config_list.len() != 0 { if config_list.len() != 0 {
let stream = Arc::new(Mutex::new(get_event_stream(Path::new(&event_device), config_list.clone()))); let stream = Arc::new(Mutex::new(get_event_stream(
let reader = EventReader::new(config_list.clone(), stream, modifiers.clone(), modifier_was_activated.clone(), environment.clone()); 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))); tasks.push(tokio::spawn(start_reader(reader)));
devices_found += 1 devices_found += 1
} }
@ -133,8 +163,15 @@ pub async fn start_reader(reader: EventReader) {
fn set_environment() -> Environment { fn set_environment() -> Environment {
match env::var("DBUS_SESSION_BUS_ADDRESS") { match env::var("DBUS_SESSION_BUS_ADDRESS") {
Ok(_) => { Ok(_) => {
let command = Command::new("sh").arg("-c").arg("systemctl --user show-environment").output().unwrap(); let command = Command::new("sh")
let vars = std::str::from_utf8(command.stdout.as_slice()).unwrap().split("\n").collect::<Vec<&str>>(); .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 { for var in vars {
if let Some((variable, value)) = var.split_once("=") { if let Some((variable, value)) = var.split_once("=") {
if let Err(env::VarError::NotPresent) = env::var(variable) { if let Err(env::VarError::NotPresent) = env::var(variable) {
@ -142,15 +179,22 @@ fn set_environment() -> Environment {
} }
} }
} }
}, }
Err(_) => { Err(_) => {
let uid = Command::new("sh").arg("-c").arg("id -u").output().unwrap(); 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(); let uid_number = std::str::from_utf8(uid.stdout.as_slice()).unwrap().trim();
if uid_number != "0" { if uid_number != "0" {
let bus_address = format!("unix:path=/run/user/{}/bus", uid_number); let bus_address = format!("unix:path=/run/user/{}/bus", uid_number);
env::set_var("DBUS_SESSION_BUS_ADDRESS", bus_address); env::set_var("DBUS_SESSION_BUS_ADDRESS", bus_address);
let command = Command::new("sh").arg("-c").arg("systemctl --user show-environment").output().unwrap(); let command = Command::new("sh")
let vars = std::str::from_utf8(command.stdout.as_slice()).unwrap().split("\n").collect::<Vec<&str>>(); .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 { for var in vars {
if let Some((variable, value)) = var.split_once("=") { if let Some((variable, value)) = var.split_once("=") {
if let Err(env::VarError::NotPresent) = env::var(variable) { 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\ 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"); 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") 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 (x11, wayland) = (String::from("x11"), String::from("wayland"));
let server: Server = match (env::var("XDG_SESSION_TYPE"), env::var("XDG_CURRENT_DESKTOP")) { let server: Server = match (
(Ok(session), Ok(desktop)) if session == wayland && supported_compositors.contains(&desktop) => { env::var("XDG_SESSION_TYPE"),
env::var("XDG_CURRENT_DESKTOP"),
) {
(Ok(session), Ok(desktop))
if session == wayland && supported_compositors.contains(&desktop) =>
{
let server = 'a: { let server = 'a: {
if desktop == String::from("KDE") { if desktop == String::from("KDE") {
if let Err(_) = Command::new("kdotool").output() { if let Err(_) = Command::new("kdotool").output() {
println!("Running on KDE but kdotool doesn't seem to be installed.\n\ println!(
Won't be able to change bindings according to the active window.\n"); "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; break 'a Server::Unsupported;
} }
} }
@ -188,28 +244,28 @@ fn set_environment() -> Environment {
Server::Connected(desktop) Server::Connected(desktop)
}; };
server server
}, }
(Ok(session), Ok(desktop)) if session == wayland => { (Ok(session), Ok(desktop)) if session == wayland => {
println!("Warning: unsupported compositor: {}, won't be able to change bindings according to the active window.\n\ 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); Currently supported desktops: Hyprland, Sway, Plasma/KWin, X11.\n", desktop);
Server::Unsupported Server::Unsupported
}, }
(Ok(session), _) if session == x11 => { (Ok(session), _) if session == x11 => {
println!("Running on X11, per application bindings enabled."); println!("Running on X11, per application bindings enabled.");
Server::Connected(session) Server::Connected(session)
}, }
(Ok(session), Err(_)) if session == wayland => { (Ok(session), Err(_)) if session == wayland => {
println!("Warning: unable to retrieve the current desktop based on XDG_CURRENT_DESKTOP env var.\n\ 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"); Won't be able to change bindings according to the active window.\n");
Server::Unsupported Server::Unsupported
}, }
(Err(_), _) => { (Err(_), _) => {
println!("Warning: unable to retrieve the session type based on XDG_SESSION_TYPE or WAYLAND_DISPLAY env vars.\n\ 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\ Is your Wayland compositor or X server running?\n\
Exiting Makima."); Exiting Makima.");
std::process::exit(0); std::process::exit(0);
}, }
_ => Server::Failed _ => Server::Failed,
}; };
Environment { Environment {
@ -221,16 +277,26 @@ fn set_environment() -> Environment {
pub fn get_event_stream(path: &Path, config: Vec<Config>) -> EventStream { pub fn get_event_stream(path: &Path, config: Vec<Config>) -> EventStream {
let mut device: Device = Device::open(path).expect("Couldn't open device path."); 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) => { Some(value) => {
if value == &true.to_string() { 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(); 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 { 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(); let evdev_devices: evdev::EnumerateDevices = evdev::enumerate();
for evdev_device in evdev_devices { for evdev_device in evdev_devices {
for config in config_files { for config in config_files {
if config.name.contains(&evdev_device.1.name().unwrap().to_string()) if config
&& devnode.to_path_buf() == evdev_device.0 { .name
return true .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;
} }

View file

@ -1,5 +1,7 @@
use evdev::{Key, uinput::{VirtualDevice, VirtualDeviceBuilder}}; use evdev::{
uinput::{VirtualDevice, VirtualDeviceBuilder},
Key,
};
pub struct VirtualDevices { pub struct VirtualDevices {
pub keys: VirtualDevice, pub keys: VirtualDevice,
@ -9,9 +11,13 @@ pub struct VirtualDevices {
impl VirtualDevices { impl VirtualDevices {
pub fn new() -> Self { pub fn new() -> Self {
let mut key_capabilities = evdev::AttributeSet::new(); 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(); 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() let keys_builder = VirtualDeviceBuilder::new()
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.") .expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
.name("Makima Virtual Keyboard/Mouse") .name("Makima Virtual Keyboard/Mouse")
@ -28,4 +34,3 @@ impl VirtualDevices {
} }
} }
} }