PovHelper - React to joystick hat directions as if they were buttons

Post your working scripts, libraries and tools
User avatar
evilC
Posts: 4716
Joined: 27 Feb 2014, 12:30

PovHelper - React to joystick hat directions as if they were buttons

23 Oct 2018, 13:39

The example code in the docs for dealing with POVs makes me want to stab my eyes out with a fork

So here's a better version

Code: Select all

#SingleInstance force

ph := new PovHelper(3)  ; Pass Joystick number here

/*
When calling Subscribe, pass direction NAMES (Up, Right, Down or Left) or INDEXES (1, 2, 3, 4)
*/
ph.Subscribe("Up", Func("Up"))
ph.Subscribe("Left", Func("Left"))
return

^Esc::
    ExitApp

Up(state){
    Tooltip % "Up " (state ? "Pressed" : "Released") " @ " A_TickCount
}

Left(state){
    Tooltip % "Left " (state ? "Pressed" : "Released") " @ " A_TickCount
}

class PovHelper {
    static PovMap := {-1: [0,0,0,0], 1: [1,0,0,0], 2: [1,1,0,0] , 3: [0,1,0,0], 4: [0,1,1,0], 5: [0,0,1,0], 6: [0,0,1,1], 7: [0,0,0,1], 8: [1,0,0,1]}
    static directionNames := {Up: 1, Right: 2, Down: 3, Left: 4}
    callbacks := {}
    currentAngle := -1
    directionStates := [0,0,0,0]
    
    __New(stickId){
        fn := this.WatchPov.Bind(this)
        this.stickId := stickId
        this.povStr := stickId "JoyPOV"
        
        SetTimer, % fn, 10
    }
    
    Subscribe(dir, callback){
        if (this.directionNames.HasKey(dir)){   ; Translate from direction name to index, if needed
            dir := this.directionNames[dir]
        }
        this.Callbacks[dir] := callback
    }
    
    WatchPov(){
        angle := GetKeyState(this.povStr)
        if (angle == this.currentAngle)
            return
        this.currentAngle := angle
        angle := (angle = -1 ? -1 : round(angle / 4500) + 1)
        newStates := this.PovMap[angle]
        Loop 4 {
            if (this.directionStates[A_Index] != newStates[A_Index]){
                this.directionStates[A_Index] := newStates[A_Index]
                if (this.callbacks.HasKey(A_Index)){
                    this.callbacks[A_Index].call(newStates[A_Index])
                }
            }
        }
    }
}
A_AhkUser
Posts: 1076
Joined: 06 Mar 2017, 16:18
GitHub: AAhkUser
Location: France

Re: PovHelper - React to joystick hat directions as if they were buttons

15 May 2019, 20:40

Hi evilC,

Nice script :thumbup:
I should mention that the script calls the subscribed Up's callback if the script is not yet connected the moment you create the povhelper object or if the joystick is disconnected while the instance's main loop is still running. I guess this is simply because "" must be distinguished from -1 as possible return values of getkeystate("joyPOV").

Compare:

Code: Select all

#NoEnv
#SingleInstance force
#Warn
SetWorkingDir % A_ScriptDir

#SingleInstance force

ph := new PovHelper(1)  ; Pass Joystick number here

/*
When calling Subscribe, pass direction NAMES (Up, Right, Down or Left) or INDEXES (1, 2, 3, 4)
*/
ph.Subscribe("Up", Func("Up"))
ph.Subscribe("Left", Func("Left"))
return

^Esc::
    ExitApp

Up(state){
    Tooltip % "Up " (state ? "Pressed" : "Released") " @ " A_TickCount
}

Left(state){
    Tooltip % "Left " (state ? "Pressed" : "Released") " @ " A_TickCount
}

class PovHelper {
    static PovMap := {-1: [0,0,0,0], 1: [1,0,0,0], 2: [1,1,0,0] , 3: [0,1,0,0], 4: [0,1,1,0], 5: [0,0,1,0], 6: [0,0,1,1], 7: [0,0,0,1], 8: [1,0,0,1]}
    static directionNames := {Up: 1, Right: 2, Down: 3, Left: 4}
	static DEAD_POINT := -1
    callbacks := {}
    currentAngle := this.DEAD_POINT
    directionStates := [0,0,0,0]
    
    __New(stickId){
        fn := this.WatchPov.Bind(this)
        this.stickId := stickId
        this.povStr := stickId "JoyPOV"
		this.getKeyStateFn := Func("GetKeyState").bind(this.povStr)
        SetTimer, % fn, 10
    }
	getKeyState(ByRef _angle:="") {
	static DEAD_POINT := PovHelper.DEAD_POINT
	return ((_angle:=this.getKeyStateFn.call()) >= DEAD_POINT)
	}
    
    Subscribe(dir, callback){
        if (this.directionNames.HasKey(dir)){   ; Translate from direction name to index, if needed
            dir := this.directionNames[dir]
        }
        this.Callbacks[dir] := callback
    }
    
    WatchPov(){
        if not (this.GetKeyState(angle)) {
			SetTimer,, Off
		return
		}
        if (angle == this.currentAngle)
            return
        this.currentAngle := angle
        angle := (angle = -1 ? -1 : round(angle / 4500) + 1)
        newStates := this.PovMap[angle]
        Loop 4 {
            if (this.directionStates[A_Index] != newStates[A_Index]){
                this.directionStates[A_Index] := newStates[A_Index]
                if (this.callbacks.HasKey(A_Index)){
                    this.callbacks[A_Index].call(newStates[A_Index])
                }
            }
        }
    }
}
Thanks for sharing this gonna help a lot! Cheers. :salute:

Return to “Scripts and Functions”

Who is online

Users browsing this forum: burque505, robodesign and 50 guests