#![cfg_attr(
not(target_os = "windows"),
allow(dead_code, reason = "only the Windows store traces keys")
)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub(crate) struct KeyTrace {
pending: Option<u32>,
taken: bool,
}
impl KeyTrace {
pub(crate) fn trace_down(&mut self, vk: u32) {
self.pending = Some(vk);
}
pub(crate) fn window_key_down(&mut self, vk: u32) {
if self.pending == Some(vk) {
self.pending = None;
}
}
pub(crate) fn trace_up(&mut self, vk: u32) {
if self.pending == Some(vk) {
self.pending = None;
self.taken = true;
}
}
pub(crate) fn take_taken(&mut self) -> bool {
std::mem::take(&mut self.taken)
}
}
#[cfg(test)]
mod tests {
use super::*;
const VK_OEM_3: u32 = 0xC0;
const VK_DOWN: u32 = 0x28;
const VK_MENU: u32 = 0x12;
#[test]
fn a_key_with_no_window_key_down_between_its_traces_was_taken() {
let mut trace = KeyTrace::default();
trace.trace_down(VK_MENU);
trace.window_key_down(VK_MENU);
trace.trace_down(VK_OEM_3);
trace.trace_up(VK_OEM_3);
assert!(trace.take_taken());
assert!(!trace.take_taken(), "asked once");
}
#[test]
fn a_key_passed_on_was_not_taken() {
let mut trace = KeyTrace::default();
trace.trace_down(VK_DOWN);
trace.window_key_down(VK_DOWN);
trace.trace_up(VK_DOWN);
trace.trace_down(VK_MENU);
trace.window_key_down(VK_MENU);
trace.trace_up(VK_MENU);
assert!(!trace.take_taken());
}
#[test]
fn a_key_down_for_another_key_does_not_pass_this_one_on() {
let mut trace = KeyTrace::default();
trace.trace_down(VK_OEM_3);
trace.window_key_down(VK_DOWN);
trace.trace_up(VK_OEM_3);
assert!(trace.take_taken());
}
}