Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

XBOX Controller Keyboard and Mouse


  • Please log in to reply
7 replies to this topic
Neodudeman
  • Members
  • 17 posts
  • Last active: Nov 22 2007 07:41 PM
  • Joined: 14 Mar 2007
Well, I've been lurking around these boards for half a year now, being newbish, and asking silly questions, and I've felt that it's about time I gave something back to the community.

This is my first publicly released script. I've worked very hard on it; unfortunately, I know that only a few of you out there can really use it.

The code is very choppy, and there are quite a few things wrong, and I would love to get some feedback.

What is it?

This script turns an XBOX Controller into both a mouse and a keyboard. By utilizing the Left Trigger and Right Trigger, you type using the POV and Face buttons. Here are the pics:
Posted ImagePosted ImagePosted Image

When neither trigger is held down, the right joystick acts as the mouse control, the A Button is Left Click, the B is Right Click, and the X is Middle Click

Here it is:

#Persistent
    ; Increase the following value to make the mouse cursor move faster:
    JoyMultiplier = 0.30

    ; Decrease the following value to require less joystick displacement-from-center
    JoyThreshold = 3

    ; Change the following to true to invert the Y-axis, which causes the mouse to
    InvertYAxis := false

    JoyThresholdUpper := 50 + JoyThreshold
    JoyThresholdLower := 50 - JoyThreshold

    if InvertYAxis
        YAxisMultiplier = -1
    else
        YAxisMultiplier = 1

    SetTimer, TriggerCheck, 5
    SetTimer, POVCheck, 5
    SetTimer, WatchJoystick, 10
    ;SetTimer, HelpBox, 5
    return

    /*
    HelpBox:
    If LTrig=D
    {
    MouseGetPos, MX, MY
    Gui, +Resize
    Gui, Add, Pic, xm vPic
    GuiControl,, Pic, *w400 *h362 xbox LEFT.jpg  ; Load the image.
    Gui, Show, x%MX% y%MY% AutoSize, xbox LEFT.jpg  ; Resize the window to match the picture size.
    return
    }
    If RTrig=D
    {
    MouseGetPos, MX, MY
    Gui, +Resize
    Gui, Add, Pic, xm vPic
    GuiControl,, Pic, *w400 *h362 xbox RIGHT.jpg  ; Load the image.
    Gui, Show, x%MX% y%MY% AutoSize, xbox RIGHT.jpg  ; Resize the window to match the picture size.
    return
    }
    If LTrig=U
        Gui, Destroy
    If RTrig=U
        Gui, Destroy
    return


    else
    {
    MouseGetPos, MX, MY
    Gui, +Resize
    Gui, Add, Pic, xm vPic
    GuiControl,, Pic, *w400 *h362 xbox BOT.jpg  ; Load the image.
    Gui, Show, x%MX% y%MY% AutoSize, xbox RIGHT.jpg  ; Resize the window to match the picture size.
    return
    }
    If LDown=0
        Gui, Destroy
    If RDown=0
        Gui, Destroy
    return
    */

    TriggerCheck:
    GetKeyState, LTrig, Joy11
    GetKeyState, Rtrig, Joy12
    If LTrig=D
        LDown=1
    If LTrig=U
        LDown=0
    If RTrig=D
        RDown=1
    If RTrig=U
        RDown=0
    Both:=RDown+LDown
    return

    Joy6::
    Button=1
    If Both=2
    {
    ;    Goto CapsLockState
        Send z
        return
    }
    Send {Enter}
    return

    CapsLockState:
    If CapsLockOn
    {
        SetCapsLockState, Off
        CapsLockOn=0
        return
    }
    SetCapsLockState, On
    CapsLockOn=1
    return

    Joy11::
    Button=0
    Keywait Joy11
    If Button=0
        Send {Backspace}
    return

    Joy12::
    Button=0
    Keywait Joy12
    If Button=0
        Send {Space}
    return

    Joy5::
    Button=1
    If Both=2
    {
    ;    Goto CapsLockState
        Send y
        return
    }
    If LDown=1
    {
        Send .
        return
    }
    If RDown=1
    {
        Send .
        return
    }
    return

    Joy1::
    Button=1
    If Both=2
    {
        Send q
        return
    }
    If LDown=1
    {
        Send a
        return
    }
    If RDown=1
    {
        Send i
        return
    }
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseClick, left,,, 1, 0, D  ; Hold down the left mouse button.
    SetTimer, WaitForLeftButtonUp, 10
    return

    Joy2::
    Button=1
    If Both=2
    {
        Send r
        return
    }
    If LDown=1
    {
        Send b
        return
    }
    If RDown=1
    {
        Send j
        return
    }
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseClick, right,,, 1, 0, D  ; Hold down the right mouse button.
    SetTimer, WaitForRightButtonUp, 10
    return

    Joy3::
    Button=1
    If Both=2
    {
        Send s
        return
    }
    If LDown=1
    {
        Send c
        return
    }
    If RDown=1
    {
        Send k
        return
    }
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseClick, middle,,, 1, 0, D  ; Hold down the right mouse button.
    SetTimer, WaitForMiddleButtonUp, 10
    return

    WaitForLeftButtonUp:
    GetKeyState, ButtA, Joy1
    if ButtA=D
        return  ; The button is still, down, so keep waiting.
    ; Otherwise, the button has been released.
    SetTimer, WaitForLeftButtonUp, off
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseClick, left,,, 1, 0, U  ; Release the mouse button.
    return

    WaitForRightButtonUp:
    GetKeyState, ButtB, Joy2
    if ButtB=D
        return  ; The button is still, down, so keep waiting.
    ; Otherwise, the button has been released.
    SetTimer, WaitForRightButtonUp, off
    MouseClick, right,,, 1, 0, U  ; Release the mouse button.
    return

    WaitForMiddleButtonUp:
    GetKeyState, ButtX, Joy3
    if ButtX=D
        return  ; The button is still, down, so keep waiting.
    ; Otherwise, the button has been released.
    SetTimer, WaitForMiddleButtonUp, off
    MouseClick, middle,,, 1, 0, U  ; Release the mouse button.
    return

    Joy4::
    Button=1
    If Both=2
    {
        Send t
        return
    }
    If LDown=1
        Send d
    If RDown=1
        Send l
    return

    POVCheck:
    GetKeyState, POV, JoyPOV

    If (OLDPov=POV)
    {
    ;    Msgbox, %oldpov%=%pov%
        return
    }
    OLDPov = %POV%

    If POV=0
        GOTO POVUp
    else If POV=9000
        GOTO POVRight
    else If POV=27000
        GOTO POVLeft
    else If POV=18000
        GOTO POVDown
    return

    POVDown:
    Button=1
    If Both=2
    {
        Send u
        return
    }
    If LDown=1
        Send e
    If RDown=1
        Send m
    return

    POVRight:
    Button=1
    If Both=2
    {
        Send v
        return
    }
    If LDown=1
        Send f
    If RDown=1
        Send n
    return

    POVLeft:
    Button=1
    If Both=2
    {
        Send w
        return
    }
    If LDown=1
        Send g
    If RDown=1
        Send o
    return

    POVUp:
    Button=1
    If Both=2
    {
        Send x
        return
    }
    If LDown=1
        Send h
    If RDown=1
        Send p
    return

    WatchJoystick:
    MouseNeedsToBeMoved := false  ; Set default.
    SetFormat, float, 03
    GetKeyState, joyx, JoyX
    GetKeyState, joyy, JoyY
    if joyx > %JoyThresholdUpper%
    {
        MouseNeedsToBeMoved := true
        DeltaX := joyx - JoyThresholdUpper
    }
    else if joyx < %JoyThresholdLower%
    {
        MouseNeedsToBeMoved := true
        DeltaX := joyx - JoyThresholdLower
    }
    else
        DeltaX = 0
    if joyy > %JoyThresholdUpper%
    {
        MouseNeedsToBeMoved := true
        DeltaY := joyy - JoyThresholdUpper
    }
    else if joyy < %JoyThresholdLower%
    {
        MouseNeedsToBeMoved := true
        DeltaY := joyy - JoyThresholdLower
    }
    else
        DeltaY = 0
    if MouseNeedsToBeMoved
    {
        SetMouseDelay, -1  ; Makes movement smoother.
        MouseMove, DeltaX * JoyMultiplier, DeltaY * JoyMultiplier * YAxisMultiplier, 0, R
    }
    return

Thanks to the Using a Joystick as a Mouse and the command reference examples.

TODO List:

Get the Help Box Working. I want a popup of the help pictures when the corresponding trigger button is pressed.

Get the CapsLock working. The send command sends as lowercase. I want to make an uppercase feature.

Get the Rumble Feature working. Does anyone know how to activate the actuators in the XBOX Controller?

Oh, and for future reference, I've mapped the XBOX Controller's Joypad numbers for anyone out there who wants to do something like this. X and Y and U and V are the stick positions.
Posted Image

Lexikos
  • Administrators
  • 9445 posts
  • Last active:
  • Joined: 17 Oct 2006
Useful; good work. 8)

Are you using the unofficial Xbox Controller Drivers (XBCD)? Have you noticed the button mappings can be completely changed via the XBCD Setup util?

I use 360 version of XBCD with my wired Xbox 360 pad, since they're MUCH more powerful than the official drivers. (I don't think there are official drivers for the original Xbox pads.) The Xbox 360 uses standard USB, so I'd guess 360 pads would be more commonly used on PCs than the original pads. There's also a "Windows" version of the 360 pad, but the only difference is they package it with a copy of the official drivers.

Here's what I'm using atm, built on top of your script:
#Persistent
; Increase the following value to make the mouse cursor move faster:
JoyMultiplier = 0.30

; Decrease the following value to require less joystick displacement-from-center
JoyThreshold = 3

; Change the following to true to invert the Y-axis, which causes the mouse to
InvertYAxis := false

JoyThresholdUpper := 50 + JoyThreshold
JoyThresholdLower := 50 - JoyThreshold

if InvertYAxis
    YAxisMultiplier = -1
else
    YAxisMultiplier = 1

SetTimer, TriggerCheck, 5
SetTimer, POVCheck, 5
SetTimer, WatchJoystick, 10
;SetTimer, HelpBox, 5

LastWheelTick := A_TickCount ; for wheel timer  -- Lexikos
WheelUpTime := WheelDownTime := 0

; Button and Axis mappings  -- Lexikos
BtnA        = Joy1
BtnB        = Joy2
BtnX        = Joy3
BtnY        = Joy4
BtnWhite    = Joy5 ; 360: right bumper
BtnBlack    = Joy6 ; 360: left bumper
BtnLT       = Joy7
BtnRT       = Joy8
BtnLS       = Joy9
BtnRS       = Joy10
BtnBack     = Joy11
BtnStart    = Joy12
AxisLX      = JoyX
AxisLY      = JoyY
AxisRX      = JoyU
AxisRY      = JoyR

Btns = A,B,X,Y,White,Black,LT,RT,LS,RS,Back,Start
Loop, Parse, Btns, `,
    if IsLabel("Pressed" A_LoopField)
        Hotkey, % Btn%A_LoopField%, Pressed%A_LoopField%
return

/*
HelpBox:
If LTrig=D
{
MouseGetPos, MX, MY
Gui, +Resize
Gui, Add, Pic, xm vPic
GuiControl,, Pic, *w400 *h362 xbox LEFT.jpg  ; Load the image.
Gui, Show, x%MX% y%MY% AutoSize, xbox LEFT.jpg  ; Resize the window to match the picture size.
return
}
If RTrig=D
{
MouseGetPos, MX, MY
Gui, +Resize
Gui, Add, Pic, xm vPic
GuiControl,, Pic, *w400 *h362 xbox RIGHT.jpg  ; Load the image.
Gui, Show, x%MX% y%MY% AutoSize, xbox RIGHT.jpg  ; Resize the window to match the picture size.
return
}
If LTrig=U
    Gui, Destroy
If RTrig=U
    Gui, Destroy
return


else
{
MouseGetPos, MX, MY
Gui, +Resize
Gui, Add, Pic, xm vPic
GuiControl,, Pic, *w400 *h362 xbox BOT.jpg  ; Load the image.
Gui, Show, x%MX% y%MY% AutoSize, xbox RIGHT.jpg  ; Resize the window to match the picture size.
return
}
If LDown=0
    Gui, Destroy
If RDown=0
    Gui, Destroy
return
*/

TriggerCheck:
GetKeyState, LTrig, %BtnLT%
GetKeyState, Rtrig, %BtnRT%
If LTrig=D
    LDown=1
If LTrig=U
    LDown=0
If RTrig=D
    RDown=1
If RTrig=U
    RDown=0
Both:=RDown+LDown
return

PressedWhite:
Button=1
If Both=2
{
    Send {Blind}z
    return
}
Send {Enter}
return

PressedLT:
Button=0
Keywait %BtnLT%
If Button=0
    Send {Backspace}
return

PressedRT:
Button=0
Keywait %BtnRT%
If Button=0
    Send {Space}
return

PressedBlack:
Button=1
If Both=2
{
    Send {Blind}y
    return
}
If LDown=1
{
    Send {Blind}.
    return
}
If RDown=1
{
    Send {Blind}.
    return
}
return

PressedA:
Button=1
If Both=2
{
    Send {Blind}q
    return
}
If LDown=1
{
    Send {Blind}a
    return
}
If RDown=1
{
    Send {Blind}i
    return
}
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, D  ; Hold down the left mouse button.
SetTimer, WaitForLeftButtonUp, 10
return

PressedB:
Button=1
If Both=2
{
    Send {Blind}r
    return
}
If LDown=1
{
    Send {Blind}b
    return
}
If RDown=1
{
    Send {Blind}j
    return
}
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, right,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForRightButtonUp, 10
return

PressedX:
Button=1
If Both=2
{
    Send {Blind}s
    return
}
If LDown=1
{
    Send {Blind}c
    return
}
If RDown=1
{
    Send {Blind}k
    return
}
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, middle,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForMiddleButtonUp, 10
return

WaitForLeftButtonUp:
GetKeyState, ButtA, %BtnA%
if ButtA=D
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForLeftButtonUp, off
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, U  ; Release the mouse button.
return

WaitForRightButtonUp:
GetKeyState, ButtB, %BtnB%
if ButtB=D
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForRightButtonUp, off
MouseClick, right,,, 1, 0, U  ; Release the mouse button.
return

WaitForMiddleButtonUp:
GetKeyState, ButtX, %BtnX%
if ButtX=D
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForMiddleButtonUp, off
MouseClick, middle,,, 1, 0, U  ; Release the mouse button.
return

PressedY:
Button=1
If Both=2
{
    Send {Blind}t
    return
}
If LDown=1
    Send {Blind}d
If RDown=1
    Send {Blind}l
return

POVCheck:
GetKeyState, POV, JoyPOV

If (OLDPov=POV)
{
;    Msgbox, %oldpov%=%pov%
    return
}
OLDPov = %POV%

If POV=0
    GOTO POVUp
else If POV=9000
    GOTO POVRight
else If POV=27000
    GOTO POVLeft
else If POV=18000
    GOTO POVDown
return

POVDown:
Button=1
If Both=2
{
    Send {Blind}u
    return
}
If LDown=1
    Send {Blind}e
If RDown=1
    Send {Blind}m
return

POVRight:
Button=1
If Both=2
{
    Send {Blind}v
    return
}
If LDown=1
    Send {Blind}f
If RDown=1
    Send {Blind}n
return

POVLeft:
Button=1
If Both=2
{
    Send {Blind}w
    return
}
If LDown=1
    Send {Blind}g
If RDown=1
    Send {Blind}o
return

POVUp:
Button=1
If Both=2
{
    Send {Blind}x
    return
}
If LDown=1
    Send {Blind}h
If RDown=1
    Send {Blind}p
return

WatchJoystick:
MouseNeedsToBeMoved := false  ; Set default.
SetFormat, float, 03
GetKeyState, joyx, %AxisLX%
GetKeyState, joyy, %AxisLY%
if joyx > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdUpper
}
else if joyx < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdLower
}
else
    DeltaX = 0
if joyy > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdUpper
}
else if joyy < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdLower
}
else
    DeltaY = 0
if MouseNeedsToBeMoved
{
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseMove, DeltaX * JoyMultiplier, DeltaY * JoyMultiplier * YAxisMultiplier, 0, R
}

; Scroll wheel with Right stick (vertical axis)  -- Lexikos
GetKeyState, joyy, %AxisRY%
if joyy > %JoyThresholdUpper%
{
    WheelUpInterval := 10 + (1.0 - (joyy-JoyThresholdUpper)/(50-JoyThreshold)) * 500
    WheelDownInterval := 0
}
else if joyy < %JoyThresholdLower%
{
    WheelUpInterval := 0
    WheelDownInterval := 10 + (1.0 - (JoyThresholdLower-joyy)/(50-JoyThreshold)) * 500
}
else
    WheelDownInterval := 0, WheelUpInterval := 0

WheelTimeDelta := A_TickCount-LastWheelTick, LastWheelTick := A_TickCount

if (WheelUpInterval > 0)
{
    WheelUpTime += WheelTimeDelta
    Loop {  ; loop so that WheelUpInterval can be shorter than the (actual) timer delay
        if (WheelUpTime < WheelUpInterval)
            break
        WheelUpTime -= WheelUpInterval
        Click WheelUp
    }
}
if (WheelDownInterval > 0)
{
    WheelDownTime += WheelTimeDelta
    Loop {
        if (WheelDownTime < WheelDownInterval)
            break
        WheelDownTime -= WheelDownInterval
        Click WheelDown
    }
}

return
What I added:[*:3hyeimau]The buttons and axes are mapped via the Btn/Axis variables. This allows the script to be used with practically any gamepad or joystick, as well as other xbox pads with different button mappings. The default mappings are what I use with my 360 pad, so you'll need to change them if you want to try this version of the script.
[*:3hyeimau]Hotkeys are automatically registered for each button -> Pressed%button_name% label -- e.g. PressedA, PressedWhite.
[*:3hyeimau]I added {Blind} to each Send {letter}. This allows CapsLock to work (though there is no button for CapsLock yet.)
[*:3hyeimau]The right stick's vertical axis controls the mouse wheel.I removed the CapsLockState subroutine, since the current state of caps lock can be determined with:
CapsLockOn := GetKeyState("CapsLock","T")
and CapsLock can be toggled via
Send {CapsLock}
(SetCapsLockState actually sends a CapsLock keypress.)

You may use my code additions (or not) however you see fit.

Get the Rumble Feature working. Does anyone know how to activate the actuators in the XBOX Controller?

I believe that requires DirectInput (part of DirectX.) It should be possible in AutoHotkey with DllCall, but not easy, and afaik hasn't been done before.

Neodudeman
  • Members
  • 17 posts
  • Last active: Nov 22 2007 07:41 PM
  • Joined: 14 Mar 2007
Thanks :-) I'm Really glad you like it. I spent quite a bit of time on it.

I'm using the driver from http://www.redcl0ud.com/xbcd.html with an Original XBOX Controller; the controller pictured in fact. I didn't realize that the button mappings could be changed. :oops:

I just did the XBOX Controller to PC Hack by soldering a male USB plug to the end of the XBOX plug. I don't own a 360, else I would have used that instead :p

I really like the changes you made, I'm all for the dynamic scripts, and would have done that with the original if I was advanced as you are in AHK. Though the mouse wheel to right-stick is a very nice addition.

A problem I've found with this script is that it cannot pause/suspend itself. I use the controller for games as well as controlling, and I want to pause the script so that I can stop using it as a mouse/keyboard and start using it as a controller.

The script I made maps a Pause/Suspend Postmessage to the Back button on the XBOX Controller.

#Persistent
DectectHiddenWindows On
SetTitleMatchMode 2
return

Joy8:: ;The Back button's Joyname. You might want to make this dynamic too.  :P 
;Just put your own AHK Script Name instead.
;Suspend Command
PostMessage, 0x111, 65305,,, XBOX Keyboard + Mouse.ahk
;Pause Command
PostMessage, 0x111, 65306,,, XBOX Keyboard + Mouse.ahk
return

It's really nice with that added script. I can now seamlessly switch between web browsing and playing Super Smash Brothers on Project64 :wink:.

I tried finding the command for the rumble feature using Winspector, but I'm, admittedly, very inexperienced in anything more advanced than GOTO and SEND. :oops:
How would a DllCall work?

Lexikos
  • Administrators
  • 9445 posts
  • Last active:
  • Joined: 17 Oct 2006

I tried finding the command for the rumble feature using Winspector, but I'm, admittedly, very inexperienced in anything more advanced than GOTO and SEND. :oops:
How would a DllCall work?

It's a lot more advanced than SendMessage. Here's a tutorial in C++. You'd need a firm understanding of DllCall and NumPut/NumGet to port it to AutoHotkey. Here's another tutorial with less code and more explanation.

ehamel2001
  • Guests
  • Last active:
  • Joined: --
i use this alot, but not for the typing part..i just want to use it as a mouse and be able to set up other key presses as in set insert to the y button for push to talk,and to set shortcuts like to open firefox. but i do not know how to edit it and take the keyboard part out,and set it up to do what i want.Could you right it so i know how to change the buttons to do what i want? if not thanks for your work and help :D

Lexikos
  • Administrators
  • 9445 posts
  • Last active:
  • Joined: 17 Oct 2006
If that's all you need, perhaps you should take a look at Using a Joystick as a Mouse.

The Goose
  • Guests
  • Last active:
  • Joined: --

I tried finding the command for the rumble feature using Winspector, but I'm, admittedly, very inexperienced in anything more advanced than GOTO and SEND. :oops:
How would a DllCall work?

It's a lot more advanced than SendMessage. Here's a tutorial in C++. You'd need a firm understanding of DllCall and NumPut/NumGet to port it to AutoHotkey. Here's another tutorial with less code and more explanation.

Has anyone made any progress on this? I have tried, but I haven't gotten very far. I am still pretty new to the game.

Lexikos
  • Administrators
  • 9445 posts
  • Last active:
  • Joined: 17 Oct 2006
If you're using an XBox 360 controller, it's very simple to use XInput.ahk. Otherwise, you're probably out of luck.