Skip to main content

xinput/functions/
enable_.rs

1use crate::*;
2
3
4
5/// \[[microsoft.com](https://learn.microsoft.com/en-us/windows/win32/api/xinput/nf-xinput-xinputenable)\]
6/// XInputEnable
7/// <span style="opacity: 50%">(1.1+)</span>
8///
9/// Meant to be called when an application gains or loses activation (<code>[WM_ACTIVATEAPP]</code>),
10/// to enable or disable XInput for this app.
11///
12/// "Disabling" xinput for the current process with <code>[xinput](crate)::[enable]\(false\)</code> will:
13/// *   Stop all vibration (including if you call <code>[xinput](crate)::[set_state]</code> again.)
14/// *   Cause <code>[xinput](crate)::[get_state]</code> to retrieve neutral data for connected controllers (no buttons held, 0ed axises.)
15///
16/// While this is plenty sufficient for games wanting to handle OS-level application focus,
17/// this is not particularly useful if you instead want to enable/disable xinput access on a
18/// *per window* or *per focused control* basis instead of application-wide.
19/// Wrapping [`get_state`], [`set_state`], etc. to filter these at a more granular level is left
20/// as an exercise to the API consumer and whatever wrappers around xinput they might write.
21///
22/// ### Arguments
23/// *   `enable`        &mdash; `true` to accept input and allow vibration, `false` to block input and vibration.
24///
25/// ### Example
26/// ```rust
27/// # use winapi::shared::minwindef::*;
28/// # use winapi::shared::windef::*;
29/// # use winapi::um::winuser::*;
30/// unsafe extern "system"
31/// fn wndproc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
32///     match msg {
33///         WM_ACTIVATEAPP  => { let _ = xinput::enable(wparam as BOOL != FALSE); },
34///         _               => {},
35///     }
36///     DefWindowProcW(hwnd, msg, wparam, lparam)
37/// }
38/// ```
39///
40/// ### Errors
41/// *   [error::INVALID_FUNCTION]       - API unavailable: requires XInput 1.1 or later
42///
43/// ### See Also
44/// *   <code>[WM_ACTIVATEAPP]</code>   &mdash; Application gains/loses activation.
45/// *   <code>[WM_ACTIVATE]</code>      &mdash; Individual top-level window gains/loses activation.  I generally don't recommend calling [`enable`] from this.
46/// *   [How is the Focus working in a windows program?](https://web.archive.org/web/20090218140801/http://www.codeguru.com/forum/archive/index.php/t-422817.html)
47///     &mdash; [archive.org](https://archive.org/)'ed codeguru.com thread from 2007 with multiple replies by "SuperKoko" detailing message order, the nuances of activated window vs focused window, etc.
48///
49/// [WM_ACTIVATEAPP]:   https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-activateapp
50/// [WM_ACTIVATE]:      https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-activate
51pub fn enable(enable: impl Into<bool>) -> Result<(), Error> {
52    fn_context!(xinput::enable => XInputEnable);
53    #[allow(non_snake_case)] let XInputEnable = imports::XInputEnable.load(core::sync::atomic::Ordering::Relaxed);
54    // SAFETY: ✔️
55    //  * fuzzed        in `tests/fuzz-xinput.rs`
56    //  * `enable`      can be true or false.  Pretty easy to have exhaustive test coverage.
57    unsafe { XInputEnable(enable.into().into()) };
58    Ok(())
59}
60
61#[test] fn spam_xinput_enable() {
62    for e in [true, true, true, false, false, false, true, false, true, false, true, false, true] {
63        if let Err(err) = enable(e) {
64            assert!(matches!(err.kind(), error::INVALID_FUNCTION | error::CO_E_NOTINITIALIZED), "unexpected error type: {err:?}");
65        }
66    }
67}