zmk_studio_api/
hid_usage.rs1use std::fmt;
2
3use crate::keycode::Keycode;
4
5pub const HID_USAGE_KEYBOARD: u16 = 0x07;
6
7pub const MOD_LCTL: u8 = 0x01;
8pub const MOD_LSFT: u8 = 0x02;
9pub const MOD_LALT: u8 = 0x04;
10pub const MOD_LGUI: u8 = 0x08;
11pub const MOD_RCTL: u8 = 0x10;
12pub const MOD_RSFT: u8 = 0x20;
13pub const MOD_RALT: u8 = 0x40;
14pub const MOD_RGUI: u8 = 0x80;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct HidUsage {
19 page: u16,
20 id: u16,
21 modifiers: u8,
22}
23
24impl HidUsage {
25 pub fn from_encoded(encoded: u32) -> Self {
34 let mut page = ((encoded >> 16) & 0xFF) as u16;
35 if page == 0 {
36 page = HID_USAGE_KEYBOARD;
37 }
38
39 Self {
40 page,
41 id: (encoded & 0xFFFF) as u16,
42 modifiers: (encoded >> 24) as u8,
43 }
44 }
45
46 pub fn from_parts(page: u16, id: u16, modifiers: u8) -> Self {
47 Self {
48 page,
49 id,
50 modifiers,
51 }
52 }
53
54 pub fn to_hid_usage(self) -> u32 {
55 ((self.modifiers as u32) << 24) | ((self.page as u32) << 16) | self.id as u32
56 }
57
58 pub fn page(self) -> u16 {
59 self.page
60 }
61
62 pub fn id(self) -> u16 {
63 self.id
64 }
65
66 pub fn modifiers(self) -> u8 {
67 self.modifiers
68 }
69
70 pub fn base(self) -> Self {
71 Self {
72 page: self.page,
73 id: self.id,
74 modifiers: 0,
75 }
76 }
77
78 pub fn known_keycode(self) -> Option<Keycode> {
79 Keycode::from_hid_usage(self.to_hid_usage())
80 }
81
82 pub fn known_base_keycode(self) -> Option<Keycode> {
83 Keycode::from_hid_usage(self.base().to_hid_usage())
84 }
85
86 pub fn modifier_labels(self) -> Vec<&'static str> {
87 let mut labels = Vec::new();
88 let mods = self.modifiers;
89 if mods & MOD_LCTL != 0 {
90 labels.push("LCTL");
91 }
92 if mods & MOD_LSFT != 0 {
93 labels.push("LSFT");
94 }
95 if mods & MOD_LALT != 0 {
96 labels.push("LALT");
97 }
98 if mods & MOD_LGUI != 0 {
99 labels.push("LGUI");
100 }
101 if mods & MOD_RCTL != 0 {
102 labels.push("RCTL");
103 }
104 if mods & MOD_RSFT != 0 {
105 labels.push("RSFT");
106 }
107 if mods & MOD_RALT != 0 {
108 labels.push("RALT");
109 }
110 if mods & MOD_RGUI != 0 {
111 labels.push("RGUI");
112 }
113 labels
114 }
115}
116
117impl fmt::Display for HidUsage {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 if let Some(keycode) = self.known_keycode() {
120 return f.write_str(keycode.to_name());
121 }
122
123 write!(
124 f,
125 "0x{:02X}{:02X}{:02X}{:02X}",
126 self.modifiers,
127 self.page,
128 (self.id >> 8) as u8,
129 self.id as u8
130 )
131 }
132}