From 5ca46c50f8d6c675f1e6ef380335a4664ee8a600 Mon Sep 17 00:00:00 2001 From: mnussbaum Date: Thu, 5 Sep 2019 07:08:19 -0700 Subject: [PATCH] Fix detection of initial rotation state This ensures that if rot8 starts while the window server output is rotated, but the physical device is in a "normal" position, rot8 will detect the initial misalignment and rotate the window server's output to reflect the device's physical state. This scenario occurs if you frequently toggle rot8 on and off as form of rotation lock, and you: 1. Use rot8 to rotate the output sideways 2. Turn rot8 off 3. Move the physical device back into a "normal" position 4. Turn rot8 back on --- Cargo.lock | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- src/main.rs | 97 +++++++++++++++++++++++++++++++++------ 3 files changed, 217 insertions(+), 14 deletions(-) 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 ad2a09e..3f4c0ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,107 @@ extern crate clap; 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; -enum BackendMode { +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 old_state = "normal"; 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 x_state: &str; - let mode = if String::from_utf8(Command::new("pidof").arg("sway").output().unwrap().stdout) + let backend = if String::from_utf8(Command::new("pidof").arg("sway").output().unwrap().stdout) .unwrap() .len() >= 1 { - BackendMode::Sway + Backend::Sway } else if String::from_utf8(Command::new("pidof").arg("Xorg").output().unwrap().stdout) .unwrap() .len() >= 1 { - BackendMode::Xorg + Backend::Xorg } else { return Err("Unable to find Sway or Xorg procceses".to_owned()); }; @@ -66,6 +136,8 @@ fn main() -> Result<(), String> { 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 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 { @@ -77,8 +149,7 @@ fn main() -> Result<(), String> { } else if path.to_str().unwrap().contains("z_raw") { continue; } else { - println!("{:?}", path); - panic!(); + panic!("Unknown accelerometer device path {:?}", path); } } Err(e) => println!("{:?}", e), @@ -124,22 +195,22 @@ fn main() -> Result<(), String> { } if new_state != old_state { - match mode { - BackendMode::Sway => { + match backend { + Backend::Sway => { Command::new("swaymsg") .arg("output") .arg(display) .arg("transform") .arg(new_state) .spawn() - .expect("rotate command failed to start"); + .expect("Swaymsg rotate command failed to start"); } - BackendMode::Xorg => { + Backend::Xorg => { Command::new("xrandr") .arg("-o") .arg(x_state) .spawn() - .expect("rotate command failed to start"); + .expect("Xrandr rotate command failed to start"); Command::new("xinput") .arg("set-prop") @@ -149,7 +220,7 @@ fn main() -> Result<(), String> { .arg("Matrix") .args(&matrix) .spawn() - .expect("rotate command failed to start"); + .expect("Xinput rotate command failed to start"); } } old_state = new_state;