Parse the basic config structure

This commit is contained in:
Takashi Kokubun 2021-12-17 10:05:39 -08:00
parent 2f8029a200
commit d9127e8a90
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
8 changed files with 186 additions and 51 deletions

92
Cargo.lock generated
View File

@ -55,6 +55,22 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "libc"
version = "0.2.111"
@ -89,18 +105,91 @@ dependencies = [
"memoffset",
]
[[package]]
name = "proc-macro2"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "serde"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_yaml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
dependencies = [
"indexmap",
"ryu",
"serde",
"yaml-rust",
]
[[package]]
name = "syn"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "wyz"
version = "0.4.0"
@ -116,7 +205,8 @@ version = "0.1.0"
dependencies = [
"evdev",
"nix",
"yaml-rust",
"serde",
"serde_yaml",
]
[[package]]

View File

@ -8,4 +8,5 @@ edition = "2021"
[dependencies]
evdev = "0.11.3"
nix = "0.23.1"
yaml-rust = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"

View File

@ -10,12 +10,12 @@ modmap:
Muhenkan: Ctrl_L
Henkan: Shift_L
- name: Kana -> Windows
- name: Kana -> Alt
wm_class:
not: jetbrains-idea
only: jetbrains-idea
remap:
# Use Windows since Alt is annoying in Electron apps (Slack, Nocturn)
KanaHira: Windows
# Use Alt since Windows is annoying in IDEA
KanaHira: Alt_L
keymap:
- name: Global

View File

@ -1,36 +1,76 @@
extern crate serde_yaml;
use serde::de::{value, SeqAccess, Visitor};
use serde::{de, Deserialize, Deserializer};
use std::collections::HashMap;
use std::error::Error;
use std::fs;
use yaml_rust::{Yaml, YamlLoader};
use std::{fmt, fs};
pub fn load_config(filename: &str) -> Result<Config, Box<dyn Error>> {
let yaml = YamlLoader::load_from_str(&fs::read_to_string(&filename)?)?;
// println!("{:#?}", yaml);
match &yaml[..] {
[yaml] => {
Ok(parse_config(yaml))
},
arr => {
Err(format!("The number of top-level elements must be 1, but got: {}", arr.len()).into())
}
}
}
fn parse_config(_yaml: &Yaml) -> Config {
Config { modmap: vec![], keymap: vec![] }
}
#[derive(Debug)]
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub modmap: Vec<Modmap>,
pub keymap: Vec<Keymap>,
}
#[derive(Debug)]
#[derive(Debug, Deserialize)]
pub struct Modmap {
// TODO
pub name: String,
pub remap: HashMap<String, String>,
pub wm_class: Option<WMClass>,
}
#[derive(Debug)]
#[derive(Debug, Deserialize)]
pub struct Keymap {
// TODO
pub name: String,
pub remap: HashMap<String, String>,
pub wm_class: Option<WMClass>,
}
#[derive(Debug, Deserialize)]
pub struct WMClass {
// TODO: validate only either `only` or `not` is set
#[serde(default, deserialize_with = "string_or_vec")]
pub only: Option<Vec<String>>,
#[serde(default, deserialize_with = "string_or_vec")]
pub not: Option<Vec<String>>,
}
pub fn load_config(filename: &str) -> Result<Config, Box<dyn Error>> {
let yaml = fs::read_to_string(&filename)?;
let config: Config = serde_yaml::from_str(&yaml)?;
return Ok(config);
}
fn string_or_vec<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
where
D: Deserializer<'de>,
{
struct StringOrVec;
impl<'de> Visitor<'de> for StringOrVec {
type Value = Option<Vec<String>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or list of strings")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Some(vec![s.to_owned()]))
}
fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let result: Vec<String> =
Deserialize::deserialize(value::SeqAccessDeserializer::new(seq))?;
Ok(Some(result))
}
}
deserializer.deserialize_any(StringOrVec)
}

View File

@ -2,10 +2,10 @@ extern crate evdev;
extern crate nix;
use evdev::Device;
use std::error::Error;
use nix::sys::select::FdSet;
use nix::sys::select::select;
use std::os::unix::io::{AsRawFd};
use nix::sys::select::FdSet;
use std::error::Error;
use std::os::unix::io::AsRawFd;
pub fn select_device() -> Result<Device, Box<dyn Error>> {
// TODO: stop hard-coding the device

View File

@ -1,19 +1,20 @@
use evdev::{EventType};
use std::error::Error;
use evdev::EventType;
use std::env;
use std::error::Error;
use std::process::exit;
mod config;
mod input;
mod output;
mod transform;
mod config;
fn event_loop() -> Result<(), Box<dyn Error>> {
let mut input_device = input::select_device()
.map_err(|e| format!("Failed to open an input device: {}", e))?;
let mut input_device =
input::select_device().map_err(|e| format!("Failed to open an input device: {}", e))?;
let mut output_device = output::build_device(&input_device)
.map_err(|e| format!("Failed to build an output device: {}", e))?;
input_device.grab()
input_device
.grab()
.map_err(|e| format!("Failed to grab an input device: {}", e))?;
loop {
@ -37,22 +38,22 @@ fn main() {
None => {
println!("Usage: xremap <file>");
exit(1);
},
}
};
let config = match config::load_config(&filename) {
Ok(config) => config,
Err(e) => {
println!("Failed to load config '{}': {}", filename, e);
exit(1);
},
}
};
println!("{:?}", config);
println!("{:#?}", config);
match event_loop() {
Ok(()) => {},
Ok(()) => {}
Err(e) => {
println!("Error: {}", e);
exit(1);
},
}
}
}

View File

@ -1,5 +1,5 @@
use evdev::uinput::{VirtualDevice, VirtualDeviceBuilder};
use evdev::{Device};
use evdev::Device;
use std::error::Error;
pub fn build_device(base_device: &Device) -> Result<VirtualDevice, Box<dyn Error>> {
@ -7,6 +7,7 @@ pub fn build_device(base_device: &Device) -> Result<VirtualDevice, Box<dyn Error
let device = match base_device.supported_keys() {
Some(keys) => builder.with_keys(keys)?,
None => builder,
}.build()?;
}
.build()?;
Ok(device)
}

View File

@ -1,13 +1,15 @@
use std::error::Error;
use evdev::{EventType, InputEvent, InputEventKind};
use evdev::uinput::VirtualDevice;
use evdev::{EventType, InputEvent, InputEventKind};
use std::error::Error;
pub fn on_event(event: InputEvent, device: &mut VirtualDevice) -> Result<(), Box<dyn Error>> {
println!("event: {:?}", event);
if event.kind() == InputEventKind::Key(evdev::Key::KEY_A) {
device.emit(&[
InputEvent::new(EventType::KEY, evdev::Key::KEY_B.code(), event.value())
])?;
device.emit(&[InputEvent::new(
EventType::KEY,
evdev::Key::KEY_B.code(),
event.value(),
)])?;
} else {
device.emit(&[event])?;
}