1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
#[macro_use]
extern crate enum_primitive_derive;
extern crate ffi_support;
extern crate num_traits;

use ffi_support::FfiStr;
pub use num_traits::{FromPrimitive, ToPrimitive};
#[cfg(feature = "serdes")]
use serde::{Deserialize, Serialize};
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::os::raw::{c_char, c_int};
use thiserror::Error;

#[cfg(target_os = "macos")]
pub const DEFAULT_PLUGIN_DIR: &str = "/usr/local/share/WootingAnalogPlugins";
#[cfg(target_os = "linux")]
pub const DEFAULT_PLUGIN_DIR: &str = "/usr/local/share/WootingAnalogPlugins";
#[cfg(target_os = "windows")]
pub const DEFAULT_PLUGIN_DIR: &str = "C:\\Program Files\\WootingAnalogPlugins";

/// The core `DeviceInfo` struct which contains all the interesting information
/// for a particular device. This is for use internally and should be ignored if you're
/// trying to use it when trying to interact with the SDK using the wrapper
#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct DeviceInfo {
    /// Device Vendor ID `vid`
    pub vendor_id: u16,
    /// Device Product ID `pid`
    pub product_id: u16,
    /// Device Manufacturer name
    pub manufacturer_name: String,
    /// Device name
    pub device_name: String,
    /// Unique device ID, which should be generated using `generate_device_id`
    pub device_id: DeviceID,
    /// Hardware type of the Device
    pub device_type: DeviceType,
}

/// The core `DeviceInfo` struct which contains all the interesting information
/// for a particular device. This is the version which the consumer of the SDK will receive
/// through the wrapper. This is not for use in the Internal workings of the SDK, that is what
/// DeviceInfo is for
#[repr(C)]
pub struct DeviceInfo_FFI {
    /// Device Vendor ID `vid`
    pub vendor_id: u16,
    /// Device Product ID `pid`
    pub product_id: u16,
    /// Device Manufacturer name
    pub manufacturer_name: *mut c_char,
    /// Device name
    pub device_name: *mut c_char,
    /// Unique device ID, which should be generated using `generate_device_id`
    pub device_id: DeviceID,
    /// Hardware type of the Device
    pub device_type: DeviceType,
}

impl From<DeviceInfo> for DeviceInfo_FFI {
    fn from(device: DeviceInfo) -> Self {
        DeviceInfo_FFI {
            vendor_id: device.vendor_id,
            product_id: device.product_id,
            manufacturer_name: CString::new(device.manufacturer_name).unwrap().into_raw(),
            device_name: CString::new(device.device_name).unwrap().into_raw(),
            device_id: device.device_id,
            device_type: device.device_type,
        }
    }
}

impl Drop for DeviceInfo_FFI {
    fn drop(&mut self) {
        //Ensure we properly drop the memory for the char pointers
        unsafe {
            let _c_string = CString::from_raw(self.manufacturer_name);
            let _c_string = CString::from_raw(self.device_name);
        }
    }
}

impl DeviceInfo_FFI {
    pub fn into_device_info(&self) -> DeviceInfo {
        DeviceInfo {
            vendor_id: self.vendor_id.clone(),
            product_id: self.product_id.clone(),
            // 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
            // We leave it up to ffi interface to drop the memory
            manufacturer_name: unsafe {
                CStr::from_ptr(self.manufacturer_name)
                    .to_str()
                    .unwrap()
                    .to_owned()
            },
            device_name: unsafe {
                CStr::from_ptr(self.device_name)
                    .to_str()
                    .unwrap()
                    .to_owned()
            },
            device_id: self.device_id.clone(),
            device_type: self.device_type.clone(),
        }
    }
}

impl DeviceInfo {
    //    pub fn new(
    //        vendor_id: u16,
    //        product_id: u16,
    //        manufacturer_name: &str,
    //        device_name: &str,
    //        serial_number: &str,
    //        device_type: DeviceType,
    //    ) -> Self {
    //        DeviceInfo {
    //            vendor_id,
    //            product_id,
    //            manufacturer_name,
    //            device_name,
    //            device_id: generate_device_id(serial_number, vendor_id, product_id),
    //            device_type
    //        }
    //    }

    pub fn new_with_id(
        vendor_id: u16,
        product_id: u16,
        manufacturer_name: String,
        device_name: String,
        device_id: DeviceID,
        device_type: DeviceType,
    ) -> Self {
        DeviceInfo {
            vendor_id,
            product_id,
            manufacturer_name,
            device_name,
            device_id,
            device_type,
        }
    }
}

/// Create a new device info struct. This is only for use in Plugins that are written in C
/// Rust plugins should use the native constructor
/// The memory for the struct has been allocated in Rust. So `drop_device_info` must be called
/// for the memory to be properly released
#[no_mangle]
pub extern "C" fn new_device_info(
    vendor_id: u16,
    product_id: u16,
    manufacturer_name: *mut c_char,
    device_name: *mut c_char,
    device_id: DeviceID,
    device_type: DeviceType,
) -> *mut DeviceInfo {
    Box::into_raw(Box::new(DeviceInfo::new_with_id(
        vendor_id,
        product_id,
        unsafe {
            CStr::from_ptr(manufacturer_name)
                .to_string_lossy()
                .into_owned()
        },
        unsafe { CStr::from_ptr(device_name).to_string_lossy().into_owned() },
        device_id,
        device_type,
    )))
}

/// Drops the given `DeviceInfo`
#[no_mangle]
pub unsafe extern "C" fn drop_device_info(device: *mut DeviceInfo) {
    Box::from_raw(device);
}

#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Clone, Primitive)]
#[repr(C)]
pub enum KeycodeType {
    /// USB HID Keycodes https://www.usb.org/document-library/hid-usage-tables-112 pg53
    HID = 0,
    /// Scan code set 1
    ScanCode1 = 1,
    /// Windows Virtual Keys
    VirtualKey = 2,
    /// Windows Virtual Keys which are translated to the current keyboard locale
    VirtualKeyTranslate = 3,
}

pub type DeviceID = u64;

#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Clone, Primitive)]
#[repr(C)]
pub enum DeviceType {
    /// Device is of type Keyboard
    Keyboard = 1,
    /// Device is of type Keypad
    Keypad = 2,
    /// Device
    Other = 3,
}

#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Clone, Primitive)]
#[repr(C)]
pub enum DeviceEventType {
    /// Device has been connected
    Connected = 1,
    /// Device has been disconnected
    Disconnected = 2,
}

#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Clone, Primitive, Error)]
#[repr(C)]
pub enum WootingAnalogResult {
    #[error("All OK")]
    Ok = 1,
    /// Item hasn't been initialized
    #[error("SDK has not been initialized")]
    UnInitialized = -2000isize,
    /// No Devices are connected
    #[error("No Devices are connected")]
    NoDevices = -1999isize,
    /// Device has been disconnected
    #[error("Device has been disconnected")]
    DeviceDisconnected = -1998isize,
    /// Generic Failure
    #[error("Generic Failure")]
    Failure = -1997isize,
    /// A given parameter was invalid
    #[error("A given parameter was invalid")]
    InvalidArgument = -1996isize,
    /// No Plugins were found
    #[error("No Plugins were found")]
    NoPlugins = -1995isize,
    /// The specified function was not found in the library
    #[error("The specified function was not found in the library")]
    FunctionNotFound = -1994isize,
    /// No Keycode mapping to HID was found for the given Keycode
    #[error("No Keycode mapping to HID was found for the given Keycode")]
    NoMapping = -1993isize,
    /// Indicates that it isn't available on this platform
    #[error("Unavailable on this platform")]
    NotAvailable = -1992isize,
    /// Indicates that the operation that is trying to be used is for an older version
    #[error("Incompatible SDK Version")]
    IncompatibleVersion = -1991isize,
    /// Indicates that the Analog SDK could not be found on the system
    #[error("The Wooting Analog SDK could not be found on the system")]
    DLLNotFound = -1990isize,
}

impl WootingAnalogResult {
    pub fn is_ok(&self) -> bool {
        *self == WootingAnalogResult::Ok
    }

    pub fn is_ok_or_no_device(&self) -> bool {
        *self == WootingAnalogResult::Ok || *self == WootingAnalogResult::NoDevices
    }
}

impl Default for WootingAnalogResult {
    fn default() -> Self {
        WootingAnalogResult::FunctionNotFound
    }
}

#[derive(Debug)]
pub struct SDKResult<T>(pub std::result::Result<T, WootingAnalogResult>);

impl<T> Default for SDKResult<T> {
    fn default() -> Self {
        Err(Default::default()).into()
    }
}

impl<T> Deref for SDKResult<T> {
    type Target = std::result::Result<T, WootingAnalogResult>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> From<std::result::Result<T, WootingAnalogResult>> for SDKResult<T> {
    fn from(ptr: std::result::Result<T, WootingAnalogResult>) -> Self {
        SDKResult(ptr)
    }
}

impl<T> Into<std::result::Result<T, WootingAnalogResult>> for SDKResult<T> {
    fn into(self) -> std::result::Result<T, WootingAnalogResult> {
        self.0
    }
}

//TODO: Figure out a way to not have to use this for the lib_wrap_option in the sdk
impl<'a> From<FfiStr<'a>> for SDKResult<FfiStr<'a>> {
    fn from(res: FfiStr<'a>) -> Self {
        Ok(res).into()
    }
}

impl From<c_int> for SDKResult<c_int> {
    fn from(res: c_int) -> Self {
        if res >= 0 {
            Ok(res).into()
        } else {
            Err(WootingAnalogResult::from_i32(res).unwrap_or(WootingAnalogResult::Failure)).into()
        }
    }
}

impl From<c_int> for SDKResult<u32> {
    fn from(res: c_int) -> Self {
        if res >= 0 {
            Ok(res as u32).into()
        } else {
            Err(WootingAnalogResult::from_i32(res).unwrap_or(WootingAnalogResult::Failure)).into()
        }
    }
}

impl Into<c_int> for WootingAnalogResult {
    fn into(self) -> c_int {
        self as c_int
    }
}

impl From<u32> for SDKResult<u32> {
    fn from(res: u32) -> Self {
        Ok(res).into()
    }
}

impl Into<i32> for SDKResult<u32> {
    fn into(self) -> i32 {
        match self.0 {
            Ok(v) => v as i32,
            Err(e) => e.into(),
        }
    }
}

impl Into<c_int> for SDKResult<c_int> {
    fn into(self) -> c_int {
        match self.0 {
            Ok(v) => v,
            Err(e) => e.into(),
        }
    }
}

impl From<f32> for SDKResult<f32> {
    fn from(res: f32) -> Self {
        if res >= 0.0 {
            Ok(res).into()
        } else {
            Err(WootingAnalogResult::from_f32(res).unwrap_or(WootingAnalogResult::Failure)).into()
        }
    }
}

impl Into<f32> for WootingAnalogResult {
    fn into(self) -> f32 {
        (self as i32) as f32
    }
}

impl Into<f32> for SDKResult<f32> {
    fn into(self) -> f32 {
        match self.0 {
            Ok(v) => v,
            Err(e) => e.into(),
        }
    }
}

impl Into<WootingAnalogResult> for SDKResult<()> {
    fn into(self) -> WootingAnalogResult {
        match self.0 {
            Ok(_) => WootingAnalogResult::Ok,
            Err(e) => e,
        }
    }
}

impl From<WootingAnalogResult> for SDKResult<()> {
    fn from(res: WootingAnalogResult) -> Self {
        if res.is_ok() {
            Ok(()).into()
        } else {
            Err(res).into()
        }
    }
}

impl Into<bool> for WootingAnalogResult {
    fn into(self) -> bool {
        self == WootingAnalogResult::Ok
    }
}

#[cfg_attr(feature = "serdes", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Clone, Hash, Eq, Primitive)]
#[repr(C)]
pub enum HIDCodes {
    A = 0x04,
    B = 0x05, //US_B
    C = 0x06, //US_C
    D = 0x07, //US_D

    E = 0x08, //US_E
    F = 0x09, //US_F
    G = 0x0a, //US_G
    H = 0x0b, //US_H
    I = 0x0c, //US_I
    J = 0x0d, //US_J
    K = 0x0e, //US_K
    L = 0x0f, //US_L

    M = 0x10, //US_M
    N = 0x11, //US_N
    O = 0x12, //US_O
    P = 0x13, //US_P
    Q = 0x14, //US_Q
    R = 0x15, //US_R
    S = 0x16, //US_S
    T = 0x17, //US_T

    U = 0x18,  //US_U
    V = 0x19,  //US_V
    W = 0x1a,  //US_W
    X = 0x1b,  //US_X
    Y = 0x1c,  //US_Y
    Z = 0x1d,  //US_Z
    N1 = 0x1e, //DIGIT1
    N2 = 0x1f, //DIGIT2

    N3 = 0x20, //DIGIT3
    N4 = 0x21, //DIGIT4
    N5 = 0x22, //DIGIT5
    N6 = 0x23, //DIGIT6
    N7 = 0x24, //DIGIT7
    N8 = 0x25, //DIGIT8
    N9 = 0x26, //DIGIT9
    N0 = 0x27, //DIGIT0

    Enter = 0x28,       //ENTER
    Escape = 0x29,      //ESCAPE
    Backspace = 0x2a,   //BACKSPACE
    Tab = 0x2b,         //TAB
    Space = 0x2c,       //SPACE
    Minus = 0x2d,       //MINUS
    Equal = 0x2e,       //EQUAL
    BracketLeft = 0x2f, //BRACKET_LEFT

    BracketRight = 0x30, //BRACKET_RIGHT
    Backslash = 0x31,    //BACKSLASH

    // = 0x32, //INTL_HASH
    Semicolon = 0x33, //SEMICOLON
    Quote = 0x34,     //QUOTE
    Backquote = 0x35, //BACKQUOTE
    Comma = 0x36,     //COMMA
    Period = 0x37,    //PERIOD

    Slash = 0x38,    //SLASH
    CapsLock = 0x39, //CAPS_LOCK
    F1 = 0x3a,       //F1
    F2 = 0x3b,       //F2
    F3 = 0x3c,       //F3
    F4 = 0x3d,       //F4
    F5 = 0x3e,       //F5
    F6 = 0x3f,       //F6

    F7 = 0x40,          //F7
    F8 = 0x41,          //F8
    F9 = 0x42,          //F9
    F10 = 0x43,         //F10
    F11 = 0x44,         //F11
    F12 = 0x45,         //F12
    PrintScreen = 0x46, //PRINT_SCREEN
    ScrollLock = 0x47,  //SCROLL_LOCK

    PauseBreak = 0x48, //PAUSE
    Insert = 0x49,     //INSERT
    Home = 0x4a,       //HOME
    PageUp = 0x4b,     //PAGE_UP
    Delete = 0x4c,     //DEL
    End = 0x4d,        //END
    PageDown = 0x4e,   //PAGE_DOWN
    ArrowRight = 0x4f, //ARROW_RIGHT

    ArrowLeft = 0x50,      //ARROW_LEFT
    ArrowDown = 0x51,      //ARROW_DOWN
    ArrowUp = 0x52,        //ARROW_UP
    NumLock = 0x53,        //NUM_LOCK
    NumpadDivide = 0x54,   //NUMPAD_DIVIDE
    NumpadMultiply = 0x55, //NUMPAD_MULTIPLY
    NumpadSubtract = 0x56, //NUMPAD_SUBTRACT
    NumpadAdd = 0x57,      //NUMPAD_ADD

    NumpadEnter = 0x58, //NUMPAD_ENTER
    Numpad1 = 0x59,     //NUMPAD1
    Numpad2 = 0x5a,     //NUMPAD2
    Numpad3 = 0x5b,     //NUMPAD3
    Numpad4 = 0x5c,     //NUMPAD4
    Numpad5 = 0x5d,     //NUMPAD5
    Numpad6 = 0x5e,     //NUMPAD6
    Numpad7 = 0x5f,     //NUMPAD7

    Numpad8 = 0x60,                //NUMPAD8
    Numpad9 = 0x61,                //NUMPAD9
    Numpad0 = 0x62,                //NUMPAD0
    NumpadDecimal = 0x63,          //NUMPAD_DECIMAL
    InternationalBackslash = 0x64, //INTL_BACKSLASH
    ContextMenu = 0x65,            //CONTEXT_MENU
    Power = 0x66,                  //POWER
    NumpadEqual = 0x67,            //NUMPAD_EQUAL

    F13 = 0x68, //F13
    F14 = 0x69, //F14
    F15 = 0x6a, //F15
    F16 = 0x6b, //F16
    F17 = 0x6c, //F17
    F18 = 0x6d, //F18
    F19 = 0x6e, //F19
    F20 = 0x6f, //F20

    F21 = 0x70, //F21
    F22 = 0x71, //F22
    F23 = 0x72, //F23

    F24 = 0x73,  //F24
    Open = 0x74, //OPEN

    Help = 0x75, //HELP

    // = 0x77, //SELECT
    Again = 0x79,      //AGAIN
    Undo = 0x7a,       //UNDO
    Cut = 0x7b,        //CUT
    Copy = 0x7c,       //COPY
    Paste = 0x7d,      //PASTE
    Find = 0x7e,       //FIND
    VolumeMute = 0x7f, //VOLUME_MUTE

    VolumeUp = 0x80,    //VOLUME_UP
    VolumeDown = 0x81,  //VOLUME_DOWN
    NumpadComma = 0x85, //NUMPAD_COMMA

    InternationalRO = 0x87,  //INTL_RO
    KanaMode = 0x88,         //KANA_MODE
    InternationalYen = 0x89, //INTL_YEN
    Convert = 0x8a,          //CONVERT
    NonConvert = 0x8b,       //NON_CONVERT
    Lang1 = 0x90,            //LANG1
    Lang2 = 0x91,            //LANG2
    Lang3 = 0x92,            //LANG3
    Lang4 = 0x93,            //LANG4

    LeftCtrl = 0xe0,   //CONTROL_LEFT
    LeftShift = 0xe1,  //SHIFT_LEFT
    LeftAlt = 0xe2,    //ALT_LEFT
    LeftMeta = 0xe3,   //META_LEFT
    RightCtrl = 0xe4,  //CONTROL_RIGHT
    RightShift = 0xe5, //SHIFT_RIGHT
    RightAlt = 0xe6,   //ALT_RIGHT
    RightMeta = 0xe7,  //META_RIGHT
}