SIGUSR1 to trigger fcitx layout change

This commit is contained in:
galister
2025-12-15 16:13:45 +09:00
parent 12e5749bda
commit 1077d2606d
9 changed files with 656 additions and 121 deletions

62
Cargo.lock generated
View File

@@ -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",

View File

@@ -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]

View File

@@ -50,6 +50,7 @@ pub struct GuiPanel<S> {
pub max_size: Vec2,
pub gui_scale: f32,
pub on_notify: Option<OnNotifyFunc<S>>,
pub initialized: bool,
interaction_transform: Option<Affine2>,
context: WguiContext,
timestep: Timestep,
@@ -165,6 +166,7 @@ impl<S: 'static> GuiPanel<S> {
interaction_transform: None,
on_notify: None,
gui_scale: params.gui_scale,
initialized: false,
})
}
@@ -194,6 +196,7 @@ impl<S: 'static> GuiPanel<S> {
on_notify: None,
interaction_transform: None,
gui_scale: params.gui_scale,
initialized: false,
})
}
@@ -230,6 +233,7 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
self.layout.content_size.x as _,
self.layout.content_size.y as _,
]));
self.initialized = true;
}
Ok(())
}

View File

@@ -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<dyn std::error::Error>> {
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

View File

@@ -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<ShouldRender> {
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,
});

View File

@@ -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<String, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>>
OrgFreedesktopDBusIntrospectable for blocking::Proxy<'a, C>
{
fn introspect(&self) -> Result<String, dbus::Error> {
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<String, dbus::Error>;
fn available_input_methods(
&self,
) -> Result<Vec<(String, String, String, String, String, String, bool)>, dbus::Error>;
fn available_keyboard_layouts(
&self,
) -> Result<
Vec<(
String,
String,
Vec<String>,
Vec<(String, String, Vec<String>)>,
)>,
dbus::Error,
>;
fn can_restart(&self) -> Result<bool, dbus::Error>;
fn check_update(&self) -> Result<bool, dbus::Error>;
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<String, dbus::Error>;
fn current_input_method_group(&self) -> Result<String, dbus::Error>;
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<String, dbus::Error>;
fn deactivate(&self) -> Result<(), dbus::Error>;
fn debug_info(&self) -> Result<String, dbus::Error>;
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<Vec<(String, String, String, i32, bool, bool)>, dbus::Error>;
fn get_addons_v2(
&self,
) -> Result<
Vec<(
String,
String,
String,
i32,
bool,
bool,
bool,
Vec<String>,
Vec<String>,
)>,
dbus::Error,
>;
fn get_config<R0: for<'b> arg::Get<'b> + 'static>(
&self,
arg0: &str,
) -> Result<
(
R0,
Vec<(
String,
Vec<(
String,
String,
String,
arg::Variant<Box<dyn arg::RefArg + 'static>>,
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<Vec<String>, 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<I1: arg::Arg + arg::Append>(
&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<i32, dbus::Error>;
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<Self, arg::TypeMismatchError> {
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<Target = T>> 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<String, dbus::Error> {
self.method_call("org.fcitx.Fcitx.Controller1", "AddonForIM", (arg0,))
.and_then(|r: (String,)| Ok(r.0))
}
fn available_input_methods(
&self,
) -> Result<Vec<(String, String, String, String, String, String, bool)>, 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<String>,
Vec<(String, String, Vec<String>)>,
)>,
dbus::Error,
> {
self.method_call(
"org.fcitx.Fcitx.Controller1",
"AvailableKeyboardLayouts",
(),
)
.and_then(
|r: (
Vec<(
String,
String,
Vec<String>,
Vec<(String, String, Vec<String>)>,
)>,
)| Ok(r.0),
)
}
fn can_restart(&self) -> Result<bool, dbus::Error> {
self.method_call("org.fcitx.Fcitx.Controller1", "CanRestart", ())
.and_then(|r: (bool,)| Ok(r.0))
}
fn check_update(&self) -> Result<bool, dbus::Error> {
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<String, dbus::Error> {
self.method_call("org.fcitx.Fcitx.Controller1", "CurrentInputMethod", ())
.and_then(|r: (String,)| Ok(r.0))
}
fn current_input_method_group(&self) -> Result<String, dbus::Error> {
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<String, dbus::Error> {
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<String, dbus::Error> {
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<Vec<(String, String, String, i32, bool, bool)>, 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<String>,
Vec<String>,
)>,
dbus::Error,
> {
self.method_call("org.fcitx.Fcitx.Controller1", "GetAddonsV2", ())
.and_then(
|r: (
Vec<(
String,
String,
String,
i32,
bool,
bool,
bool,
Vec<String>,
Vec<String>,
)>,
)| Ok(r.0),
)
}
fn get_config<R0: for<'b> arg::Get<'b> + 'static>(
&self,
arg0: &str,
) -> Result<
(
R0,
Vec<(
String,
Vec<(
String,
String,
String,
arg::Variant<Box<dyn arg::RefArg + 'static>>,
arg::PropMap,
)>,
)>,
),
dbus::Error,
> {
self.method_call("org.fcitx.Fcitx.Controller1", "GetConfig", (arg0,))
.and_then(
|r: (
arg::Variant<R0>,
Vec<(
String,
Vec<(
String,
String,
String,
arg::Variant<Box<dyn arg::RefArg + 'static>>,
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<Vec<String>, dbus::Error> {
self.method_call("org.fcitx.Fcitx.Controller1", "InputMethodGroups", ())
.and_then(|r: (Vec<String>,)| 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<I1: arg::Arg + arg::Append>(
&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<i32, dbus::Error> {
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", ())
}
}

View File

@@ -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<dyn FnMut(Message, &Connection) -> bool + Send>;
@@ -74,6 +77,20 @@ impl DbusConnector {
Ok(())
}
pub fn fcitx_keymap(&mut self) -> anyhow::Result<String> {
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<u32> {
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(())
}
}

View File

@@ -578,6 +578,12 @@ pub struct XkbKeymap {
}
impl XkbKeymap {
pub fn from_layout_str(layout: &str) -> Option<Self> {
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

View File

@@ -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<MonitorState>,
state: MonitorState,
}
impl WlKeymapMonitor {
pub fn new() -> anyhow::Result<Self> {
let connection = Connection::connect_to_env()?;
let (globals, mut queue) = registry_queue_init::<MonitorState>(&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<XkbKeymap> {
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<XkbKeymap> {
self.state.keymap.take()
}
}
struct MonitorState {
seat: WlSeat,
keyboard: Option<WlKeyboard>,