diff --git a/README.md b/README.md index f8a7924..198ead6 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,18 @@ Configuration file settings: ```ini usb_device = "1050:0407" - monitor_input = "Hdmi1" + on_usb_connect = "Hdmi1" + on_usb_disconnect = "Hdmi2" ``` -`usb_device` is which USB device to watch (vendor id / device id in hex), and `monitor_input` is which monitor input -to switch to, when this device is connected. Supported values are `Hdmi1`, `Hdmi2`, `DisplayPort1`, `DisplayPort2` +`usb_device` is which USB device to watch (vendor id / device id in hex), and `on_usb_connect` is which monitor input +to switch to, when this device is connected. Supported values are `Hdmi1`, `Hdmi2`, `DisplayPort1`, `DisplayPort2`. If your monitor has an USB-C port, it's usually reported as `DisplayPort2`. Input can also be specified as a "raw" -decimal or hexadecimal value: `monitor_input = 0x10` +decimal or hexadecimal value: `on_usb_connect = 0x10` + +The optional `on_usb_disconnect` settings allows to switch in the other direction when the USB device is disconnected. +Note that the preferred way is to have this app installed on both computers. Switching "away" is problematic: if the +other computer has put the monitors to sleep, they will switch immediately back to the original input. ### USB Device IDs To locate the ID of your USB device ID on Windows: diff --git a/src/app.rs b/src/app.rs index 7da7d7a..f5497b7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,16 +18,24 @@ impl usb::UsbCallback for App { fn device_added(&self, device_id: &str) { debug!("Detected device change. Added device: {:?}", device_id); if device_id == self.config.usb_device { - info!("Detected device we're looking for {:?}", &self.config.usb_device); + info!("Monitored device ({:?}) is connected", &self.config.usb_device); std::thread::spawn(|| { wake_displays().map_err(|err| error!("{:?}", err)); }); - display_control::switch_to(self.config.monitor_input); + if let Some(input) = self.config.on_usb_connect { + display_control::switch_to(input); + } } } fn device_removed(&self, device_id: &str) { debug!("Detected device change. Removed device: {:?}", device_id); + if device_id == self.config.usb_device { + info!("Monitored device is ({:?}) is disconnected", &self.config.usb_device); + if let Some(input) = self.config.on_usb_disconnect { + display_control::switch_to(input); + } + } } } diff --git a/src/configuration.rs b/src/configuration.rs index 9125a61..b813451 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -11,7 +11,9 @@ use serde::{Deserialize, Deserializer}; pub struct Configuration { #[serde(deserialize_with = "Configuration::deserialize_usb_device")] pub usb_device: String, - pub monitor_input: InputSource, + #[serde(alias = "monitor_input")] + pub on_usb_connect: Option, + pub on_usb_disconnect: Option, } impl Configuration { @@ -99,11 +101,13 @@ mod tests { let config = load_test_config( r#" usb_device = "dead:BEEF" - monitor_input = "DisplayPort2" + on_usb_connect = "DisplayPort2" + on_usb_disconnect = DisplayPort1 "#, ) .unwrap(); - assert_eq!(config.monitor_input.value(), 0x10); + assert_eq!(config.on_usb_connect.unwrap().value(), 0x10); + assert_eq!(config.on_usb_disconnect.unwrap().value(), 0x0f); } #[test] @@ -112,10 +116,12 @@ mod tests { r#" usb_device = "dead:BEEF" monitor_input = 22 + on_usb_disconnect = 33 "#, ) .unwrap(); - assert_eq!(config.monitor_input.value(), 22); + assert_eq!(config.on_usb_connect.unwrap().value(), 22); + assert_eq!(config.on_usb_disconnect.unwrap().value(), 33); } #[test] @@ -123,10 +129,12 @@ mod tests { let config = load_test_config( r#" usb_device = "dead:BEEF" - monitor_input = "0x10" + on_usb_connect = "0x10" + on_usb_disconnect = "0x20" "#, ) .unwrap(); - assert_eq!(config.monitor_input.value(), 16); + assert_eq!(config.on_usb_connect.unwrap().value(), 0x10); + assert_eq!(config.on_usb_disconnect.unwrap().value(), 0x20); } } diff --git a/src/input_source.rs b/src/input_source.rs index 14a9014..7d90d44 100644 --- a/src/input_source.rs +++ b/src/input_source.rs @@ -3,11 +3,11 @@ // This code is licensed under MIT license (see LICENSE.txt for details) // +use paste::paste; use serde::de::Error; use serde::{Deserialize, Deserializer}; use std::convert::TryFrom; use std::fmt; -use paste::paste; macro_rules! symbolic_input_source { (