-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3458871
commit 2c4bd59
Showing
8 changed files
with
286 additions
and
257 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
Oops, something went wrong.