Pi66

pind
Simple Rust hotkey daemon.
git clone https://git.pi66.xyz/pind

← back to log

fix some issues

author: 6z7y
date: 2025-08-31 13:53
hash: 46515d293d3c2fca32534afe3ee0ba34694212c0

Diffstat:

M

src/main.rs
59 +++++++++++++++---------------
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
diff --git a/src/main.rs b/src/main.rs
index 81ac9dc..214e287 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,11 +26,10 @@


 use evdev::{AttributeSet, Device, KeyCode, enumerate};
-use std::{env::{var,args},fs::read_to_string, path::PathBuf, process::{exit,Command, Stdio}, sync::{Arc, OnceLock}, thread, time::Duration};
+use std::{env::{var,args},fs::read_to_string, path::PathBuf, process::{exit,Command, Stdio}, sync::{Arc, OnceLock}, thread};

 const DELAY  :u64  =  25; // 25ms
 const CONFIG :&str =  "/etc/pind/pindrc";
-
 static BINDINGS: OnceLock<Arc<Vec<(AttributeSet<KeyCode>, String)>>> = OnceLock::new();

 fn get_bindings() -> Arc<Vec<(AttributeSet<KeyCode>, String)>>
@@ -153,46 +152,48 @@ fn load_config(config: &str) -> Vec<(AttributeSet<KeyCode>, String)>
         .collect()
 }

-fn read_keys(bindings: &[(AttributeSet<KeyCode>, String)], device_path: PathBuf, delay: u64, user: String)
-{
+fn read_keys(kc: &[(AttributeSet<KeyCode>, String)], kbs: PathBuf, delay: u64, user: String) {
+    let mut state: Vec<(u64, u64)> = vec![(0, 0); kc.len()];
+    let mut tick = 1;
+    let init = (220 + delay - 1) / delay;
+
     loop {
-        if let Ok(dev) = Device::open(&device_path).and_then(|d| d.get_key_state()) {
-            for (key, cmd) in bindings {
-                if dev == *key {
-                    run(cmd, &user);
+        if let Ok(keys) = Device::open(&kbs).and_then(|d| d.get_key_state()) {
+            for (i, (combo, cmd)) in kc.iter().enumerate() {
+                let pressed = combo.iter().all(|k| keys.contains(k));
+                let (since, last) = &mut state[i];
+                if pressed {
+                    if *since == 0 {
+                        run(cmd, &user);
+                        *since = tick;
+                        *last = tick;
+                    } else if tick - *since >= init && tick > *last {
+                        run(cmd, &user);
+                        *last = tick;
+                    }
+                } else {
+                    *since = 0;
                 }
             }
         }
-        thread::sleep(Duration::from_millis(delay));
+        thread::sleep(std::time::Duration::from_millis(delay));
+        tick = tick.wrapping_add(1);
     }
 }

 fn main()
 {
     let user = args().nth(1).unwrap_or_else(|| error("USER", "Username argument required"));
-    
     let bindings = get_bindings();
-    if bindings.is_empty() {
-        error("binding", "No key bindings detected");
-    }
-    
+    if bindings.is_empty() { error("binding", "No key bindings detected"); }
     let keyboards = keyboards();
-    if keyboards.is_empty() {
-        error("Hardware", "No keyboards detected");
-    }
+    if keyboards.is_empty() { error("Hardware", "No keyboards detected"); }

-    // Use a single Arc and share references
-    let handles: Vec<_> = keyboards.into_iter()
-        .map(|keyboard| {
-            let bindings_ref = Arc::clone(&bindings);
-            let user_ref = user.clone();
-            
-            thread::spawn(move || {
-                let bindings_slice: &[(AttributeSet<KeyCode>, String)] = &bindings_ref;
-                read_keys(bindings_slice, keyboard, DELAY, user_ref);
-            })
-        })
-        .collect();
+    let handles: Vec<_> = keyboards.into_iter().map(|keyboard| {
+        let bindings_ref = Arc::clone(&bindings);
+        let user_ref = user.clone();
+        thread::spawn(move || read_keys(&bindings_ref, keyboard, DELAY, user_ref))
+    }).collect();

     for handle in handles {
         handle.join().unwrap_or_else(|_| error("Thread", "Keyboard thread panicked"));