mirror of
https://codeberg.org/icewind/shortcutd.git
synced 2026-06-03 17:24:08 +02:00
allow some bare shortcuts, example work
This commit is contained in:
parent
60465ac735
commit
42237bc965
9 changed files with 232 additions and 63 deletions
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
|
|
@ -65,16 +65,3 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.artifact_name }}-${{ matrix.target }}
|
name: ${{ matrix.artifact_name }}-${{ matrix.target }}
|
||||||
path: result/bin/${{ matrix.artifact_name }}
|
path: result/bin/${{ matrix.artifact_name }}
|
||||||
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: check
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: cachix/install-nix-action@v20
|
|
||||||
- uses: icewind1991/attic-action@v1
|
|
||||||
with:
|
|
||||||
name: ci
|
|
||||||
instance: https://cache.icewind.me
|
|
||||||
authToken: '${{ secrets.ATTIC_TOKEN }}'
|
|
||||||
- run: nix build .#test
|
|
||||||
|
|
|
||||||
132
Cargo.lock
generated
132
Cargo.lock
generated
|
|
@ -11,6 +11,55 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is-terminal",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -207,6 +256,54 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|
@ -324,9 +421,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "evdev-shortcut"
|
name = "evdev-shortcut"
|
||||||
version = "0.1.1"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa8872ec4c0a6e6f5d6649384273a88a4941a0bd637a25712eadd74da2cb0748"
|
checksum = "cb870dc02f8a7955fa4ff451bbdd8bf9362d71b245a76bbe73a4c000cf012709"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"evdev",
|
"evdev",
|
||||||
|
|
@ -495,6 +592,12 @@ version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
|
|
@ -546,6 +649,18 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.3.1",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
@ -957,6 +1072,7 @@ dependencies = [
|
||||||
name = "shortcutd"
|
name = "shortcutd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"evdev-shortcut",
|
"evdev-shortcut",
|
||||||
"futures",
|
"futures",
|
||||||
"test-case",
|
"test-case",
|
||||||
|
|
@ -1029,6 +1145,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structmeta"
|
name = "structmeta"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -1297,6 +1419,12 @@ version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
||||||
32
README.md
32
README.md
|
|
@ -11,8 +11,7 @@ The shortcutd daemon hooks into the evdev system and exposes a dbus interface fo
|
||||||
By separating out the code that hooks into evdev (which needs to be done as root) into a separate daemon
|
By separating out the code that hooks into evdev (which needs to be done as root) into a separate daemon
|
||||||
it allows non-privileged users to hook into global shortcuts.
|
it allows non-privileged users to hook into global shortcuts.
|
||||||
|
|
||||||
Protection against clients using the shortcutd daemon for a keylogger is done by only allowing shortcuts that
|
Protection against clients using the shortcutd daemon for a keylogger is done by only allowing 3 shortcuts without modifiers to be registered at the same time.
|
||||||
contain at least one modifier key.
|
|
||||||
|
|
||||||
## Starting the daemon
|
## Starting the daemon
|
||||||
|
|
||||||
|
|
@ -22,33 +21,32 @@ contain at least one modifier key.
|
||||||
## Rust api
|
## Rust api
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
use futures::{pin_mut, StreamExt};
|
||||||
use shortcutd::{Shortcut, ShortcutClient};
|
use shortcutd::{Shortcut, ShortcutClient};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
#[tokio::main]
|
||||||
let mut client = ShortcutClient::new()?;
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let client = ShortcutClient::new().await?;
|
||||||
let shortcut: Shortcut = "<Ctrl><Alt>-KeyP".parse()?;
|
|
||||||
|
|
||||||
client.register(shortcut, |s| {
|
|
||||||
eprintln!("shortcut1 {}", s);
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let shortcut: Shortcut = "<Ctrl><Alt>-KeyO".parse()?;
|
let shortcut: Shortcut = "<Ctrl><Alt>-KeyO".parse()?;
|
||||||
|
|
||||||
client.register(shortcut, |s| {
|
let stream = client.listen(shortcut).await?;
|
||||||
eprintln!("shortcut2 {}", s);
|
|
||||||
})?;
|
|
||||||
|
|
||||||
loop {
|
pin_mut!(stream);
|
||||||
client.process(Duration::from_millis(1000))?;
|
|
||||||
|
while let Some(event) = stream.next().await {
|
||||||
|
println!("{} {}", event.shortcut, event.state.as_str());
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## D-Bus api
|
## D-Bus api
|
||||||
|
|
||||||
- register a new shortcut using the `Register` method at `nl.icewind.shortcutd`/`register`
|
- register a new shortcut using the `Register` method at `nl.icewind.shortcutd`/`register`
|
||||||
- listen to the signal at the path returned from the `Register` method to get notified when the shortcut is triggered
|
- listen to the signal at the path returned from the `Register` method to get notified when the shortcut is triggered.
|
||||||
|
|
||||||
|
A boolean parameter is provided with the signal to distinguish shortcut presses from releases.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ path = "src/lib.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
zbus = { version = "3.13.1", features = ["tokio"], default-features = false }
|
zbus = { version = "3.13.1", features = ["tokio"], default-features = false }
|
||||||
evdev-shortcut = { version = "0.1.1", default_features = false }
|
evdev-shortcut = { version = "0.1.2", default_features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test-case = "3.1.0"
|
test-case = "3.1.0"
|
||||||
tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"] }
|
||||||
|
clap = { version = "4.3.4", features = ["derive"] }
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
use shortcutd::{ShortcutClient};
|
use clap::Parser;
|
||||||
use std::error::Error;
|
use evdev_shortcut::Shortcut;
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
use futures::stream::iter;
|
use futures::stream::iter;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use shortcutd::ShortcutClient;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(author, version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
/// Shortcut to listen to
|
||||||
|
shortcuts: Vec<Shortcut>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let args = Args::parse();
|
||||||
let client = ShortcutClient::new().await?;
|
let client = ShortcutClient::new().await?;
|
||||||
|
|
||||||
let streams = [
|
let stream = iter(args.shortcuts)
|
||||||
Box::pin(client.register("<Ctrl>-KeyM".parse()?).await?),
|
.then(|shortcut| async { Box::pin(client.listen(shortcut).await.unwrap()) })
|
||||||
Box::pin(client.register("<Ctrl><Alt>-KeyO".parse()?).await?),
|
.flatten_unordered(None);
|
||||||
];
|
|
||||||
|
|
||||||
let stream = iter(streams).flatten_unordered(None);
|
|
||||||
|
|
||||||
pin_mut!(stream);
|
pin_mut!(stream);
|
||||||
|
|
||||||
|
|
|
||||||
19
client/examples/simple.rs
Normal file
19
client/examples/simple.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
use futures::{pin_mut, StreamExt};
|
||||||
|
use shortcutd::{Shortcut, ShortcutClient};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let client = ShortcutClient::new().await?;
|
||||||
|
|
||||||
|
let shortcut: Shortcut = "<Ctrl><Alt>-KeyO".parse()?;
|
||||||
|
|
||||||
|
let stream = client.listen(shortcut).await?;
|
||||||
|
|
||||||
|
pin_mut!(stream);
|
||||||
|
|
||||||
|
while let Some(event) = stream.next().await {
|
||||||
|
println!("{} {}", event.shortcut, event.state.as_str());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
pub use evdev_shortcut::Shortcut;
|
pub use evdev_shortcut::Shortcut;
|
||||||
use evdev_shortcut::{ShortcutEvent, ShortcutState};
|
use evdev_shortcut::{ShortcutEvent, ShortcutState};
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use zbus::{Connection, fdo};
|
|
||||||
use zbus::dbus_proxy;
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use zbus::dbus_proxy;
|
||||||
|
use zbus::{fdo, Connection};
|
||||||
|
|
||||||
#[dbus_proxy(
|
#[dbus_proxy(
|
||||||
interface = "nl.icewind.shortcutd",
|
interface = "nl.icewind.shortcutd",
|
||||||
|
|
@ -14,7 +14,6 @@ trait Register {
|
||||||
async fn register(&self, shortcut: &str) -> fdo::Result<String>;
|
async fn register(&self, shortcut: &str) -> fdo::Result<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[dbus_proxy(
|
#[dbus_proxy(
|
||||||
interface = "nl.icewind.shortcutd",
|
interface = "nl.icewind.shortcutd",
|
||||||
default_service = "nl.icewind.shortcutd"
|
default_service = "nl.icewind.shortcutd"
|
||||||
|
|
@ -39,14 +38,17 @@ impl ShortcutClient {
|
||||||
ShortcutClient { connection }
|
ShortcutClient { connection }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register(
|
pub async fn listen(
|
||||||
&self,
|
&self,
|
||||||
shortcut: Shortcut,
|
shortcut: Shortcut,
|
||||||
) -> Result<impl Stream<Item = ShortcutEvent> + '_, zbus::Error> {
|
) -> Result<impl Stream<Item = ShortcutEvent> + '_, zbus::Error> {
|
||||||
let register = RegisterProxy::new(&self.connection).await?;
|
let register = RegisterProxy::new(&self.connection).await?;
|
||||||
let path = register.register(&format!("{}", shortcut)).await?;
|
let path = register.register(&format!("{}", shortcut)).await?;
|
||||||
|
|
||||||
let p = ShortcutSignalProxy::builder(&self.connection).path(path.as_str())?.build().await?;
|
let p = ShortcutSignalProxy::builder(&self.connection)
|
||||||
|
.path(path.as_str())?
|
||||||
|
.build()
|
||||||
|
.await?;
|
||||||
let signals = p.receive_triggered().await?;
|
let signals = p.receive_triggered().await?;
|
||||||
|
|
||||||
Ok(signals.filter_map(move |signal| {
|
Ok(signals.filter_map(move |signal| {
|
||||||
|
|
@ -55,7 +57,11 @@ impl ShortcutClient {
|
||||||
let pressed = signal.args().ok()?.pressed;
|
let pressed = signal.args().ok()?.pressed;
|
||||||
Some(ShortcutEvent {
|
Some(ShortcutEvent {
|
||||||
shortcut,
|
shortcut,
|
||||||
state: if pressed { ShortcutState::Pressed } else { ShortcutState::Released },
|
state: if pressed {
|
||||||
|
ShortcutState::Pressed
|
||||||
|
} else {
|
||||||
|
ShortcutState::Released
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ path = "src/server.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
main_error = "0.1.0"
|
main_error = "0.1.0"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
evdev-shortcut = "0.1.1"
|
evdev-shortcut = "0.1.3"
|
||||||
tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"] }
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
zbus = { version = "3.13.1", features = ["tokio"], default-features = false }
|
zbus = { version = "3.13.1", features = ["tokio"], default-features = false }
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,38 @@
|
||||||
use main_error::MainError;
|
|
||||||
use evdev_shortcut::{Shortcut, ShortcutEvent, ShortcutListener, ShortcutState};
|
use evdev_shortcut::{Shortcut, ShortcutEvent, ShortcutListener, ShortcutState};
|
||||||
use glob::GlobError;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use glob::GlobError;
|
||||||
|
use main_error::MainError;
|
||||||
|
use std::path::PathBuf;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use zbus::{ConnectionBuilder, dbus_interface, fdo, SignalContext, ObjectServer};
|
|
||||||
use zbus::export::futures_util::pin_mut;
|
use zbus::export::futures_util::pin_mut;
|
||||||
|
use zbus::{dbus_interface, fdo, ConnectionBuilder, ObjectServer, SignalContext};
|
||||||
|
|
||||||
struct Register {
|
struct Register {
|
||||||
listener: ShortcutListener,
|
listener: ShortcutListener,
|
||||||
|
bare_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_BARE: usize = 3;
|
||||||
|
|
||||||
#[dbus_interface(name = "nl.icewind.shortcutd")]
|
#[dbus_interface(name = "nl.icewind.shortcutd")]
|
||||||
impl Register {
|
impl Register {
|
||||||
async fn register(&mut self, shortcut: &str, #[zbus(object_server)] server: &ObjectServer) -> Result<String, fdo::Error> {
|
async fn register(
|
||||||
|
&mut self,
|
||||||
|
shortcut: &str,
|
||||||
|
#[zbus(object_server)] server: &ObjectServer,
|
||||||
|
) -> Result<String, fdo::Error> {
|
||||||
match shortcut.parse::<Shortcut>() {
|
match shortcut.parse::<Shortcut>() {
|
||||||
Ok(shortcut) => {
|
Ok(shortcut) => {
|
||||||
|
if shortcut.modifiers.is_empty() && !self.listener.has(&shortcut) {
|
||||||
|
dbg!(&shortcut);
|
||||||
|
if self.bare_count >= MAX_BARE {
|
||||||
|
return Err(fdo::Error::InvalidArgs(format!(
|
||||||
|
"Only {} shortcuts without modifiers are allowed",
|
||||||
|
MAX_BARE
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
self.bare_count += 1;
|
||||||
|
}
|
||||||
info!(%shortcut, "registering shortcut");
|
info!(%shortcut, "registering shortcut");
|
||||||
self.listener.add(shortcut.clone());
|
self.listener.add(shortcut.clone());
|
||||||
let path = format!("/{}", shortcut.identifier());
|
let path = format!("/{}", shortcut.identifier());
|
||||||
|
|
@ -49,6 +66,7 @@ async fn main() -> Result<(), MainError> {
|
||||||
|
|
||||||
let bus = Register {
|
let bus = Register {
|
||||||
listener,
|
listener,
|
||||||
|
bare_count: 0,
|
||||||
};
|
};
|
||||||
let conn = ConnectionBuilder::system()?
|
let conn = ConnectionBuilder::system()?
|
||||||
.name("nl.icewind.shortcutd")?
|
.name("nl.icewind.shortcutd")?
|
||||||
|
|
@ -63,7 +81,12 @@ async fn main() -> Result<(), MainError> {
|
||||||
let event: ShortcutEvent = event;
|
let event: ShortcutEvent = event;
|
||||||
let identifier = format!("/{}", event.shortcut.identifier());
|
let identifier = format!("/{}", event.shortcut.identifier());
|
||||||
if let Ok(signal_interface) = server.interface::<_, ShortcutSignal>(identifier).await {
|
if let Ok(signal_interface) = server.interface::<_, ShortcutSignal>(identifier).await {
|
||||||
if let Err(e) = ShortcutSignal::triggered(signal_interface.signal_context(), event.state == ShortcutState::Pressed).await {
|
if let Err(e) = ShortcutSignal::triggered(
|
||||||
|
signal_interface.signal_context(),
|
||||||
|
event.state == ShortcutState::Pressed,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
eprintln!("{e:#}");
|
eprintln!("{e:#}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue