From 1a9b7146fd1e2ad0723590d5953d259da8cdcfdf Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 5 Apr 2024 17:25:07 +0200 Subject: [PATCH] config: allow configuring repeat rates via toml --- toml-config/src/config.rs | 10 +++ toml-config/src/config/parsers.rs | 1 + toml-config/src/config/parsers/action.rs | 12 ++++ toml-config/src/config/parsers/config.rs | 15 ++++- toml-config/src/config/parsers/repeat_rate.rs | 45 +++++++++++++ toml-config/src/lib.rs | 8 +++ toml-spec/spec/spec.generated.json | 39 ++++++++++++ toml-spec/spec/spec.generated.md | 63 +++++++++++++++++++ toml-spec/spec/spec.yaml | 50 +++++++++++++++ 9 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 toml-config/src/config/parsers/repeat_rate.rs diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index 514f424e..eb2458bf 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -117,6 +117,9 @@ pub enum Action { workspace: Option, output: OutputMatch, }, + SetRepeatRate { + rate: RepeatRate, + }, } #[derive(Debug, Clone, Default)] @@ -269,9 +272,16 @@ pub enum ConfigKeymap { Defined { name: String, map: Keymap }, } +#[derive(Debug, Clone)] +pub struct RepeatRate { + pub rate: i32, + pub delay: i32, +} + #[derive(Debug, Clone)] pub struct Config { pub keymap: Option, + pub repeat_rate: Option, pub shortcuts: Vec<(ModifiedKeySym, Action)>, pub on_graphics_initialized: Option, pub on_idle: Option, diff --git a/toml-config/src/config/parsers.rs b/toml-config/src/config/parsers.rs index 3bd9abc6..316cafa0 100644 --- a/toml-config/src/config/parsers.rs +++ b/toml-config/src/config/parsers.rs @@ -25,6 +25,7 @@ mod mode; pub mod modified_keysym; mod output; mod output_match; +mod repeat_rate; pub mod shortcuts; mod status; mod theme; diff --git a/toml-config/src/config/parsers/action.rs b/toml-config/src/config/parsers/action.rs index 16ca5083..009e71ce 100644 --- a/toml-config/src/config/parsers/action.rs +++ b/toml-config/src/config/parsers/action.rs @@ -17,6 +17,7 @@ use { log_level::{LogLevelParser, LogLevelParserError}, output::{OutputParser, OutputParserError}, output_match::{OutputMatchParser, OutputMatchParserError}, + repeat_rate::{RepeatRateParser, RepeatRateParserError}, status::{StatusParser, StatusParserError}, theme::{ThemeParser, ThemeParserError}, StringParser, StringParserError, @@ -77,6 +78,8 @@ pub enum ActionParserError { ConfigureIdle(#[source] IdleParserError), #[error("Could not parse a move-to-output action")] MoveToOutput(#[source] OutputMatchParserError), + #[error("Could not parse a set-repeat-rate action")] + RepeatRate(#[source] RepeatRateParserError), } pub struct ActionParser<'a>(pub &'a Context<'a>); @@ -295,6 +298,14 @@ impl ActionParser<'_> { output, }) } + + fn parse_set_repeat_rate(&mut self, ext: &mut Extractor<'_>) -> ParseResult { + let rate = ext + .extract(val("rate"))? + .parse_map(&mut RepeatRateParser(self.0)) + .map_spanned_err(ActionParserError::RepeatRate)?; + Ok(Action::SetRepeatRate { rate }) + } } impl<'a> Parser for ActionParser<'a> { @@ -345,6 +356,7 @@ impl<'a> Parser for ActionParser<'a> { "set-render-device" => self.parse_set_render_device(&mut ext), "configure-idle" => self.parse_configure_idle(&mut ext), "move-to-output" => self.parse_move_to_output(&mut ext), + "set-repeat-rate" => self.parse_set_repeat_rate(&mut ext), v => { ext.ignore_unused(); return Err(ActionParserError::UnknownType(v.to_string()).spanned(ty.span)); diff --git a/toml-config/src/config/parsers/config.rs b/toml-config/src/config/parsers/config.rs index ea70ab81..89e213b6 100644 --- a/toml-config/src/config/parsers/config.rs +++ b/toml-config/src/config/parsers/config.rs @@ -16,6 +16,7 @@ use { keymap::KeymapParser, log_level::LogLevelParser, output::OutputsParser, + repeat_rate::RepeatRateParser, shortcuts::{ShortcutsParser, ShortcutsParserError}, status::StatusParser, theme::ThemeParser, @@ -95,7 +96,7 @@ impl Parser for ConfigParser<'_> { _, idle_val, ), - (explicit_sync,), + (explicit_sync, repeat_rate_val), ) = ext.extract(( ( opt(val("keymap")), @@ -121,7 +122,7 @@ impl Parser for ConfigParser<'_> { opt(val("$schema")), opt(val("idle")), ), - (recover(opt(bol("explicit-sync"))),), + (recover(opt(bol("explicit-sync"))), opt(val("repeat-rate"))), ))?; let mut keymap = None; if let Some(value) = keymap_val { @@ -256,8 +257,18 @@ impl Parser for ConfigParser<'_> { } } } + let mut repeat_rate = None; + if let Some(value) = repeat_rate_val { + match value.parse(&mut RepeatRateParser(self.0)) { + Ok(v) => repeat_rate = Some(v), + Err(e) => { + log::warn!("Could not parse the repeat rate: {}", self.0.error(e)); + } + } + } Ok(Config { keymap, + repeat_rate, shortcuts, on_graphics_initialized, on_idle, diff --git a/toml-config/src/config/parsers/repeat_rate.rs b/toml-config/src/config/parsers/repeat_rate.rs new file mode 100644 index 00000000..af16ca7b --- /dev/null +++ b/toml-config/src/config/parsers/repeat_rate.rs @@ -0,0 +1,45 @@ +use { + crate::{ + config::{ + context::Context, + extractor::{s32, Extractor, ExtractorError}, + parser::{DataType, ParseResult, Parser, UnexpectedDataType}, + RepeatRate, + }, + toml::{ + toml_span::{Span, Spanned}, + toml_value::Value, + }, + }, + indexmap::IndexMap, + thiserror::Error, +}; + +#[derive(Debug, Error)] +pub enum RepeatRateParserError { + #[error(transparent)] + Expected(#[from] UnexpectedDataType), + #[error(transparent)] + Extract(#[from] ExtractorError), +} + +pub struct RepeatRateParser<'a>(pub &'a Context<'a>); + +impl Parser for RepeatRateParser<'_> { + type Value = RepeatRate; + type Error = RepeatRateParserError; + const EXPECTED: &'static [DataType] = &[DataType::Table]; + + fn parse_table( + &mut self, + span: Span, + table: &IndexMap, Spanned>, + ) -> ParseResult { + let mut ext = Extractor::new(self.0, span, table); + let (rate, delay) = ext.extract((s32("rate"), s32("delay")))?; + Ok(RepeatRate { + rate: rate.value, + delay: delay.value, + }) + } +} diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index cd11f70b..d40318f8 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -172,6 +172,9 @@ impl Action { } }) } + Action::SetRepeatRate { rate } => { + Box::new(move || s.set_repeat_rate(rate.rate, rate.delay)) + } } } } @@ -728,6 +731,11 @@ fn load_config(initial_load: bool, persistent: &Rc) { if let Some(keymap) = config.keymap { state.set_keymap(&keymap); } + if let Some(repeat_rate) = config.repeat_rate { + persistent + .seat + .set_repeat_rate(repeat_rate.rate, repeat_rate.delay); + } on_new_connector(move |c| { for connector in &config.connectors { if connector.match_.matches(c) { diff --git a/toml-spec/spec/spec.generated.json b/toml-spec/spec/spec.generated.json index 8fa28507..560ef5b6 100644 --- a/toml-spec/spec/spec.generated.json +++ b/toml-spec/spec/spec.generated.json @@ -284,6 +284,23 @@ "keymap" ] }, + { + "description": "Sets the keyboard repeat rate.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-x = { type = \"set-repeat-rate\", rate = { rate = 25, delay = 250 } }\n ```\n", + "type": "object", + "properties": { + "type": { + "const": "set-repeat-rate" + }, + "rate": { + "description": "The rate.", + "$ref": "#/$defs/RepeatRate" + } + }, + "required": [ + "type", + "rate" + ] + }, { "description": "Sets the status command.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-j = { type = \"set-status\", status = { exec = \"i3status\" } }\n ```\n", "type": "object", @@ -418,6 +435,10 @@ "description": "The keymap to use.\n\n- Example:\n\n ```toml\n keymap = \"\"\"\n xkb_keymap {\n xkb_keycodes { include \"evdev+aliases(qwerty)\" };\n xkb_types { include \"complete\" };\n xkb_compat { include \"complete\" };\n xkb_symbols { include \"pc+us+inet(evdev)\" };\n };\n \"\"\"\n ```\n", "$ref": "#/$defs/Keymap" }, + "repeat-rate": { + "description": "The keyboard repeat rate.\n\n- Example:\n \n ```toml\n repeat-rate = { rate = 25, delay = 250 }\n ```\n", + "$ref": "#/$defs/RepeatRate" + }, "shortcuts": { "description": "The compositor shortcuts.\n\nThe keys should be in the following format:\n\n```\n(MOD-)*KEYSYM\n```\n\n`MOD` should be one of `shift`, `lock`, `ctrl`, `mod1`, `mod2`, `mod3`, `mod4`,\n`mod5`, `caps`, `alt`, `num`, or `logo`.\n\n`KEYSYM` should be the name of a keysym. The authorative location for these names\nis [1] with the `XKB_KEY_` prefix removed.\n\nThe keysym should be the unmodified keysym. E.g. `shift-q` not `shift-Q`.\n\n[1]: https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n", "type": "object", @@ -985,6 +1006,24 @@ } ] }, + "RepeatRate": { + "description": "Describes a keyboard repeat rate.\n\n- Example:\n\n ```toml\n repeat-rate = { rate = 25, delay = 250 }\n ```\n", + "type": "object", + "properties": { + "rate": { + "type": "integer", + "description": "The number of times to repeat per second." + }, + "delay": { + "type": "integer", + "description": "The number of milliseconds after a key is pressed before repeating begins.\n" + } + }, + "required": [ + "rate", + "delay" + ] + }, "SimpleActionName": { "type": "string", "description": "The name of a `simple` Action.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n", diff --git a/toml-spec/spec/spec.generated.md b/toml-spec/spec/spec.generated.md index a83d4b20..eeaa716d 100644 --- a/toml-spec/spec/spec.generated.md +++ b/toml-spec/spec/spec.generated.md @@ -405,6 +405,25 @@ This table is a tagged union. The variant is determined by the `type` field. It The value of this field should be a [Keymap](#types-Keymap). +- `set-repeat-rate`: + + Sets the keyboard repeat rate. + + - Example: + + ```toml + [shortcuts] + alt-x = { type = "set-repeat-rate", rate = { rate = 25, delay = 250 } } + ``` + + The table has the following fields: + + - `rate` (required): + + The rate. + + The value of this field should be a [RepeatRate](#types-RepeatRate). + - `set-status`: Sets the status command. @@ -652,6 +671,18 @@ The table has the following fields: The value of this field should be a [Keymap](#types-Keymap). +- `repeat-rate` (optional): + + The keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + + The value of this field should be a [RepeatRate](#types-RepeatRate). + - `shortcuts` (optional): The compositor shortcuts. @@ -2038,6 +2069,38 @@ The table has the following fields: The value of this field should be a string. + +### `RepeatRate` + +Describes a keyboard repeat rate. + +- Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + +Values of this type should be tables. + +The table has the following fields: + +- `rate` (required): + + The number of times to repeat per second. + + The value of this field should be a number. + + The numbers should be integers. + +- `delay` (required): + + The number of milliseconds after a key is pressed before repeating begins. + + The value of this field should be a number. + + The numbers should be integers. + + ### `SimpleActionName` diff --git a/toml-spec/spec/spec.yaml b/toml-spec/spec/spec.yaml index 560ee880..7d2e416b 100644 --- a/toml-spec/spec/spec.yaml +++ b/toml-spec/spec/spec.yaml @@ -382,6 +382,21 @@ Action: description: The keymap. required: true ref: Keymap + set-repeat-rate: + description: | + Sets the keyboard repeat rate. + + - Example: + + ```toml + [shortcuts] + alt-x = { type = "set-repeat-rate", rate = { rate = 25, delay = 250 } } + ``` + fields: + rate: + description: The rate. + required: true + ref: RepeatRate set-status: description: | Sets the status command. @@ -1649,6 +1664,17 @@ Config: }; """ ``` + repeat-rate: + ref: RepeatRate + required: false + description: | + The keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` shortcuts: kind: map values: @@ -1983,3 +2009,27 @@ Idle: integer_only: true minimum: 0 required: false + + +RepeatRate: + kind: table + description: | + Describes a keyboard repeat rate. + + - Example: + + ```toml + repeat-rate = { rate = 25, delay = 250 } + ``` + fields: + rate: + kind: number + integer_only: true + required: true + description: The number of times to repeat per second. + delay: + kind: number + integer_only: true + required: true + description: | + The number of milliseconds after a key is pressed before repeating begins.