use crate::{
action,
binding::{self, ActionSet, ActionSetId, LayoutId},
device::{self, GamepadKind},
event,
source::{Axis, Button},
User,
};
use std::{collections::HashMap, time::Instant};
pub type UserId = usize;
pub struct System {
gamepad_input: gilrs::Gilrs,
users: Vec<User>,
actions: HashMap<action::Id, action::Action>,
layouts: Vec<LayoutId>,
action_sets: HashMap<ActionSetId, ActionSet>,
unassigned_devices: Vec<device::Id>,
device_to_user: HashMap<device::Id, UserId>,
disconnected_device_users: HashMap<device::Id, UserId>,
}
impl System {
pub fn new() -> Self {
Self {
gamepad_input: gilrs::Gilrs::new().unwrap(),
users: Vec::new(),
actions: HashMap::new(),
layouts: Vec::new(),
action_sets: HashMap::new(),
unassigned_devices: vec![device::Id::Mouse, device::Id::Keyboard],
device_to_user: HashMap::new(),
disconnected_device_users: HashMap::new(),
}
.initialize_gamepads()
}
fn initialize_gamepads(mut self) -> Self {
let existing_gamepad_ids = self
.gamepad_input
.gamepads()
.map(|(id, _)| id)
.collect::<Vec<_>>();
for id in existing_gamepad_ids {
self.connect_gamepad(id);
}
self
}
pub fn add_users(&mut self, count: usize) -> &mut Self {
self.users.extend((0..count).map(|_| User::default()));
self.assign_unused_devices();
self
}
pub fn add_action(&mut self, name: action::Id, action: action::Action) -> &mut Self {
self.actions.insert(name, action);
self
}
pub fn add_layout(&mut self, layout: LayoutId) -> &mut Self {
self.layouts.push(layout);
self
}
pub fn add_action_set(&mut self, id: ActionSetId, set: ActionSet) -> &mut Self {
self.action_sets.insert(id, set);
self
}
pub fn set_user_layout(&mut self, user_id: UserId, layout: LayoutId) -> &mut Self {
if let Some(user) = self.users.get_mut(user_id) {
user.set_layout(layout, &self.actions);
}
self
}
pub fn mark_action_set_enabled(
&mut self,
user_id: UserId,
set_id: ActionSetId,
enabled: bool,
) -> &mut Self {
if let Some(user) = self.users.get_mut(user_id) {
if enabled {
if let Some(action_set) = self.action_sets.get(&set_id) {
user.enable_action_set(set_id, action_set, &self.actions);
}
} else {
user.disable_action_set(set_id);
}
}
self
}
pub fn enable_action_set_for_all(&mut self, id: ActionSetId) -> &mut Self {
if let Some(action_set) = self.action_sets.get(&id) {
for user in self.users.iter_mut() {
user.enable_action_set(id, action_set, &self.actions);
}
}
self
}
fn assign_unused_devices(&mut self) {
let unused_devices = self.unassigned_devices.drain(..).collect::<Vec<_>>();
for device in unused_devices {
match device {
device::Id::Mouse | device::Id::Keyboard => {
if let Some(first_user_id) = self.users.iter().position(|_| true) {
self.assign_device(device, first_user_id);
} else {
self.unassigned_devices.push(device);
}
}
device::Id::Gamepad(_, _) => {
if let Some(user_id) = self
.users
.iter()
.position(|user| !user.has_gamepad_device())
{
self.assign_device(device, user_id);
} else {
self.unassigned_devices.push(device);
}
}
}
}
}
fn assign_device(&mut self, device: device::Id, user_id: UserId) {
self.users[user_id].add_device(device);
self.device_to_user.insert(device, user_id);
if cfg!(feature = "log") {
log::info!(
target: crate::LOG,
"assigning {} to user {}",
device,
user_id
);
}
}
fn unassign_device(&mut self, device: device::Id) {
if let Some(user_id) = self.device_to_user.remove(&device) {
self.users[user_id].remove_device(device);
self.disconnected_device_users.insert(device, user_id);
if cfg!(feature = "log") {
log::info!(
target: crate::LOG,
"unassigning {} from user {}",
device,
user_id
);
}
} else {
self.unassigned_devices.push(device);
}
}
fn get_gamepad_kind(&self, _id: &gilrs::GamepadId) -> GamepadKind {
GamepadKind::DualAxisGamepad
}
fn connect_gamepad(&mut self, id: gilrs::GamepadId) {
let device = device::Id::Gamepad(self.get_gamepad_kind(&id), id);
if let Some(user_id) = self.disconnected_device_users.remove(&device) {
if !self.users[user_id].has_gamepad_device() {
self.assign_device(device, user_id);
return;
}
}
if let Some(user_id) = self
.users
.iter()
.position(|user| !user.has_gamepad_device())
{
self.assign_device(device, user_id);
return;
}
self.unassigned_devices.push(device);
}
fn disconnect_gamepad(&mut self, id: gilrs::GamepadId) {
self.unassign_device(device::Id::Gamepad(self.get_gamepad_kind(&id), id));
}
fn read_gamepad_events(&mut self) {
use gilrs::EventType;
use std::convert::TryFrom;
while let Some(gilrs::Event {
id,
event,
..
}) = self.gamepad_input.next_event()
{
let time = Instant::now();
let gamepad_kind = self.get_gamepad_kind(&id);
let device = device::Id::Gamepad(gamepad_kind, id);
match event {
EventType::Connected => self.connect_gamepad(id),
EventType::Disconnected => self.disconnect_gamepad(id),
EventType::Dropped => {}
EventType::ButtonPressed(btn, _) => {
if let Some(button) = Button::try_from(btn).ok() {
self.process_event(
device,
event::Event::new(
binding::Source::Gamepad(
gamepad_kind,
binding::Gamepad::Button(button),
),
event::State::ButtonState(event::ButtonState::Pressed),
),
time,
);
}
}
EventType::ButtonReleased(btn, _) => {
if let Some(button) = Button::try_from(btn).ok() {
self.process_event(
device,
event::Event::new(
binding::Source::Gamepad(
gamepad_kind,
binding::Gamepad::Button(button),
),
event::State::ButtonState(event::ButtonState::Released),
),
time,
);
}
}
EventType::ButtonRepeated(_btn, _) => {}
EventType::ButtonChanged(btn, value, _) => {
if let Some(button) = Button::try_from(btn).ok() {
self.process_event(
device,
event::Event::new(
binding::Source::Gamepad(
gamepad_kind,
binding::Gamepad::Button(button),
),
event::State::ValueChanged(value),
),
time,
);
}
}
EventType::AxisChanged(axis, value, _) => {
if let Some(axis) = Axis::try_from(axis).ok() {
self.process_event(
device,
event::Event::new(
binding::Source::Gamepad(
gamepad_kind,
binding::Gamepad::Axis(axis),
),
event::State::ValueChanged(value),
),
time,
);
}
}
}
}
}
pub fn send_event(&mut self, source: event::Source, event: event::Event) {
self.process_event(
match source {
event::Source::Mouse => device::Id::Mouse,
event::Source::Keyboard => device::Id::Keyboard,
},
event,
Instant::now(),
);
}
fn process_event(&mut self, device: device::Id, event: event::Event, time: Instant) {
for event in self.parse_event(event) {
self.update_user_actions(device, event, time);
}
}
fn parse_event(&mut self, event: event::Event) -> Vec<event::Event> {
let mut events = vec![event.clone()];
if let event::Event {
source: binding::Source::Gamepad(kind, binding::Gamepad::Button(Button::FaceBottom)),
..
} = event
{
events.push(event::Event {
source: binding::Source::Gamepad(
kind,
binding::Gamepad::Button(Button::VirtualConfirm),
),
..event
});
}
if let event::Event {
source: binding::Source::Gamepad(kind, binding::Gamepad::Button(Button::FaceRight)),
..
} = event
{
events.push(event::Event {
source: binding::Source::Gamepad(
kind,
binding::Gamepad::Button(Button::VirtualDeny),
),
..event
});
}
events
}
fn update_user_actions(&mut self, device: device::Id, event: event::Event, time: Instant) {
if let Some(user_id) = self.device_to_user.get(&device) {
if let Some(user) = self.users.get_mut(*user_id) {
user.process_event(&event, &time);
}
}
}
pub fn update(&mut self) {
self.read_gamepad_events();
let time = Instant::now();
for user in self.users.iter_mut() {
user.update(&time);
}
}
pub fn get_user_ids(&self) -> Vec<UserId> {
(0..self.users.len()).collect()
}
pub fn get_user_action(
&self,
user_id: UserId,
action_id: action::Id,
) -> Option<&action::State> {
self.users
.get(user_id)
.map(|user| user.get_action(action_id))
.flatten()
}
}