#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
use crate::*;
use minidl::Library;
use winapi::shared::minwindef::*;
use winapi::um::libloaderapi::*;
use winapi::um::winnt::*;
use std::os::windows::ffi::OsStrExt;
use std::sync::Once;
use core::convert::*;
use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem::*;
use core::ptr::null_mut;
use core::sync::atomic::{AtomicPtr, Ordering, Ordering::Relaxed};
type XINPUT_BATTERY_INFORMATION = crate::BatteryInformation;
type XINPUT_CAPABILITIES = crate::Capabilities;
type XINPUT_KEYSTROKE = crate::Keystroke;
type XINPUT_STATE = crate::State;
type XINPUT_VIBRATION = crate::Vibration;
type GUID = crate::DSoundAudioDeviceGuid;
pub(crate) static XInputGetState: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, pState: *mut XINPUT_STATE) -> DWORD> = AtomicFn::new(lazy::XInputGetState);
pub(crate) static XInputSetState: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, pVibration: *mut XINPUT_VIBRATION) -> DWORD> = AtomicFn::new(lazy::XInputSetState);
pub(crate) static XInputGetCapabilities: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, dwFlags: DWORD, pCapabilities: *mut XINPUT_CAPABILITIES) -> DWORD> = AtomicFn::new(lazy::XInputGetCapabilities);
pub(crate) static XInputGetDSoundAudioDeviceGuids: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, pDSoundRenderGuid: *mut GUID, pDSoundCaptureGuid: *mut GUID) -> DWORD> = AtomicFn::new(lazy::XInputGetDSoundAudioDeviceGuids);
pub(crate) static XInputGetAudioDeviceIds: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, pRenderDeviceId: LPWSTR, pRenderCount: *mut UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: *mut UINT) -> DWORD> = AtomicFn::new(lazy::XInputGetAudioDeviceIds);
pub(crate) static XInputEnable: AtomicFn<unsafe extern "system" fn(enable: BOOL)> = AtomicFn::new(lazy::XInputEnable);
pub(crate) static XInputGetBatteryInformation: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, devType: BYTE, pBatteryInformation: *mut XINPUT_BATTERY_INFORMATION) -> DWORD> = AtomicFn::new(lazy::XInputGetBatteryInformation);
pub(crate) static XInputGetKeystroke: AtomicFn<unsafe extern "system" fn(dwUserIndex: u32, dwReserved: u32, pKeystroke: *mut XINPUT_KEYSTROKE) -> DWORD> = AtomicFn::new(lazy::XInputGetKeystroke);
pub(crate) static _XInputGetStateEx: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, pState: *mut XINPUT_STATE) -> DWORD> = AtomicFn::new(lazy::_XInputGetStateEx);
pub(crate) static _XInputWaitForGuideButton: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD, dwFlag: DWORD, pUnknown: *mut c_void) -> DWORD> = AtomicFn::new(lazy::_XInputWaitForGuideButton);
pub(crate) static _XInputCancelGuideButtonWait: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD) -> DWORD> = AtomicFn::new(lazy::_XInputCancelGuideButtonWait);
pub(crate) static _XInputPowerOffController: AtomicFn<unsafe extern "system" fn(dwUserIndex: DWORD) -> DWORD> = AtomicFn::new(lazy::_XInputPowerOffController);
const THINDX_XINPUT_PANIC_MESSAGE : &'static str = "invalid value for `%THINDX_XINPUT%`: expected one of `1.4`, `1.3`, `1.2`, `1.1`, `9.1`, `9.1.0`, or `uap`";
const THINDX_XINPUT_DLL_BUILD_TIME : Option<&'static str> = match option_env!("THINDX_XINPUT") {
None => None,
Some(ver) => Some(thindx_xinput_var_to_dll_name(ver)),
};
const fn thindx_xinput_var_to_dll_name(thindx_xinput: &str) -> &'static str {
match thindx_xinput.as_bytes() {
b"uap" => "XInputUap.dll",
b"1.4" | b"1_4" => "XInput1_4.dll",
b"1.3" | b"1_3" => "xinput1_3.dll",
b"1.2" | b"1_2" => "xinput1_2.dll",
b"1.1" | b"1_1" => "xinput1_1.dll",
b"9.1" | b"9_1" | b"9.1.0" | b"9_1_0" => "XInput9_1_0.dll",
_ => panic!("{}", THINDX_XINPUT_PANIC_MESSAGE),
}
}
fn init() {
static ONCE : Once = Once::new();
ONCE.call_once(||{
unsafe {
let xinput_env_dll = std::env::var_os("THINDX_XINPUT").map(|env| {
let env = env.to_str().unwrap_or_else(|| panic!("{}", THINDX_XINPUT_PANIC_MESSAGE));
thindx_xinput_var_to_dll_name(env)
}).or(THINDX_XINPUT_DLL_BUILD_TIME);
let known_dlls = &[
"XInput1_4.dll",
"xinput1_3.dll",
"xinput1_2.dll",
"xinput1_1.dll",
"XInput9_1_0.dll",
"XInputUap.dll", ];
let lib = xinput_env_dll.and_then(|dll| Library::load(dll).ok()); let lib = lib.or_else(|| known_dlls.iter().find_map(|dll| library_get(dll))); let lib = lib.or_else(|| known_dlls.iter().find_map(|dll| Library::load(dll).ok()));
let get_state : unsafe extern "system" fn(dwUserIndex: DWORD, pState: *mut XINPUT_STATE) -> DWORD = lib.and_then(|lib| lib.sym_opt("XInputGetState\0")).unwrap_or(fallback::XInputGetState);
XInputGetState .store(get_state, Relaxed);
XInputSetState .store(lib.and_then(|lib| lib.sym_opt("XInputSetState\0" )).unwrap_or(fallback::XInputSetState ), Relaxed);
XInputGetCapabilities .store(lib.and_then(|lib| lib.sym_opt("XInputGetCapabilities\0" )).unwrap_or(fallback::XInputGetCapabilities ), Relaxed);
XInputGetDSoundAudioDeviceGuids .store(lib.and_then(|lib| lib.sym_opt("XInputGetDSoundAudioDeviceGuids\0" )).unwrap_or(fallback::XInputGetDSoundAudioDeviceGuids ), Relaxed);
XInputGetAudioDeviceIds .store(lib.and_then(|lib| lib.sym_opt("XInputGetAudioDeviceIds\0" )).unwrap_or(fallback::XInputGetAudioDeviceIds ), Relaxed);
XInputEnable .store(lib.and_then(|lib| lib.sym_opt("XInputEnable\0" )).unwrap_or(fallback::XInputEnable ), Relaxed);
XInputGetBatteryInformation .store(lib.and_then(|lib| lib.sym_opt("XInputGetBatteryInformation\0" )).unwrap_or(fallback::XInputGetBatteryInformation ), Relaxed);
XInputGetKeystroke .store(lib.and_then(|lib| lib.sym_opt("XInputGetKeystroke\0" )).unwrap_or(fallback::XInputGetKeystroke ), Relaxed);
_XInputGetStateEx .store(lib.and_then(|lib| lib.sym_opt_by_ordinal(100 )).unwrap_or(get_state ), Relaxed);
_XInputWaitForGuideButton .store(lib.and_then(|lib| lib.sym_opt_by_ordinal(101 )).unwrap_or(fallback::_XInputWaitForGuideButton ), Relaxed);
_XInputCancelGuideButtonWait .store(lib.and_then(|lib| lib.sym_opt_by_ordinal(102 )).unwrap_or(fallback::_XInputCancelGuideButtonWait ), Relaxed);
_XInputPowerOffController .store(lib.and_then(|lib| lib.sym_opt_by_ordinal(103 )).unwrap_or(fallback::_XInputPowerOffController ), Relaxed);
}
});
}
mod fallback {
#![allow(non_snake_case)]
#![allow(unused_variables)]
use super::*;
const ERROR_INVALID_FUNCTION : u32 = error::INVALID_FUNCTION.to_u32();
pub extern "system" fn XInputGetState( dwUserIndex: DWORD, pState: *mut XINPUT_STATE ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputSetState( dwUserIndex: DWORD, pVibration: *mut XINPUT_VIBRATION ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputGetCapabilities( dwUserIndex: DWORD, dwFlags: DWORD, pCapabilities: *mut XINPUT_CAPABILITIES ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputGetDSoundAudioDeviceGuids( dwUserIndex: DWORD, pDSoundRenderGuid: *mut GUID, pDSoundCaptureGuid: *mut GUID ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputGetAudioDeviceIds( dwUserIndex: DWORD, pRenderDeviceId: LPWSTR, pRenderCount: *mut UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: *mut UINT ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputEnable( enable: BOOL ) {}
pub extern "system" fn XInputGetBatteryInformation( dwUserIndex: DWORD, devType: BYTE, pBatteryInformation: *mut XINPUT_BATTERY_INFORMATION ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn XInputGetKeystroke( dwUserIndex: u32, dwReserved: u32, pKeystroke: *mut XINPUT_KEYSTROKE ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn _XInputWaitForGuideButton( dwUserIndex: DWORD, dwFlag: DWORD, pUnknown: *mut c_void ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn _XInputCancelGuideButtonWait( dwUserIndex: DWORD ) -> DWORD { ERROR_INVALID_FUNCTION }
pub extern "system" fn _XInputPowerOffController( dwUserIndex: DWORD ) -> DWORD { ERROR_INVALID_FUNCTION }
}
mod lazy {
use super::*;
pub unsafe extern "system" fn XInputGetState( dwUserIndex: DWORD, pState: *mut XINPUT_STATE ) -> DWORD { super::init(); unsafe { super::XInputGetState.load(Relaxed)(dwUserIndex, pState) } }
pub unsafe extern "system" fn XInputSetState( dwUserIndex: DWORD, pVibration: *mut XINPUT_VIBRATION ) -> DWORD { super::init(); unsafe { super::XInputSetState.load(Relaxed)(dwUserIndex, pVibration) } }
pub unsafe extern "system" fn XInputGetCapabilities( dwUserIndex: DWORD, dwFlags: DWORD, pCapabilities: *mut XINPUT_CAPABILITIES ) -> DWORD { super::init(); unsafe { super::XInputGetCapabilities.load(Relaxed)(dwUserIndex, dwFlags, pCapabilities) } }
pub unsafe extern "system" fn XInputGetDSoundAudioDeviceGuids( dwUserIndex: DWORD, pDSoundRenderGuid: *mut GUID, pDSoundCaptureGuid: *mut GUID ) -> DWORD { super::init(); unsafe { super::XInputGetDSoundAudioDeviceGuids.load(Relaxed)(dwUserIndex, pDSoundRenderGuid, pDSoundCaptureGuid) } }
pub unsafe extern "system" fn XInputGetAudioDeviceIds( dwUserIndex: DWORD, pRenderDeviceId: LPWSTR, pRenderCount: *mut UINT, pCaptureDeviceId: LPWSTR, pCaptureCount: *mut UINT ) -> DWORD { super::init(); unsafe { super::XInputGetAudioDeviceIds.load(Relaxed)(dwUserIndex, pRenderDeviceId, pRenderCount, pCaptureDeviceId, pCaptureCount) } }
pub unsafe extern "system" fn XInputEnable( enable: BOOL ) { super::init(); unsafe { super::XInputEnable.load(Relaxed)(enable) } }
pub unsafe extern "system" fn XInputGetBatteryInformation( dwUserIndex: DWORD, devType: BYTE, pBatteryInformation: *mut XINPUT_BATTERY_INFORMATION ) -> DWORD { super::init(); unsafe { super::XInputGetBatteryInformation.load(Relaxed)(dwUserIndex, devType, pBatteryInformation) } }
pub unsafe extern "system" fn XInputGetKeystroke( dwUserIndex: u32, dwReserved: u32, pKeystroke: *mut XINPUT_KEYSTROKE ) -> DWORD { super::init(); unsafe { super::XInputGetKeystroke.load(Relaxed)(dwUserIndex, dwReserved, pKeystroke) } }
pub unsafe extern "system" fn _XInputGetStateEx( dwUserIndex: DWORD, pState: *mut XINPUT_STATE ) -> DWORD { super::init(); unsafe { super::_XInputGetStateEx.load(Relaxed)(dwUserIndex, pState) } }
pub unsafe extern "system" fn _XInputWaitForGuideButton( dwUserIndex: DWORD, dwFlag: DWORD, pUnknown: *mut c_void ) -> DWORD { super::init(); unsafe { super::_XInputWaitForGuideButton.load(Relaxed)(dwUserIndex, dwFlag, pUnknown) } }
pub unsafe extern "system" fn _XInputCancelGuideButtonWait( dwUserIndex: DWORD ) -> DWORD { super::init(); unsafe { super::_XInputCancelGuideButtonWait.load(Relaxed)(dwUserIndex) } }
pub unsafe extern "system" fn _XInputPowerOffController( dwUserIndex: DWORD ) -> DWORD { super::init(); unsafe { super::_XInputPowerOffController.load(Relaxed)(dwUserIndex) } }
}
fn library_get(name: impl AsRef<std::ffi::OsStr>) -> Option<Library> {
let name = name.as_ref();
let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut hmodule = null_mut();
if 0 == unsafe { GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, name.as_ptr(), &mut hmodule) } { return None }
unsafe { Library::from_ptr(hmodule.cast()) }
}
pub(crate) struct AtomicFn<F: Copy>(AtomicPtr<c_void>, PhantomData<F>);
impl<F: Copy> AtomicFn<F> {
pub const fn new(f: F) -> Self { Self(AtomicPtr::new(unsafe { const_transmute_copy(f) }), PhantomData) }
pub fn load(&self, order: Ordering) -> F { let p = self.0.load(order); unsafe { const_transmute_copy(p) } }
pub fn store(&self, value: F, order: Ordering) { self.0.store(unsafe { const_transmute_copy(value) }, order) }
}
const unsafe fn const_transmute_copy<S: Copy, D: Copy>(src: S) -> D {
struct Assert<S, D>(PhantomData<(S, D)>);
impl<S, D> Assert<S, D> { const SAME_LAYOUT : () = assert!(align_of::<S>() == align_of::<D>() && size_of::<S>() == size_of::<D>()); }
let _ = Assert::<S, D>::SAME_LAYOUT;
union U<S: Copy, D: Copy> { src: S, dst: D }
let u = U::<S, D> { src };
unsafe { u.dst }
}