1use std::sync::mpsc;
2
3use cue_sdk_sys as ffi;
4
5use crate::callback;
6use crate::device::DeviceId;
7use crate::error::{self, Result};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15#[repr(u32)]
16pub enum MacroKeyId {
17 Key1 = ffi::CorsairMacroKeyId_CMKI_1,
18 Key2 = ffi::CorsairMacroKeyId_CMKI_2,
19 Key3 = ffi::CorsairMacroKeyId_CMKI_3,
20 Key4 = ffi::CorsairMacroKeyId_CMKI_4,
21 Key5 = ffi::CorsairMacroKeyId_CMKI_5,
22 Key6 = ffi::CorsairMacroKeyId_CMKI_6,
23 Key7 = ffi::CorsairMacroKeyId_CMKI_7,
24 Key8 = ffi::CorsairMacroKeyId_CMKI_8,
25 Key9 = ffi::CorsairMacroKeyId_CMKI_9,
26 Key10 = ffi::CorsairMacroKeyId_CMKI_10,
27 Key11 = ffi::CorsairMacroKeyId_CMKI_11,
28 Key12 = ffi::CorsairMacroKeyId_CMKI_12,
29 Key13 = ffi::CorsairMacroKeyId_CMKI_13,
30 Key14 = ffi::CorsairMacroKeyId_CMKI_14,
31 Key15 = ffi::CorsairMacroKeyId_CMKI_15,
32 Key16 = ffi::CorsairMacroKeyId_CMKI_16,
33 Key17 = ffi::CorsairMacroKeyId_CMKI_17,
34 Key18 = ffi::CorsairMacroKeyId_CMKI_18,
35 Key19 = ffi::CorsairMacroKeyId_CMKI_19,
36 Key20 = ffi::CorsairMacroKeyId_CMKI_20,
37}
38
39impl MacroKeyId {
40 pub(crate) fn from_ffi(raw: ffi::CorsairMacroKeyId) -> Option<Self> {
41 match raw {
42 ffi::CorsairMacroKeyId_CMKI_1 => Some(Self::Key1),
43 ffi::CorsairMacroKeyId_CMKI_2 => Some(Self::Key2),
44 ffi::CorsairMacroKeyId_CMKI_3 => Some(Self::Key3),
45 ffi::CorsairMacroKeyId_CMKI_4 => Some(Self::Key4),
46 ffi::CorsairMacroKeyId_CMKI_5 => Some(Self::Key5),
47 ffi::CorsairMacroKeyId_CMKI_6 => Some(Self::Key6),
48 ffi::CorsairMacroKeyId_CMKI_7 => Some(Self::Key7),
49 ffi::CorsairMacroKeyId_CMKI_8 => Some(Self::Key8),
50 ffi::CorsairMacroKeyId_CMKI_9 => Some(Self::Key9),
51 ffi::CorsairMacroKeyId_CMKI_10 => Some(Self::Key10),
52 ffi::CorsairMacroKeyId_CMKI_11 => Some(Self::Key11),
53 ffi::CorsairMacroKeyId_CMKI_12 => Some(Self::Key12),
54 ffi::CorsairMacroKeyId_CMKI_13 => Some(Self::Key13),
55 ffi::CorsairMacroKeyId_CMKI_14 => Some(Self::Key14),
56 ffi::CorsairMacroKeyId_CMKI_15 => Some(Self::Key15),
57 ffi::CorsairMacroKeyId_CMKI_16 => Some(Self::Key16),
58 ffi::CorsairMacroKeyId_CMKI_17 => Some(Self::Key17),
59 ffi::CorsairMacroKeyId_CMKI_18 => Some(Self::Key18),
60 ffi::CorsairMacroKeyId_CMKI_19 => Some(Self::Key19),
61 ffi::CorsairMacroKeyId_CMKI_20 => Some(Self::Key20),
62 _ => None,
63 }
64 }
65}
66
67#[derive(Debug, Clone)]
73pub enum Event {
74 DeviceConnectionChanged {
76 device_id: DeviceId,
77 is_connected: bool,
78 },
79 KeyEvent {
81 device_id: DeviceId,
82 key_id: MacroKeyId,
83 is_pressed: bool,
84 },
85}
86
87impl Event {
88 pub(crate) fn from_ffi(raw: &ffi::CorsairEvent) -> Option<Self> {
90 match raw.id {
91 ffi::CorsairEventId_CEI_DeviceConnectionStatusChangedEvent => {
92 let inner = unsafe { &*raw.event_union.deviceConnectionStatusChangedEvent };
96 Some(Event::DeviceConnectionChanged {
97 device_id: DeviceId::from_ffi(inner.deviceId),
98 is_connected: inner.isConnected,
99 })
100 }
101 ffi::CorsairEventId_CEI_KeyEvent => {
102 let inner = unsafe { &*raw.event_union.keyEvent };
105 let key_id = MacroKeyId::from_ffi(inner.keyId)?;
106 Some(Event::KeyEvent {
107 device_id: DeviceId::from_ffi(inner.deviceId),
108 key_id,
109 is_pressed: inner.isPressed,
110 })
111 }
112 _ => None,
113 }
114 }
115}
116
117pub struct EventSubscription {
127 rx: mpsc::Receiver<Event>,
128 _sender: callback::EventSender,
130}
131
132impl EventSubscription {
133 pub(crate) fn new(sender: callback::EventSender, rx: mpsc::Receiver<Event>) -> Result<Self> {
135 let ctx = callback::sender_as_context(&sender);
136 error::check(unsafe {
139 ffi::CorsairSubscribeForEvents(Some(callback::event_trampoline), ctx)
140 })?;
141 Ok(Self {
142 rx,
143 _sender: sender,
144 })
145 }
146
147 pub fn recv(&self) -> Option<Event> {
149 self.rx.recv().ok()
150 }
151
152 pub fn try_recv(&self) -> Option<Event> {
154 self.rx.try_recv().ok()
155 }
156
157 pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
159 self.rx.iter()
160 }
161}
162
163impl Drop for EventSubscription {
164 fn drop(&mut self) {
165 unsafe {
169 let _ = ffi::CorsairUnsubscribeFromEvents();
170 }
171 }
172}
173
174#[cfg(feature = "async")]
186pub struct AsyncEventSubscription {
187 rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
188 _sender: callback::AsyncEventSender,
190}
191
192#[cfg(feature = "async")]
193impl AsyncEventSubscription {
194 pub(crate) fn new(
197 sender: callback::AsyncEventSender,
198 rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
199 ) -> Result<Self> {
200 let ctx = callback::async_sender_as_context(&sender);
201 error::check(unsafe {
205 ffi::CorsairSubscribeForEvents(Some(callback::async_event_trampoline), ctx)
206 })?;
207 Ok(Self {
208 rx,
209 _sender: sender,
210 })
211 }
212
213 pub async fn recv(&mut self) -> Option<Event> {
218 self.rx.recv().await
219 }
220}
221
222#[cfg(feature = "async")]
223impl Drop for AsyncEventSubscription {
224 fn drop(&mut self) {
225 unsafe {
229 let _ = ffi::CorsairUnsubscribeFromEvents();
230 }
231 }
232}