kanata-evsieve 1.3.1

evsieve functionality for use by kanata
Documentation
// SPDX-License-Identifier: GPL-2.0-or-later

use std::collections::HashMap;

use crate::event::{Channel, Event};
use crate::key::Key;

/// Represents a --merge argument.
pub struct Merge {
    /// The keys that are subject to getting merged by this argument.
    keys: Vec<Key>,

    /// How many down events each (type, code, domain) pair has.
    state: HashMap<Channel, usize>,
}

impl Merge {
    pub fn new(keys: Vec<Key>) -> Merge {
        Merge {
            keys,
            state: HashMap::new(),
        }
    }

    #[allow(clippy::needless_return)]
    fn apply(&mut self, event: Event, output_events: &mut Vec<Event>) {
        // If this merge is not applicable to this event, silently pass it on.
        if !event.ev_type().is_key() || !self.keys.iter().any(|key| key.matches(&event)) {
            output_events.push(event);
            return;
        }

        let current_down_count: &mut usize = self.state.entry(event.channel()).or_insert(0);
        let last_down_count: usize = *current_down_count;
        match event.value {
            // If this is a KEY_DOWN (1) event, add one to the down count.
            1 => *current_down_count += 1,
            // If this is a KEY_UP (0) event, substract one from the down count, but never go below zero.
            0 => *current_down_count = current_down_count.saturating_sub(1),
            // Otherwise, silently pass on and ignore this event.
            _ => {
                output_events.push(event);
                return;
            }
        }

        match (last_down_count, event.value) {
            // If a KEY_UP event let to the down count becoming zero, or a KEY_DOWN event let to the
            // count becoming one, write it to the output. Importantly, do not pass the event on in
            // case a KEY_UP event resulted into the event staying zero (last: 0, current: 0).
            (1, 0) | (0, 1) => output_events.push(event),
            // Otherwise, drop this event.
            _ => return,
        }
    }

    pub fn apply_to_all(&mut self, events: &[Event], output_events: &mut Vec<Event>) {
        for &event in events {
            self.apply(event, output_events);
        }
    }
}