From 78451d122a0cddc36d43459623c02c9ce01a9eb4 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Wed, 18 Sep 2019 10:28:34 +0200 Subject: [PATCH] Fix bug on Windows that prevented ALT key from being registered correctly --- native/libwinbridge/bridge.cpp | 13 +++++++--- native/libwinbridge/bridge.h | 2 +- src/bridge/windows.rs | 2 +- src/context/windows.rs | 47 ++++++++++++++++++---------------- src/install.rs | 19 ++++++++++---- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/native/libwinbridge/bridge.cpp b/native/libwinbridge/bridge.cpp index 449ed67..e5a4b27 100644 --- a/native/libwinbridge/bridge.cpp +++ b/native/libwinbridge/bridge.cpp @@ -205,8 +205,15 @@ LRESULT CALLBACK window_procedure(HWND window, unsigned int msg, WPARAM wp, LPAR RAWINPUT* raw = reinterpret_cast(lpb.data()); // Make sure it's a keyboard type event, relative to a key press. - if (raw->header.dwType == RIM_TYPEKEYBOARD && raw->data.keyboard.Message == WM_KEYDOWN) + if (raw->header.dwType == RIM_TYPEKEYBOARD) { + // We only want KEY UP AND KEY DOWN events + if (raw->data.keyboard.Message != WM_KEYDOWN && raw->data.keyboard.Message != WM_KEYUP) { + return 0; + } + + int is_key_down = raw->data.keyboard.Message == WM_KEYDOWN; + DWORD currentTick = GetTickCount(); // If enough time has passed between the last keypress and now, refresh the keyboard layout @@ -241,9 +248,9 @@ LRESULT CALLBACK window_procedure(HWND window, unsigned int msg, WPARAM wp, LPAR // We need to call the callback in two different ways based on the type of key // The only modifier we use that has a result > 0 is the BACKSPACE, so we have to consider it. if (result >= 1 && raw->data.keyboard.VKey != VK_BACK) { - keypress_callback(manager_instance, reinterpret_cast(buffer.data()), buffer.size(), 0, raw->data.keyboard.VKey); + keypress_callback(manager_instance, reinterpret_cast(buffer.data()), buffer.size(), 0, raw->data.keyboard.VKey, is_key_down); }else{ - keypress_callback(manager_instance, nullptr, 0, 1, raw->data.keyboard.VKey); + keypress_callback(manager_instance, nullptr, 0, 1, raw->data.keyboard.VKey, is_key_down); } } } diff --git a/native/libwinbridge/bridge.h b/native/libwinbridge/bridge.h index ef20f7e..e9ddbf8 100644 --- a/native/libwinbridge/bridge.h +++ b/native/libwinbridge/bridge.h @@ -39,7 +39,7 @@ extern "C" int32_t initialize(void * self, wchar_t * ico_path, wchar_t * bmp_pat * Called when a new keypress is made, the first argument is an int array, * while the second is the size of the array. */ -typedef void (*KeypressCallback)(void * self, int32_t *buffer, int32_t len, int32_t is_modifier, int32_t key_code); +typedef void (*KeypressCallback)(void * self, int32_t *buffer, int32_t len, int32_t is_modifier, int32_t key_code, int32_t is_key_down); extern KeypressCallback keypress_callback; /* diff --git a/src/bridge/windows.rs b/src/bridge/windows.rs index 40480a5..6866cbe 100644 --- a/src/bridge/windows.rs +++ b/src/bridge/windows.rs @@ -50,7 +50,7 @@ extern { // KEYBOARD pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const i32, - i32, i32, i32)); + i32, i32, i32, i32)); pub fn eventloop(); pub fn send_string(string: *const u16); diff --git a/src/context/windows.rs b/src/context/windows.rs index bb11f96..d45715f 100644 --- a/src/context/windows.rs +++ b/src/context/windows.rs @@ -103,33 +103,36 @@ impl super::Context for WindowsContext { // Native bridge code extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const i32, len: i32, - is_modifier: i32, key_code: i32) { + is_modifier: i32, key_code: i32, is_key_down: i32) { unsafe { let _self = _self as *mut WindowsContext; + if is_key_down != 0 { // KEY DOWN EVENT + if is_modifier == 0 { // Char event + // Convert the received buffer to a character + let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); + let r = std::char::from_u32(buffer[0] as u32); - if is_modifier == 0 { // Char event - // Convert the received buffer to a character - let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); - let r = std::char::from_u32(buffer[0] as u32); - - // Send the char through the channel - if let Some(c) = r { - let event = Event::Key(KeyEvent::Char(c)); - (*_self).send_channel.send(event).unwrap(); + // Send the char through the channel + if let Some(c) = r { + let event = Event::Key(KeyEvent::Char(c)); + (*_self).send_channel.send(event).unwrap(); + } } - }else{ // Modifier event - let modifier: Option = match key_code { - 0x5B | 0x5C => Some(META), - 0x10 => Some(SHIFT), - 0x12 => Some(ALT), - 0x11 => Some(CTRL), - 0x08 => Some(BACKSPACE), - _ => None, - }; + }else{ // KEY UP event + if is_modifier != 0 { // Modifier event + let modifier: Option = match key_code { + 0x5B | 0x5C => Some(META), + 0x10 => Some(SHIFT), + 0x12 => Some(ALT), + 0x11 => Some(CTRL), + 0x08 => Some(BACKSPACE), + _ => None, + }; - if let Some(modifier) = modifier { - let event = Event::Key(KeyEvent::Modifier(modifier)); - (*_self).send_channel.send(event).unwrap(); + if let Some(modifier) = modifier { + let event = Event::Key(KeyEvent::Modifier(modifier)); + (*_self).send_channel.send(event).unwrap(); + } } } } diff --git a/src/install.rs b/src/install.rs index afdfe60..bd14c28 100644 --- a/src/install.rs +++ b/src/install.rs @@ -20,8 +20,6 @@ // This functions are used to register/unregister espanso from the system daemon manager. use crate::config::ConfigSet; -use std::fs::create_dir_all; -use std::process::{Command, ExitStatus}; // INSTALLATION @@ -36,7 +34,10 @@ const MAC_PLIST_CONTENT : &str = include_str!("res/mac/com.federicoterzi.espanso const MAC_PLIST_FILENAME : &str = "com.federicoterzi.espanso.plist"; #[cfg(target_os = "macos")] -pub fn install(config_set: ConfigSet) { +pub fn install(_config_set: ConfigSet) { + use std::fs::create_dir_all; + use std::process::{Command, ExitStatus}; + let home_dir = dirs::home_dir().expect("Could not get user home directory"); let library_dir = home_dir.join("Library"); let agents_dir = library_dir.join("LaunchAgents"); @@ -81,7 +82,10 @@ pub fn install(config_set: ConfigSet) { } #[cfg(target_os = "macos")] -pub fn uninstall(config_set: ConfigSet) { +pub fn uninstall(_config_set: ConfigSet) { + use std::fs::create_dir_all; + use std::process::{Command, ExitStatus}; + let home_dir = dirs::home_dir().expect("Could not get user home directory"); let library_dir = home_dir.join("Library"); let agents_dir = library_dir.join("LaunchAgents"); @@ -101,6 +105,11 @@ pub fn uninstall(config_set: ConfigSet) { } #[cfg(target_os = "windows")] -pub fn install(config_set: ConfigSet) { +pub fn install(_config_set: ConfigSet) { + println!("Windows does not support system daemon integration.") +} + +#[cfg(target_os = "windows")] +pub fn uninstall(_config_set: ConfigSet) { println!("Windows does not support system daemon integration.") } \ No newline at end of file