diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5e34218..fb20336 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -911,6 +911,7 @@ dependencies = [ "rand 0.9.1", "reqwest", "serde", + "serde-xml-rs", "serde_json", "sysinfo", "tauri", @@ -923,7 +924,6 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", - "url", "vergen", "vergen-gix", "x11rb", @@ -4825,6 +4825,18 @@ dependencies = [ "typeid", ] +[[package]] +name = "serde-xml-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176b7ff880ab6ead7a020e773e9c096467fe347615a3e22ac29300cbdef67a5d" +dependencies = [ + "log", + "serde", + "thiserror 1.0.69", + "xml-rs", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -7084,6 +7096,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xml-rs" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + [[package]] name = "yoke" version = "0.8.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index af03973..24a748b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,7 +22,6 @@ zbus = { version = "5.1.0", features = ["tokio"] } tokio = { version = "1.42.0", features = ["rt-multi-thread", "process"] } eyre = "0.6.12" nom = "8" -url = "2.5.2" reqwest = { version = "0.12.8", features = ["json"] } thiserror = "2" libc = "0.2.159" @@ -38,6 +37,7 @@ tauri-plugin-shell = "2.0.0" tauri-plugin-dialog = "2.0.0" tauri-plugin-cli = "2.0.0" libaosc = { version = "0.3", default-features = false, features = ["arch"] } +serde-xml-rs = "0.8.0" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 64ce4f5..87e021c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -6,8 +6,10 @@ use axum::Router; use eyre::ContextCompat; use eyre::OptionExt; use eyre::Result; -use parser::list_zoneinfo; -use parser::ZoneInfo; +use parser::timezone::list_zoneinfo; +use parser::timezone::ZoneInfo; +use parser::xkeyboard::get_keyboard_layouts; +use parser::xkeyboard::KeyboardLayouts; use rand::prelude::SliceRandom; use rand::rng; use reqwest::Client; @@ -302,6 +304,11 @@ fn list_timezone() -> TauriResult> { Ok(list_zoneinfo()?) } +#[tauri::command] +fn list_xkeyboard_config() -> TauriResult { + Ok(get_keyboard_layouts()?) +} + #[tauri::command] async fn set_config(state: State<'_, DkState<'_>>, config: &str) -> TauriResult<()> { let proxy = &state.proxy; @@ -928,6 +935,7 @@ pub async fn run() { is_lang_already_set, is_offline_install, is_block_username, + list_xkeyboard_config, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/parser/mod.rs b/src-tauri/src/parser/mod.rs new file mode 100644 index 0000000..d468b90 --- /dev/null +++ b/src-tauri/src/parser/mod.rs @@ -0,0 +1,2 @@ +pub mod timezone; +pub mod xkeyboard; diff --git a/src-tauri/src/parser.rs b/src-tauri/src/parser/timezone.rs similarity index 100% rename from src-tauri/src/parser.rs rename to src-tauri/src/parser/timezone.rs diff --git a/src-tauri/src/parser/xkeyboard.rs b/src-tauri/src/parser/xkeyboard.rs new file mode 100644 index 0000000..31394b7 --- /dev/null +++ b/src-tauri/src/parser/xkeyboard.rs @@ -0,0 +1,100 @@ +// Copy from https://github.com/pop-os/distinst/blob/8322c936a91ba5812ac9cbef79282a04bad738ea/crates/locales/src/keyboard_layout.rs#L82 + +use eyre::Result; +use serde::{Deserialize, Serialize}; +use serde_xml_rs as xml; +use std::{fs::File, io::BufReader}; + +/// A list of keyboard layouts parsed from `/usr/share/X11/xkb/rules/base.xml`. +#[derive(Debug, Deserialize, Serialize)] +pub struct KeyboardLayouts { + #[serde(rename = "layoutList")] + pub layout_list: LayoutList, +} + +impl KeyboardLayouts { + /// Fetch the layouts from the layout list. + pub fn get_layouts(&self) -> &[KeyboardLayout] { + &self.layout_list.layout + } + + /// Fetch the layouts from the layout list. + pub fn get_layouts_mut(&mut self) -> &mut [KeyboardLayout] { + &mut self.layout_list.layout + } +} + +/// A list of keyboard layouts. +#[derive(Debug, Deserialize, Serialize)] +pub struct LayoutList { + pub layout: Vec, +} + +/// A keyboard layout, which contains an optional list of variants, a name, and a description. +#[derive(Debug, Deserialize, Serialize)] +pub struct KeyboardLayout { + #[serde(rename = "configItem")] + pub config_item: ConfigItem, + #[serde(rename = "variantList")] + pub variant_list: Option, +} + +impl KeyboardLayout { + /// Fetches the name of the keyboard layout. + pub fn get_name(&self) -> &str { + &self.config_item.name + } + + /// Fetches a description of the layout. + pub fn get_description(&self) -> &str { + &self.config_item.description + } + + /// Fetches a list of possible layout variants. + pub fn get_variants(&self) -> Option<&Vec> { + self.variant_list.as_ref().and_then(|x| x.variant.as_ref()) + } +} + +/// Contains the name and description of a keyboard layout. +#[derive(Debug, Deserialize, Serialize)] +pub struct ConfigItem { + pub name: String, + #[serde(rename = "shortDescription")] + pub short_description: Option, + pub description: String, +} + +/// A list of possible variants of a keyboard layout. +#[derive(Debug, Deserialize, Serialize)] +pub struct VariantList { + pub variant: Option>, +} + +/// A variant of a keyboard layout. +#[derive(Debug, Deserialize, Serialize)] +pub struct KeyboardVariant { + #[serde(rename = "configItem")] + pub config_item: ConfigItem, +} + +impl KeyboardVariant { + /// The name of this variant of a keybaord layout. + pub fn get_name(&self) -> &str { + &self.config_item.name + } + + /// A description of this variant of a keyboard layout. + pub fn get_description(&self) -> &str { + &self.config_item.description + } +} + +const X11_BASE_RULES: &str = "/usr/share/X11/xkb/rules/base.xml"; + +/// Fetches a list of keyboard layouts from `/usr/share/X11/xkb/rules/base.xml`. +pub fn get_keyboard_layouts() -> Result { + Ok(xml::from_reader(BufReader::new(File::open( + X11_BASE_RULES, + )?))?) +} diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 3ddcdc6..fb31436 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -4,11 +4,11 @@ use std::path::Path; use eyre::{OptionExt, Result}; use libaosc::arch::get_arch_name; use reqwest::Client; +use reqwest::Url; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::time::Instant; -use url::Url; use x11rb::connection::Connection; use x11rb::protocol::xproto::{ AtomEnum, ClientMessageEvent, ConnectionExt as ConnectionExtB, EventMask,