Jump to content
LaunchBox Community Forums

Auto Hotkey Scripts


Lordmonkus

Recommended Posts

20 minutes ago, -neo- said:

I swapped over controller to an original Xbox 360 i have kicking around, works spot on as you said it would 😁

Any ideas why it doesn't work with a "Power A enhanced  Xbox one/windows 10 controller"

Glad you got it to work!  At least with one controller.  I only have an original 360 controller (wireless), so can't attest to the other.

It looks like the Power A is a corded controller.  So it may be related to what @skizzosjt was mentioning regarding the joy number (not to be confused with the Button #).  That is, it might be being seen as Joy controller #2, or #4 or something other than 1Joy.  So "1Joy6" may need to be "2Joy6" or "4Joy6".

Link to comment
Share on other sites

3 hours ago, JoeViking245 said:

Glad you got it to work!  At least with one controller.  I only have an original 360 controller (wireless), so can't attest to the other.

It looks like the Power A is a corded controller.  So it may be related to what @skizzosjt was mentioning regarding the joy number (not to be confused with the Button #).  That is, it might be being seen as Joy controller #2, or #4 or something other than 1Joy.  So "1Joy6" may need to be "2Joy6" or "4Joy6".

Looks like mine is controller 1 after all, @skizzosjt  any ideas how to make this work with the power A controller ?

 

controller.png

Link to comment
Share on other sites

6 hours ago, -neo- said:

Any ideas why it doesn't work with a "Power A enhanced  Xbox one/windows 10 controller", this does have 2 extra buttons underneath but they don't register on the PC, you can program these to act like the other buttons but i never have, in windows when i run "set up USB controller" the same buttons (5&6) are shown as working the same way on both controllers 🤔

 

2 hours ago, -neo- said:

Looks like mine is controller 1 after all, @skizzosjt  any ideas how to make this work with the power A controller ?

Hi Neo, I just explained this on page 56 so please go read those two posts. Make sure you read this new post here in it's entirety too. Also the two "underneath" buttons are duplicates of whatever you program them to be via the controller's program button which is also on the underside. These buttons on the bottom of the controller only are detected by any program or game if you assigned them a button, so if you never programmed them, it makes sense why no program or game detects them.

 

 

 

6 hours ago, JoeViking245 said:

It looks like the Power A is a corded controller.  So it may be related to what @skizzosjt was mentioning regarding the joy number (not to be confused with the Button #).  That is, it might be being seen as Joy controller #2, or #4 or something other than 1Joy.  So "1Joy6" may need to be "2Joy6" or "4Joy6".

They have exact same controller I do and the key issue there is due to it being an Xbox One model. But I'd bet also lending to the issue as a whole is same thing you and I mention about Joy (controller) number.

 

 

 

I played around with an example of how to use Xbox One or Xbox Series X controller specific hotkeys, or detecting any controller input from these models without use of xinput library. Since you need an active window for GetKeyState to capture those inputs correctly, I thought maybe I make a little menu to select a few things. This is just a proof of concept script, as it does nothing practical other than demonstrate this.

 

Recently found triple click hotkey examples, so thought I'd show an example of that here too. This one you would need to triple click on the Guide button to bring up a window. Now that a window from the script is in focus, controller specific hotkeys and GetKeyState will work for even Xbox One and Series X controllers. These two examples just will have soundbeep activate when the buttons are detected

vk07::                                  ;Xbox Guide button
SetTimer, TripleClickDetect, -200       ;run timer only once after 200ms passes due to negative symbol
GuideClickCount++                       
If (GuideClickCount = 3) {
        Gui, Main:New, , HTPC Menu
        Gui, Main:Show, w500 h500
        Goto, CheckControllerState
}
Return
TripleClickDetect:                      ;this will clear the click count variable
GuideClickCount :=                      ;creating a 200ms window to detect 3 clicks
Return                                  

MainGuiClose:
ExitApp

CheckControllerState:
SetTimer, ControllerInputCheck, 16      ;timer will consistently start in 16ms intervals
ControllerInputCheck:
Return

2Joy6::                                 ;"2nd controller's Right Bumper"  per Windows/AHK
If (GetKeyState("2Joy5"))               ;"2nd controller's Left Bumper"  per Windows/AHK
     SoundBeep

 

 

This one the difference from script above is just removing the Return after the ControllerInputCheck timer. So this works more like a normal controller state checking script rather than a hotkey. Changed the controller button used too for sake of example

vk07::                                  ;Xbox Guide button
SetTimer, TripleClickDetect, -200       ;run timer only once after 200ms passes due to negative symbol
GuideClickCount++                       
If (GuideClickCount = 3) {
        Gui, Main:New, , HTPC Menu
        Gui, Main:Show, w500 h500
        Goto, CheckControllerState
}
Return
TripleClickDetect:                      ;this will clear the click count variable
GuideClickCount :=                      ;creating a 200ms window to detect 3 clicks
Return                                  

MainGuiClose:
ExitApp

CheckControllerState:
SetTimer, ControllerInputCheck, 16      ;timer will consistently start in 16ms intervals
ControllerInputCheck:
If (GetKeyState("2Joy1"))               ;"2nd controller's A button"  per Windows/AHK
     SoundBeep

 

Users with Xbox One and Series X model controllers will notice the script stops detecting controller input as soon as a script window no longer has focus. Once back in focus, it works again. Unlike Xbox 360 controllers that can still have controller specific hotkeys and GetKeyState work even when a script window is not in focus.

 

 

 

And here is more specific example of having an interface to use with a controller. Get the GUI to show by triple clicking the Guide button. Then what you can do here is use left/right on the D-Pad to select between the two buttons. You can open an instance of Notepad, or exit the script. Use the "A" button on your controller to select either of them. Note you need to be more specific with your If/Else logic like I did or else you will get "turbo fire" going on.....or you need to really reduce the timer interval/frequency but then that creates input lag. Which may be fine for some silly example like this but actual gaming use you obviously don't want more lag due to needing more X ms before detection. Without being more specific with If/Else logic, when you use the controller to open notepad several instances of notepad will open because maybe you hold the button down for 120ms but it checks every 16ms so there would be multiple fires of the send command.

This same method works for using xinput library too. When I have more time I will show what I made a while ago with help from JoeViking since I think that will be helpful to community for understanding

vk07::                                  ;Xbox Guide button
SetTimer, TripleClickDetect, -200       ;run timer only once after 200ms passes due to negative symbol
GuideClickCount++                       
If (GuideClickCount = 3) {
        Gui, Main:New, , HTPC Menu
        Gui, Main:Show, w500 h500
        Gui, Main:Add, Button, x25 y25 w70 gRunNotepad, Launch Notepad
        Gui, Main:Add, Button, x400 y25 w70 gMainGuiClose, Exit Script
        Goto, CheckControllerState
}
Return
TripleClickDetect:                      ;this will clear the click count variable
GuideClickCount :=                      ;creating a 200ms window to detect 3 clicks
Return                                  

MainGuiClose:
ExitApp

RunNotepad:
Run, Notepad
Return

CheckControllerState:
SetTimer, ControllerInputCheck, 16      ;timer will consistently start in 16ms intervals
ControllerInputCheck:                   ;Joy #, button #, POV #, per AHK's Official Controller Test Script
If (GetKeyState("2Joy1")) {             ;2nd controller's A button
        If (A_Btn_Pressed != 1) {
                A_Btn_Pressed := 1
                Send {Enter down} 
        }
}
Else If (A_Btn_Pressed = 1) {
        A_Btn_Pressed := 0
        Send {Enter up}
} 
If (GetKeyState("2JoyPOV") = 9000) {    ;2nd controller's Right D-Pad button 
        If (DPad_Right_Pressed != 1 ) {
                DPad_Right_Pressed := 1     
                Send {Right down}
        }
}
Else If (DPad_Right_Pressed = 1) {
        DPad_Right_Pressed := 0
        Send {Right up}
}
If (GetKeyState("2JoyPOV") = 27000) {    ;2nd controller's Left D-Pad button 
        If (DPad_Left_Pressed != 1 ) {
                DPad_Left_Pressed := 1     
                Send {Left down}
        }
}
Else If (DPad_Left_Pressed = 1) {
        DPad_Left_Pressed := 0
        Send {Left up}
}

 

Note from AHK's docs seems controllers can have different POV values which is the D-pad. Since I know Neo has same controller as I used in this example I know it will work for them but for others left/right might have different values and you would have to find that out through AHK's Controller Test Script

https://www.autohotkey.com/docs/v1/misc/RemapController.htm

 

Note for all these scripts I shared in this post just now. Unless your controller comes up as #2, users need to change the Joy (controller) number accordingly per Windows and therefore AHK's Controller Test Script

https://www.autohotkey.com/docs/v1/scripts/index.htm#ControllerTest

 

 

Edited by skizzosjt
changed variable names from "down" to "pressed" (less potential to confuse direction vs button is pressed)
  • Thanks 2
Link to comment
Share on other sites

On 1/15/2024 at 3:21 PM, pafftis said:

its my config.

I used this code, but I still can't close the emulator. I tried the second joystick, but it still doesn't work. I hold down the button and press the second one after it, but it still doesn't come out.

 

image.png

Can you tell me if my script is correct?

Link to comment
Share on other sites

  • 2 weeks later...

Here is some example of using xinput library with AHK in order to work with any xinput controller regardless of any script owned window being in focus. You need a few things to make this work. First is the xinput library. For anyone wondering why I keep calling this a library it's just an AHK term for describing a script that typically doesn't do anything by itself, but using a supplement script calling to the functions in the "library" script. The 2nd thing is this supplement script that has all the meat and potatoes part, where you code this button does this and that joystick does that sort of stuff.

Now what I've got to show here is something that will basically make your controller work like a mouse. What I discovered is if you put the logic for mouse movement and checking ALL the buttons into the same script, it seems AHK genuinely does not run fast enough to make the mouse movement work well while doing all the additional checks. AHK is not multi-threaded. So a way to make pseudo multi-threaded AHK  is to launch multiple scripts simultaneously. So I have one script dedicated to using the left joystick as controlling the mouse (this makes it feel as smooth as possible), and a separate script dedicated to all the buttons. I then created a third script to launch these two meat and potatoes scripts....so in total, I got four scripts here to do this.

 

The latest xinput library will use xinput1_4.dll but will fall back to xinput1_3.dll if you're on an older OS like Windows 7. Please note I did not create any of this specific xinput.ahk library script. All credit for the xinput library goes to the author Lexikos

Name this script below as xinput.ahk

Spoiler
/*  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.

 

 

 

This is the script for just manipulating the left joystick and it will control your mouse cursor

Name this script as xinput remap mouse only.ahk

Spoiler
#Include xinput.ahk
#Persistent
XInput_Init()

SetMouseDelay, -1
MouseMoveInterval := 3
SetTimer, InputCheck, 0
InputCheck:
state := Xinput_GetState(0)
If (state)
{
        If (state.bRightTrigger > 175) {                         ;Right Trigger = modifier to enable fast mouse movement
                If (RT_Pressed != 1) {
                        MouseMoveInterval := 20
                        RT_Pressed := 1                        
                }
        }     
        Else If (MouseMoveInterval != 3) {
                RT_Pressed := 0
                MouseMoveInterval := 3
        }

        ;Left Joy Stick (0 = Center and +/- 9000 is the deadzone)
        ;Range between -32768 and 32767. 
        If (state.sThumbLX < -9000 && state.sThumbLX >= -32768)   ;Left joystick left = move mouse left
                MouseMove, -%MouseMoveInterval%, 0, 0, R
        If (state.sThumbLX > 9000 && state.sThumbLX <= 32767)     ;Left joystick right = move mouse right
                MouseMove, %MouseMoveInterval%, 0, 0, R
        If (state.sThumbLY > 9000 && state.sThumbLY <= 32767)     ;Left joystick up = move mouse up
                MouseMove, 0, -%MouseMoveInterval%, 0, R
        If (state.sThumbLY < -9000 && state.sThumbLY >= -32768)   ;Left joystick down = move mouse down
                MouseMove, 0, %MouseMoveInterval%, 0, R
}

 

 

 

This is the script for everything else on the controller

Name this script as xinput remap.ahk

Spoiler
#Include xinput.ahk
#Persistent
XInput_Init()

SetTimer, InputCheck, 16
InputCheck:
state := Xinput_GetState(0)
If (state)
{
        If (state.wButtons = 4096) {             ;A button = Left Mouse Click
                If (A_BtnDown != 1) {
                        Send {LButton down}
                        Sleep, 50
                        A_BtnDown := 1
                }
        }
        Else If (A_BtnDown = 1) {
                Send {LButton Up}
                A_BtnDown := 0
        }

        If (state.wButtons = 8192) {             ;B button = Right Mouse Click
                If (B_BtnDown != 1) {
                        Send, {RButton}
                        B_BtnDown := 1
                }
        }
        Else If (B_BtnDown = 1)
                B_BtnDown := 0

        If (state.wButtons = 16384) {            ;X button = Double Left Mouse Click
                If (X_BtnDown != 1) {
                        Send, {LButton 2}
                        X_BtnDown := 1
                }
        }
        Else If (X_BtnDown = 1)
                X_BtnDown := 0                

        If (state.wButtons = 32768) {            ;Y button = rumble test
                If (Y_BtnDown != 1) {
                        XInput_SetState(0, 65535, 65535)        ;making controller #1 rumble at 100% example
                        Sleep, 2000
                        XInput_SetState(0, 0, 0)                ;turning rumble off
                        Y_BtnDown := 1
                }
        }
        Else If (Y_BtnDown = 1)
                Y_BtnDown := 0 
        
        If (state.wButtons = 1) {                ;D-Pad Up = Up key / Page Up key
                If (DPad_Up_Pressed != 1) {
                        If (RT_Pressed = 1) {
                                Send {Up down}
                                DPad_Up_Pressed := 0
                        }
                        Else If (LT_Pressed = 1) {
                                Send {PgUp}
                                DPad_Up_Pressed := 1
                        }
                        Else {
                                Send {Up down}
                                DPad_Up_Pressed := 1
                        }
                }
        }
        Else If (DPad_Up_Pressed = 1) {
                DPad_Up_Pressed := 0
                Send {Up up}
        }

        If (state.wButtons = 2) {                ;D-Pad Down = Down key / Page Down key
                If (DPad_Down_Pressed != 1) {
                        If (RT_Pressed = 1) {
                                Send {Down down}
                                DPad_Down_Pressed := 0
                        }
                        Else If (LT_Pressed = 1) {
                                Send {PgDn}
                                DPad_Down_Pressed := 1
                        }
                        Else {
                                Send {Down down}
                                DPad_Down_Pressed := 1
                        }
                }
        }
        Else If (DPad_Down_Pressed = 1) {
                DPad_Down_Pressed := 0
                Send {Down up}
        }

        If (state.wButtons = 4) {                ;D-Pad Left = Left key
                If (DPad_Left_Pressed != 1) {
                        If (RT_Pressed = 1) {
                                Send {Left down}
                                DPad_Left_Pressed := 0
                        }
                        Else {
                                Send {Left down}
                                DPad_Left_Pressed := 1
                        }
                }
        }
        Else If (DPad_Left_Pressed = 1) {
                DPad_Left_Pressed := 0
                Send {Left up}
        }        
        
        If (state.wButtons = 8) {                ;D-Pad Right = Right key
                If (DPad_Right_Pressed != 1) {
                        If (RT_Pressed = 1) {
                                Send {Right down}
                                DPad_Right_Pressed := 0
                        }
                        Else {
                                Send {Right down}
                                DPad_Right_Pressed := 1
                        }
                }
        }
        Else If (DPad_Right_Pressed = 1) {
                DPad_Right_Pressed := 0
                Send {Right up}
        }    

        If (state.wButtons = 1024) {            ;Guide button = NOT IN USE
                If (Guide_BtnDown != 1) {
                        SoundBeep, 400
                        Guide_BtnDown := 1
                }
        }
        Else If (Guide_BtnDown = 1)
                Guide_BtnDown := 0 

        If(state.wButtons = 16) {                ;Start = NOT IN USE
                If (Start_Pressed != 1) {
                        SoundBeep, 500
                        Start_Pressed := 1
                }
        }
        Else If (Start_Pressed = 1)
                Start_Pressed := 0

        If (state.wButtons = 32) {              ;Back = NOT IN USE
                If (Back_Pressed != 1) {
                        SoundBeep, 600
                        Back_Pressed := 1
                }
        }
        Else If (Back_Pressed = 1)
                Back_Pressed := 0

        If (state.wButtons = 256) {              ;Left Bumper = NOT IN USE
                If (Left_Bumper_Pressed != 1) {
                        SoundBeep, 700
                        Left_Bumper_Pressed := 1
                }
        }
        Else If (Left_Bumper_Pressed = 1)
                Left_Bumper_Pressed := 0

        If (state.wButtons = 512) {              ;Right Bumper = NOT IN USE
                If (Right_Bumper_Pressed != 1) {
                        SoundBeep, 800
                        Right_Bumper_Pressed := 1
                }
        }
        Else If (Right_Bumper_Pressed = 1)
                Right_Bumper_Pressed := 0
                
        If (state.wButtons = 64) {               ;Left Joystick Click = NOT IN USE
                If (LJS_Pressed != 1) {
                        SoundBeep, 900
                        LJS_Pressed := 1
                }
        }
        Else If (LJS_Pressed = 1)
                LJS_Pressed := 0

        If (state.wButtons = 128) {              ;Right Joystick Click = NOT IN USE
                If (RJS_Pressed != 1) {
                        SoundBeep, 1000
                        RJS_Pressed := 1
                }
        }
        Else If (RJS_Pressed = 1)
                RJS_Pressed := 0
        
        If (state.bLeftTrigger > 175) {          ;Left Trigger (range 0 - 255) = modifier to enable pg up/dn keys
                If (LT_Pressed != 1)
                        LT_Pressed := 1                        
        }     
        Else If (LT_Pressed = 1)
                LT_Pressed := 0

        If (state.bRightTrigger > 175) {         ;Right Trigger (range 0 - 255) = modifier to enable fast mouse movement, and rapid direction input
                If (RT_Pressed != 1) 
                        RT_Pressed := 1                        
        }     
        Else If (RT_Pressed = 1)
                RT_Pressed := 0

        If (state.sThumbRX < -9000 && state.sThumbLX >= -32768) {       ;Right joystick left = NOT IN USE
                If (RJS_Left_Engaged <= 1) {
                        SoundBeep, 1100
                }
                Else
                        RJS_Left_Engaged := RJS_Left_Engaged - 1        ;maybe don't need this depending on how it will be used
        }
        
        If (state.sThumbRX > 9000 && state.sThumbLX <= 32767) {         ;Right joystick right = NOT IN USE
                If (RJS_Right_Engaged <= 1) {
                        SoundBeep, 1200
                }
                Else
                        RJS_Right_Engaged := RJS_Right_Engaged - 1      ;maybe don't need this depending on how it will be used
        }

        If (state.sThumbRY > 9000 && state.sThumbLX <= 32767) {         ;Right joystick up = mouse wheel up
                If (RJS_Up_Engaged <= 1) {
                        Click, WheelUp, 1
                        RJS_Up_Engaged := 5                        
                }
                Else
                        RJS_Up_Engaged := RJS_Up_Engaged - 1
        }
        If (state.sThumbRY < -9000 && state.sThumbLX >= -32768) {       ;Right joystick down = mouse wheel down
                If (RJS_Down_Engaged <= 1) {
                        Click, WheelDown, 1
                        RJS_Down_Engaged := 5                        
                }
                Else
                        RJS_Down_Engaged := RJS_Down_Engaged - 1        
        }
}

+F12::  ;Shift + F12
SoundBeep
DetectHiddenWindows, on
SetTitleMatchMode, 2
WinClose, xinput remap mouse only.ahk ahk_class AutoHotkey
WinClose, xinput remap.ahk ahk_class AutoHotkey
ExitApp

 

 

 

This is the script to launch this stuff simultaneously. You could alternatively just open them both manually and not use this last script.

Name this script as xinput remap launcher.ahk

Run, xinput remap mouse only.ahk
Run, xinput remap.ahk

 

 

Put all of these scripts into the SAME FOLDER and then run xinput remap launcher.ahk to play around with this script. Alternatively don't use the last script and just manually run xinput remap.ahk and xinput remap mouse only.ahk.

image.thumb.png.e82e9730142a5714115bbccca078dbd8.png

Comments are all over the script to describe what is going on but here is a list of that for understanding.

Left joystick  = will act like your mouse

*Take note if you hold the right trigger it will change from a "slow" mouse movement speed to a "fast" mouse movement speed

A button = left mouse click

B button = right mouse click

X button = double left mouse click

Y button = make your controller rumble for 2 seconds

D-pad directions all are coordinated to the keyboard arrow keys

*Take note if you hold the right trigger it will change from only allowing 1 step per D-pad push to what will mimic "turbo fire" or how keyboards repeat keys when held down

*Take note if you hold the left trigger it will change the UP and DOWN D-pad buttons into the Page Up and Page Down keys respectively

Right joystick up/down = rolling the mouse wheel up/down respectively

 

The following buttons don't really do anything specific, so I just made them a bunch of various SoundBeep frequencies.

Guide button

Start button

Back/View button

Left and Right bumpers

Left and Right joystick clicks

Right joystick Left and Right

 

You can terminate the script by pushing SHIFT+F12

 

Have fun! And hope this shows some users how to make use of xinput for making your controller do unique stuff!

Also thanks to JoeViking245 for helping me learn how to use this xinput library!

 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

I would like to add onto my last post above. I recently wanted to make a hotkey using two face buttons and quickly realized I couldn't use the same method I had been employing. That is because I only made combo hotkeys using the triggers and a single face button. This worked because the left and right trigger both go to independent variables, being bLeftTrigger and bRightTrigger respectively. Along with the single face button I was using goes to wButtons. So in that example each button (or trigger) pressed to activate the hotkey is stored in it's own variable. But what happens if you want to use multiple buttons that all get stored to the same variable, in this case wButtons? You cannot have a single variable be different values simultaneously so I knew there was a different approach needed

As I scratched my head I recalled AHK MsgBox options works by adding all of the various option's values when you need to use multiple options simultaneously. I wondered if it worked the same way here. So as I tested this, it did in fact turn out to be the right way to do this with xinput

For ex, this will be pressing the Start button, and the X button together

Start button value = 16

X button value = 16384

Add them together for a sum of 16400. Using that value, check wButtons, for ex...

If (state.wButtons = 16400)

This will be checking if both the Start button and X button are pressed simultaneously. The sum of all the various individual button combos is always a unique value so this is how xinput knows which buttons are pressed like this. All "face buttons" are going to the same wButtons variable. To be specific, that means, A, B, X, Y, Left Bumper, Right Bumper, Back/View, Start, Guide, Left Joystick click, Right Joystick click, and the D-pad directions. Any time you need to check a combo of those, you need to add their values together and check for that value. By contrast, only the left and right triggers, and the joystick axis go to their own individual variable.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...