RKTK API Docs RKTK Home Repo

kmsm/state/
hid_report.rs

1use heapless::Vec;
2use usbd_hid::descriptor::{KeyboardReport, MediaKeyboardReport, MouseReport};
3
4use crate::{
5    interface::state::{
6        KeymapInfo,
7        input_event::InputEvent,
8        output_event::{EventType, OutputEvent},
9    },
10    keycode::KeyCode,
11};
12
13#[derive(Debug, PartialEq, Clone)]
14pub struct Report {
15    pub keyboard_report: Option<KeyboardReport>,
16    pub mouse_report: Option<MouseReport>,
17    pub media_keyboard_report: Option<MediaKeyboardReport>,
18    pub highest_layer: u8,
19}
20
21pub struct HidReportState<
22    const LAYER: usize,
23    const ROW: usize,
24    const COL: usize,
25    const ENCODER_COUNT: usize,
26    const NORMAL_MAX_PRESSED_KEYS: usize,
27    const ONESHOT_STATE_SIZE: usize,
28    const TAP_DANCE_MAX_DEFINITIONS: usize,
29    const TAP_DANCE_MAX_REPEATS: usize,
30    const COMBO_KEY_MAX_DEFINITIONS: usize,
31    const COMBO_KEY_MAX_SOURCES: usize,
32> {
33    state: super::State<
34        LAYER,
35        ROW,
36        COL,
37        ENCODER_COUNT,
38        NORMAL_MAX_PRESSED_KEYS,
39        ONESHOT_STATE_SIZE,
40        TAP_DANCE_MAX_DEFINITIONS,
41        TAP_DANCE_MAX_REPEATS,
42        COMBO_KEY_MAX_DEFINITIONS,
43        COMBO_KEY_MAX_SOURCES,
44    >,
45    next_send_keyboard_report: bool,
46    next_send_mkb_report: bool,
47}
48
49impl<
50    const LAYER: usize,
51    const ROW: usize,
52    const COL: usize,
53    const ENCODER_COUNT: usize,
54    const NORMAL_MAX_PRESSED_KEYS: usize,
55    const ONESHOT_STATE_SIZE: usize,
56    const TAP_DANCE_MAX_DEFINITIONS: usize,
57    const TAP_DANCE_MAX_REPEATS: usize,
58    const COMBO_KEY_MAX_DEFINITIONS: usize,
59    const COMBO_KEY_MAX_SOURCES: usize,
60>
61    HidReportState<
62        LAYER,
63        ROW,
64        COL,
65        ENCODER_COUNT,
66        NORMAL_MAX_PRESSED_KEYS,
67        ONESHOT_STATE_SIZE,
68        TAP_DANCE_MAX_DEFINITIONS,
69        TAP_DANCE_MAX_REPEATS,
70        COMBO_KEY_MAX_DEFINITIONS,
71        COMBO_KEY_MAX_SOURCES,
72    >
73{
74    pub fn new(
75        keymap: crate::keymap::Keymap<
76            LAYER,
77            ROW,
78            COL,
79            ENCODER_COUNT,
80            TAP_DANCE_MAX_DEFINITIONS,
81            TAP_DANCE_MAX_REPEATS,
82            COMBO_KEY_MAX_DEFINITIONS,
83            COMBO_KEY_MAX_SOURCES,
84        >,
85        config: crate::interface::state::config::StateConfig,
86    ) -> Self {
87        Self {
88            state: super::State::new(keymap, config),
89            next_send_keyboard_report: false,
90            next_send_mkb_report: false,
91        }
92    }
93
94    pub fn update(&mut self, event: InputEvent, since_last_update: core::time::Duration) -> Report {
95        self.update_with_cb(event, since_last_update, |_| {})
96    }
97
98    pub fn update_with_cb(
99        &mut self,
100        event: InputEvent,
101        since_last_update: core::time::Duration,
102        mut cb: impl FnMut(OutputEvent),
103    ) -> Report {
104        let mut keyboard_change = self.next_send_keyboard_report;
105        self.next_send_keyboard_report = false;
106        let mut keys: Vec<u8, 6> = Vec::new();
107        let mut modifier = 0u8;
108
109        let mut mouse_change = false;
110        let mut movement = (0, 0);
111        let mut scroll = (0, 0);
112        let mut mouse_buttons = 0u8;
113
114        let mut media_keyboard_change = self.next_send_mkb_report;
115        let mut media_keys = 0u16;
116
117        self.state.update(event, since_last_update, |ev| {
118            match ev {
119                OutputEvent::KeyCode((kc, ev)) => {
120                    match kc {
121                        KeyCode::Key(key) => {
122                            if ev != EventType::Pressing {
123                                keyboard_change = true;
124                            }
125                            if ev != EventType::Released && !keys.contains(&(key as u8)) {
126                                let _ = keys.push(key as u8);
127                            }
128                            // If both `Pressing` and `Released` events are sent same time, that means key
129                            // should be released in next report.
130                            if ev == EventType::Released && keys.contains(&(key as u8)) {
131                                self.next_send_keyboard_report = true;
132                            }
133                        }
134                        KeyCode::Media(m) => {
135                            if ev != EventType::Pressing {
136                                media_keyboard_change = true;
137                            }
138                            if ev != EventType::Released {
139                                media_keys = m as u16;
140                            }
141                            if ev == EventType::Released && media_keys == m as u16 {
142                                self.next_send_mkb_report = true;
143                            }
144                        }
145                        KeyCode::Modifier(m) => {
146                            if ev != EventType::Pressing {
147                                keyboard_change = true;
148                            }
149                            if ev != EventType::Released {
150                                modifier |= m as u8;
151                            }
152                        }
153                        KeyCode::Mouse(m) => {
154                            if ev != EventType::Pressing {
155                                mouse_change = true;
156                            }
157                            if ev != EventType::Released {
158                                mouse_buttons |= m as u8;
159                            }
160                        }
161                        // Other types of key codes will not appear as the HID report.
162                        _ => {}
163                    }
164                }
165                OutputEvent::MouseMove(m) => {
166                    mouse_change = true;
167                    movement.0 += m.0;
168                    movement.1 += m.1;
169                }
170                OutputEvent::MouseScroll((pan, wheel)) => {
171                    mouse_change = true;
172                    scroll.0 += pan;
173                    scroll.1 += wheel;
174                }
175            }
176            cb(ev);
177        });
178
179        Report {
180            keyboard_report: if keyboard_change {
181                keys.resize_default(6).unwrap();
182                let keycodes = keys.into_array().unwrap();
183                Some(KeyboardReport {
184                    keycodes,
185                    modifier,
186                    leds: 0,
187                    reserved: 0,
188                })
189            } else {
190                None
191            },
192            mouse_report: if mouse_change {
193                Some(MouseReport {
194                    buttons: mouse_buttons,
195                    x: movement.0,
196                    y: movement.1,
197                    pan: scroll.0,
198                    wheel: scroll.1,
199                })
200            } else {
201                None
202            },
203            media_keyboard_report: if media_keyboard_change {
204                Some(MediaKeyboardReport {
205                    usage_id: media_keys,
206                })
207            } else {
208                None
209            },
210            highest_layer: self.state.shared.highest_layer() as u8,
211        }
212    }
213
214    pub fn inner(
215        &self,
216    ) -> &super::State<
217        LAYER,
218        ROW,
219        COL,
220        ENCODER_COUNT,
221        NORMAL_MAX_PRESSED_KEYS,
222        ONESHOT_STATE_SIZE,
223        TAP_DANCE_MAX_DEFINITIONS,
224        TAP_DANCE_MAX_REPEATS,
225        COMBO_KEY_MAX_DEFINITIONS,
226        COMBO_KEY_MAX_SOURCES,
227    > {
228        &self.state
229    }
230
231    pub fn get_keymap_info() -> KeymapInfo {
232        KeymapInfo {
233            layer_count: LAYER as u8,
234            max_tap_dance_key_count: TAP_DANCE_MAX_DEFINITIONS as u8,
235            max_tap_dance_repeat_count: TAP_DANCE_MAX_REPEATS as u8,
236            oneshot_state_size: ONESHOT_STATE_SIZE as u8,
237        }
238    }
239}