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