1
0

add barebones on-disk mode persistance

This commit is contained in:
Daniel Prilik
2020-10-31 00:15:34 -04:00
parent d14a92dfe5
commit 82e08c8e4a
6 changed files with 101 additions and 7 deletions

21
Cargo.lock generated
View File

@@ -111,6 +111,15 @@ dependencies = [
"libdbus-sys", "libdbus-sys",
] ]
[[package]]
name = "directories"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
dependencies = [
"dirs-sys",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "1.0.5" version = "1.0.5"
@@ -122,6 +131,17 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dirs-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]] [[package]]
name = "evdev-rs" name = "evdev-rs"
version = "0.4.0" version = "0.4.0"
@@ -356,6 +376,7 @@ dependencies = [
name = "surface-dial-daemon" name = "surface-dial-daemon"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"directories",
"evdev-rs", "evdev-rs",
"hidapi", "hidapi",
"notify-rust", "notify-rust",

View File

@@ -5,6 +5,7 @@ authors = ["Daniel Prilik <danielprilik@gmail.com>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
directories = "3.0"
# master includes a PR that implements `Send` for `Device` and `UInputDevice` # master includes a PR that implements `Send` for `Device` and `UInputDevice`
evdev-rs = { git = "https://github.com/ndesh26/evdev-rs.git" } evdev-rs = { git = "https://github.com/ndesh26/evdev-rs.git" }
hidapi = { version = "1.2.3", default-features = false, features = ["linux-shared-hidraw"] } hidapi = { version = "1.2.3", default-features = false, features = ["linux-shared-hidraw"] }

View File

@@ -38,8 +38,7 @@ It would be cool to create some sort of GUI overlay (similar to the Windows one)
- [x] Dynamically switch between operating modes - [x] Dynamically switch between operating modes
- [x] Using some-sort of on-device mechanism (e.g: long-press) - [x] Using some-sort of on-device mechanism (e.g: long-press)
- [ ] Context-sensitive (based on currently open application) - [ ] Context-sensitive (based on currently open application)
- [ ] Mode Persistence - [x] Mode Persistence (keep mode when dial disconnects)
- _At the moment, whenever the dial disconnects, the daemon is re-launched, which resets the active mode to the default one. It would be good to have some on-disk persistence to remember the last selected mode._
- [x] Haptic Feedback - [x] Haptic Feedback
- https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/radial-controller-protocol-implementation - https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/radial-controller-protocol-implementation
- https://www.usb.org/sites/default/files/hutrr63b_-_haptics_page_redline_0.pdf - https://www.usb.org/sites/default/files/hutrr63b_-_haptics_page_redline_0.pdf

58
src/config.rs Normal file
View File

@@ -0,0 +1,58 @@
use std::fs;
use std::io::prelude::*;
use crate::DynResult;
// This current implementation is incredibly barebones.
// It literally just reads/writes the last selected mode from the file.
//
// No TOML, No JSON, just raw text.
//
// It shouldn't be too hard to get a proper serde-based implementation up and
// running, it's moreso that it'll bump compile times for no good reason. I'll
// set that all up once I need the complexity.
pub struct Config {
pub last_mode: usize,
}
fn get_cfg_file() -> DynResult<fs::File> {
let proj_dirs = directories::ProjectDirs::from("com", "prilik", "surface-dial-daemon")
.ok_or("could not open config directory")?;
let cfg_folder = proj_dirs.config_dir();
let cfg_file_path = proj_dirs.config_dir().join("config.txt");
fs::create_dir_all(cfg_folder).map_err(|_| "could not create config dir")?;
if !cfg_file_path.exists() {
fs::write(&cfg_file_path, "0")?;
}
let cfg_file = fs::OpenOptions::new()
.write(true)
.read(true)
.open(cfg_file_path)
.map_err(|e| format!("could not open config file: {}", e))?;
Ok(cfg_file)
}
impl Config {
pub fn from_disk() -> DynResult<Config> {
let mut cfg_file = get_cfg_file()?;
let mut content = String::new();
cfg_file.read_to_string(&mut content)?;
let last_mode = content.parse()?;
Ok(Config { last_mode })
}
pub fn to_disk(&self) -> DynResult<()> {
let mut cfg_file = get_cfg_file()?;
cfg_file.write_all(format!("{}", self.last_mode).as_bytes())?;
Ok(())
}
}

View File

@@ -39,7 +39,11 @@ pub struct DialController {
} }
impl DialController { impl DialController {
pub fn new(device: DialDevice, modes: Vec<Box<dyn ControlMode>>) -> DialController { pub fn new(
device: DialDevice,
initial_mode: usize,
modes: Vec<Box<dyn ControlMode>>,
) -> DialController {
let metas = modes.iter().map(|m| m.meta()).collect(); let metas = modes.iter().map(|m| m.meta()).collect();
let new_mode = Arc::new(Mutex::new(None)); let new_mode = Arc::new(Mutex::new(None));
@@ -48,7 +52,7 @@ impl DialController {
device, device,
modes, modes,
active_mode: ActiveMode::Normal(0), active_mode: ActiveMode::Normal(initial_mode),
new_mode: new_mode.clone(), new_mode: new_mode.clone(),
meta_mode: Box::new(MetaMode::new(new_mode, 0, metas)), meta_mode: Box::new(MetaMode::new(new_mode, 0, metas)),
@@ -162,9 +166,14 @@ impl ControlMode for MetaMode {
self.first_release = false; self.first_release = false;
} else { } else {
*self.new_mode.lock().unwrap() = Some(self.current_mode); *self.new_mode.lock().unwrap() = Some(self.current_mode);
haptics.buzz(1)?;
crate::config::Config {
last_mode: self.current_mode,
}
.to_disk()?;
self.notif.take().unwrap().close(); self.notif.take().unwrap().close();
haptics.buzz(1)?;
} }
Ok(()) Ok(())
} }

View File

@@ -1,6 +1,7 @@
#![allow(clippy::collapsible_if, clippy::new_without_default)] #![allow(clippy::collapsible_if, clippy::new_without_default)]
mod common; mod common;
mod config;
pub mod controller; pub mod controller;
mod dial_device; mod dial_device;
mod error; mod error;
@@ -22,12 +23,16 @@ fn main() {
} }
fn true_main() -> DynResult<()> { fn true_main() -> DynResult<()> {
println!("Started."); println!("Started");
let cfg = config::Config::from_disk()?;
let dial = DialDevice::new(std::time::Duration::from_millis(750))?; let dial = DialDevice::new(std::time::Duration::from_millis(750))?;
println!("Found the dial."); println!("Found the dial");
std::thread::spawn(move || { std::thread::spawn(move || {
// TODO: use this persistent notification for the meta mode.
let active_notification = Notification::new() let active_notification = Notification::new()
.hint(Hint::Resident(true)) .hint(Hint::Resident(true))
.hint(Hint::Category("device".into())) .hint(Hint::Category("device".into()))
@@ -48,6 +53,7 @@ fn true_main() -> DynResult<()> {
let mut controller = DialController::new( let mut controller = DialController::new(
dial, dial,
cfg.last_mode,
vec![ vec![
Box::new(controller::controls::ScrollZoom::new()), Box::new(controller::controls::ScrollZoom::new()),
Box::new(controller::controls::Volume::new()), Box::new(controller::controls::Volume::new()),