1use anyhow::{Result, anyhow};
7use core::fmt;
8use kanata_keyberon::key_code::KeyCode;
9
10use crate::{cfg::SimpleSExpr, keys::OsCode};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub enum CustomAction {
14 Cmd(&'static [&'static str]),
15 CmdLog(LogLevel, LogLevel, &'static [&'static str]),
16 CmdOutputKeys(&'static [&'static str]),
17 PushMessage(&'static [SimpleSExpr]),
18 Unicode(char),
19 Mouse(Btn),
20 MouseTap(Btn),
21 FakeKey {
22 coord: Coord,
23 action: FakeKeyAction,
24 },
25 FakeKeyOnRelease {
26 coord: Coord,
27 action: FakeKeyAction,
28 },
29 FakeKeyOnIdle(FakeKeyOnIdle),
30 FakeKeyOnPhysicalIdle(FakeKeyOnIdle),
31 FakeKeyHoldForDuration(FakeKeyHoldForDuration),
32 Delay(u16),
33 DelayOnRelease(u16),
34 MWheel {
35 direction: MWheelDirection,
36 interval: u16,
37 distance: u16,
38 inertial_scroll_params: Option<&'static MWheelInertial>,
39 },
40 MWheelNotch {
41 direction: MWheelDirection,
42 },
43 MoveMouse {
44 direction: MoveDirection,
45 interval: u16,
46 distance: u16,
47 },
48 MoveMouseAccel {
49 direction: MoveDirection,
50 interval: u16,
51 accel_time: u16,
52 min_distance: u16,
53 max_distance: u16,
54 },
55 MoveMouseSpeed {
56 speed: u16,
57 },
58 SequenceCancel,
59 SequenceLeader(u16, SequenceInputMode),
60 SequenceNoerase(u16),
66 LiveReload,
67 LiveReloadNext,
68 LiveReloadPrev,
69 LiveReloadNum(u16),
73 LiveReloadFile(&'static str),
74 Repeat,
75 CancelMacroOnRelease,
76 CancelMacroOnNextPress(u32),
77 DynamicMacroRecord(u16),
78 DynamicMacroRecordStop(u16),
79 DynamicMacroPlay(u16),
80 SendArbitraryCode(u16),
81 CapsWord(CapsWordCfg),
82 SetMouse {
83 x: u16,
84 y: u16,
85 },
86 Unmodded {
87 keys: &'static [KeyCode],
88 mods: UnmodMods,
89 },
90 Unshifted {
91 keys: &'static [KeyCode],
92 },
93 ReverseReleaseOrder,
94 ClipboardSet(&'static str),
95 ClipboardCmdSet(&'static [&'static str]),
96 ClipboardSave(u16),
97 ClipboardRestore(u16),
98 ClipboardSaveSet(u16, &'static str),
99 ClipboardSaveCmdSet(u16, &'static [&'static str]),
100 ClipboardSaveSwap(u16, u16),
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104pub enum Btn {
105 Left,
106 Right,
107 Mid,
108 Forward,
109 Backward,
110}
111
112impl fmt::Display for Btn {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match self {
115 Btn::Left => write!(f, "‹🖰"),
116 Btn::Right => write!(f, "🖰›"),
117 Btn::Mid => write!(f, "🖱"),
118 Btn::Backward => write!(f, "⎌🖰"),
119 Btn::Forward => write!(f, "🖰↷"),
120 }
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
125pub struct Coord {
126 pub x: u8,
127 pub y: u16,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub enum FakeKeyAction {
132 Press,
133 Release,
134 Tap,
135 Toggle,
136}
137
138#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
140pub struct FakeKeyOnIdle {
141 pub coord: Coord,
142 pub action: FakeKeyAction,
143 pub idle_duration: u16,
144}
145
146#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
149pub struct FakeKeyHoldForDuration {
150 pub coord: Coord,
151 pub hold_duration: u16,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
155pub enum MWheelDirection {
156 Up,
157 Down,
158 Left,
159 Right,
160}
161impl fmt::Display for MWheelDirection {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 match self {
164 MWheelDirection::Up => write!(f, "🖱↑"),
165 MWheelDirection::Down => write!(f, "🖱↓"),
166 MWheelDirection::Left => write!(f, "🖱←"),
167 MWheelDirection::Right => write!(f, "🖱→"),
168 }
169 }
170}
171
172impl TryFrom<OsCode> for MWheelDirection {
173 type Error = ();
174 fn try_from(value: OsCode) -> Result<Self, Self::Error> {
175 use OsCode::*;
176 Ok(match value {
177 MouseWheelUp => MWheelDirection::Up,
178 MouseWheelDown => MWheelDirection::Down,
179 MouseWheelLeft => MWheelDirection::Left,
180 MouseWheelRight => MWheelDirection::Right,
181 _ => return Err(()),
182 })
183 }
184}
185
186#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
187pub struct MWheelInertial {
188 pub initial_velocity: ordered_float::OrderedFloat<f32>,
189 pub maximum_velocity: ordered_float::OrderedFloat<f32>,
190 pub acceleration_multiplier: ordered_float::OrderedFloat<f32>,
191 pub deceleration_multiplier: ordered_float::OrderedFloat<f32>,
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195pub enum MoveDirection {
196 Up,
197 Down,
198 Left,
199 Right,
200}
201impl fmt::Display for MoveDirection {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 match self {
204 MoveDirection::Up => write!(f, "↑"),
205 MoveDirection::Down => write!(f, "↓"),
206 MoveDirection::Left => write!(f, "←"),
207 MoveDirection::Right => write!(f, "→"),
208 }
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Hash)]
213pub struct CapsWordCfg {
214 pub keys_to_capitalize: &'static [KeyCode],
215 pub keys_nonterminal: &'static [KeyCode],
216 pub timeout: u16,
217 pub repress_behaviour: CapsWordRepressBehaviour,
218}
219
220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
221pub enum CapsWordRepressBehaviour {
222 Overwrite,
223 Toggle,
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
237pub enum SequenceInputMode {
238 HiddenSuppressed,
239 HiddenDelayType,
240 VisibleBackspaced,
241}
242
243const SEQ_VISIBLE_BACKSPACED: &str = "visible-backspaced";
244const SEQ_HIDDEN_SUPPRESSED: &str = "hidden-suppressed";
245const SEQ_HIDDEN_DELAY_TYPE: &str = "hidden-delay-type";
246
247impl SequenceInputMode {
248 pub fn try_from_str(s: &str) -> Result<Self> {
249 match s {
250 SEQ_VISIBLE_BACKSPACED => Ok(SequenceInputMode::VisibleBackspaced),
251 SEQ_HIDDEN_SUPPRESSED => Ok(SequenceInputMode::HiddenSuppressed),
252 SEQ_HIDDEN_DELAY_TYPE => Ok(SequenceInputMode::HiddenDelayType),
253 _ => Err(anyhow!(SequenceInputMode::err_msg())),
254 }
255 }
256
257 pub fn err_msg() -> String {
258 format!(
259 "sequence input mode must be one of: {SEQ_VISIBLE_BACKSPACED}, {SEQ_HIDDEN_SUPPRESSED}, {SEQ_HIDDEN_DELAY_TYPE}"
260 )
261 }
262}
263
264const LOG_LEVEL_DEBUG: &str = "debug";
265const LOG_LEVEL_INFO: &str = "info";
266const LOG_LEVEL_WARN: &str = "warn";
267const LOG_LEVEL_ERROR: &str = "error";
268const LOG_LEVEL_NONE: &str = "none";
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
271pub enum LogLevel {
272 Debug,
274 Info,
275 Warn,
276 Error,
277 None,
278}
279
280impl LogLevel {
281 pub fn try_from_str(s: &str) -> Result<Self> {
282 match s {
283 LOG_LEVEL_DEBUG => Ok(LogLevel::Debug),
284 LOG_LEVEL_INFO => Ok(LogLevel::Info),
285 LOG_LEVEL_WARN => Ok(LogLevel::Warn),
286 LOG_LEVEL_ERROR => Ok(LogLevel::Error),
287 LOG_LEVEL_NONE => Ok(LogLevel::None),
288 _ => Err(anyhow!(LogLevel::err_msg())),
289 }
290 }
291
292 pub fn get_level(&self) -> Option<log::Level> {
293 match self {
294 LogLevel::Debug => Some(log::Level::Debug),
295 LogLevel::Info => Some(log::Level::Info),
296 LogLevel::Warn => Some(log::Level::Warn),
297 LogLevel::Error => Some(log::Level::Error),
298 LogLevel::None => None,
299 }
300 }
301
302 pub fn err_msg() -> String {
303 format!(
304 "log level must be one of: {LOG_LEVEL_DEBUG}, {LOG_LEVEL_INFO}, {LOG_LEVEL_WARN}, {LOG_LEVEL_ERROR}, {LOG_LEVEL_NONE}"
305 )
306 }
307}
308
309#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
310pub struct UnmodMods(u8);
311
312bitflags::bitflags! {
313 impl UnmodMods: u8 {
314 const LSft = 0b00000001;
315 const RSft = 0b00000010;
316 const LAlt = 0b00000100;
317 const RAlt = 0b00001000;
318 const LCtl = 0b00010000;
319 const RCtl = 0b00100000;
320 const LMet = 0b01000000;
321 const RMet = 0b10000000;
322 }
323}