feat(config): add options to configure keyboard layout on Wayland
This commit is contained in:
parent
c68d59797e
commit
47eb2b0b69
|
@ -107,6 +107,10 @@ pub trait Config: Send + Sync {
|
|||
// If false, avoid applying the built-in patches to the current config.
|
||||
fn apply_patch(&self) -> bool;
|
||||
|
||||
// On Wayland, overrides the auto-detected keyboard configuration (RMLVO)
|
||||
// which is used both for the detection and injection process.
|
||||
fn keyboard_layout(&self) -> Option<RMLVOConfig>;
|
||||
|
||||
fn is_match<'a>(&self, app: &AppProperties<'a>) -> bool;
|
||||
|
||||
fn pretty_dump(&self) -> String {
|
||||
|
@ -192,6 +196,15 @@ pub enum ToggleKey {
|
|||
LeftMeta,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RMLVOConfig {
|
||||
pub rules: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub layout: Option<String>,
|
||||
pub variant: Option<String>,
|
||||
pub options: Option<String>,
|
||||
}
|
||||
|
||||
pub fn load_store(config_dir: &Path) -> Result<(impl ConfigStore, Vec<NonFatalErrorSet>)> {
|
||||
store::DefaultConfigStore::load(config_dir)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
use anyhow::Result;
|
||||
use std::{convert::TryInto, path::Path};
|
||||
use std::{collections::BTreeMap, convert::TryInto, path::Path};
|
||||
use thiserror::Error;
|
||||
|
||||
mod yaml;
|
||||
|
@ -43,6 +43,7 @@ pub(crate) struct ParsedConfig {
|
|||
pub paste_shortcut_event_delay: Option<usize>,
|
||||
pub inject_delay: Option<usize>,
|
||||
pub key_delay: Option<usize>,
|
||||
pub keyboard_layout: Option<BTreeMap<String, String>>,
|
||||
|
||||
|
||||
// Includes
|
||||
|
@ -73,4 +74,4 @@ impl ParsedConfig {
|
|||
pub enum ParsedConfigError {
|
||||
#[error("can't load config `{0}`")]
|
||||
LoadFailed(#[from] anyhow::Error),
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Mapping;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::util::is_yaml_empty;
|
||||
|
@ -53,7 +54,7 @@ pub(crate) struct YAMLConfig {
|
|||
|
||||
#[serde(default)]
|
||||
pub paste_shortcut_event_delay: Option<usize>,
|
||||
|
||||
|
||||
#[serde(default)]
|
||||
pub paste_shortcut: Option<String>,
|
||||
|
||||
|
@ -78,6 +79,9 @@ pub(crate) struct YAMLConfig {
|
|||
#[serde(default)]
|
||||
pub apply_patch: Option<bool>,
|
||||
|
||||
#[serde(default)]
|
||||
pub keyboard_layout: Option<Mapping>,
|
||||
|
||||
// Include/Exclude
|
||||
#[serde(default)]
|
||||
pub includes: Option<Vec<String>>,
|
||||
|
@ -139,6 +143,18 @@ impl TryFrom<YAMLConfig> for ParsedConfig {
|
|||
word_separators: yaml_config.word_separators,
|
||||
backspace_limit: yaml_config.backspace_limit,
|
||||
apply_patch: yaml_config.apply_patch,
|
||||
keyboard_layout: yaml_config.keyboard_layout.map(|mapping| {
|
||||
mapping
|
||||
.into_iter()
|
||||
.filter_map(|(key, value)| {
|
||||
if let (Some(key), Some(value)) = (key.as_str(), value.as_str()) {
|
||||
Some((key.to_string(), value.to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
|
||||
pre_paste_delay: yaml_config.pre_paste_delay,
|
||||
restore_clipboard_delay: yaml_config.restore_clipboard_delay,
|
||||
|
@ -161,7 +177,7 @@ impl TryFrom<YAMLConfig> for ParsedConfig {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::convert::TryInto;
|
||||
use std::{collections::BTreeMap, convert::TryInto};
|
||||
|
||||
#[test]
|
||||
fn conversion_to_parsed_config_works_correctly() {
|
||||
|
@ -183,6 +199,13 @@ mod tests {
|
|||
backspace_delay: 30
|
||||
word_separators: ["'", "."]
|
||||
backspace_limit: 10
|
||||
apply_patch: false
|
||||
keyboard_layout:
|
||||
rules: test_rule
|
||||
model: test_model
|
||||
layout: test_layout
|
||||
variant: test_variant
|
||||
options: test_options
|
||||
|
||||
use_standard_includes: true
|
||||
includes: ["test1"]
|
||||
|
@ -199,6 +222,15 @@ mod tests {
|
|||
.unwrap();
|
||||
let parsed_config: ParsedConfig = config.try_into().unwrap();
|
||||
|
||||
let keyboard_layout: BTreeMap<String, String> =
|
||||
vec![
|
||||
("rules".to_string(), "test_rule".to_string()),
|
||||
("model".to_string(), "test_model".to_string()),
|
||||
("layout".to_string(), "test_layout".to_string()),
|
||||
("variant".to_string(), "test_variant".to_string()),
|
||||
("options".to_string(), "test_options".to_string()),
|
||||
].into_iter().collect();
|
||||
|
||||
assert_eq!(
|
||||
parsed_config,
|
||||
ParsedConfig {
|
||||
|
@ -216,9 +248,10 @@ mod tests {
|
|||
key_delay: Some(20),
|
||||
backspace_limit: Some(10),
|
||||
apply_patch: Some(false),
|
||||
keyboard_layout: Some(keyboard_layout),
|
||||
|
||||
pre_paste_delay: Some(300),
|
||||
|
||||
|
||||
toggle_key: Some("CTRL".to_string()),
|
||||
word_separators: Some(vec!["'".to_owned(), ".".to_owned()]),
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ use super::{
|
|||
parse::ParsedConfig,
|
||||
path::calculate_paths,
|
||||
util::os_matches,
|
||||
AppProperties, Backend, Config, ToggleKey,
|
||||
AppProperties, Backend, Config, RMLVOConfig, ToggleKey,
|
||||
};
|
||||
use crate::{counter::next_id, merge};
|
||||
use anyhow::Result;
|
||||
use log::error;
|
||||
use regex::Regex;
|
||||
use std::{iter::FromIterator, path::PathBuf};
|
||||
use std::{collections::HashSet, path::Path};
|
||||
use std::{iter::FromIterator, path::PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
const STANDARD_INCLUDES: &[&str] = &["../match/**/*.yml"];
|
||||
|
@ -79,7 +79,7 @@ impl Config for ResolvedConfig {
|
|||
|
||||
if let Some(source_path) = self.source_path.as_ref() {
|
||||
if let Some(source_path) = source_path.to_str() {
|
||||
return source_path
|
||||
return source_path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,16 @@ impl Config for ResolvedConfig {
|
|||
fn apply_patch(&self) -> bool {
|
||||
self.parsed.apply_patch.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn keyboard_layout(&self) -> Option<RMLVOConfig> {
|
||||
self.parsed.keyboard_layout.as_ref().map(|layout| RMLVOConfig {
|
||||
rules: layout.get("rules").map(String::from),
|
||||
model: layout.get("model").map(String::from),
|
||||
layout: layout.get("layout").map(String::from),
|
||||
variant: layout.get("variant").map(String::from),
|
||||
options: layout.get("options").map(String::from),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvedConfig {
|
||||
|
@ -336,6 +346,7 @@ impl ResolvedConfig {
|
|||
key_delay,
|
||||
word_separators,
|
||||
backspace_limit,
|
||||
keyboard_layout,
|
||||
includes,
|
||||
excludes,
|
||||
extra_includes,
|
||||
|
|
|
@ -23,7 +23,13 @@ use regex::Regex;
|
|||
use std::{collections::HashMap, path::Path, sync::Arc};
|
||||
|
||||
use self::config::LegacyConfig;
|
||||
use crate::matches::{MatchEffect, group::loader::yaml::{parse::{YAMLMatch, YAMLVariable}, try_convert_into_match, try_convert_into_variable}};
|
||||
use crate::matches::{
|
||||
group::loader::yaml::{
|
||||
parse::{YAMLMatch, YAMLVariable},
|
||||
try_convert_into_match, try_convert_into_variable,
|
||||
},
|
||||
MatchEffect,
|
||||
};
|
||||
use crate::{config::store::DefaultConfigStore, counter::StructId};
|
||||
use crate::{
|
||||
config::Config,
|
||||
|
@ -333,16 +339,25 @@ impl Config for LegacyInteropConfig {
|
|||
}
|
||||
|
||||
fn word_separators(&self) -> Vec<String> {
|
||||
self.config.word_separators.iter().map(|c| String::from(*c)).collect()
|
||||
self
|
||||
.config
|
||||
.word_separators
|
||||
.iter()
|
||||
.map(|c| String::from(*c))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn backspace_limit(&self) -> usize {
|
||||
self.config.backspace_limit.try_into().unwrap()
|
||||
}
|
||||
|
||||
|
||||
fn apply_patch(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn keyboard_layout(&self) -> Option<crate::config::RMLVOConfig> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct LegacyMatchGroup {
|
||||
|
|
Loading…
Reference in New Issue
Block a user