use super::*;
use std::collections::{HashMap, HashSet};
use std::sync::{Mutex, Once};
use std::time::Duration;
use std::thread::JoinHandle;
use std::option::Option::Some;
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct JoyConSerialNumber(pub String);
pub struct JoyConManager {
devices: HashMap<JoyConSerialNumber, Arc<Mutex<JoyConDevice>>>,
hid_api: Option<HidApi>,
scanner: Option<JoinHandle<()>>,
scan_interval: Duration,
new_devices: crossbeam_channel::Receiver<Arc<Mutex<JoyConDevice>>>,
}
impl JoyConManager {
pub fn get_instance() -> Arc<Mutex<Self>> {
static mut SINGLETON: Option<Arc<Mutex<JoyConManager>>> = None;
static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
let instance = JoyConManager::new()
.unwrap();
SINGLETON = Some(instance);
});
match SINGLETON.clone() {
Some(manager) => manager,
None => unreachable!()
}
}
}
fn new() -> JoyConResult<Arc<Mutex<Self>>> {
Self::with_interval(std::time::Duration::from_millis(100))
}
fn with_interval(interval: Duration) -> JoyConResult<Arc<Mutex<Self>>> {
let (tx, rx) =
crossbeam_channel::unbounded();
let manager = {
let mut manager = JoyConManager {
devices: HashMap::new(),
hid_api: None,
scanner: None,
scan_interval: interval,
new_devices: rx,
};
manager.scan()?
.into_iter()
.for_each(|new_device| {
let _ = tx.send(new_device);
});
Arc::new(Mutex::new(manager))
};
let scanner = {
let manager = Arc::downgrade(&manager);
std::thread::spawn(move || {
while let Some(manager) = manager.upgrade() {
let interval = {
let mut manager = match manager.lock() {
Ok(m) => m,
Err(m) => m.into_inner(),
};
if let Ok(new_devices) = manager.scan() {
let send_result = new_devices.into_iter()
.try_for_each::<_, Result<(), crossbeam_channel::SendError<_>>>(|new_device| {
tx.send(new_device)
});
if send_result.is_err() {
return;
}
}
manager.scan_interval.clone()
};
std::thread::sleep(interval)
}
})
};
if let Ok(mut manager) = manager.lock() {
manager.scanner = Some(scanner);
}
Ok(manager)
}
pub fn set_interval(&mut self, interval: Duration) {
self.scan_interval = interval;
}
pub fn scan(&mut self) -> JoyConResult<Vec<Arc<Mutex<JoyConDevice>>>> {
let hid_api = if let Some(hidapi) = &mut self.hid_api {
hidapi.refresh_devices()?;
hidapi
} else {
self.hid_api = Some(HidApi::new()?);
match &mut self.hid_api {
Some(hid_api) => hid_api,
None => unreachable!(),
}
};
let previous_device_serials = self.devices.keys()
.cloned()
.collect::<HashSet<_>>();
let detected_device_serials = hid_api.device_list()
.filter(|&device_info|
JoyConDevice::check_type_of_device(device_info)
.is_ok()
)
.flat_map(|device_info|
device_info.serial_number()
.map(|s| s.to_string())
.map(JoyConSerialNumber)
)
.collect::<HashSet<_>>();
let mut detected_devices = hid_api.device_list()
.filter(|&device_info|
JoyConDevice::check_type_of_device(device_info)
.is_ok()
)
.flat_map(|di| {
let serial_number = di.serial_number()
.map(|s| s.to_string())
.map(JoyConSerialNumber)?;
let device = JoyConDevice::new(di, hid_api).ok()?;
Some((serial_number, device))
})
.map(|(serial, device)| (serial, Arc::new(Mutex::new(device))))
.collect::<HashMap<_, _>>();
{
let removed_keys = previous_device_serials.difference(&detected_device_serials);
removed_keys.for_each(|key| {
if let Some(device) = self.devices.get(&key) {
let mut device = match device.lock() {
Ok(d) => d,
Err(e) => e.into_inner()
};
device.forget_device();
}
});
}
{
let reconnected_keys = previous_device_serials.intersection(&detected_device_serials)
.filter(|&k| {
if let Some(device) = self.devices.get(k) {
!match device.lock() {
Ok(d) => d,
Err(d) => d.into_inner(),
}.is_connected()
} else {
unreachable!()
}
}).collect::<HashSet<_>>();
reconnected_keys.iter()
.for_each(|&k| {
if let (Some(device), Some(new_device)) = (self.devices.get(k), detected_devices.remove(k)) {
let mut device = match device.lock() {
Ok(d) => d,
Err(e) => e.into_inner()
};
let new_device = {
if let Ok(new_device) = Arc::try_unwrap(new_device) {
match new_device.into_inner() {
Ok(d) => d,
Err(e) => e.into_inner()
}
} else { unreachable!() }
};
*device = new_device;
} else { unreachable!() }
});
}
let mut new_devices = Vec::new();
{
let connected_keys = detected_device_serials.difference(&previous_device_serials);
connected_keys.for_each(|key| {
if let Some(device) = detected_devices.remove(key) {
let device_cloned = Arc::clone(&device);
new_devices.push(device_cloned);
self.devices.insert(key.clone(), device);
}
});
}
Ok(new_devices)
}
pub fn managed_devices(&self) -> Vec<Arc<Mutex<JoyConDevice>>> {
self.devices.values()
.map(|d| Arc::clone(d))
.collect()
}
pub fn new_devices(&self) -> crossbeam_channel::Receiver<Arc<Mutex<JoyConDevice>>> {
self.new_devices.clone()
}
}
lazy_static! {
pub static ref JOYCON_RECEIVER: crossbeam_channel::Receiver<Arc<Mutex<JoyConDevice>>> = {
let manager = JoyConManager::get_instance();
let manager = match manager.lock() {
Ok(manager) => manager,
Err(e) => e.into_inner(),
};
manager.new_devices()
};
}