XBOX One Controller

Get help with using AutoHotkey and its commands and hotkeys
Canmaster
Posts: 3
Joined: 09 Apr 2016, 03:49

XBOX One Controller

Post by Canmaster » 08 Jan 2017, 05:59

Microsoft have made some updates for the XBOX One Controller for Windows 10 and now i't wont work with autohotkey anymore or atleast as a global key it did work before.

If i use this code for example

Joy1::
Msgbox hello
return

the script wont work if it's minimized but if i Open the script it works, if I change controller to a XBOX 360 Controller it works fine as global key.

Does it have to do something with https://msdn.microsoft.com/en-us/librar ... s.85).aspx ?

User avatar
evilC
Posts: 4787
Joined: 27 Feb 2014, 12:30

Re: XBOX One Controller

Post by evilC » 08 Jan 2017, 12:09

"the script wont work if it's minimized but if i Open the script it works"
That script has no GUI, so it cannot be minimized.
What do you mean by "Open the script"?

User avatar
nnnik
Posts: 4480
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: XBOX One Controller

Post by nnnik » 08 Jan 2017, 13:18

Recommends AHK Studio

Vilain Joueur
Posts: 2
Joined: 22 Apr 2019, 16:40

Re: XBOX One Controller

Post by Vilain Joueur » 22 Apr 2019, 17:06

Hello! I wanted to add support for the Xbox One controller (wireless) and spent some time writing AutoHotkey scripts for it.

First is an updated version of XInput.ahk. I only changed the constant values (for buttons) and their names to make it clearer what each button corresponds to.

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          := 0x1
    XINPUT_GAMEPAD_DPAD_DOWN        := 0x2
    XINPUT_GAMEPAD_DPAD_LEFT        := 0x4
    XINPUT_GAMEPAD_DPAD_RIGHT       := 0x8
    XINPUT_GAMEPAD_MENU             := 0x10
    XINPUT_GAMEPAD_VIEW             := 0x20
    XINPUT_GAMEPAD_LEFT_STICK       := 0x40
    XINPUT_GAMEPAD_RIGHT_STICK      := 0x80
    XINPUT_GAMEPAD_LEFT_BUMPER      := 0x100
    XINPUT_GAMEPAD_RIGHT_BUMPER     := 0x200
    XINPUT_GAMEPAD_XBOX             := 0x400
    XINPUT_GAMEPAD_A                := 0x1000
    XINPUT_GAMEPAD_B                := 0x2000
    XINPUT_GAMEPAD_X                := 0x4000
    XINPUT_GAMEPAD_Y                := 0x8000

    ; Gamepad thresholds
    XINPUT_GAMEPAD_LEFT_STICK_DEADZONE  := 7849
    XINPUT_GAMEPAD_RIGHT_STICK_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  Broken Link for safety

    Remarks:
        XInput.dll returns controller state as a binary structure:
            http msdn.microsoft.com /en-us/library/microsoft.directx_sdk.reference.xinput_state  Broken Link for safety
            http msdn.microsoft.com /en-us/library/microsoft.directx_sdk.reference.xinput_gamepad  Broken Link for safety
*/
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  Broken Link for safety
    
    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  Broken Link for safety
    
    Remarks:
        XInput.dll returns capabilities via a binary structure:
            http msdn.microsoft.com /en-us/library/microsoft.directx_sdk.reference.xinput_capabilities  Broken Link for safety
*/
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.
Second is a script to manage the sticks. In particular a new way to move the mouse with the right stick (the script provided in the AutoHotkey documentation doesn't emulate mouse movement well). The right stick sensibility can be changed and you can reduce the timer period for even faster response times.

Code: Select all

#Persistent
#SingleInstance force
#Include XInput.ahk

XInput_Init()

ReleasePressedDirectionalKey(key)
{
	GetKeyState, state, %key%
	if state = D
		Send {%key% up}
}

stickSensibility := 3 / 1000

Thread, interrupt, 0  ; Make all threads always-interruptible.

SetTimer, Sticks, 5
return

Sticks:
    Loop, 4 {
        if state := XInput_GetState(A_Index-1) {
			
			LSx := state.sThumbLX
			LSy := state.sThumbLY
			RSx := state.sThumbRX
			RSy := state.sThumbRY
			
			if (abs(LSx) < XINPUT_GAMEPAD_LEFT_STICK_DEADZONE)
			{
				ReleasePressedDirectionalKey("Right")
				ReleasePressedDirectionalKey("Left")
				LSx := 0
				xDirection := ""
				xDirectionLast := ""
			}				
			if (abs(LSy) < XINPUT_GAMEPAD_LEFT_STICK_DEADZONE)
			{
				ReleasePressedDirectionalKey("Up")
				ReleasePressedDirectionalKey("Down")
				LSy := 0
				yDirection := ""
				yDirectionLast := ""
			}
			if LSx
				xDirection := LSx > 0 ? "Right" : "Left"
			if LSy
				yDirection := LSy > 0 ? "Up" : "Down"
			;MsgBox % LSx . " / " . xDirection . " / " . xDirectionLast . " / " . LSy . " / " . yDirection . " / " . yDirectionLast
			if (xDirection != "" && xDirection != xDirectionLast)
			{
				ReleasePressedDirectionalKey(xDirectionLast)
				Send {%xDirection% down}
				xDirectionLast := xDirection
			}
			if (yDirection != "" && yDirection != yDirectionLast)
			{
				ReleasePressedDirectionalKey(yDirectionLast)
				Send {%yDirection% down}
				yDirectionLast := yDirection
			}
			;8 689 = RS dead zone
			;24 078 = RS live zone
			;32 767	= radius
			RSHypotenuse := sqrt(RSx * RSx + RSy * RSy)
			if (RSHypotenuse > XINPUT_GAMEPAD_RIGHT_STICK_DEADZONE) {
				RSValue := RSHypotenuse - XINPUT_GAMEPAD_RIGHT_STICK_DEADZONE
				RSValueInProportion := RSValue / (32767 - XINPUT_GAMEPAD_RIGHT_STICK_DEADZONE)
				;MsgBox % RSx . " - " . RSy . " - " . RSHypotenuse . " - " . RSValue . " - " . RSValueInProportion
				SetMouseDelay, -1 ; Makes movement smoother.
				if RSValueInProportion > 1
					RSValueInProportion := 1
				S := (1 - RSValueInProportion) * 100
				RSx *= RSValueInProportion * stickSensibility				
				RSy *= RSValueInProportion * stickSensibility				
				MouseMove, RSx, -RSy, S, R
			}
        }
    }
return
Cheers!

Seeds
Posts: 76
Joined: 31 Dec 2018, 01:39

Re: XBOX One Controller

Post by Seeds » 23 Apr 2019, 00:37

Hi villain, not to derail this topic, but with your updated xinput.ahk, this will work with latest windows 10 updates? I have implemented xinput.ahk into my script, and included an older version of the xinput 1_3.dll in my scripts directory to make it work. If I didn't have to include an old version of xinput.dll it would be awesome. Would I have to rewrite my entire xinput controller handlers with your script? That would be a lot of work.

Vilain Joueur
Posts: 2
Joined: 22 Apr 2019, 16:40

Re: XBOX One Controller

Post by Vilain Joueur » 23 Apr 2019, 09:18

Hello Seeds! I think it should, at least it works for me! I just changed the values of a few constants for the buttons because they weren't accurate for my controller. I don't think you need to include the dll if you're using XInput.ahk. I'm not sure what your scripts do. I guess you could try and see if they still work with the last version of W10.

vpl91
Posts: 1
Joined: 24 Jul 2019, 19:07

Re: XBOX One Controller

Post by vpl91 » 24 Jul 2019, 19:12

Hey guys, I'm net to all this and I can safely say that I'm also really bad at creating scripts.

I was trying to create a simple Xbox Controller "A button mashing" loop.

The thing is, I don't really know what I'm doing :headwall:

Is this anything close to being right?

Code: Select all

XINPUT_GAMEPAD_A::
Loop
{
	Send, {XINPUT_GAMEPAD_A}
	Sleep, 100
	
	}until GetKeyState("XINPUT_GAMEPAD_B")

Esc:: Stop:=1

Return
If anyone can help me make this, I'd really appreciate it.

User avatar
evilC
Posts: 4787
Joined: 27 Feb 2014, 12:30

Re: XBOX One Controller

Post by evilC » 25 Jul 2019, 05:04

What on earth makes you think XINPUT_GAMEPAD_A:: is a valid hotkey, or a valid syntax for the Send command?
AHK simply cannot send XInput, period, let alone using that syntax for input
You are literally saying "Why does this feature that I just made up not work?"
Because you made it up and it is not part of the software...

User avatar
boiler
Posts: 6629
Joined: 21 Dec 2014, 02:44

Re: XBOX One Controller

Post by boiler » 25 Jul 2019, 14:46

@evilC: XINPUT_GAMEPAD_A and the like are variable names from lexikos' XInput, so apparently vpl91 is misapplying some things he found there.

ctind
Posts: 23
Joined: 04 Nov 2019, 17:46

Re: XBOX One Controller

Post by ctind » 14 Jan 2021, 12:23

Apologies for necro-posting. I don't like creating new threads unnecessarily.

I am trying to make heads or tails of how to add the new XBOX ONE xinput library (post #4) to AHK. I know the old post (https://autohotkey.com/board/topic/35848-xinput-xbox-360-controller-api/) said something about adding a library to the lib folder within the AHK install directory but there is no "Lib" folder. (Is there another place?) I am running AHK on W10 1909 64-bit and have AHK 1.1.33.02 32-bit Unicode installed as default. It is however, installed to the "Program Files" directory, not "Program Files (x86)" I doubt that really matters though.

What I read in the old forums for the xinput library is that AutoHotKey_L is required. Then I read that the current ahk IS the "L" version.
My head is spinning at this point and I am *FAR* from proficient in AHK. If somebody can give me the "down-n-dirty" on how to get the Xbox ONE Xinput lib (from post number 4 in this thread) installed using the current version of AHK (or which ever version of AHK that I need to install) to give me the functionality with my XBOX ONE controller that I need, I would be indebted to you. Thank you all in advance for the countless hours you have so selflessly dedicated to helping others. Such as myself.

Post Reply

Return to “Ask For Help”