wooting_analog_common/
lib.rs

1#[macro_use]
2extern crate enum_primitive_derive;
3extern crate ffi_support;
4extern crate num_traits;
5
6use ffi_support::FfiStr;
7pub use num_traits::{FromPrimitive, ToPrimitive};
8#[cfg(feature = "serdes")]
9use serde::{Deserialize, Serialize};
10use std::ffi::{CStr, CString};
11use std::ops::Deref;
12use std::os::raw::{c_char, c_int};
13use thiserror::Error;
14
15#[cfg(target_os = "macos")]
16pub const DEFAULT_PLUGIN_DIR: &str = "/usr/local/share/WootingAnalogPlugins";
17#[cfg(target_os = "linux")]
18pub const DEFAULT_PLUGIN_DIR: &str = "/usr/local/share/WootingAnalogPlugins";
19#[cfg(target_os = "windows")]
20pub const DEFAULT_PLUGIN_DIR: &str = "C:\\Program Files\\WootingAnalogPlugins";
21
22/// The core `DeviceInfo` struct which contains all the interesting information
23/// for a particular device. This is for use internally and should be ignored if you're
24/// trying to use it when trying to interact with the SDK using the wrapper
25#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
26#[derive(Clone, Debug)]
27pub struct DeviceInfo {
28    /// Device Vendor ID `vid`
29    pub vendor_id: u16,
30    /// Device Product ID `pid`
31    pub product_id: u16,
32    /// Device Manufacturer name
33    pub manufacturer_name: String,
34    /// Device name
35    pub device_name: String,
36    /// Unique device ID, which should be generated using `generate_device_id`
37    pub device_id: DeviceID,
38    /// Hardware type of the Device
39    pub device_type: DeviceType,
40}
41
42/// The core `DeviceInfo` struct which contains all the interesting information
43/// for a particular device. This is the version which the consumer of the SDK will receive
44/// through the wrapper. This is not for use in the Internal workings of the SDK, that is what
45/// DeviceInfo is for
46#[repr(C)]
47pub struct DeviceInfo_FFI {
48    /// Device Vendor ID `vid`
49    pub vendor_id: u16,
50    /// Device Product ID `pid`
51    pub product_id: u16,
52    /// Device Manufacturer name
53    pub manufacturer_name: *mut c_char,
54    /// Device name
55    pub device_name: *mut c_char,
56    /// Unique device ID, which should be generated using `generate_device_id`
57    pub device_id: DeviceID,
58    /// Hardware type of the Device
59    pub device_type: DeviceType,
60}
61
62impl From<DeviceInfo> for DeviceInfo_FFI {
63    fn from(device: DeviceInfo) -> Self {
64        DeviceInfo_FFI {
65            vendor_id: device.vendor_id,
66            product_id: device.product_id,
67            manufacturer_name: CString::new(device.manufacturer_name).unwrap().into_raw(),
68            device_name: CString::new(device.device_name).unwrap().into_raw(),
69            device_id: device.device_id,
70            device_type: device.device_type,
71        }
72    }
73}
74
75impl Drop for DeviceInfo_FFI {
76    fn drop(&mut self) {
77        //Ensure we properly drop the memory for the char pointers
78        unsafe {
79            let _c_string = CString::from_raw(self.manufacturer_name);
80            let _c_string = CString::from_raw(self.device_name);
81        }
82    }
83}
84
85impl DeviceInfo_FFI {
86    pub fn into_device_info(&self) -> DeviceInfo {
87        DeviceInfo {
88            vendor_id: self.vendor_id.clone(),
89            product_id: self.product_id.clone(),
90            // In this case we use CStr rather than CString as we don't want the memory to be dropped here which may cause a double free
91            // We leave it up to ffi interface to drop the memory
92            manufacturer_name: unsafe {
93                CStr::from_ptr(self.manufacturer_name)
94                    .to_str()
95                    .unwrap()
96                    .to_owned()
97            },
98            device_name: unsafe {
99                CStr::from_ptr(self.device_name)
100                    .to_str()
101                    .unwrap()
102                    .to_owned()
103            },
104            device_id: self.device_id.clone(),
105            device_type: self.device_type.clone(),
106        }
107    }
108}
109
110impl DeviceInfo {
111    //    pub fn new(
112    //        vendor_id: u16,
113    //        product_id: u16,
114    //        manufacturer_name: &str,
115    //        device_name: &str,
116    //        serial_number: &str,
117    //        device_type: DeviceType,
118    //    ) -> Self {
119    //        DeviceInfo {
120    //            vendor_id,
121    //            product_id,
122    //            manufacturer_name,
123    //            device_name,
124    //            device_id: generate_device_id(serial_number, vendor_id, product_id),
125    //            device_type
126    //        }
127    //    }
128
129    pub fn new_with_id(
130        vendor_id: u16,
131        product_id: u16,
132        manufacturer_name: String,
133        device_name: String,
134        device_id: DeviceID,
135        device_type: DeviceType,
136    ) -> Self {
137        DeviceInfo {
138            vendor_id,
139            product_id,
140            manufacturer_name,
141            device_name,
142            device_id,
143            device_type,
144        }
145    }
146}
147
148/// Create a new device info struct. This is only for use in Plugins that are written in C
149/// Rust plugins should use the native constructor
150/// The memory for the struct has been allocated in Rust. So `drop_device_info` must be called
151/// for the memory to be properly released
152#[no_mangle]
153pub extern "C" fn new_device_info(
154    vendor_id: u16,
155    product_id: u16,
156    manufacturer_name: *mut c_char,
157    device_name: *mut c_char,
158    device_id: DeviceID,
159    device_type: DeviceType,
160) -> *mut DeviceInfo {
161    Box::into_raw(Box::new(DeviceInfo::new_with_id(
162        vendor_id,
163        product_id,
164        unsafe {
165            CStr::from_ptr(manufacturer_name)
166                .to_string_lossy()
167                .into_owned()
168        },
169        unsafe { CStr::from_ptr(device_name).to_string_lossy().into_owned() },
170        device_id,
171        device_type,
172    )))
173}
174
175/// Drops the given `DeviceInfo`
176#[no_mangle]
177pub unsafe extern "C" fn drop_device_info(device: *mut DeviceInfo) {
178    Box::from_raw(device);
179}
180
181#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
182#[derive(Debug, PartialEq, Clone, Primitive)]
183#[repr(C)]
184pub enum KeycodeType {
185    /// USB HID Keycodes https://www.usb.org/document-library/hid-usage-tables-112 pg53
186    HID = 0,
187    /// Scan code set 1
188    ScanCode1 = 1,
189    /// Windows Virtual Keys
190    VirtualKey = 2,
191    /// Windows Virtual Keys which are translated to the current keyboard locale
192    VirtualKeyTranslate = 3,
193}
194
195pub type DeviceID = u64;
196
197#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
198#[derive(Debug, PartialEq, Clone, Primitive)]
199#[repr(C)]
200pub enum DeviceType {
201    /// Device is of type Keyboard
202    Keyboard = 1,
203    /// Device is of type Keypad
204    Keypad = 2,
205    /// Device
206    Other = 3,
207}
208
209#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
210#[derive(Debug, PartialEq, Clone, Primitive)]
211#[repr(C)]
212pub enum DeviceEventType {
213    /// Device has been connected
214    Connected = 1,
215    /// Device has been disconnected
216    Disconnected = 2,
217}
218
219#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
220#[derive(Debug, PartialEq, Clone, Primitive, Error)]
221#[repr(C)]
222pub enum WootingAnalogResult {
223    #[error("All OK")]
224    Ok = 1,
225    /// Item hasn't been initialized
226    #[error("SDK has not been initialized")]
227    UnInitialized = -2000isize,
228    /// No Devices are connected
229    #[error("No Devices are connected")]
230    NoDevices = -1999isize,
231    /// Device has been disconnected
232    #[error("Device has been disconnected")]
233    DeviceDisconnected = -1998isize,
234    /// Generic Failure
235    #[error("Generic Failure")]
236    Failure = -1997isize,
237    /// A given parameter was invalid
238    #[error("A given parameter was invalid")]
239    InvalidArgument = -1996isize,
240    /// No Plugins were found
241    #[error("No Plugins were found")]
242    NoPlugins = -1995isize,
243    /// The specified function was not found in the library
244    #[error("The specified function was not found in the library")]
245    FunctionNotFound = -1994isize,
246    /// No Keycode mapping to HID was found for the given Keycode
247    #[error("No Keycode mapping to HID was found for the given Keycode")]
248    NoMapping = -1993isize,
249    /// Indicates that it isn't available on this platform
250    #[error("Unavailable on this platform")]
251    NotAvailable = -1992isize,
252    /// Indicates that the operation that is trying to be used is for an older version
253    #[error("Incompatible SDK Version")]
254    IncompatibleVersion = -1991isize,
255    /// Indicates that the Analog SDK could not be found on the system
256    #[error("The Wooting Analog SDK could not be found on the system")]
257    DLLNotFound = -1990isize,
258}
259
260impl WootingAnalogResult {
261    pub fn is_ok(&self) -> bool {
262        *self == WootingAnalogResult::Ok
263    }
264
265    pub fn is_ok_or_no_device(&self) -> bool {
266        *self == WootingAnalogResult::Ok || *self == WootingAnalogResult::NoDevices
267    }
268}
269
270impl Default for WootingAnalogResult {
271    fn default() -> Self {
272        WootingAnalogResult::FunctionNotFound
273    }
274}
275
276#[derive(Debug)]
277pub struct SDKResult<T>(pub std::result::Result<T, WootingAnalogResult>);
278
279impl<T> Default for SDKResult<T> {
280    fn default() -> Self {
281        Err(Default::default()).into()
282    }
283}
284
285impl<T> Deref for SDKResult<T> {
286    type Target = std::result::Result<T, WootingAnalogResult>;
287
288    fn deref(&self) -> &Self::Target {
289        &self.0
290    }
291}
292
293impl<T> From<std::result::Result<T, WootingAnalogResult>> for SDKResult<T> {
294    fn from(ptr: std::result::Result<T, WootingAnalogResult>) -> Self {
295        SDKResult(ptr)
296    }
297}
298
299impl<T> Into<std::result::Result<T, WootingAnalogResult>> for SDKResult<T> {
300    fn into(self) -> std::result::Result<T, WootingAnalogResult> {
301        self.0
302    }
303}
304
305//TODO: Figure out a way to not have to use this for the lib_wrap_option in the sdk
306impl<'a> From<FfiStr<'a>> for SDKResult<FfiStr<'a>> {
307    fn from(res: FfiStr<'a>) -> Self {
308        Ok(res).into()
309    }
310}
311
312impl From<c_int> for SDKResult<c_int> {
313    fn from(res: c_int) -> Self {
314        if res >= 0 {
315            Ok(res).into()
316        } else {
317            Err(WootingAnalogResult::from_i32(res).unwrap_or(WootingAnalogResult::Failure)).into()
318        }
319    }
320}
321
322impl From<c_int> for SDKResult<u32> {
323    fn from(res: c_int) -> Self {
324        if res >= 0 {
325            Ok(res as u32).into()
326        } else {
327            Err(WootingAnalogResult::from_i32(res).unwrap_or(WootingAnalogResult::Failure)).into()
328        }
329    }
330}
331
332impl Into<c_int> for WootingAnalogResult {
333    fn into(self) -> c_int {
334        self as c_int
335    }
336}
337
338impl From<u32> for SDKResult<u32> {
339    fn from(res: u32) -> Self {
340        Ok(res).into()
341    }
342}
343
344impl Into<i32> for SDKResult<u32> {
345    fn into(self) -> i32 {
346        match self.0 {
347            Ok(v) => v as i32,
348            Err(e) => e.into(),
349        }
350    }
351}
352
353impl Into<c_int> for SDKResult<c_int> {
354    fn into(self) -> c_int {
355        match self.0 {
356            Ok(v) => v,
357            Err(e) => e.into(),
358        }
359    }
360}
361
362impl From<f32> for SDKResult<f32> {
363    fn from(res: f32) -> Self {
364        if res >= 0.0 {
365            Ok(res).into()
366        } else {
367            Err(WootingAnalogResult::from_f32(res).unwrap_or(WootingAnalogResult::Failure)).into()
368        }
369    }
370}
371
372impl Into<f32> for WootingAnalogResult {
373    fn into(self) -> f32 {
374        (self as i32) as f32
375    }
376}
377
378impl Into<f32> for SDKResult<f32> {
379    fn into(self) -> f32 {
380        match self.0 {
381            Ok(v) => v,
382            Err(e) => e.into(),
383        }
384    }
385}
386
387impl Into<WootingAnalogResult> for SDKResult<()> {
388    fn into(self) -> WootingAnalogResult {
389        match self.0 {
390            Ok(_) => WootingAnalogResult::Ok,
391            Err(e) => e,
392        }
393    }
394}
395
396impl From<WootingAnalogResult> for SDKResult<()> {
397    fn from(res: WootingAnalogResult) -> Self {
398        if res.is_ok() {
399            Ok(()).into()
400        } else {
401            Err(res).into()
402        }
403    }
404}
405
406impl Into<bool> for WootingAnalogResult {
407    fn into(self) -> bool {
408        self == WootingAnalogResult::Ok
409    }
410}
411
412#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
413#[derive(Debug, PartialEq, Clone, Hash, Eq, Primitive)]
414#[repr(C)]
415pub enum HIDCodes {
416    A = 0x04,
417    B = 0x05, //US_B
418    C = 0x06, //US_C
419    D = 0x07, //US_D
420
421    E = 0x08, //US_E
422    F = 0x09, //US_F
423    G = 0x0a, //US_G
424    H = 0x0b, //US_H
425    I = 0x0c, //US_I
426    J = 0x0d, //US_J
427    K = 0x0e, //US_K
428    L = 0x0f, //US_L
429
430    M = 0x10, //US_M
431    N = 0x11, //US_N
432    O = 0x12, //US_O
433    P = 0x13, //US_P
434    Q = 0x14, //US_Q
435    R = 0x15, //US_R
436    S = 0x16, //US_S
437    T = 0x17, //US_T
438
439    U = 0x18,  //US_U
440    V = 0x19,  //US_V
441    W = 0x1a,  //US_W
442    X = 0x1b,  //US_X
443    Y = 0x1c,  //US_Y
444    Z = 0x1d,  //US_Z
445    N1 = 0x1e, //DIGIT1
446    N2 = 0x1f, //DIGIT2
447
448    N3 = 0x20, //DIGIT3
449    N4 = 0x21, //DIGIT4
450    N5 = 0x22, //DIGIT5
451    N6 = 0x23, //DIGIT6
452    N7 = 0x24, //DIGIT7
453    N8 = 0x25, //DIGIT8
454    N9 = 0x26, //DIGIT9
455    N0 = 0x27, //DIGIT0
456
457    Enter = 0x28,       //ENTER
458    Escape = 0x29,      //ESCAPE
459    Backspace = 0x2a,   //BACKSPACE
460    Tab = 0x2b,         //TAB
461    Space = 0x2c,       //SPACE
462    Minus = 0x2d,       //MINUS
463    Equal = 0x2e,       //EQUAL
464    BracketLeft = 0x2f, //BRACKET_LEFT
465
466    BracketRight = 0x30, //BRACKET_RIGHT
467    Backslash = 0x31,    //BACKSLASH
468
469    // = 0x32, //INTL_HASH
470    Semicolon = 0x33, //SEMICOLON
471    Quote = 0x34,     //QUOTE
472    Backquote = 0x35, //BACKQUOTE
473    Comma = 0x36,     //COMMA
474    Period = 0x37,    //PERIOD
475
476    Slash = 0x38,    //SLASH
477    CapsLock = 0x39, //CAPS_LOCK
478    F1 = 0x3a,       //F1
479    F2 = 0x3b,       //F2
480    F3 = 0x3c,       //F3
481    F4 = 0x3d,       //F4
482    F5 = 0x3e,       //F5
483    F6 = 0x3f,       //F6
484
485    F7 = 0x40,          //F7
486    F8 = 0x41,          //F8
487    F9 = 0x42,          //F9
488    F10 = 0x43,         //F10
489    F11 = 0x44,         //F11
490    F12 = 0x45,         //F12
491    PrintScreen = 0x46, //PRINT_SCREEN
492    ScrollLock = 0x47,  //SCROLL_LOCK
493
494    PauseBreak = 0x48, //PAUSE
495    Insert = 0x49,     //INSERT
496    Home = 0x4a,       //HOME
497    PageUp = 0x4b,     //PAGE_UP
498    Delete = 0x4c,     //DEL
499    End = 0x4d,        //END
500    PageDown = 0x4e,   //PAGE_DOWN
501    ArrowRight = 0x4f, //ARROW_RIGHT
502
503    ArrowLeft = 0x50,      //ARROW_LEFT
504    ArrowDown = 0x51,      //ARROW_DOWN
505    ArrowUp = 0x52,        //ARROW_UP
506    NumLock = 0x53,        //NUM_LOCK
507    NumpadDivide = 0x54,   //NUMPAD_DIVIDE
508    NumpadMultiply = 0x55, //NUMPAD_MULTIPLY
509    NumpadSubtract = 0x56, //NUMPAD_SUBTRACT
510    NumpadAdd = 0x57,      //NUMPAD_ADD
511
512    NumpadEnter = 0x58, //NUMPAD_ENTER
513    Numpad1 = 0x59,     //NUMPAD1
514    Numpad2 = 0x5a,     //NUMPAD2
515    Numpad3 = 0x5b,     //NUMPAD3
516    Numpad4 = 0x5c,     //NUMPAD4
517    Numpad5 = 0x5d,     //NUMPAD5
518    Numpad6 = 0x5e,     //NUMPAD6
519    Numpad7 = 0x5f,     //NUMPAD7
520
521    Numpad8 = 0x60,                //NUMPAD8
522    Numpad9 = 0x61,                //NUMPAD9
523    Numpad0 = 0x62,                //NUMPAD0
524    NumpadDecimal = 0x63,          //NUMPAD_DECIMAL
525    InternationalBackslash = 0x64, //INTL_BACKSLASH
526    ContextMenu = 0x65,            //CONTEXT_MENU
527    Power = 0x66,                  //POWER
528    NumpadEqual = 0x67,            //NUMPAD_EQUAL
529
530    F13 = 0x68, //F13
531    F14 = 0x69, //F14
532    F15 = 0x6a, //F15
533    F16 = 0x6b, //F16
534    F17 = 0x6c, //F17
535    F18 = 0x6d, //F18
536    F19 = 0x6e, //F19
537    F20 = 0x6f, //F20
538
539    F21 = 0x70, //F21
540    F22 = 0x71, //F22
541    F23 = 0x72, //F23
542
543    F24 = 0x73,  //F24
544    Open = 0x74, //OPEN
545
546    Help = 0x75, //HELP
547
548    // = 0x77, //SELECT
549    Again = 0x79,      //AGAIN
550    Undo = 0x7a,       //UNDO
551    Cut = 0x7b,        //CUT
552    Copy = 0x7c,       //COPY
553    Paste = 0x7d,      //PASTE
554    Find = 0x7e,       //FIND
555    VolumeMute = 0x7f, //VOLUME_MUTE
556
557    VolumeUp = 0x80,    //VOLUME_UP
558    VolumeDown = 0x81,  //VOLUME_DOWN
559    NumpadComma = 0x85, //NUMPAD_COMMA
560
561    InternationalRO = 0x87,  //INTL_RO
562    KanaMode = 0x88,         //KANA_MODE
563    InternationalYen = 0x89, //INTL_YEN
564    Convert = 0x8a,          //CONVERT
565    NonConvert = 0x8b,       //NON_CONVERT
566    Lang1 = 0x90,            //LANG1
567    Lang2 = 0x91,            //LANG2
568    Lang3 = 0x92,            //LANG3
569    Lang4 = 0x93,            //LANG4
570
571    LeftCtrl = 0xe0,   //CONTROL_LEFT
572    LeftShift = 0xe1,  //SHIFT_LEFT
573    LeftAlt = 0xe2,    //ALT_LEFT
574    LeftMeta = 0xe3,   //META_LEFT
575    RightCtrl = 0xe4,  //CONTROL_RIGHT
576    RightShift = 0xe5, //SHIFT_RIGHT
577    RightAlt = 0xe6,   //ALT_RIGHT
578    RightMeta = 0xe7,  //META_RIGHT
579}