diff --git a/src/key/keystate.rs b/src/key/keystate.rs index 60b7f8c..d652fe5 100644 --- a/src/key/keystate.rs +++ b/src/key/keystate.rs @@ -1,7 +1,8 @@ use std::ffi::OsString; -use winapi::um::winuser::{GetKeyNameTextW, KBDLLHOOKSTRUCT, LLKHF_EXTENDED}; +use winapi::um::winuser::{GetKeyNameTextW, KBDLLHOOKSTRUCT, LLKHF_EXTENDED, LLKHF_UP}; use wio::wide::FromWide; +use crate::get_flag; #[allow(clippy::struct_excessive_bools)] pub struct KeyState { @@ -31,7 +32,8 @@ impl KeyState { } /// `key_down` if the event was a keydown event, this should be true. if it was keyup it should be false - pub fn update(&mut self, key: KBDLLHOOKSTRUCT, key_down: bool) { + pub fn update(&mut self, key: KBDLLHOOKSTRUCT) { + let key_down = !get_flag(key.flags, LLKHF_UP); self.kbdllstruct = key; match key.vkCode { @@ -40,7 +42,7 @@ impl KeyState { 164 | 165 => self.alt_down = key_down, 91 => self.win_down = key_down, _ => {}, - } + }; } /// true if the key is an auxiliary key like shift, control or the windows key @@ -48,22 +50,28 @@ impl KeyState { matches!(self.kbdllstruct.vkCode, 160..=165 | 91) } - #[no_mangle] + #[no_mangle] //required to not get garbage from native call pub fn name(&self) -> String { unsafe { - #[allow(clippy::if_not_else)] //clippy wrongfully assumes the != here is unecessary - let flags = if self.kbdllstruct.flags & LLKHF_EXTENDED != 0 { 1 << 24 } else { 0 }; + let flags = if get_flag(self.kbdllstruct.flags, LLKHF_EXTENDED) { 1 << 24 } else { 0 }; + let mut out = [0_u16; 128]; GetKeyNameTextW((self.kbdllstruct.scanCode << 16 | flags /*this distinguishes special keys by setting a flag. yes only microsoft thinks that input and flags in 1 param is a good idea*/) as i32, (&mut out).as_mut_ptr(), 128); let null_pos = out.iter().position(|x| *x == b'\0' as u16).unwrap_or_else(|| out.len()); OsString::from_wide(&out[..null_pos]).to_str().unwrap().to_owned() } } + + ///true if this event is keydown, otherwise false + pub fn is_down(&self) -> bool { + !get_flag(self.kbdllstruct.flags, LLKHF_UP) + } } #[cfg(test)] mod tests { use crate::key::keystate::KeyState; + use winapi::um::winuser::LLKHF_UP; #[test] fn is_aux_key() { @@ -71,4 +79,17 @@ mod tests { k.kbdllstruct.vkCode = 160; assert!(k.is_aux_key()); } + + #[test] + fn is_down() { + let mut k = KeyState::new(); + + k.kbdllstruct.flags = LLKHF_UP; + + assert!(!k.is_down()); + + k.kbdllstruct.flags = 0; + + assert!(k.is_down()); + } } diff --git a/src/lib.rs b/src/lib.rs index 206b236..e236e29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,46 @@ //disable silly rules #![allow( clippy::module_name_repetitions, //complains about function names which makes no sense, so disabled -clippy::must_use_candidate, //no i dont wannt to add the must_use attribute to everything +clippy::must_use_candidate, //no i dont want to add the must_use attribute to everything clippy::cast_lossless, clippy::cast_possible_wrap, //lossy casts are required to work with garbage WinApi )] //endregion pub mod logging; pub mod key; + +///gets the flag at the position of `flag`. `flag` must have exactly 1 bit set +fn get_flag(val: u32, flag: u32) -> bool { + if has_one_bit_set(flag) { + val & flag != 0 + } else { + panic!("flag must have 1 bit set") + } +} + +///true if exactly 1 bit of the given number is set +fn has_one_bit_set(n: u32) -> bool { + //Dont ask me why this works! its mathgic! + n > 0 && !(n & (n - 1) > 0) +} + +#[cfg(test)] +mod tests { + #[test] + fn get_flag() { + assert!(super::get_flag(5, 1 << 2)); + assert!(!super::get_flag(3, 1 << 2)); + } + + #[test] + #[should_panic] + fn get_flag_panic() { + super::get_flag(0, 3); + } + + #[test] + fn has_one_bit_set() { + assert!(super::has_one_bit_set(1)); + assert!(!super::has_one_bit_set(3)); + } +} diff --git a/src/main.rs b/src/main.rs index 9fd31ba..4aa37a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,12 +21,12 @@ fn main() { } } -unsafe extern "system" fn hook_callback(_code: i32, w_param: usize, l_param: isize) -> isize { +unsafe extern "system" fn hook_callback(_code: i32, _w_param: usize, l_param: isize) -> isize { let mut state = KEYSTATE.lock().unwrap(); let key = *(l_param as PKBDLLHOOKSTRUCT); - state.update(key, w_param == 256); + state.update(key); //Check if keydown and not aux key - if w_param != 256 || state.is_aux_key() { return 0; } + if state.is_down() || state.is_aux_key() { return 0; } LOGGER.log(&state); 0 }