diff --git a/Cargo.lock b/Cargo.lock index ebdd46c..380c73c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -42,16 +50,47 @@ name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "numtoa" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.54" @@ -65,12 +104,64 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rot8" version = "0.1.1" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -78,6 +169,16 @@ name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.2" @@ -97,11 +198,24 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.1" @@ -127,19 +241,34 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/Cargo.toml b/Cargo.toml index ccad21c..ac8a890 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,8 @@ keywords = ["sway", "x11", "display", "rotation"] edition = "2018" [dependencies] -glob = "0.3" clap = "2.33" +glob = "0.3" +regex = "1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/src/main.rs b/src/main.rs index 23fd6cc..5c69dba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,80 +1,158 @@ -extern crate glob; extern crate clap; -use clap::{Arg, App}; +extern crate glob; +extern crate regex; + +use clap::{App, Arg}; +use glob::glob; +use serde::Deserialize; use std::fs; +use std::process::Command; use std::thread; use std::time::Duration; -use std::process::Command; -use glob::glob; -fn main() { - let mut mode = ""; - let mut old_state = "normal"; +enum Backend { + Sway, + Xorg, +} + +#[derive(Deserialize)] +struct SwayOutput { + name: String, + transform: String, +} + +fn get_window_server_rotation_state(display: &str, backend: &Backend) -> Result { + match backend { + Backend::Sway => { + let raw_rotation_state = String::from_utf8( + Command::new("swaymsg") + .arg("-t") + .arg("get_outputs") + .arg("--raw") + .output() + .expect("Swaymsg get outputs command failed to start") + .stdout, + ) + .unwrap(); + let deserialized: Vec = serde_json::from_str(&raw_rotation_state) + .expect("Unable to deserialize swaymsg JSON output"); + for output in deserialized { + if output.name == display { + return Ok(output.transform); + } + } + + return Err(format!( + "Unable to determine rotation state: display {} not found in 'swaymsg -t get_outputs'", + display + ) + .to_owned()); + } + Backend::Xorg => { + let raw_rotation_state = String::from_utf8( + Command::new("xrandr") + .output() + .expect("Xrandr get outputs command failed to start") + .stdout, + ) + .unwrap(); + let xrandr_output_pattern = regex::Regex::new(format!( + r"^{} connected .+? .+? (normal |inverted |left |right )?\(normal left inverted right x axis y axis\) .+$", + regex::escape(display), + ).as_str()).unwrap(); + for xrandr_output_line in raw_rotation_state.split("\n") { + if !xrandr_output_pattern.is_match(xrandr_output_line) { + continue; + } + + let xrandr_output_captures = + xrandr_output_pattern.captures(xrandr_output_line).unwrap(); + if let Some(transform) = xrandr_output_captures.get(1) { + return Ok(transform.as_str().to_owned()); + } else { + return Ok("normal".to_owned()); + } + } + + return Err(format!( + "Unable to determine rotation state: display {} not found in xrandr output", + display + ) + .to_owned()); + } + } +} + +fn main() -> Result<(), String> { let mut new_state: &str; let mut path_x: String = "".to_string(); let mut path_y: String = "".to_string(); - let mut matrix: [&str;9]; + let mut matrix: [&str; 9]; let mut x_state: &str; - let sway_pid = String::from_utf8(Command::new("pidof") - .arg("sway") - .output() - .unwrap() - .stdout).unwrap(); - - let x_pid = String::from_utf8(Command::new("pidof") - .arg("x") - .output() - .unwrap() - .stdout).unwrap(); - - if sway_pid.len() >= 1 { - mode = "sway"; - } - if x_pid.len() >= 1 { - mode = "x"; - } + let backend = if String::from_utf8(Command::new("pidof").arg("sway").output().unwrap().stdout) + .unwrap() + .len() + >= 1 + { + Backend::Sway + } else if String::from_utf8(Command::new("pidof").arg("Xorg").output().unwrap().stdout) + .unwrap() + .len() + >= 1 + { + Backend::Xorg + } else { + return Err("Unable to find Sway or Xorg procceses".to_owned()); + }; let matches = App::new("rot8") - .version("0.1.1") - .arg(Arg::with_name("sleep") - .default_value("500") - .long("sleep") - .value_name("SLEEP") - .help("Set sleep millis") - .takes_value(true)) - .arg(Arg::with_name("display") - .default_value("eDP-1") - .long("display") - .value_name("DISPLAY") - .help("Set Display Device") - .takes_value(true)) - .arg(Arg::with_name("touchscreen") - .default_value("ELAN0732:00 04F3:22E1") - .long("touchscreen") - .value_name("TOUCHSCREEN") - .help("Set Touchscreen Device (X11)") - .takes_value(true)) - .get_matches(); + .version("0.1.1") + .arg( + Arg::with_name("sleep") + .default_value("500") + .long("sleep") + .value_name("SLEEP") + .help("Set sleep millis") + .takes_value(true), + ) + .arg( + Arg::with_name("display") + .default_value("eDP-1") + .long("display") + .value_name("DISPLAY") + .help("Set Display Device") + .takes_value(true), + ) + .arg( + Arg::with_name("touchscreen") + .default_value("ELAN0732:00 04F3:22E1") + .long("touchscreen") + .value_name("TOUCHSCREEN") + .help("Set Touchscreen Device (X11)") + .takes_value(true), + ) + .get_matches(); let sleep = matches.value_of("sleep").unwrap_or("default.conf"); let display = matches.value_of("display").unwrap_or("default.conf"); - let touchscreen = matches.value_of("touchscreen").unwrap_or("default.conf"); + let touchscreen = matches.value_of("touchscreen").unwrap_or("default.conf"); + let old_state_owned = get_window_server_rotation_state(display, &backend)?; + let mut old_state = old_state_owned.as_str(); - for entry in glob("/sys/bus/iio/devices/iio:device*/in_accel_*_raw").unwrap(){ - match entry { + for entry in glob("/sys/bus/iio/devices/iio:device*/in_accel_*_raw").unwrap() { + match entry { Ok(path) => { - if path.to_str().unwrap().contains("x_raw"){ + if path.to_str().unwrap().contains("x_raw") { path_x = path.to_str().unwrap().to_owned(); - } else if path.to_str().unwrap().contains("y_raw"){ + } else if path.to_str().unwrap().contains("y_raw") { path_y = path.to_str().unwrap().to_owned(); - } else if path.to_str().unwrap().contains("z_raw"){ + } else if path.to_str().unwrap().contains("z_raw") { continue; } else { - println!("{:?}", path); - panic!(); + panic!("Unknown accelerometer device path {:?}", path); } - }, - Err(e) => println!("{:?}",e) + } + Err(e) => println!("{:?}", e), } } @@ -89,22 +167,19 @@ fn main() { new_state = "180"; x_state = "normal"; matrix = ["-1", "0", "1", "0", "-1", "1", "0", "0", "1"]; - } - else { - - new_state = "90"; - x_state = "left"; - matrix = ["0", "-1", "1", "1", "0", "0", "0", "0", "1"]; + } else { + new_state = "90"; + x_state = "right"; + matrix = ["0", "-1", "1", "1", "0", "0", "0", "0", "1"]; } } else if x > 500000 { if y > 500000 { new_state = "180"; x_state = "inverted"; matrix = ["-1", "0", "1", "0", "-1", "1", "0", "0", "1"]; - } - else { + } else { new_state = "270"; - x_state = "right"; + x_state = "left"; matrix = ["0", "1", "0", "-1", "0", "1", "0", "0", "1"]; } } else { @@ -112,8 +187,7 @@ fn main() { new_state = "180"; x_state = "inverted"; matrix = ["-1", "0", "1", "0", "-1", "1", "0", "0", "1"]; - } - else { + } else { new_state = "normal"; x_state = "normal"; matrix = ["1", "0", "0", "0", "1", "0", "0", "0", "1"]; @@ -121,25 +195,28 @@ fn main() { } if new_state != old_state { - if mode == "sway" { - Command::new("swaymsg") + match backend { + Backend::Sway => { + Command::new("swaymsg") .arg("output") .arg(display) .arg("transform") .arg(new_state) .spawn() - .expect("rotate command failed to start"); - - old_state = new_state; - } - if mode == "x" { - Command::new("xrandr") + .expect("Swaymsg rotate command failed to start") + .wait() + .expect("Swaymsg rotate command wait failed"); + } + Backend::Xorg => { + Command::new("xrandr") .arg("-o") .arg(x_state) .spawn() - .expect("rotate command failed to start"); + .expect("Xrandr rotate command failed to start") + .wait() + .expect("Xrandr rotate command wait failed"); - Command::new("xinput") + Command::new("xinput") .arg("set-prop") .arg(touchscreen) .arg("Coordinate") @@ -147,13 +224,13 @@ fn main() { .arg("Matrix") .args(&matrix) .spawn() - .expect("rotate command failed to start"); - - old_state = new_state; + .expect("Xinput rotate command failed to start") + .wait() + .expect("Xinput rotate command wait failed"); + } } + old_state = new_state; } thread::sleep(Duration::from_millis(sleep.parse::().unwrap_or(0))); } } - -