Skip to content

Commit

Permalink
Local fixes I never pushed
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed Jul 4, 2023
1 parent 3458871 commit 2c4bd59
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 257 deletions.
6 changes: 6 additions & 0 deletions stick/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ use lookit::Lookit;

use crate::{Controller, Remap};

#[cfg(windows)]
mod lookit {
#[derive(Debug)]
pub(crate) struct Lookit {}
}

/// Future that you can `.await` to connect to
/// [`Controller`](crate::Controller)s
#[derive(Debug)]
Expand Down
20 changes: 16 additions & 4 deletions stick/src/ctlr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,22 @@ use std::{
use lookit::It;

use crate::{
platform::{connect, platform, PlatformController, Support},
platform::{platform, CtlrId, Support},
Event,
};

#[cfg(windows)]
pub(crate) mod lookit {
#[derive(Debug)]
pub(crate) struct It {}

impl It {
pub fn id(&self) -> u8 {
todo!()
}
}
}

#[repr(i8)]
enum Btn {
Exit = 0,
Expand Down Expand Up @@ -271,7 +283,7 @@ pub struct Controller {
// Shared remapping.
remap: Arc<Info>,
//
raw: PlatformController,
raw: CtlrId,
// Button states
btns: u128,
// Number button states
Expand All @@ -298,7 +310,7 @@ impl Controller {
let btns = 0;
let nums = 0;
let axis = [0.0; Axs::Count as usize];
let (id, name, raw) = connect(which)?;
let (id, name, raw) = platform().connect(which)?;
let remap = remap.0.get(&id).cloned().unwrap_or_default();
let ready = true;
Some(Self {
Expand Down Expand Up @@ -581,7 +593,7 @@ impl Future for Controller {
let mut this = self.as_mut();

if this.ready {
if let Some(event) = platform().event(&mut this.raw) {
if let Poll::Ready(event) = platform().event(&mut this.raw) {
let out = Self::process(&mut *this, event);
return if out.is_pending() {
Self::poll(self, cx)
Expand Down
2 changes: 1 addition & 1 deletion stick/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ mod platform {

mod platform;

pub(crate) use platform::{connect, platform, PlatformController, Support};
pub(crate) use platform::{platform, CtlrId, Support};
}

mod connector;
Expand Down
2 changes: 2 additions & 0 deletions stick/src/linux/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub(crate) struct Controller {
}

pub(crate) fn connect(it: It) -> Option<(u64, String, Controller)> {
// Some controllers may not have haptic force feedback while others might
// ONLY have haptic force feedback and no controls.
let file = it.file_open() // Try Read & Write first
.or_else(|it| it.file_open_r()) // Then Readonly second
.or_else(|it| it.file_open_w()) // Then Writeonly third
Expand Down
28 changes: 18 additions & 10 deletions stick/src/platform/platform.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
#![allow(unsafe_code)]

use lookit::It;
use std::task::{Context, Poll};

use crate::Event;

// Choose platform driver implementation.
#[allow(unused_attributes)]
#[cfg_attr(target_os = "linux", path = "../linux/linux.rs")]
#[cfg_attr(target_os = "windows", path = "../windows/windows.rs")]
#[path = "unsupported.rs"]
mod driver;

// Import the device type from the target platform.
pub(crate) use driver::Controller as PlatformController;

// Single required method for each platform.
pub(crate) fn connect(it: It) -> Option<(u64, String, PlatformController)> {
driver::connect(it)
}
/// Controller ID.
pub(crate) struct CtlrId(u32);

/// Required platform support trait.
pub(crate) trait Support {
/// Window gained focus, start receiving events.
fn enable(self);
/// Window lost focus, stop receiving events.
fn disable(self);
fn rumble(self, controller: &mut PlatformController, left: f32, right: f32);
fn event(self, device: &mut PlatformController) -> Option<crate::Event>;
/// Set left and right rumble value for controller.
fn rumble(self, ctlr: &CtlrId, left: f32, right: f32);
/// Attempt getting a new event from a connected controller.
fn event(self, ctlr: &CtlrId, cx: &mut Context<'_>) -> Poll<Event>;
/// Attempt connecting to a new controller.
fn connect(self, cx: &mut Context<'_>) -> Poll<(u64, String, CtlrId)>;
}

/// Get platform support implementation.
///
/// Each platform must implement this function to work.
pub(crate) fn platform() -> impl Support {
driver::platform()
}
41 changes: 41 additions & 0 deletions stick/src/windows/controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::rc::Rc;
use crate::Event;
use winapi::shared::minwindef::DWORD;
use super::XInputHandle;
use crate::ctlr::lookit::It;

pub(crate) struct Controller {
pub(crate) xinput: Rc<XInputHandle>,
pub(crate) device_id: u8,
pub(crate) pending_events: Vec<Event>,
pub(crate) last_packet: DWORD,
}

impl Controller {
#[allow(unused)]
fn new(device_id: u8, xinput: Rc<XInputHandle>) -> Self {
Self {
xinput,
device_id,
pending_events: Vec::new(),
last_packet: 0,
}
}

/// Stereo rumble effect (left is low frequency, right is high frequency).
pub(super) fn rumble(&mut self, left: f32, right: f32) {
self.xinput
.set_state(
self.device_id as u32,
(u16::MAX as f32 * left) as u16,
(u16::MAX as f32 * right) as u16,
)
.unwrap()
}
}

pub(crate) fn connect(it: It) -> Option<(u64, String, Controller)> {
let name = "XInput Controller";
let controller = Controller::new(it.id(), todo!());
Some((0, name.to_string(), controller))
}
83 changes: 83 additions & 0 deletions stick/src/windows/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use self::controller::Controller;
use self::xinput::XInputHandle;
use super::{CtlrId, Support};
use crate::Event;
use std::mem::MaybeUninit;
use std::sync::Once;
use std::sync::atomic::{AtomicU8, Ordering};
use std::task::{Context, Poll};
use std::rc::Rc;

mod controller;
mod xinput;

static mut PLATFORM: MaybeUninit<Platform> = MaybeUninit::uninit();
static ONCE: Once = Once::new();
static CONNECTED: AtomicU8 = AtomicU8::new(0);
static READY: AtomicU8 = AtomicU8::new(0);

pub(super) struct Platform(Option<Rc<XInputHandle>>);

impl Support for &Platform {
fn enable(self) {
if let Some(ref xinput) = self.0 {
unsafe { (xinput.xinput_enable)(true as _) };
}
}

fn disable(self) {
if let Some(ref xinput) = self.0 {
unsafe { (xinput.xinput_enable)(false as _) };
}
}

fn rumble(self, ctlr: &CtlrId, left: f32, right: f32) {
todo!()
}

fn event(self, ctlr: &CtlrId, cx: &mut Context<'_>) -> Poll<Event> {
todo!()
}

fn connect(self, cx: &mut Context<'_>) -> Poll<(u64, String, CtlrId)> {
// Early return optimization if timeout hasn't passed yet.
// FIXME

// DirectInput only allows for 4 controllers
let connected = CONNECTED.load(Ordering::Relaxed);
for id in 0..4 {
let mask = 1 << id;
let was_connected = (connected & mask) != 0;
if let Some(ref xinput) = self.0 {
if xinput.get_state(id).is_ok() {
CONNECTED.fetch_or(mask, Ordering::Relaxed);
if !was_connected {
// we have a new device!
return Poll::Ready(CtlrId(id));
}
} else {
// set deviceto unplugged
CONNECTED.fetch_and(!mask, Ordering::Relaxed);
}
}
}

xinput::register_wake_timeout(100, cx.waker());

Poll::Pending
}
}

pub(super) fn platform() -> &'static Platform {
ONCE.call_once(|| unsafe {
PLATFORM = MaybeUninit::new(Platform(if let Ok(xinput) = XInputHandle::load_default() {
Some(xinput)
} else {
None
}));
});

unsafe {
PLATFORM.assume_init_ref()
}
}
Loading

0 comments on commit 2c4bd59

Please sign in to comment.