fix(detect): exclude software-generated events by default on Windows to avoid reading back espanso's events

This commit is contained in:
Federico Terzi 2021-08-22 21:45:49 +02:00
parent 2129494ae3
commit 53eef3ce7b
4 changed files with 39 additions and 3 deletions

View File

@ -60,6 +60,12 @@ pub struct SourceCreationOptions {
// List of global hotkeys the detection module has to register
// NOTE: Hotkeys don't work under the EVDEV backend yet (Wayland)
pub hotkeys: Vec<HotKey>,
// If true, filter out keyboard events without an explicit HID device source on Windows.
// This is needed to filter out the software-generated events, including
// those from espanso, but might need to be disabled when using some software-level keyboards.
// Disabling this option might conflict with the undo feature.
pub win32_exclude_orphan_events: bool,
}
// This struct identifies the keyboard layout that
@ -80,6 +86,7 @@ impl Default for SourceCreationOptions {
use_evdev: false,
evdev_keyboard_rmlvo: None,
hotkeys: Vec::new(),
win32_exclude_orphan_events: true,
}
}
}
@ -87,7 +94,7 @@ impl Default for SourceCreationOptions {
#[cfg(target_os = "windows")]
pub fn get_source(options: SourceCreationOptions) -> Result<Box<dyn Source>> {
info!("using Win32Source");
Ok(Box::new(win32::Win32Source::new(&options.hotkeys)))
Ok(Box::new(win32::Win32Source::new(&options.hotkeys, options.win32_exclude_orphan_events)))
}
#[cfg(target_os = "macos")]
@ -115,4 +122,4 @@ pub fn get_source(options: SourceCreationOptions) -> Result<Box<dyn Source>> {
Ok(Box::new(evdev::EVDEVSource::new(options)))
}
pub use layout::get_active_layout;
pub use layout::get_active_layout;

View File

@ -64,6 +64,12 @@ pub struct RawInputEvent {
pub key_code: i32,
pub variant: i32,
pub status: i32,
// Only relevant for keyboard events, this is set to 1
// if a keyboard event has an explicit source, 0 otherwise.
// This is needed to filter out software generated events,
// including those from espanso.
pub has_known_source: i32,
}
#[repr(C)]
@ -91,15 +97,18 @@ pub struct Win32Source {
handle: *mut c_void,
callback: LazyCell<SourceCallback>,
hotkeys: Vec<HotKey>,
exclude_orphan_events: bool,
}
#[allow(clippy::new_without_default)]
impl Win32Source {
pub fn new(hotkeys: &[HotKey]) -> Win32Source {
pub fn new(hotkeys: &[HotKey], exclude_orphan_events: bool) -> Win32Source {
Self {
handle: std::ptr::null_mut(),
callback: LazyCell::new(),
hotkeys: hotkeys.to_vec(),
exclude_orphan_events,
}
}
}
@ -148,6 +157,16 @@ impl Source for Win32Source {
}
extern "C" fn callback(_self: *mut Win32Source, event: RawInputEvent) {
// Filter out keyboard events without an explicit HID device source.
// This is needed to filter out the software-generated events, including
// those from espanso.
if event.event_type == INPUT_EVENT_TYPE_KEYBOARD && event.has_known_source == 0 {
if unsafe { (*_self).exclude_orphan_events } {
trace!("skipping keyboard event with unknown HID source (probably software generated).");
return;
}
}
let event: Option<InputEvent> = event.into();
if let Some(callback) = unsafe { (*_self).callback.borrow() } {
if let Some(event) = event {
@ -391,6 +410,7 @@ mod tests {
key_code: 0,
variant: INPUT_LEFT_VARIANT,
status: INPUT_STATUS_PRESSED,
has_known_source: 1,
}
}
@ -459,6 +479,7 @@ mod tests {
key_code: 123,
variant: INPUT_LEFT_VARIANT,
status: INPUT_STATUS_PRESSED,
has_known_source: 1,
}
.into();
assert!(result.is_none());

View File

@ -121,6 +121,8 @@ LRESULT CALLBACK detect_window_procedure(HWND window, unsigned int msg, WPARAM w
return 0;
}
event.has_known_source = (raw->header.hDevice == 0) ? 0 : 1;
// The alt key sends a SYSKEYDOWN instead of KEYDOWN event
int is_key_down = raw->data.keyboard.Message == WM_KEYDOWN ||
raw->data.keyboard.Message == WM_SYSKEYDOWN;

View File

@ -60,6 +60,12 @@ typedef struct {
// Pressed or Released status
int32_t status;
// Only relevant for keyboard events, this is set to 1
// if a keyboard event has an explicit source, 0 otherwise.
// This is needed to filter out software generated events,
// including those from espanso.
int32_t has_known_source;
} InputEvent;
typedef struct {