KeyState uses flag to determine event type instead of seperate parameter

added is_down method to KeyState
added more tests
add get_flag and has_one_bit_set functions to lib.rs
change main.rs to use is_down instead of w_param for checking event type
This commit is contained in:
LordMZTE 2020-09-01 01:18:34 +02:00
parent dde124e76a
commit ee15231a47
3 changed files with 67 additions and 10 deletions

View file

@ -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());
}
}

View file

@ -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));
}
}

View file

@ -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
}