diff --git a/espanso-detect/src/lib.rs b/espanso-detect/src/lib.rs index 60ad3f3..636caf0 100644 --- a/espanso-detect/src/lib.rs +++ b/espanso-detect/src/lib.rs @@ -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, + + // 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> { 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> { Ok(Box::new(evdev::EVDEVSource::new(options))) } -pub use layout::get_active_layout; \ No newline at end of file +pub use layout::get_active_layout; diff --git a/espanso-detect/src/win32/mod.rs b/espanso-detect/src/win32/mod.rs index 4c60f9d..7e5537e 100644 --- a/espanso-detect/src/win32/mod.rs +++ b/espanso-detect/src/win32/mod.rs @@ -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, hotkeys: Vec, + + 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 = 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()); diff --git a/espanso-detect/src/win32/native.cpp b/espanso-detect/src/win32/native.cpp index 04a5ad6..673ccdb 100644 --- a/espanso-detect/src/win32/native.cpp +++ b/espanso-detect/src/win32/native.cpp @@ -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; diff --git a/espanso-detect/src/win32/native.h b/espanso-detect/src/win32/native.h index c6e7dee..a93b9f7 100644 --- a/espanso-detect/src/win32/native.h +++ b/espanso-detect/src/win32/native.h @@ -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 {