1use std::{fmt, mem, ptr};
2#[cfg(feature = "unstable_xtarget_notification")]
3use std::{marker, pin, thread};
4use std::borrow::Borrow;
5use winapi::um::xinput::XINPUT_GAMEPAD;
6use winapi::shared::winerror;
7use crate::*;
8
9#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
11#[repr(transparent)]
12pub struct XButtons {
13 pub raw: u16,
14}
15
16#[allow(non_snake_case)]
18#[inline]
19pub const fn XButtons(raw: u16) -> XButtons {
20 XButtons { raw }
21}
22
23#[macro_export]
30macro_rules! XButtons {
31 (UP) => { $crate::XButtons { raw: $crate::XButtons::UP } };
32 (DOWN) => { $crate::XButtons { raw: $crate::XButtons::DOWN } };
33 (LEFT) => { $crate::XButtons { raw: $crate::XButtons::LEFT } };
34 (RIGHT) => { $crate::XButtons { raw: $crate::XButtons::RIGHT } };
35 (START) => { $crate::XButtons { raw: $crate::XButtons::START } };
36 (BACK) => { $crate::XButtons { raw: $crate::XButtons::BACK } };
37 (LTHUMB) => { $crate::XButtons { raw: $crate::XButtons::LTHUMB } };
38 (RTHUMB) => { $crate::XButtons { raw: $crate::XButtons::RTHUMB } };
39 (LB) => { $crate::XButtons { raw: $crate::XButtons::LB } };
40 (RB) => { $crate::XButtons { raw: $crate::XButtons::RB } };
41 (GUIDE) => { $crate::XButtons { raw: $crate::XButtons::GUIDE } };
42 (A) => { $crate::XButtons { raw: $crate::XButtons::A } };
43 (B) => { $crate::XButtons { raw: $crate::XButtons::B } };
44 (X) => { $crate::XButtons { raw: $crate::XButtons::X } };
45 (Y) => { $crate::XButtons { raw: $crate::XButtons::Y } };
46
47 ($($face:ident)|*) => {
48 $crate::XButtons { raw: 0 $(| $crate::XButtons!($face).raw)* }
49 };
50}
51
52impl XButtons {
53 pub const UP: u16 = 0x0001;
55 pub const DOWN: u16 = 0x0002;
57 pub const LEFT: u16 = 0x0004;
59 pub const RIGHT: u16 = 0x0008;
61 pub const START: u16 = 0x0010;
63 pub const BACK: u16 = 0x0020;
65 pub const LTHUMB: u16 = 0x0040;
67 pub const RTHUMB: u16 = 0x0080;
69 pub const LB: u16 = 0x0100;
71 pub const RB: u16 = 0x0200;
73 pub const GUIDE: u16 = 0x0400;
75 pub const A: u16 = 0x1000;
77 pub const B: u16 = 0x2000;
79 pub const X: u16 = 0x4000;
81 pub const Y: u16 = 0x8000;
83}
84
85impl From<u16> for XButtons {
86 #[inline]
87 fn from(raw: u16) -> Self {
88 XButtons { raw }
89 }
90}
91impl From<XButtons> for u16 {
92 #[inline]
93 fn from(buttons: XButtons) -> Self {
94 buttons.raw
95 }
96}
97impl AsRef<u16> for XButtons {
98 #[inline]
99 fn as_ref(&self) -> &u16 {
100 &self.raw
101 }
102}
103impl AsMut<u16> for XButtons {
104 #[inline]
105 fn as_mut(&mut self) -> &mut u16 {
106 &mut self.raw
107 }
108}
109
110impl fmt::Debug for XButtons {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 if f.alternate() {
113 const NAMES: [&'static str; 16] = [
114 "UP", "DOWN", "LEFT", "RIGHT",
115 "START", "BACK", "LTHUMB", "RTHUMB",
116 "LB", "RB", "GUIDE", "?",
117 "A", "B", "X", "Y",
118 ];
119 let mut comma = false;
120 for index in 0..16 {
121 if self.raw & (1 << index) != 0 {
122 if comma {
123 f.write_str("|")?;
124 comma = true;
125 }
126 f.write_str(NAMES[index])?;
127 }
128 }
129 Ok(())
130 }
131 else {
132 write!(f, "XButtons({:#x})", self.raw)
133 }
134 }
135}
136
137#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
143#[repr(C)]
144pub struct XGamepad {
145 pub buttons: XButtons,
146 pub left_trigger: u8,
147 pub right_trigger: u8,
148 pub thumb_lx: i16,
149 pub thumb_ly: i16,
150 pub thumb_rx: i16,
151 pub thumb_ry: i16,
152}
153
154impl From<XINPUT_GAMEPAD> for XGamepad {
155 #[inline]
156 fn from(gamepad: XINPUT_GAMEPAD) -> Self {
157 unsafe { mem::transmute(gamepad) }
158 }
159}
160impl From<XGamepad> for XINPUT_GAMEPAD {
161 #[inline]
162 fn from(report: XGamepad) -> XINPUT_GAMEPAD {
163 unsafe { mem::transmute(report) }
164 }
165}
166impl AsRef<XINPUT_GAMEPAD> for XGamepad {
167 #[inline]
168 fn as_ref(&self) -> &XINPUT_GAMEPAD {
169 unsafe { mem::transmute(self) }
170 }
171}
172impl AsMut<XINPUT_GAMEPAD> for XGamepad {
173 #[inline]
174 fn as_mut(&mut self) -> &mut XINPUT_GAMEPAD {
175 unsafe { mem::transmute(self) }
176 }
177}
178
179#[cfg(feature = "unstable_xtarget_notification")]
181#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash)]
182#[repr(C)]
183pub struct XNotification {
184 pub large_motor: u8,
185 pub small_motor: u8,
186 pub led_number: u8,
187}
188
189#[cfg(feature = "unstable_xtarget_notification")]
191pub struct XRequestNotification {
192 client: Client,
193 xurn: bus::RequestNotification<bus::XUsbRequestNotification>,
194 _unpin: marker::PhantomPinned,
195}
196
197#[cfg(feature = "unstable_xtarget_notification")]
198impl XRequestNotification {
199 #[inline]
201 pub fn is_attached(&self) -> bool {
202 self.xurn.buffer.SerialNo != 0
203 }
204
205 #[inline]
212 pub fn spawn_thread<F: FnMut(&XRequestNotification, XNotification) + Send + 'static>(self, mut f: F) -> thread::JoinHandle<()> {
213 thread::spawn(move || {
214 let mut reqn = self;
216 let mut reqn = unsafe { pin::Pin::new_unchecked(&mut reqn) };
217 loop {
218 reqn.as_mut().request();
219 let result = reqn.as_mut().poll(true);
220 match result {
221 Ok(None) => {},
222 Ok(Some(data)) => f(&reqn, data),
223 Err(_) => break,
225 }
226 }
227 })
228 }
229
230 #[inline(never)]
232 pub fn request(self: pin::Pin<&mut Self>) {
233 unsafe {
234 let device = self.client.device;
235 let xurn = &mut self.get_unchecked_mut().xurn;
236 if xurn.buffer.SerialNo != 0 {
237 xurn.ioctl(device);
238 }
239 }
240 }
241
242 #[inline(never)]
255 pub fn poll(self: pin::Pin<&mut Self>, wait: bool) -> Result<Option<XNotification>, Error> {
256 unsafe {
257 let device = self.client.device;
258 let xurn = &mut self.get_unchecked_mut().xurn;
259 match xurn.poll(device, wait) {
260 Ok(()) => Ok(Some(XNotification {
261 large_motor: xurn.buffer.LargeMotor,
262 small_motor: xurn.buffer.SmallMotor,
263 led_number: xurn.buffer.LedNumber,
264 })),
265 Err(winerror::ERROR_IO_INCOMPLETE) => Ok(None),
266 Err(winerror::ERROR_OPERATION_ABORTED) => {
267 xurn.buffer.SerialNo = 0;
272 Err(Error::OperationAborted)
273 },
274 Err(err) => Err(Error::WinError(err)),
275 }
276 }
277 }
278}
279
280#[cfg(feature = "unstable_xtarget_notification")]
281unsafe impl Sync for XRequestNotification {}
282#[cfg(feature = "unstable_xtarget_notification")]
283unsafe impl Send for XRequestNotification {}
284
285#[cfg(feature = "unstable_xtarget_notification")]
286impl fmt::Debug for XRequestNotification {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 f.debug_struct("XRequestNotification")
289 .field("client", &format_args!("{:?}", self.client))
290 .field("serial_no", &self.xurn.buffer.SerialNo)
291 .finish()
292 }
293}
294
295#[cfg(feature = "unstable_xtarget_notification")]
296impl Drop for XRequestNotification {
297 fn drop(&mut self) {
298 unsafe {
299 let this = pin::Pin::new_unchecked(self);
300 if this.xurn.buffer.SerialNo != 0 {
301 let device = this.client.device;
302 let xurn = &mut this.get_unchecked_mut().xurn;
303 let _ = xurn.cancel(device);
304 }
305 }
306 }
307}
308
309pub type XTarget = Xbox360Wired<Client>;
311
312pub struct Xbox360Wired<CL: Borrow<Client>> {
314 client: CL,
315 event: Event,
316 serial_no: u32,
317 id: TargetId,
318}
319
320impl<CL: Borrow<Client>> Xbox360Wired<CL> {
321 #[inline]
323 pub fn new(client: CL, id: TargetId) -> Xbox360Wired<CL> {
324 let event = Event::new(false, false);
325 Xbox360Wired { client, event, serial_no: 0, id }
326 }
327
328 #[inline]
330 pub fn is_attached(&self) -> bool {
331 self.serial_no != 0
332 }
333
334 #[inline]
336 pub fn id(&self) -> TargetId {
337 self.id
338 }
339
340 #[inline]
342 pub fn client(&self) -> &CL {
343 &self.client
344 }
345
346 #[inline]
348 pub fn drop(mut self) -> CL {
349 let _ = self.unplug();
350
351 unsafe {
352 let client = (&self.client as *const CL).read();
353 ptr::drop_in_place(&mut self.event);
354 mem::forget(self);
355 client
356 }
357 }
358
359 #[inline(never)]
361 pub fn plugin(&mut self) -> Result<(), Error> {
362 if self.is_attached() {
363 return Err(Error::AlreadyConnected);
364 }
365
366 let mut plugin = bus::PluginTarget::x360_wired(1, self.id.vendor, self.id.product);
367 let device = self.client.borrow().device;
368
369 while unsafe { plugin.ioctl(device, self.event.handle) }.is_err() {
371 plugin.SerialNo += 1;
372 if plugin.SerialNo >= u16::MAX as u32 {
373 return Err(Error::NoFreeSlot);
374 }
375 }
376
377 self.serial_no = plugin.SerialNo;
378 Ok(())
379 }
380
381 #[inline(never)]
383 pub fn unplug(&mut self) -> Result<(), Error> {
384 if !self.is_attached() {
385 return Err(Error::NotPluggedIn);
386 }
387
388 unsafe {
389 let mut unplug = bus::UnplugTarget::new(self.serial_no);
390 let device = self.client.borrow().device;
391 unplug.ioctl(device, self.event.handle)?;
392 }
393
394 self.serial_no = 0;
395 Ok(())
396 }
397
398 #[inline(never)]
402 pub fn wait_ready(&mut self) -> Result<(), Error> {
403 if !self.is_attached() {
404 return Err(Error::NotPluggedIn);
405 }
406
407 unsafe {
408 let mut wait = bus::WaitDeviceReady::new(self.serial_no);
409 let device = self.client.borrow().device;
410 wait.ioctl(device, self.event.handle)?;
411 }
412
413 Ok(())
414 }
415
416 #[inline(never)]
418 pub fn get_user_index(&mut self) -> Result<u32, Error> {
419 if !self.is_attached() {
420 return Err(Error::NotPluggedIn);
421 }
422
423 let user_index = unsafe {
424 let mut gui = bus::XUsbGetUserIndex::new(self.serial_no);
425 let device = self.client.borrow().device;
426 match gui.ioctl(device, self.event.handle) {
427 Ok(()) => (),
428 Err(winerror::ERROR_INVALID_DEVICE_OBJECT_PARAMETER) => return Err(Error::UserIndexOutOfRange),
430 Err(err) => return Err(Error::WinError(err)),
431 }
432
433 gui.UserIndex
434 };
435
436 Ok(user_index)
437 }
438
439 #[inline(never)]
441 pub fn update(&mut self, gamepad: &XGamepad) -> Result<(), Error> {
442 if !self.is_attached() {
443 return Err(Error::NotPluggedIn);
444 }
445
446 unsafe {
447 let mut xsr = bus::XUsbSubmitReport::new(self.serial_no, *gamepad);
448 let device = self.client.borrow().device;
449 match xsr.ioctl(device, self.event.handle) {
450 Ok(()) => Ok(()),
451 Err(winerror::ERROR_DEV_NOT_EXIST) => Err(Error::TargetNotReady),
452 Err(err) => Err(Error::WinError(err)),
453 }
454 }
455 }
456
457 #[cfg(feature = "unstable_xtarget_notification")]
464 #[inline(never)]
465 pub fn request_notification(&mut self) -> Result<XRequestNotification, Error> {
466 if !self.is_attached() {
467 return Err(Error::NotPluggedIn);
468 }
469
470 let client = self.client.borrow().try_clone()?;
471 let xurn = bus::RequestNotification::new(
472 bus::XUsbRequestNotification::new(self.serial_no));
473
474 Ok(XRequestNotification { client, xurn, _unpin: marker::PhantomPinned })
475 }
476}
477
478impl<CL: Borrow<Client>> fmt::Debug for Xbox360Wired<CL> {
479 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
480 f.debug_struct("Xbox360Wired")
481 .field("client", &format_args!("{:?}", self.client.borrow()))
482 .field("event", &format_args!("{:?}", self.event))
483 .field("serial_no", &self.serial_no)
484 .field("vendor_id", &self.id.vendor)
485 .field("product_id", &self.id.product)
486 .finish()
487 }
488}
489
490impl<CL: Borrow<Client>> Drop for Xbox360Wired<CL> {
491 #[inline]
492 fn drop(&mut self) {
493 let _ = self.unplug();
494 }
495}