kbd_global/error.rs
1//! Error types for the kbd-global runtime.
2//!
3//! Errors are scoped to the operation that produces them:
4//!
5//! - [`StartupError`] — manager construction and engine spawn
6//! - [`RegisterError`] — binding registration (hotkeys, sequences, tap-hold)
7//! - [`LayerError`] — layer definition and stack operations
8//! - [`QueryError`] — hotkey queries that accept parseable input
9//! - [`ShutdownError`] — manager and engine shutdown
10//! - [`ManagerStopped`] — standalone error for simple queries with no
11//! domain failure modes
12
13/// The manager has been shut down or the engine thread has exited.
14///
15/// Returned standalone by query methods whose only failure mode is
16/// a dead engine, and as a variant inside other scoped error types.
17#[derive(Debug, thiserror::Error)]
18#[error("hotkey manager is no longer running")]
19pub struct ManagerStopped;
20
21/// Error returned when starting the manager or spawning the engine.
22///
23/// Covers device access, unsupported feature requests (e.g. grab mode
24/// without the `grab` feature), and engine thread failures.
25#[derive(Debug, thiserror::Error)]
26#[non_exhaustive]
27pub enum StartupError {
28 /// An input device operation failed (open, read, ioctl, etc.).
29 #[error("input device operation failed")]
30 Device,
31 /// The requested feature is not supported by the selected backend.
32 ///
33 /// Returned when calling [`HotkeyManagerBuilder::grab()`](crate::manager::HotkeyManagerBuilder::grab)
34 /// without the `grab` feature enabled.
35 #[error("requested feature is unsupported by the selected backend")]
36 UnsupportedFeature,
37 /// An internal engine failure occurred (thread panic, fd error, etc.).
38 #[error("hotkey engine encountered an internal failure")]
39 Engine,
40}
41
42impl From<kbd_evdev::error::Error> for StartupError {
43 fn from(error: kbd_evdev::error::Error) -> Self {
44 tracing::warn!(%error, "evdev backend error");
45 Self::Device
46 }
47}
48
49/// Error returned when registering a binding fails.
50///
51/// Covers hotkey registration, sequence registration, and tap-hold
52/// registration through the manager.
53#[derive(Debug, thiserror::Error)]
54#[non_exhaustive]
55pub enum RegisterError {
56 /// A hotkey string like `"Ctrl+A"` could not be parsed.
57 #[error("parse error: {0}")]
58 Parse(#[from] kbd::error::ParseHotkeyError),
59 /// The hotkey is already bound to another action.
60 #[error("hotkey registration conflicts with an existing binding")]
61 AlreadyRegistered,
62 /// The requested feature is not supported by the selected backend.
63 ///
64 /// Returned when registering a tap-hold binding without grab mode enabled.
65 #[error("requested feature is unsupported by the selected backend")]
66 UnsupportedFeature,
67 /// The manager has been shut down or the engine thread has exited.
68 #[error(transparent)]
69 ManagerStopped(#[from] ManagerStopped),
70}
71
72impl From<kbd::error::RegisterError> for RegisterError {
73 fn from(error: kbd::error::RegisterError) -> Self {
74 match error {
75 kbd::error::RegisterError::Parse(e) => Self::Parse(e),
76 kbd::error::RegisterError::AlreadyRegistered => Self::AlreadyRegistered,
77 _ => unreachable!("unknown kbd::error::RegisterError variant"),
78 }
79 }
80}
81
82/// Error returned when a layer operation fails.
83///
84/// Covers layer definition, push, pop, and toggle operations
85/// through the manager.
86#[derive(Debug, thiserror::Error)]
87#[non_exhaustive]
88pub enum LayerError {
89 /// A layer with the given name was already defined.
90 #[error("a layer with this name is already defined")]
91 AlreadyDefined,
92 /// No layer with the given name has been defined.
93 #[error("no layer with this name has been defined")]
94 NotDefined,
95 /// No active layers to pop from the stack.
96 #[error("no active layer to pop")]
97 EmptyStack,
98 /// The manager has been shut down or the engine thread has exited.
99 #[error(transparent)]
100 ManagerStopped(#[from] ManagerStopped),
101}
102
103impl From<kbd::error::LayerError> for LayerError {
104 fn from(error: kbd::error::LayerError) -> Self {
105 match error {
106 kbd::error::LayerError::AlreadyDefined => Self::AlreadyDefined,
107 kbd::error::LayerError::NotDefined => Self::NotDefined,
108 kbd::error::LayerError::EmptyStack => Self::EmptyStack,
109 _ => unreachable!("unknown kbd::error::LayerError variant"),
110 }
111 }
112}
113
114/// Error returned by query methods that accept parseable hotkey input.
115///
116/// Methods like [`is_registered()`](crate::manager::HotkeyManager::is_registered)
117/// and [`bindings_for_key()`](crate::manager::HotkeyManager::bindings_for_key)
118/// can fail from string parsing or a dead engine.
119#[derive(Debug, thiserror::Error)]
120#[non_exhaustive]
121pub enum QueryError {
122 /// A hotkey string could not be parsed.
123 #[error("parse error: {0}")]
124 Parse(#[from] kbd::error::ParseHotkeyError),
125 /// The manager has been shut down or the engine thread has exited.
126 #[error(transparent)]
127 ManagerStopped(#[from] ManagerStopped),
128}
129
130/// Error returned when shutting down the manager.
131#[derive(Debug, thiserror::Error)]
132#[non_exhaustive]
133pub enum ShutdownError {
134 /// An internal engine failure occurred (thread panic, mutex poison, etc.).
135 #[error("hotkey engine encountered an internal failure")]
136 Engine,
137 /// The manager has been shut down or the engine thread has exited.
138 #[error(transparent)]
139 ManagerStopped(#[from] ManagerStopped),
140}