From 1077d2606db2c90c047e5702038149bc82a0b74c Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:13:45 +0900 Subject: [PATCH] SIGUSR1 to trigger fcitx layout change --- Cargo.lock | 62 +-- wlx-overlay-s/Cargo.toml | 2 +- wlx-overlay-s/src/gui/panel/mod.rs | 4 + wlx-overlay-s/src/main.rs | 31 +- wlx-overlay-s/src/overlays/keyboard/mod.rs | 28 +- wlx-overlay-s/src/subsystem/dbus/fcitx5.rs | 548 +++++++++++++++++++++ wlx-overlay-s/src/subsystem/dbus/mod.rs | 39 +- wlx-overlay-s/src/subsystem/hid/mod.rs | 6 + wlx-overlay-s/src/subsystem/hid/wayland.rs | 57 --- 9 files changed, 656 insertions(+), 121 deletions(-) create mode 100644 wlx-overlay-s/src/subsystem/dbus/fcitx5.rs diff --git a/Cargo.lock b/Cargo.lock index 9034d0f..1077496 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,15 +764,6 @@ dependencies = [ "objc2 0.5.2", ] -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2 0.6.3", -] - [[package]] name = "blocking" version = "1.6.2" @@ -1360,17 +1351,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73736a89c4aff73035ba2ed2e565061954da00d4970fc9ac25dcc85a2a20d790" -dependencies = [ - "dispatch2", - "nix 0.30.1", - "windows-sys 0.61.2", -] - [[package]] name = "cursor-icon" version = "1.2.0" @@ -1583,8 +1563,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", - "libc", "objc2 0.6.3", ] @@ -3617,7 +3595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "libc", "objc2 0.5.2", "objc2-core-data", @@ -3648,7 +3626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -3660,7 +3638,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3694,7 +3672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3716,7 +3694,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal 0.2.2", @@ -3728,7 +3706,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-contacts", "objc2-foundation 0.2.2", @@ -3747,7 +3725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "dispatch", "libc", "objc2 0.5.2", @@ -3780,7 +3758,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-app-kit", "objc2-foundation 0.2.2", @@ -3793,7 +3771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3816,7 +3794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal 0.2.2", @@ -3852,7 +3830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", @@ -3872,7 +3850,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", ] @@ -3884,7 +3862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.10.0", - "block2 0.5.1", + "block2", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", @@ -5052,6 +5030,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.4.7" @@ -6768,7 +6756,7 @@ dependencies = [ "android-activity", "atomic-waker", "bitflags 2.10.0", - "block2 0.5.1", + "block2", "bytemuck", "calloop 0.13.0", "cfg_aliases", @@ -6872,7 +6860,6 @@ dependencies = [ "chrono-tz", "clap", "config", - "ctrlc", "dbus", "futures", "glam", @@ -6899,6 +6886,7 @@ dependencies = [ "serde_json", "serde_json5", "serde_yaml", + "signal-hook", "slotmap", "smallvec", "smithay", diff --git a/wlx-overlay-s/Cargo.toml b/wlx-overlay-s/Cargo.toml index fab1147..4cf2aea 100644 --- a/wlx-overlay-s/Cargo.toml +++ b/wlx-overlay-s/Cargo.toml @@ -26,7 +26,6 @@ chrono = "0.4.42" chrono-tz = "0.10.4" clap = { version = "4.5.53", features = ["derive"] } config = "0.15.19" -ctrlc = { version = "3.5.1", features = ["termination"] } dbus = { version = "0.9.9" } futures = "0.3.31" glam = { workspace = true, features = ["mint", "serde"] } @@ -99,6 +98,7 @@ wayland-egl = { version = "0.32.8", optional = true } bytes = { version = "1.11.0", optional = true } wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "a72587d23f3bb8624d9aeb1f13c0a21e65350f51", default-features = false, optional = true } rust-embed = { workspace = true } +signal-hook = "0.3.18" ################################ [build-dependencies] diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs index 6d9dfca..df867f6 100644 --- a/wlx-overlay-s/src/gui/panel/mod.rs +++ b/wlx-overlay-s/src/gui/panel/mod.rs @@ -50,6 +50,7 @@ pub struct GuiPanel { pub max_size: Vec2, pub gui_scale: f32, pub on_notify: Option>, + pub initialized: bool, interaction_transform: Option, context: WguiContext, timestep: Timestep, @@ -165,6 +166,7 @@ impl GuiPanel { interaction_transform: None, on_notify: None, gui_scale: params.gui_scale, + initialized: false, }) } @@ -194,6 +196,7 @@ impl GuiPanel { on_notify: None, interaction_transform: None, gui_scale: params.gui_scale, + initialized: false, }) } @@ -230,6 +233,7 @@ impl OverlayBackend for GuiPanel { self.layout.content_size.x as _, self.layout.content_size.y as _, ])); + self.initialized = true; } Ok(()) } diff --git a/wlx-overlay-s/src/main.rs b/wlx-overlay-s/src/main.rs index 174b6ad..7b56b09 100644 --- a/wlx-overlay-s/src/main.rs +++ b/wlx-overlay-s/src/main.rs @@ -36,7 +36,10 @@ use std::{ sync::atomic::{AtomicBool, AtomicUsize, Ordering}, }; +use anyhow::Context; use clap::Parser; +use libc::{SIGINT, SIGTERM, SIGUSR1}; +use signal_hook::iterator::Signals; use sysinfo::Pid; use tracing::level_filters::LevelFilter; use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; @@ -45,6 +48,7 @@ use crate::subsystem::dbus::DbusConnector; pub static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0); pub static RUNNING: AtomicBool = AtomicBool::new(true); +pub static KEYMAP_CHANGE: AtomicBool = AtomicBool::new(false); /// The lightweight desktop overlay for OpenVR and OpenXR #[derive(Default, Parser, Debug)] @@ -114,11 +118,7 @@ fn main() -> Result<(), Box> { return Ok(()); } - let _ = ctrlc::set_handler({ - || { - RUNNING.store(false, Ordering::Relaxed); - } - }); + setup_signal_hooks()?; auto_run(args); @@ -200,6 +200,27 @@ const fn args_get_openxr(args: &Args) -> bool { ret } +fn setup_signal_hooks() -> anyhow::Result<()> { + let mut signals = Signals::new([SIGINT, SIGTERM, SIGUSR1])?; + + std::thread::spawn(move || { + for signal in signals.forever() { + match signal { + SIGUSR1 => { + log::info!("SIGUSR1 received (keymap changed)"); + KEYMAP_CHANGE.store(true, Ordering::Relaxed); + continue; + } + _ => { + RUNNING.store(false, Ordering::Relaxed); + break; + } + } + } + }); + Ok(()) +} + fn logging_init(args: &mut Args) { let log_file_path = args .log_to diff --git a/wlx-overlay-s/src/overlays/keyboard/mod.rs b/wlx-overlay-s/src/overlays/keyboard/mod.rs index 99306d3..d1e9da5 100644 --- a/wlx-overlay-s/src/overlays/keyboard/mod.rs +++ b/wlx-overlay-s/src/overlays/keyboard/mod.rs @@ -2,22 +2,24 @@ use std::{ cell::Cell, collections::HashMap, process::{Child, Command}, + sync::atomic::Ordering, }; use crate::{ + KEYMAP_CHANGE, backend::input::{HoverResult, PointerHit}, gui::panel::GuiPanel, overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier}, state::AppState, subsystem::hid::{ ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta, XkbKeymap, - wayland::WlKeymapMonitor, }, windowing::{ backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender}, window::OverlayWindowConfig, }, }; +use anyhow::Context; use glam::{Affine3A, Quat, Vec3, vec3}; use slotmap::{SlotMap, new_key_type}; use wgui::{ @@ -66,7 +68,6 @@ pub fn create_keyboard( active_keymap: KeyboardPanelKey::default(), default_state, layout, - wkm: WlKeymapMonitor::new()?, }; backend.active_keymap = backend.add_new_keymap(keymap.as_ref(), app)?; @@ -99,7 +100,6 @@ struct KeyboardBackend { active_keymap: KeyboardPanelKey, default_state: KeyboardState, layout: layout::Layout, - wkm: WlKeymapMonitor, } impl KeyboardBackend { @@ -167,10 +167,28 @@ impl OverlayBackend for KeyboardBackend { self.panel().init(app) } fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { - if let Some(keymap) = self.wkm.check() { + while KEYMAP_CHANGE.swap(false, Ordering::Relaxed) { + let keymap: XkbKeymap; + if let Ok(fcitx_layout) = app + .dbus + .fcitx_keymap() + .context("Could not fetch Fcitx5 keymap") + .inspect_err(|e| log::warn!("{e:?}")) + && fcitx_layout.starts_with("keyboard-") + && let Some(fcitx_keymap) = XkbKeymap::from_layout_str(&fcitx_layout[9..]) + { + keymap = fcitx_keymap; + } else { + break; + } + app.hid_provider.keymap_changed(&keymap); if self.switch_keymap(&keymap, app)? { - return Ok(match self.panel().should_render(app)? { + let panel = self.panel(); + if !panel.initialized { + panel.init(app)?; + } + return Ok(match panel.should_render(app)? { ShouldRender::Should | ShouldRender::Can => ShouldRender::Should, ShouldRender::Unable => ShouldRender::Unable, }); diff --git a/wlx-overlay-s/src/subsystem/dbus/fcitx5.rs b/wlx-overlay-s/src/subsystem/dbus/fcitx5.rs new file mode 100644 index 0000000..700140f --- /dev/null +++ b/wlx-overlay-s/src/subsystem/dbus/fcitx5.rs @@ -0,0 +1,548 @@ +// This code was autogenerated with `dbus-codegen-rust -g -m None -d org.fcitx.Fcitx5 -p /controller`, see https://github.com/diwic/dbus-rs +use dbus; +#[allow(unused_imports)] +use dbus::arg; +use dbus::blocking; + +pub trait OrgFreedesktopDBusIntrospectable { + fn introspect(&self) -> Result; +} + +impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref> + OrgFreedesktopDBusIntrospectable for blocking::Proxy<'a, C> +{ + fn introspect(&self) -> Result { + self.method_call("org.freedesktop.DBus.Introspectable", "Introspect", ()) + .and_then(|r: (String,)| Ok(r.0)) + } +} + +pub trait OrgFcitxFcitxController1 { + fn activate(&self) -> Result<(), dbus::Error>; + fn add_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error>; + fn addon_for_im(&self, arg0: &str) -> Result; + fn available_input_methods( + &self, + ) -> Result, dbus::Error>; + fn available_keyboard_layouts( + &self, + ) -> Result< + Vec<( + String, + String, + Vec, + Vec<(String, String, Vec)>, + )>, + dbus::Error, + >; + fn can_restart(&self) -> Result; + fn check_update(&self) -> Result; + fn configure(&self) -> Result<(), dbus::Error>; + fn configure_addon(&self, arg0: &str) -> Result<(), dbus::Error>; + fn configure_im(&self, arg0: &str) -> Result<(), dbus::Error>; + fn current_input_method(&self) -> Result; + fn current_input_method_group(&self) -> Result; + fn current_input_method_info( + &self, + ) -> Result< + ( + String, + String, + String, + String, + String, + String, + String, + bool, + String, + arg::PropMap, + ), + dbus::Error, + >; + fn current_ui(&self) -> Result; + fn deactivate(&self) -> Result<(), dbus::Error>; + fn debug_info(&self) -> Result; + fn exit(&self) -> Result<(), dbus::Error>; + fn full_input_method_group_info( + &self, + arg0: &str, + ) -> Result< + ( + String, + String, + String, + arg::PropMap, + Vec<( + String, + String, + String, + String, + String, + String, + String, + bool, + String, + arg::PropMap, + )>, + ), + dbus::Error, + >; + fn get_addons(&self) -> Result, dbus::Error>; + fn get_addons_v2( + &self, + ) -> Result< + Vec<( + String, + String, + String, + i32, + bool, + bool, + bool, + Vec, + Vec, + )>, + dbus::Error, + >; + fn get_config arg::Get<'b> + 'static>( + &self, + arg0: &str, + ) -> Result< + ( + R0, + Vec<( + String, + Vec<( + String, + String, + String, + arg::Variant>, + arg::PropMap, + )>, + )>, + ), + dbus::Error, + >; + fn input_method_group_info( + &self, + arg0: &str, + ) -> Result<(String, Vec<(String, String)>), dbus::Error>; + fn input_method_groups(&self) -> Result, dbus::Error>; + fn open_wayland_connection(&self, arg0: &str) -> Result<(), dbus::Error>; + fn open_wayland_connection_socket(&self, arg0: arg::OwnedFd) -> Result<(), dbus::Error>; + fn open_x11_connection(&self, arg0: &str) -> Result<(), dbus::Error>; + fn refresh(&self) -> Result<(), dbus::Error>; + fn reload_addon_config(&self, arg0: &str) -> Result<(), dbus::Error>; + fn reload_config(&self) -> Result<(), dbus::Error>; + fn remove_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error>; + fn reopen_wayland_connection_socket( + &self, + arg0: &str, + arg1: arg::OwnedFd, + ) -> Result<(), dbus::Error>; + fn reset_imlist(&self) -> Result<(), dbus::Error>; + fn restart(&self) -> Result<(), dbus::Error>; + fn save(&self) -> Result<(), dbus::Error>; + fn set_addons_state(&self, arg0: Vec<(&str, bool)>) -> Result<(), dbus::Error>; + fn set_config( + &self, + arg0: &str, + arg1: I1, + ) -> Result<(), dbus::Error>; + fn set_current_im(&self, arg0: &str) -> Result<(), dbus::Error>; + fn set_input_method_group_info( + &self, + arg0: &str, + arg1: &str, + arg2: Vec<(&str, &str)>, + ) -> Result<(), dbus::Error>; + fn set_log_rule(&self, arg0: &str) -> Result<(), dbus::Error>; + fn state(&self) -> Result; + fn switch_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error>; + fn toggle(&self) -> Result<(), dbus::Error>; +} + +#[derive(Debug)] +pub struct OrgFcitxFcitxController1InputMethodGroupsChanged {} + +impl arg::AppendAll for OrgFcitxFcitxController1InputMethodGroupsChanged { + fn append(&self, _: &mut arg::IterAppend) {} +} + +impl arg::ReadAll for OrgFcitxFcitxController1InputMethodGroupsChanged { + fn read(_: &mut arg::Iter) -> Result { + Ok(OrgFcitxFcitxController1InputMethodGroupsChanged {}) + } +} + +impl dbus::message::SignalArgs for OrgFcitxFcitxController1InputMethodGroupsChanged { + const NAME: &'static str = "InputMethodGroupsChanged"; + const INTERFACE: &'static str = "org.fcitx.Fcitx.Controller1"; +} + +impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref> OrgFcitxFcitxController1 + for blocking::Proxy<'a, C> +{ + fn activate(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Activate", ()) + } + + fn add_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "AddInputMethodGroup", + (arg0,), + ) + } + + fn addon_for_im(&self, arg0: &str) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "AddonForIM", (arg0,)) + .and_then(|r: (String,)| Ok(r.0)) + } + + fn available_input_methods( + &self, + ) -> Result, dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "AvailableInputMethods", ()) + .and_then(|r: (Vec<(String, String, String, String, String, String, bool)>,)| Ok(r.0)) + } + + fn available_keyboard_layouts( + &self, + ) -> Result< + Vec<( + String, + String, + Vec, + Vec<(String, String, Vec)>, + )>, + dbus::Error, + > { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "AvailableKeyboardLayouts", + (), + ) + .and_then( + |r: ( + Vec<( + String, + String, + Vec, + Vec<(String, String, Vec)>, + )>, + )| Ok(r.0), + ) + } + + fn can_restart(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "CanRestart", ()) + .and_then(|r: (bool,)| Ok(r.0)) + } + + fn check_update(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "CheckUpdate", ()) + .and_then(|r: (bool,)| Ok(r.0)) + } + + fn configure(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Configure", ()) + } + + fn configure_addon(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "ConfigureAddon", (arg0,)) + } + + fn configure_im(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "ConfigureIM", (arg0,)) + } + + fn current_input_method(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "CurrentInputMethod", ()) + .and_then(|r: (String,)| Ok(r.0)) + } + + fn current_input_method_group(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "CurrentInputMethodGroup", ()) + .and_then(|r: (String,)| Ok(r.0)) + } + + fn current_input_method_info( + &self, + ) -> Result< + ( + String, + String, + String, + String, + String, + String, + String, + bool, + String, + arg::PropMap, + ), + dbus::Error, + > { + self.method_call("org.fcitx.Fcitx.Controller1", "CurrentInputMethodInfo", ()) + } + + fn current_ui(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "CurrentUI", ()) + .and_then(|r: (String,)| Ok(r.0)) + } + + fn deactivate(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Deactivate", ()) + } + + fn debug_info(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "DebugInfo", ()) + .and_then(|r: (String,)| Ok(r.0)) + } + + fn exit(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Exit", ()) + } + + fn full_input_method_group_info( + &self, + arg0: &str, + ) -> Result< + ( + String, + String, + String, + arg::PropMap, + Vec<( + String, + String, + String, + String, + String, + String, + String, + bool, + String, + arg::PropMap, + )>, + ), + dbus::Error, + > { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "FullInputMethodGroupInfo", + (arg0,), + ) + } + + fn get_addons(&self) -> Result, dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "GetAddons", ()) + .and_then(|r: (Vec<(String, String, String, i32, bool, bool)>,)| Ok(r.0)) + } + + fn get_addons_v2( + &self, + ) -> Result< + Vec<( + String, + String, + String, + i32, + bool, + bool, + bool, + Vec, + Vec, + )>, + dbus::Error, + > { + self.method_call("org.fcitx.Fcitx.Controller1", "GetAddonsV2", ()) + .and_then( + |r: ( + Vec<( + String, + String, + String, + i32, + bool, + bool, + bool, + Vec, + Vec, + )>, + )| Ok(r.0), + ) + } + + fn get_config arg::Get<'b> + 'static>( + &self, + arg0: &str, + ) -> Result< + ( + R0, + Vec<( + String, + Vec<( + String, + String, + String, + arg::Variant>, + arg::PropMap, + )>, + )>, + ), + dbus::Error, + > { + self.method_call("org.fcitx.Fcitx.Controller1", "GetConfig", (arg0,)) + .and_then( + |r: ( + arg::Variant, + Vec<( + String, + Vec<( + String, + String, + String, + arg::Variant>, + arg::PropMap, + )>, + )>, + )| Ok(((r.0).0, r.1)), + ) + } + + fn input_method_group_info( + &self, + arg0: &str, + ) -> Result<(String, Vec<(String, String)>), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "InputMethodGroupInfo", + (arg0,), + ) + } + + fn input_method_groups(&self) -> Result, dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "InputMethodGroups", ()) + .and_then(|r: (Vec,)| Ok(r.0)) + } + + fn open_wayland_connection(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "OpenWaylandConnection", + (arg0,), + ) + } + + fn open_wayland_connection_socket(&self, arg0: arg::OwnedFd) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "OpenWaylandConnectionSocket", + (arg0,), + ) + } + + fn open_x11_connection(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "OpenX11Connection", (arg0,)) + } + + fn refresh(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Refresh", ()) + } + + fn reload_addon_config(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "ReloadAddonConfig", (arg0,)) + } + + fn reload_config(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "ReloadConfig", ()) + } + + fn remove_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "RemoveInputMethodGroup", + (arg0,), + ) + } + + fn reopen_wayland_connection_socket( + &self, + arg0: &str, + arg1: arg::OwnedFd, + ) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "ReopenWaylandConnectionSocket", + (arg0, arg1), + ) + } + + fn reset_imlist(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "ResetIMList", ()) + } + + fn restart(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Restart", ()) + } + + fn save(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Save", ()) + } + + fn set_addons_state(&self, arg0: Vec<(&str, bool)>) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "SetAddonsState", (arg0,)) + } + + fn set_config( + &self, + arg0: &str, + arg1: I1, + ) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "SetConfig", + (arg0, arg::Variant(arg1)), + ) + } + + fn set_current_im(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "SetCurrentIM", (arg0,)) + } + + fn set_input_method_group_info( + &self, + arg0: &str, + arg1: &str, + arg2: Vec<(&str, &str)>, + ) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "SetInputMethodGroupInfo", + (arg0, arg1, arg2), + ) + } + + fn set_log_rule(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "SetLogRule", (arg0,)) + } + + fn state(&self) -> Result { + self.method_call("org.fcitx.Fcitx.Controller1", "State", ()) + .and_then(|r: (i32,)| Ok(r.0)) + } + + fn switch_input_method_group(&self, arg0: &str) -> Result<(), dbus::Error> { + self.method_call( + "org.fcitx.Fcitx.Controller1", + "SwitchInputMethodGroup", + (arg0,), + ) + } + + fn toggle(&self) -> Result<(), dbus::Error> { + self.method_call("org.fcitx.Fcitx.Controller1", "Toggle", ()) + } +} diff --git a/wlx-overlay-s/src/subsystem/dbus/mod.rs b/wlx-overlay-s/src/subsystem/dbus/mod.rs index 1590ebd..77ee546 100644 --- a/wlx-overlay-s/src/subsystem/dbus/mod.rs +++ b/wlx-overlay-s/src/subsystem/dbus/mod.rs @@ -9,8 +9,11 @@ use dbus::{ message::MatchRule, }; -use crate::subsystem::dbus::notifications::OrgFreedesktopNotifications; +use crate::subsystem::dbus::{ + fcitx5::OrgFcitxFcitxController1, notifications::OrgFreedesktopNotifications, +}; +mod fcitx5; mod notifications; pub type DbusReceiveCallback = Box bool + Send>; @@ -74,6 +77,20 @@ impl DbusConnector { Ok(()) } + pub fn fcitx_keymap(&mut self) -> anyhow::Result { + let connection = Connection::new_session()?; + let proxy = connection.with_proxy( + "org.fcitx.Fcitx5", + "/controller", + Duration::from_millis(500), + ); + + let result = proxy + .current_input_method() + .context("Could not get D-Bus response"); + result + } + pub fn notify_send( &mut self, summary: &str, @@ -83,16 +100,12 @@ impl DbusConnector { replaces_id: u32, transient: bool, ) -> anyhow::Result { - let connection = self - .connection - .take() - .context("Not connected") - .or_else(|_| Connection::new_session())?; + let connection = Connection::new_session()?; let proxy = connection.with_proxy( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", - Duration::from_millis(1000), + Duration::from_millis(500), ); let mut hints = PropMap::new(); @@ -109,25 +122,19 @@ impl DbusConnector { hints, timeout, )?; - self.connection = Some(connection); - Ok(retval) } pub fn notify_close(&mut self, id: u32) -> anyhow::Result<()> { - let connection = self - .connection - .take() - .context("Not connected") - .or_else(|_| Connection::new_session())?; + let connection = Connection::new_session()?; + let proxy = connection.with_proxy( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", - Duration::from_millis(1000), + Duration::from_millis(500), ); proxy.close_notification(id)?; - self.connection = Some(connection); Ok(()) } } diff --git a/wlx-overlay-s/src/subsystem/hid/mod.rs b/wlx-overlay-s/src/subsystem/hid/mod.rs index 64f314e..38e0aa8 100644 --- a/wlx-overlay-s/src/subsystem/hid/mod.rs +++ b/wlx-overlay-s/src/subsystem/hid/mod.rs @@ -578,6 +578,12 @@ pub struct XkbKeymap { } impl XkbKeymap { + pub fn from_layout_str(layout: &str) -> Option { + let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); + xkb::Keymap::new_from_names(&context, "", "", layout, "", None, xkb::COMPILE_NO_FLAGS) + .map(|inner| XkbKeymap { inner }) + } + pub fn label_for_key(&self, key: VirtualKey, modifier: KeyModifier) -> String { let mut state = xkb::State::new(&self.inner); if modifier > 0 diff --git a/wlx-overlay-s/src/subsystem/hid/wayland.rs b/wlx-overlay-s/src/subsystem/hid/wayland.rs index ce56ec2..1ac255f 100644 --- a/wlx-overlay-s/src/subsystem/hid/wayland.rs +++ b/wlx-overlay-s/src/subsystem/hid/wayland.rs @@ -1,5 +1,4 @@ use anyhow::Context; -use wayland_client::{EventQueue, globals::GlobalList}; use wlx_capture::wayland::wayland_client::{ Connection, Dispatch, Proxy, QueueHandle, globals::{GlobalListContents, registry_queue_init}, @@ -13,62 +12,6 @@ use xkbcommon::xkb; use super::XkbKeymap; -pub struct WlKeymapMonitor { - connection: Connection, - globals: GlobalList, - queue: EventQueue, - state: MonitorState, -} - -impl WlKeymapMonitor { - pub fn new() -> anyhow::Result { - let connection = Connection::connect_to_env()?; - let (globals, mut queue) = registry_queue_init::(&connection)?; - let qh = queue.handle(); - let seat: WlSeat = globals - .bind(&qh, 4..=9, ()) - .unwrap_or_else(|_| panic!("{}", WlSeat::interface().name)); - - let mut state = MonitorState { - seat, - keyboard: None, - keymap: None, - }; - - // this gets us the wl_seat - let _ = queue.blocking_dispatch(&mut state); - - // this gets us the wl_keyboard - let _ = queue.blocking_dispatch(&mut state); - - Ok(Self { - connection, - globals, - queue, - state, - }) - } - - pub fn check(&mut self) -> Option { - let Some(read_guard) = self.connection.prepare_read() else { - return None; - }; - read_guard - .read() - .context("could not read wayland events") - .inspect_err(|e| log::warn!("{e:?}")) - .ok()?; - - self.queue.dispatch_pending(&mut self.state).ok()?; - - self.take_keymap() - } - - pub fn take_keymap(&mut self) -> Option { - self.state.keymap.take() - } -} - struct MonitorState { seat: WlSeat, keyboard: Option,