Refactor device creation and check whether any HyperX devices are
connected if no supported device is found
This commit is contained in:
@@ -13,63 +13,72 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use hidapi::{HidApi, HidDevice, HidError};
|
use hidapi::{HidApi, HidDevice, HidError};
|
||||||
use std::{fmt::Display, time::Duration};
|
use std::{collections::HashSet, fmt::Display, time::Duration};
|
||||||
use thistermination::TerminationFull;
|
use thistermination::TerminationFull;
|
||||||
|
|
||||||
// Possible vendor IDs [HyperX, HP]
|
type DeviceFactory = fn(DeviceState) -> Box<dyn Device>;
|
||||||
const VENDOR_IDS: [u16; 2] = [0x0951, 0x03F0];
|
|
||||||
// All supported product IDs
|
struct DeviceEntry {
|
||||||
const PRODUCT_IDS: [u16; 13] = [
|
vendor_ids: &'static [u16],
|
||||||
0x1718, 0x018B, 0x0D93, 0x0696, 0x0b92, 0x05B7, 0x16EA, 0x16EB, 0x0c9d, 0x06BE, 0x1743, 0x1765,
|
product_ids: &'static [u16],
|
||||||
0x098D,
|
factory: DeviceFactory,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEVICE_REGISTER: &[DeviceEntry] = &[
|
||||||
|
DeviceEntry {
|
||||||
|
vendor_ids: &cloud_ii_wireless::VENDOR_IDS,
|
||||||
|
product_ids: &cloud_ii_wireless::PRODUCT_IDS,
|
||||||
|
factory: |s| Box::new(CloudIIWireless::new_from_state(s)),
|
||||||
|
},
|
||||||
|
DeviceEntry {
|
||||||
|
vendor_ids: &cloud_ii_wireless_dts::VENDOR_IDS,
|
||||||
|
product_ids: &cloud_ii_wireless_dts::PRODUCT_IDS,
|
||||||
|
factory: |s| Box::new(CloudIIWirelessDTS::new_from_state(s)),
|
||||||
|
},
|
||||||
|
DeviceEntry {
|
||||||
|
vendor_ids: &cloud_iii_s_wireless::VENDOR_IDS,
|
||||||
|
product_ids: &cloud_iii_s_wireless::PRODUCT_IDS,
|
||||||
|
factory: |s| Box::new(CloudIIISWireless::new_from_state(s)),
|
||||||
|
},
|
||||||
|
DeviceEntry {
|
||||||
|
vendor_ids: &cloud_iii_wireless::VENDOR_IDS,
|
||||||
|
product_ids: &cloud_iii_wireless::PRODUCT_IDS,
|
||||||
|
factory: |s| Box::new(CloudIIIWireless::new_from_state(s)),
|
||||||
|
},
|
||||||
|
DeviceEntry {
|
||||||
|
vendor_ids: &cloud_alpha_wireless::VENDOR_IDS,
|
||||||
|
product_ids: &cloud_alpha_wireless::PRODUCT_IDS,
|
||||||
|
factory: |s| Box::new(CloudAlphaWireless::new_from_state(s)),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const RESPONSE_BUFFER_SIZE: usize = 256;
|
const RESPONSE_BUFFER_SIZE: usize = 256;
|
||||||
const RESPONSE_DELAY: Duration = Duration::from_millis(50);
|
const RESPONSE_DELAY: Duration = Duration::from_millis(50);
|
||||||
|
|
||||||
pub fn connect_compatible_device() -> Result<Box<dyn Device>, DeviceError> {
|
pub fn connect_compatible_device() -> Result<Box<dyn Device>, DeviceError> {
|
||||||
let state = DeviceState::new(&PRODUCT_IDS, &VENDOR_IDS)?;
|
let all_product_ids: Vec<u16> = DEVICE_REGISTER
|
||||||
|
.iter()
|
||||||
|
.flat_map(|e| e.product_ids.iter().copied())
|
||||||
|
.collect();
|
||||||
|
let all_vendor_ids: Vec<u16> = DEVICE_REGISTER
|
||||||
|
.iter()
|
||||||
|
.flat_map(|e| e.vendor_ids.iter().copied())
|
||||||
|
.collect();
|
||||||
|
let state = DeviceState::new(&all_product_ids, &all_vendor_ids)?;
|
||||||
debug_println!("Found device selecting handler");
|
debug_println!("Found device selecting handler");
|
||||||
let name = state
|
let name = state
|
||||||
.hid_device
|
.hid_device
|
||||||
.get_product_string()?
|
.get_product_string()?
|
||||||
.ok_or(DeviceError::NoDeviceFound())?;
|
.ok_or(DeviceError::NoDeviceFound())?;
|
||||||
println!("Connecting to {}", name);
|
println!("Connecting to {}", name);
|
||||||
let mut device: Box<dyn Device> = match (state.vendor_id, state.product_id) {
|
let entry = DEVICE_REGISTER
|
||||||
(v, p)
|
.iter()
|
||||||
if cloud_ii_wireless::VENDOR_IDS.contains(&v)
|
.find(|e| {
|
||||||
&& cloud_ii_wireless::PRODUCT_IDS.contains(&p) =>
|
e.vendor_ids.contains(&state.vendor_id) && e.product_ids.contains(&state.product_id)
|
||||||
{
|
})
|
||||||
Box::new(CloudIIWireless::new_from_state(state))
|
.ok_or(DeviceError::NoDeviceFound())?;
|
||||||
}
|
|
||||||
(v, p)
|
|
||||||
if cloud_ii_wireless_dts::VENDOR_IDS.contains(&v)
|
|
||||||
&& cloud_ii_wireless_dts::PRODUCT_IDS.contains(&p) =>
|
|
||||||
{
|
|
||||||
Box::new(CloudIIWirelessDTS::new_from_state(state))
|
|
||||||
}
|
|
||||||
(v, p)
|
|
||||||
if cloud_iii_s_wireless::VENDOR_IDS.contains(&v)
|
|
||||||
&& cloud_iii_s_wireless::PRODUCT_IDS.contains(&p) =>
|
|
||||||
{
|
|
||||||
Box::new(CloudIIISWireless::new_from_state(state))
|
|
||||||
}
|
|
||||||
(v, p)
|
|
||||||
if cloud_iii_wireless::VENDOR_IDS.contains(&v)
|
|
||||||
&& cloud_iii_wireless::PRODUCT_IDS.contains(&p) =>
|
|
||||||
{
|
|
||||||
Box::new(CloudIIIWireless::new_from_state(state))
|
|
||||||
}
|
|
||||||
(v, p)
|
|
||||||
if cloud_alpha_wireless::VENDOR_IDS.contains(&v)
|
|
||||||
&& cloud_alpha_wireless::PRODUCT_IDS.contains(&p) =>
|
|
||||||
{
|
|
||||||
Box::new(CloudAlphaWireless::new_from_state(state))
|
|
||||||
}
|
|
||||||
(_, _) => return Err(DeviceError::NoDeviceFound()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize capability flags
|
let mut device = (entry.factory)(state);
|
||||||
device.init_capabilities();
|
device.init_capabilities();
|
||||||
|
|
||||||
Ok(device)
|
Ok(device)
|
||||||
@@ -114,6 +123,7 @@ impl Display for DeviceState {
|
|||||||
impl DeviceState {
|
impl DeviceState {
|
||||||
pub fn new(product_ids: &[u16], vendor_ids: &[u16]) -> Result<Self, DeviceError> {
|
pub fn new(product_ids: &[u16], vendor_ids: &[u16]) -> Result<Self, DeviceError> {
|
||||||
let hid_api = HidApi::new()?;
|
let hid_api = HidApi::new()?;
|
||||||
|
let mut potential_devices = HashSet::new();
|
||||||
debug_println!(
|
debug_println!(
|
||||||
"Devices: {:?}",
|
"Devices: {:?}",
|
||||||
hid_api
|
hid_api
|
||||||
@@ -122,7 +132,7 @@ impl DeviceState {
|
|||||||
.map(|d| { (d.vendor_id(), d.product_id(), d.product_string()) })
|
.map(|d| { (d.vendor_id(), d.product_id(), d.product_string()) })
|
||||||
.collect::<Vec<(u16, u16, Option<&str>)>>()
|
.collect::<Vec<(u16, u16, Option<&str>)>>()
|
||||||
);
|
);
|
||||||
let (hid_device, product_id, vendor_id) = hid_api
|
let device_lookup_result = hid_api
|
||||||
.device_list()
|
.device_list()
|
||||||
.find_map(|info| {
|
.find_map(|info| {
|
||||||
if product_ids.contains(&info.product_id())
|
if product_ids.contains(&info.product_id())
|
||||||
@@ -140,10 +150,44 @@ impl DeviceState {
|
|||||||
info.vendor_id(),
|
info.vendor_id(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
|
if let Some(name) = info.product_string() {
|
||||||
|
if name.contains("HyperX") {
|
||||||
|
potential_devices.insert((
|
||||||
|
info.vendor_id(),
|
||||||
|
info.product_id(),
|
||||||
|
info.product_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ok_or(DeviceError::NoDeviceFound())?;
|
.ok_or(DeviceError::NoDeviceFound());
|
||||||
|
let (hid_device, product_id, vendor_id) = match device_lookup_result {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(DeviceError::NoDeviceFound()) => {
|
||||||
|
if !potential_devices.is_empty() {
|
||||||
|
let names = potential_devices
|
||||||
|
.iter()
|
||||||
|
.map(|e| {
|
||||||
|
format!(
|
||||||
|
" vendorID: 0x{:04X} productID: 0x{:04X} name: {}",
|
||||||
|
e.0,
|
||||||
|
e.1,
|
||||||
|
e.2.unwrap_or("Unknown")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",\n");
|
||||||
|
println!(
|
||||||
|
"Found the following HyperX device{}: [\n{}\n]\nHowever, either {} not supported or the product ID is not yet known.",
|
||||||
|
if potential_devices.len() > 1 { "s" } else { "" }, names, if potential_devices.len() > 1 { "they are" } else { "it is" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Err(DeviceError::NoDeviceFound());
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
let hid_device = hid_device?;
|
let hid_device = hid_device?;
|
||||||
let device_name = hid_device.get_product_string()?;
|
let device_name = hid_device.get_product_string()?;
|
||||||
Ok(DeviceState {
|
Ok(DeviceState {
|
||||||
|
|||||||
Reference in New Issue
Block a user