add barebones on-disk mode persistance
This commit is contained in:
21
Cargo.lock
generated
21
Cargo.lock
generated
@@ -111,6 +111,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "dirs"
|
||||
version = "1.0.5"
|
||||
@@ -122,6 +131,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "evdev-rs"
|
||||
version = "0.4.0"
|
||||
@@ -356,6 +376,7 @@ dependencies = [
|
||||
name = "surface-dial-daemon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"directories",
|
||||
"evdev-rs",
|
||||
"hidapi",
|
||||
"notify-rust",
|
||||
|
||||
@@ -5,6 +5,7 @@ authors = ["Daniel Prilik <danielprilik@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
directories = "3.0"
|
||||
# master includes a PR that implements `Send` for `Device` and `UInputDevice`
|
||||
evdev-rs = { git = "https://github.com/ndesh26/evdev-rs.git" }
|
||||
hidapi = { version = "1.2.3", default-features = false, features = ["linux-shared-hidraw"] }
|
||||
|
||||
@@ -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] Using some-sort of on-device mechanism (e.g: long-press)
|
||||
- [ ] Context-sensitive (based on currently open application)
|
||||
- [ ] Mode Persistence
|
||||
- _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] Mode Persistence (keep mode when dial disconnects)
|
||||
- [x] Haptic Feedback
|
||||
- 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
|
||||
|
||||
58
src/config.rs
Normal file
58
src/config.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,11 @@ pub struct 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 new_mode = Arc::new(Mutex::new(None));
|
||||
@@ -48,7 +52,7 @@ impl DialController {
|
||||
device,
|
||||
|
||||
modes,
|
||||
active_mode: ActiveMode::Normal(0),
|
||||
active_mode: ActiveMode::Normal(initial_mode),
|
||||
|
||||
new_mode: new_mode.clone(),
|
||||
meta_mode: Box::new(MetaMode::new(new_mode, 0, metas)),
|
||||
@@ -162,9 +166,14 @@ impl ControlMode for MetaMode {
|
||||
self.first_release = false;
|
||||
} else {
|
||||
*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();
|
||||
haptics.buzz(1)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
10
src/main.rs
10
src/main.rs
@@ -1,6 +1,7 @@
|
||||
#![allow(clippy::collapsible_if, clippy::new_without_default)]
|
||||
|
||||
mod common;
|
||||
mod config;
|
||||
pub mod controller;
|
||||
mod dial_device;
|
||||
mod error;
|
||||
@@ -22,12 +23,16 @@ fn main() {
|
||||
}
|
||||
|
||||
fn true_main() -> DynResult<()> {
|
||||
println!("Started.");
|
||||
println!("Started");
|
||||
|
||||
let cfg = config::Config::from_disk()?;
|
||||
|
||||
let dial = DialDevice::new(std::time::Duration::from_millis(750))?;
|
||||
println!("Found the dial.");
|
||||
println!("Found the dial");
|
||||
|
||||
std::thread::spawn(move || {
|
||||
// TODO: use this persistent notification for the meta mode.
|
||||
|
||||
let active_notification = Notification::new()
|
||||
.hint(Hint::Resident(true))
|
||||
.hint(Hint::Category("device".into()))
|
||||
@@ -48,6 +53,7 @@ fn true_main() -> DynResult<()> {
|
||||
|
||||
let mut controller = DialController::new(
|
||||
dial,
|
||||
cfg.last_mode,
|
||||
vec![
|
||||
Box::new(controller::controls::ScrollZoom::new()),
|
||||
Box::new(controller::controls::Volume::new()),
|
||||
|
||||
Reference in New Issue
Block a user