initial commit
This commit is contained in:
commit
54863c2577
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
1401
Cargo.lock
generated
Normal file
1401
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "susuwatari"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rdev = { version = "0.5.3", features = ["unstable_grab"] }
|
||||
tokio = { version = "1.39.2", features = ["full"] }
|
||||
tokio-process = "0.2.5"
|
||||
arboard = "3.4.0"
|
18
shell.nix
Normal file
18
shell.nix
Normal file
|
@ -0,0 +1,18 @@
|
|||
{ pkgs ? import <nixpkgs> { overlays = [ (import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz)) ]; },}:
|
||||
with pkgs;
|
||||
|
||||
mkShell {
|
||||
nativeBuildInputs = with xorg; [
|
||||
pkg-config
|
||||
] ++ [
|
||||
cargo
|
||||
rustc
|
||||
];
|
||||
buildInputs = [
|
||||
latest.rustChannels.stable.rust
|
||||
xorg.libX11
|
||||
xorg.libXi
|
||||
xorg.libXtst
|
||||
libevdev
|
||||
];
|
||||
}
|
149
src/main.rs
Normal file
149
src/main.rs
Normal file
|
@ -0,0 +1,149 @@
|
|||
use rdev::{grab, Event, EventType, Key};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::task;
|
||||
use tokio::process::Command;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use arboard::Clipboard;
|
||||
|
||||
enum Hotkey {
|
||||
ControlPressed,
|
||||
ControlReleased,
|
||||
ModPressed,
|
||||
ModReleased,
|
||||
KeyC,
|
||||
KeyV,
|
||||
}
|
||||
|
||||
struct History {
|
||||
entries: Vec<String>,
|
||||
clipboard: Clipboard,
|
||||
}
|
||||
|
||||
impl History {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
entries: vec!["1".into(), "2".into(), "3".into()],
|
||||
clipboard: Clipboard::new().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
//clipboard.get_text().unwrap()
|
||||
}
|
||||
|
||||
async fn paste(&self) {
|
||||
if self.entries.len() == 0 {
|
||||
return
|
||||
}
|
||||
match self.select_entry().await {
|
||||
Ok(entry) => {
|
||||
println!("# {}", entry);
|
||||
}
|
||||
Err(why) => {
|
||||
eprintln!("error pasting clipboard : {}", why);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn select_entry(&self) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let input_data = self.entries.join("\n");
|
||||
|
||||
// Prepare the command
|
||||
let mut cmd = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg("marukuru -l 10")
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
let stdin = cmd.stdin.as_mut().ok_or("Failed to open stdin")?;
|
||||
stdin.write_all(input_data.as_bytes()).await?;
|
||||
|
||||
println!("awaiting");
|
||||
|
||||
// Await the command to complete
|
||||
let output = cmd.wait_with_output().await?;
|
||||
|
||||
Ok(String::from_utf8(output.stdout)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Create a channel for communication between the grab callback and the main task
|
||||
let (tx, mut rx) = mpsc::channel(100);
|
||||
|
||||
// Define the callback function
|
||||
let callback = move |event: Event| -> Option<Event> {
|
||||
let tx = tx.clone();
|
||||
task::spawn(async move {
|
||||
match event.event_type {
|
||||
EventType::KeyPress(Key::KeyC) => {
|
||||
tx.send(Hotkey::KeyC).await.unwrap();
|
||||
}
|
||||
EventType::KeyPress(Key::KeyV) => {
|
||||
tx.send(Hotkey::KeyV).await.unwrap();
|
||||
}
|
||||
EventType::KeyPress(Key::MetaLeft) => {
|
||||
tx.send(Hotkey::ModPressed).await.unwrap();
|
||||
}
|
||||
EventType::KeyRelease(Key::MetaLeft) => {
|
||||
tx.send(Hotkey::ModReleased).await.unwrap();
|
||||
}
|
||||
EventType::KeyPress(Key::ControlLeft) => {
|
||||
tx.send(Hotkey::ControlPressed).await.unwrap();
|
||||
}
|
||||
EventType::KeyRelease(Key::ControlLeft) => {
|
||||
tx.send(Hotkey::ControlReleased).await.unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
Some(event)
|
||||
};
|
||||
|
||||
// Spawn a task to handle the event grabbing
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
if let Err(error) = grab(callback.clone()) {
|
||||
println!("Error: {:?}", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut ctrl_pressed = false;
|
||||
let mut mod_pressed = false;
|
||||
let mut history = History::new();
|
||||
|
||||
// Main task to handle state updates
|
||||
while let Some(hotkey) = rx.recv().await {
|
||||
match hotkey {
|
||||
Hotkey::ControlPressed => {
|
||||
ctrl_pressed = true;
|
||||
}
|
||||
Hotkey::ControlReleased => {
|
||||
ctrl_pressed = false;
|
||||
}
|
||||
Hotkey::ModPressed => {
|
||||
mod_pressed = true;
|
||||
}
|
||||
Hotkey::ModReleased => {
|
||||
mod_pressed = false;
|
||||
}
|
||||
Hotkey::KeyC => {
|
||||
if ctrl_pressed {
|
||||
println!("copied");
|
||||
history.update();
|
||||
}
|
||||
}
|
||||
Hotkey::KeyV => {
|
||||
if mod_pressed {
|
||||
println!("paste");
|
||||
history.paste().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue