fret_runtime/
shortcut_routing_diagnostics.rs1use std::collections::HashMap;
2use std::sync::Arc;
3
4use fret_core::{AppWindowId, FrameId, KeyCode, Modifiers};
5
6use crate::CommandId;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ShortcutRoutingPhase {
14 PreDispatch,
15 PostDispatch,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum ShortcutRoutingOutcome {
20 ReservedForIme,
22 ConsumedByWidget,
24 CommandDispatched,
26 CommandDisabled,
28 SequenceContinuation,
30 SequenceReplay,
32 NoMatch,
34 NoKeymap,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct ShortcutRoutingDecision {
40 pub seq: u64,
41 pub frame_id: FrameId,
42 pub phase: ShortcutRoutingPhase,
43 pub key: KeyCode,
44 pub modifiers: Modifiers,
45 pub repeat: bool,
46 pub deferred: bool,
47 pub focus_is_text_input: bool,
48 pub ime_composing: bool,
49 pub pending_sequence_len: u32,
50 pub outcome: ShortcutRoutingOutcome,
51 pub command: Option<CommandId>,
52 pub command_enabled: Option<bool>,
53 pub key_contexts: Vec<Arc<str>>,
54}
55
56#[derive(Default)]
57pub struct WindowShortcutRoutingDiagnosticsStore {
58 next_seq: u64,
59 per_window: HashMap<AppWindowId, Vec<ShortcutRoutingDecision>>,
60}
61
62impl WindowShortcutRoutingDiagnosticsStore {
63 const MAX_ENTRIES_PER_WINDOW: usize = 128;
64
65 pub fn record(&mut self, window: AppWindowId, mut decision: ShortcutRoutingDecision) {
66 decision.seq = self.next_seq;
67 self.next_seq = self.next_seq.saturating_add(1);
68
69 let entries = self.per_window.entry(window).or_default();
70 entries.push(decision);
71 if entries.len() > Self::MAX_ENTRIES_PER_WINDOW {
72 let extra = entries.len().saturating_sub(Self::MAX_ENTRIES_PER_WINDOW);
73 entries.drain(0..extra);
74 }
75 }
76
77 pub fn snapshot_since(
78 &self,
79 window: AppWindowId,
80 since_seq: u64,
81 max_entries: usize,
82 ) -> Vec<ShortcutRoutingDecision> {
83 let Some(entries) = self.per_window.get(&window) else {
84 return Vec::new();
85 };
86 entries
87 .iter()
88 .filter(|e| e.seq >= since_seq)
89 .take(max_entries)
90 .cloned()
91 .collect()
92 }
93}