use crate::emit_handler::{Emit, EmitHandler};
use crate::event::Event;
use crate::event_handler::PRESS;
use crate::operators::{ActiveOperator, OperatorAction, StaticOperator};
use evdev::KeyCode as Key;
use std::collections::HashMap;
use std::usize;
pub struct OperatorHandler {
active: Vec<Box<dyn ActiveOperator>>,
candidates: Option<Candidates>,
lookup_map: HashMap<Key, Vec<Box<dyn StaticOperator>>>,
emit_handler: EmitHandler,
}
impl OperatorHandler {
pub fn new(operators: Vec<Box<dyn StaticOperator>>) -> OperatorHandler {
let mut lookup_map: HashMap<Key, Vec<Box<dyn StaticOperator>>> = HashMap::new();
for operator in &operators {
for (key, op) in operator.get_operators() {
match lookup_map.get_mut(&key) {
Some(current) => current.push(op),
None => {
lookup_map.insert(key, vec![op]);
}
};
}
}
OperatorHandler {
active: vec![],
candidates: None,
lookup_map,
emit_handler: EmitHandler::new(),
}
}
#[cfg(test)]
pub fn assert_base_state(&self) {
assert!(self.active.is_empty());
assert!(self.candidates.is_none());
}
#[cfg(test)]
pub fn assert_emitted_modifiers_are_synced(&self) {
self.emit_handler.assert_emitted_modifiers_are_synced();
}
pub fn map_events(&mut self, events: Vec<Event>) -> Vec<Event> {
events
.into_iter()
.flat_map(|event| {
self.emit_handler.on_event(&event);
let events = process_event(event, &mut self.active, &mut self.candidates, &self.lookup_map);
self.emit_handler.map_output(events)
})
.collect()
}
}
#[derive(Debug)]
enum CandidateState {
Canceled,
Done,
Matching,
}
#[derive(Debug)]
struct Candidate {
operator: Box<dyn ActiveOperator>,
state: CandidateState,
emitted: Vec<Emit>,
unhandled: Vec<Event>,
}
#[derive(Debug)]
struct Candidates {
start_event: Event,
events: Vec<Event>,
operators: Vec<Candidate>,
}
enum Node {
Event(Event),
Operator(Box<dyn ActiveOperator>),
CandidateChosen(usize),
CandidatesCanceled,
}
fn process_event(
event: Event,
right: &mut Vec<Box<dyn ActiveOperator>>,
candidates: &mut Option<Candidates>,
lookup_map: &HashMap<Key, Vec<Box<dyn StaticOperator>>>,
) -> Vec<Emit> {
let mut emit: Vec<Emit> = vec![];
let mut left: Vec<Node> = vec![Node::Event(event)];
loop {
match left.pop() {
Some(Node::Event(event)) => {
match right.pop() {
Some(mut operator) => match operator.on_event(&event) {
OperatorAction::Undecided => {
right.push(operator);
}
OperatorAction::Cancel => {
unreachable!()
}
OperatorAction::Unhandled => {
left.push(Node::Operator(operator));
left.push(Node::Event(event));
}
OperatorAction::Partial(emitted, unhandled) => {
right.push(operator);
emit.extend(emitted);
unhandled_back_to_stack(unhandled, &mut left);
}
OperatorAction::Done(new_emit, unhandled) => {
emit.extend(new_emit);
unhandled_back_to_stack(unhandled, &mut left);
}
},
None => {
match candidates {
Some(candidates) => try_candidates(event, &mut left, candidates),
None => static_lookup(event, candidates, &lookup_map, &mut emit),
};
}
};
}
Some(Node::Operator(operator)) => {
right.push(operator);
}
Some(Node::CandidateChosen(chosen)) => {
let candidate = candidates.take().unwrap().operators.into_iter().nth(chosen).unwrap();
emit.extend(candidate.emitted);
if !matches!(candidate.state, CandidateState::Done) {
right.push(candidate.operator);
}
unhandled_back_to_stack(candidate.unhandled, &mut left);
}
Some(Node::CandidatesCanceled) => {
let taken = candidates.take().unwrap();
emit.push(Emit::Single(taken.start_event.clone()));
unhandled_back_to_stack(taken.events, &mut left);
}
None => {
return emit;
}
};
}
}
fn unhandled_back_to_stack(events: Vec<Event>, nodes: &mut Vec<Node>) {
nodes.extend(
events
.iter()
.rev()
.map(|event| Node::Event(event.clone()))
.collect::<Vec<_>>(),
);
}
fn try_candidates(event: Event, left: &mut Vec<Node>, candidates: &mut Candidates) {
candidates.events.push(event.clone());
let mut first = true;
for (usize, candidate) in candidates.operators.iter_mut().enumerate() {
match candidate.state {
CandidateState::Canceled => {
continue;
}
CandidateState::Done => {
if first {
if !matches!(event, Event::Tick) {
todo!()
}
candidate.unhandled.push(event.clone());
left.push(Node::CandidateChosen(usize));
return;
} else {
candidate.unhandled.push(event.clone());
}
}
CandidateState::Matching => {
match candidate.operator.on_event(&event) {
OperatorAction::Undecided => {
first = false;
}
OperatorAction::Cancel => {
candidate.state = CandidateState::Canceled;
}
OperatorAction::Unhandled => {
candidate.unhandled.push(event.clone());
if first {
left.push(Node::CandidateChosen(usize));
return;
}
}
OperatorAction::Partial(new_emit, unhandled) => {
candidate.emitted.extend(new_emit);
candidate.unhandled.extend(unhandled);
if first {
left.push(Node::CandidateChosen(usize));
return;
}
}
OperatorAction::Done(new_emit, unhandled) => {
candidate.emitted.extend(new_emit);
candidate.unhandled.extend(unhandled);
candidate.state = CandidateState::Done;
if first {
left.push(Node::CandidateChosen(usize));
return;
}
}
};
}
};
}
if first {
left.push(Node::CandidatesCanceled);
}
}
fn static_lookup(
event: Event,
candidates: &mut Option<Candidates>,
lookup_map: &HashMap<Key, Vec<Box<dyn StaticOperator>>>,
emit: &mut Vec<Emit>,
) {
let (device, key_event) = match &event {
Event::KeyEvent(device, key_event) => (device, key_event),
Event::Tick => {
return;
}
_ => {
emit.push(Emit::Single(event));
return;
}
};
if key_event.value() != PRESS {
emit.push(Emit::key_event(device.clone(), key_event.clone()));
return;
}
match lookup_map.get(&key_event.key) {
Some(operators) => {
debug_assert!(!operators.is_empty());
debug_assert!(candidates.is_none());
let new_candidates: Vec<_> = operators
.iter()
.map(|operator| Candidate {
operator: operator.get_active_operator(&event),
state: CandidateState::Matching,
emitted: vec![],
unhandled: vec![],
})
.collect();
candidates.replace(Candidates {
start_event: event,
events: vec![],
operators: new_candidates,
});
}
None => {
emit.push(Emit::key_event(device.clone(), key_event.clone()));
}
};
}