Handle repeated keys

This commit is contained in:
htrefil 2020-11-14 15:57:32 +01:00
parent 57039fa93b
commit 16e1e6ce3f
4 changed files with 94 additions and 157 deletions

134
Cargo.lock generated
View file

@ -228,101 +228,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "futures"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
[[package]]
name = "futures-executor"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb"
[[package]]
name = "futures-macro"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d"
[[package]]
name = "futures-task"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
dependencies = [
"once_cell",
]
[[package]]
name = "futures-util"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
[[package]]
name = "getrandom"
version = "0.1.15"
@ -400,7 +311,6 @@ name = "input"
version = "0.1.0"
dependencies = [
"bindgen",
"futures",
"inotify",
"libc",
"serde",
@ -531,12 +441,6 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "openssl"
version = "0.10.30"
@ -576,38 +480,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pin-project"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.19"
@ -644,18 +522,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
[[package]]
name = "proc-macro2"
version = "1.0.24"

View file

@ -13,10 +13,10 @@ serde = { version = "1.0.117", features = ["derive"] }
inotify = "0.9.1"
tokio = { version = "0.3.3", features = ["fs", "io-util", "net", "sync", "rt", "time"] }
libc = "0.2.77"
futures = "0.3.7"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["winuser"] }
tokio = { version = "0.3.3", features = ["sync"] }
[build-dependencies]
bindgen = "0.55.1"

View file

@ -25,7 +25,7 @@ pub enum Direction {
Down, // The key is pressed.
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum KeyKind {
Key(Key),
Button(Button),

View file

@ -1,35 +1,106 @@
use crate::event::Event;
use crate::event::{Direction, Event, Key, KeyKind};
use std::io::Error;
use std::time::{Duration, Instant};
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::sync::oneshot::{self, Receiver};
use tokio::time;
use winapi::um::winuser::{self, INPUT};
pub struct EventWriter(());
pub struct EventWriter {
event_sender: UnboundedSender<Event>,
error_receiver: Receiver<Error>,
}
impl EventWriter {
pub async fn new() -> Result<Self, Error> {
Ok(Self(()))
let (event_sender, event_receiver) = mpsc::unbounded_channel();
let (error_sender, error_receiver) = oneshot::channel();
tokio::spawn(async move {
if let Err(err) = handle_events(event_receiver).await {
let _ = error_sender.send(err);
}
});
Ok(Self {
event_sender,
error_receiver,
})
}
pub async fn write(&mut self, event: Event) -> Result<(), Error> {
if let Some(mut events) = event.to_raw() {
return self.write_raw(events.as_mut_slice());
}
Ok(())
}
fn write_raw(&mut self, events: &mut [INPUT]) -> Result<(), Error> {
let written = unsafe {
winuser::SendInput(
events.len() as _,
events.as_mut_ptr(),
std::mem::size_of_val(&events[0]) as _,
)
};
if written != 1 {
return Err(Error::last_os_error());
if let Ok(err) = self.error_receiver.try_recv() {
return Err(err);
}
self.event_sender.send(event).unwrap();
Ok(())
}
}
const REPEAT_INTERVAL: Duration = Duration::from_millis(20);
const REPEAT_AFTER: Duration = Duration::from_millis(500);
async fn handle_events(mut receiver: UnboundedReceiver<Event>) -> Result<(), Error> {
let mut pressed: Option<(Key, Instant)> = None;
let mut interval = time::interval(REPEAT_INTERVAL);
loop {
tokio::select! {
_ = interval.tick() => {
if let Some((key, created)) = pressed {
if created.elapsed() < REPEAT_AFTER {
continue;
}
write_event(Event::Key { kind: KeyKind::Key(key), direction: Direction::Down })?;
}
}
event = receiver.recv() => {
let event = match event {
Some(event) => event,
None => return Ok(()),
};
if let Event::Key { kind: KeyKind::Key(key), direction } = event {
match direction {
Direction::Up => {
if pressed.map(|(k, _)| k == key).unwrap_or(false) {
pressed = None;
}
}
Direction::Down => {
pressed = Some((key, Instant::now()));
}
}
}
write_event(event)?;
}
}
}
}
fn write_event(event: Event) -> Result<(), Error> {
if let Some(mut events) = event.to_raw() {
return write_raw(events.as_mut_slice());
}
Ok(())
}
fn write_raw(events: &mut [INPUT]) -> Result<(), Error> {
let written = unsafe {
winuser::SendInput(
events.len() as _,
events.as_mut_ptr(),
std::mem::size_of_val(&events[0]) as _,
)
};
if written != 1 {
return Err(Error::last_os_error());
}
Ok(())
}