XInput - Xbox Controller API

Post your working scripts, libraries and tools
lexikos
Posts: 6207
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

XInput - Xbox Controller API

26 Mar 2017, 06:05

XInput

Originally posted on the old forum.

XInput.ahk wraps a few key functions of XInput, a.k.a. the Microsoft Common Controller API. It provides the following capabilities not otherwise accessible to scripts:
  • The official drivers report to Windows one axis for both analog triggers, making it impossible to detect when both triggers are pulled at once. XInput allows one to retrieve the state of each analog trigger individually.
  • Set level of controller vibration - left and right motor speeds.
Other capabilities of the XInput API that this script does not currently support include:
  • Detect input on attached messenger kits (mini keyboards which can be attached to a controller).
  • Retrieve battery levels of wireless controllers.
  • Access the audio input/output of a given controller's headset.
Required: xinput1_*.dll - You probably already have it.

Usage notes are written above each function.

Code: Select all

/*  XInput by Lexikos
 *  Requires AutoHotkey 1.1+.
 */

/*
    Function: XInput_Init
    
    Initializes XInput.ahk with the given XInput DLL.
    
    Parameters:
        dll     -   The path or name of the XInput DLL to load.
*/
XInput_Init(dll:="")
{
    global
    if _XInput_hm
        return
    
    ;======== CONSTANTS DEFINED IN XINPUT.H ========
    
    ; NOTE: These are based on my outdated copy of the DirectX SDK.
    ;       Newer versions of XInput may require additional constants.
    
    ; Device types available in XINPUT_CAPABILITIES
    XINPUT_DEVTYPE_GAMEPAD          := 0x01

    ; Device subtypes available in XINPUT_CAPABILITIES
    XINPUT_DEVSUBTYPE_GAMEPAD       := 0x01

    ; Flags for XINPUT_CAPABILITIES
    XINPUT_CAPS_VOICE_SUPPORTED     := 0x0004

    ; Constants for gamepad buttons
    XINPUT_GAMEPAD_DPAD_UP          := 0x0001
    XINPUT_GAMEPAD_DPAD_DOWN        := 0x0002
    XINPUT_GAMEPAD_DPAD_LEFT        := 0x0004
    XINPUT_GAMEPAD_DPAD_RIGHT       := 0x0008
    XINPUT_GAMEPAD_START            := 0x0010
    XINPUT_GAMEPAD_BACK             := 0x0020
    XINPUT_GAMEPAD_LEFT_THUMB       := 0x0040
    XINPUT_GAMEPAD_RIGHT_THUMB      := 0x0080
    XINPUT_GAMEPAD_LEFT_SHOULDER    := 0x0100
    XINPUT_GAMEPAD_RIGHT_SHOULDER   := 0x0200
    XINPUT_GAMEPAD_GUIDE            := 0x0400
    XINPUT_GAMEPAD_A                := 0x1000
    XINPUT_GAMEPAD_B                := 0x2000
    XINPUT_GAMEPAD_X                := 0x4000
    XINPUT_GAMEPAD_Y                := 0x8000

    ; Gamepad thresholds
    XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  := 7849
    XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE := 8689
    XINPUT_GAMEPAD_TRIGGER_THRESHOLD    := 30

    ; Flags to pass to XInputGetCapabilities
    XINPUT_FLAG_GAMEPAD             := 0x00000001
    
    ;=============== END CONSTANTS =================
    
    if (dll = "")
        Loop %A_WinDir%\System32\XInput1_*.dll
            dll := A_LoopFileName
    if (dll = "")
        dll := "XInput1_3.dll"
    
    _XInput_hm := DllCall("LoadLibrary" ,"str",dll ,"ptr")
    
    if !_XInput_hm
        throw Exception("Failed to initialize XInput: " dll " not found.")
    
   (_XInput_GetState        := DllCall("GetProcAddress" ,"ptr",_XInput_hm ,"ptr",100 ,"ptr"))
|| (_XInput_GetState        := DllCall("GetProcAddress" ,"ptr",_XInput_hm ,"astr","XInputGetState" ,"ptr"))
    _XInput_SetState        := DllCall("GetProcAddress" ,"ptr",_XInput_hm ,"astr","XInputSetState" ,"ptr")
    _XInput_GetCapabilities := DllCall("GetProcAddress" ,"ptr",_XInput_hm ,"astr","XInputGetCapabilities" ,"ptr")
    
    if !(_XInput_GetState && _XInput_SetState && _XInput_GetCapabilities)
    {
        XInput_Term()
        throw Exception("Failed to initialize XInput: function not found.")
    }
}

/*
    Function: XInput_GetState
    
    Retrieves the current state of the specified controller.

    Parameters:
        UserIndex   -   [in] Index of the user's controller. Can be a value from 0 to 3.
    
    Returns:
        The current state of the controller as an associative array.
    
    ErrorLevel:
        If the function succeeds, ErrorLevel is ERROR_SUCCESS (zero).
        If the controller is not connected, ErrorLevel is ERROR_DEVICE_NOT_CONNECTED (1167).
        If the function fails, ErrorLevel is an error code defined in Winerror.h.
            http://msdn.microsoft.com/en-us/library/ms681381.aspx

    Remarks:
        XInput.dll returns controller state as a binary structure:
            http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.reference.xinput_state
            http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.reference.xinput_gamepad
*/
XInput_GetState(UserIndex)
{
    global _XInput_GetState
    
    VarSetCapacity(xiState,16)

    if ErrorLevel := DllCall(_XInput_GetState ,"uint",UserIndex ,"uint",&xiState)
        return 0
    
    return {
    (Join,
        dwPacketNumber: NumGet(xiState,  0, "UInt")
        wButtons:       NumGet(xiState,  4, "UShort")
        bLeftTrigger:   NumGet(xiState,  6, "UChar")
        bRightTrigger:  NumGet(xiState,  7, "UChar")
        sThumbLX:       NumGet(xiState,  8, "Short")
        sThumbLY:       NumGet(xiState, 10, "Short")
        sThumbRX:       NumGet(xiState, 12, "Short")
        sThumbRY:       NumGet(xiState, 14, "Short")
    )}
}

/*
    Function: XInput_SetState
    
    Sends data to a connected controller. This function is used to activate the vibration
    function of a controller.
    
    Parameters:
        UserIndex       -   [in] Index of the user's controller. Can be a value from 0 to 3.
        LeftMotorSpeed  -   [in] Speed of the left motor, between 0 and 65535.
        RightMotorSpeed -   [in] Speed of the right motor, between 0 and 65535.
    
    Returns:
        If the function succeeds, the return value is 0 (ERROR_SUCCESS).
        If the controller is not connected, the return value is 1167 (ERROR_DEVICE_NOT_CONNECTED).
        If the function fails, the return value is an error code defined in Winerror.h.
            http://msdn.microsoft.com/en-us/library/ms681381.aspx
    
    Remarks:
        The left motor is the low-frequency rumble motor. The right motor is the
        high-frequency rumble motor. The two motors are not the same, and they create
        different vibration effects.
*/
XInput_SetState(UserIndex, LeftMotorSpeed, RightMotorSpeed)
{
    global _XInput_SetState
    return DllCall(_XInput_SetState ,"uint",UserIndex ,"uint*",LeftMotorSpeed|RightMotorSpeed<<16)
}

/*
    Function: XInput_GetCapabilities
    
    Retrieves the capabilities and features of a connected controller.
    
    Parameters:
        UserIndex   -   [in] Index of the user's controller. Can be a value in the range 0–3.
        Flags       -   [in] Input flags that identify the controller type.
                                0   - All controllers.
                                1   - XINPUT_FLAG_GAMEPAD: Xbox 360 Controllers only.
    
    Returns:
        The controller capabilities, as an associative array.
    
    ErrorLevel:
        If the function succeeds, ErrorLevel is 0 (ERROR_SUCCESS).
        If the controller is not connected, ErrorLevel is 1167 (ERROR_DEVICE_NOT_CONNECTED).
        If the function fails, ErrorLevel is an error code defined in Winerror.h.
            http://msdn.microsoft.com/en-us/library/ms681381.aspx
    
    Remarks:
        XInput.dll returns capabilities via a binary structure:
            http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.reference.xinput_capabilities
*/
XInput_GetCapabilities(UserIndex, Flags)
{
    global _XInput_GetCapabilities
    
    VarSetCapacity(xiCaps,20)
    
    if ErrorLevel := DllCall(_XInput_GetCapabilities ,"uint",UserIndex ,"uint",Flags ,"ptr",&xiCaps)
        return 0
    
    return,
    (Join
        {
            Type:                   NumGet(xiCaps,  0, "UChar"),
            SubType:                NumGet(xiCaps,  1, "UChar"),
            Flags:                  NumGet(xiCaps,  2, "UShort"),
            Gamepad:
            {
                wButtons:           NumGet(xiCaps,  4, "UShort"),
                bLeftTrigger:       NumGet(xiCaps,  6, "UChar"),
                bRightTrigger:      NumGet(xiCaps,  7, "UChar"),
                sThumbLX:           NumGet(xiCaps,  8, "Short"),
                sThumbLY:           NumGet(xiCaps, 10, "Short"),
                sThumbRX:           NumGet(xiCaps, 12, "Short"),
                sThumbRY:           NumGet(xiCaps, 14, "Short")
            },
            Vibration:
            {
                wLeftMotorSpeed:    NumGet(xiCaps, 16, "UShort"),
                wRightMotorSpeed:   NumGet(xiCaps, 18, "UShort")
            }
        }
    )
}

/*
    Function: XInput_Term
    Unloads the previously loaded XInput DLL.
*/
XInput_Term() {
    global
    if _XInput_hm
        DllCall("FreeLibrary","uint",_XInput_hm), _XInput_hm :=_XInput_GetState :=_XInput_SetState :=_XInput_GetCapabilities :=0
}

; TODO: XInputEnable, 'GetBatteryInformation and 'GetKeystroke.

Code: Select all

; Example: Control the vibration motors using the analog triggers of each controller.
XInput_Init()
Loop {
    Loop, 4 {
        if State := XInput_GetState(A_Index-1) {
            LT := State.bLeftTrigger
            RT := State.bRightTrigger
            XInput_SetState(A_Index-1, LT*257, RT*257)
        }
    }
    Sleep, 100
}
User avatar
SnowFlake
Posts: 368
Joined: 28 Apr 2015, 05:41
Google: floowsnaake
GitHub: floowsnaake
Contact:

Re: XInput - Xbox Controller API

11 Apr 2017, 16:15

isn't this similar to the one evilC made?
:yawn:
lexikos
Posts: 6207
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: XInput - Xbox Controller API

11 Apr 2017, 17:03

Clearly not. This is a simple wrapper around the XInput API, with virtually the same usage as the API. The original script apparently predates evilC's library by about 9 years.
alpha0
Posts: 2
Joined: 27 Apr 2017, 23:55

Re: XInput - Xbox Controller API

28 Apr 2017, 02:28

what do these scripts do and how can I use controller key presses in my script
ziggurat
Posts: 1
Joined: 11 Jan 2018, 05:10

Re: XInput - Xbox Controller API

12 Jan 2018, 03:22

Hi I am trying to use This wrapper. I downloaded https://youtu.be/SgFW8WflLng which seams to use the most reason version from the old forum on page 4.
It works great with a Xbox One controller connected via USB or Bluetooth.

The problem I have is when I use Nvidia GameStream. Which is my preferred way to play gamepad games. With Nvidia GameStream it emulates the Xbox controller too, but this wrapper does not detect the controller :( Every other game or program I tried find the Nvidia GameStream Xinput controller. One thing to note, Nvidia does not populate the gamepad list found in control panel. I wonder if this script could be updated for a more universal detection of Xinput controllers?
lexikos
Posts: 6207
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: XInput - Xbox Controller API

12 Jan 2018, 05:28

The script uses the only universal method of detection of Xinput controllers - the official API.

It is likely that Nvidia GameStream does not give you a controller at all, but intercepts the Xinput APIs to pretend you have a controller. Your script may be missing some requirement for GameStream to install its hooks; e.g. the use of Direct3D or OpenGL.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 27 guests