wooting_analog_plugin_dev/lib.rs
1extern crate ffi_support;
2pub extern crate wooting_analog_common;
3
4use ffi_support::FfiStr;
5use std::collections::HashMap;
6use std::hash::Hasher;
7use std::os::raw::{c_float, c_ushort};
8use wooting_analog_common::*;
9
10pub static ANALOG_SDK_PLUGIN_VERSION: &str = env!("CARGO_PKG_VERSION");
11
12/// The core Plugin trait which needs to be implemented for an Analog Plugin to function
13pub trait Plugin {
14 /// Get a name describing the `Plugin`.
15 fn name(&mut self) -> SDKResult<&'static str>;
16
17 /// Initialise the plugin with the given function for device events. Returns an int indicating the number of connected devices
18 fn initialise(
19 &mut self,
20 callback: Box<dyn Fn(DeviceEventType, &DeviceInfo) + Send>,
21 ) -> SDKResult<u32>;
22
23 /// A function fired to check if the plugin is currently initialised
24 fn is_initialised(&mut self) -> bool;
25
26 /// This function is fired by the SDK to collect up all Device Info structs. The memory for the struct should be retained and only dropped
27 /// when the device is disconnected or the plugin is unloaded. This ensures that the Device Info is not garbled when it's being accessed by the client.
28 ///
29 /// # Notes
30 ///
31 /// Although, the client should be copying any data they want to use for a prolonged time as there is no lifetime guarantee on the data.
32 fn device_info(&mut self) -> SDKResult<Vec<DeviceInfo>>;
33
34 /// A callback fired immediately before the plugin is unloaded. Use this if
35 /// you need to do any cleanup.
36 fn unload(&mut self) {}
37
38 /// Function called to get the analog value for a particular HID key `code` from the device with ID `device`.
39 /// If `device` is 0 then no specific device is specified and the value should be read from all devices and combined
40 fn read_analog(&mut self, code: u16, device: DeviceID) -> SDKResult<f32>;
41
42 /// Function called to get the full analog read buffer for a particular device with ID `device`. `max_length` is the maximum amount
43 /// of keys that can be accepted, any more beyond this will be ignored by the SDK.
44 /// If `device` is 0 then no specific device is specified and the data should be read from all devices and combined
45 fn read_full_buffer(
46 &mut self,
47 max_length: usize,
48 device: DeviceID,
49 ) -> SDKResult<HashMap<c_ushort, c_float>>;
50}
51
52/// Declare a plugin type and its constructor.
53///
54/// # Notes
55///
56/// This works by automatically generating an `extern "C"` function with a
57/// pre-defined signature and symbol name. Therefore you will only be able to
58/// declare one plugin per library.
59#[macro_export]
60macro_rules! declare_plugin {
61 ($plugin_type:ty, $constructor:path) => {
62 #[no_mangle]
63 pub extern "C" fn _plugin_create() -> *mut $crate::Plugin {
64 // make sure the constructor is the correct type.
65 let constructor: fn() -> $plugin_type = $constructor;
66
67 let object = constructor();
68 let boxed: Box<$crate::Plugin> = Box::new(object);
69 Box::into_raw(boxed)
70 }
71
72 #[no_mangle]
73 pub extern "C" fn plugin_version() -> &'static str {
74 ANALOG_SDK_PLUGIN_VERSION
75 }
76 };
77}
78
79pub fn generate_device_id(serial_number: &str, vendor_id: u16, product_id: u16) -> DeviceID {
80 use std::collections::hash_map::DefaultHasher;
81 let mut s = DefaultHasher::new();
82 s.write_u16(vendor_id);
83 s.write_u16(product_id);
84 s.write(serial_number.as_bytes());
85 s.finish()
86}
87
88mod ffi {
89 use super::*;
90
91 #[no_mangle]
92 pub extern "C" fn generate_device_id(
93 serial_number: FfiStr,
94 vendor_id: u16,
95 product_id: u16,
96 ) -> DeviceID {
97 let serial = {
98 if let Some(str) = serial_number.into_opt_string() {
99 str
100 } else {
101 return 0;
102 }
103 };
104 super::generate_device_id(&serial, vendor_id, product_id)
105 }
106}