Enhanced Joystick support

Monkey Targets Forums/Desktop/Enhanced Joystick support

Earok(Posted 2012) [#1]
Featuring
- 16 simultaneous joysticks
- 128 buttons per joystick
- 8 axes per joystick
- POV hat (Including the XBox 360 controller DPad)

GLFW/Windows only at this stage, but maybe not too hard to hack for other platforms and targets.

Apologies about the hacky mess, it's the first C I've written in a decade. Call EJoyInit() during OnCreate() and EJoyUpdate() during OnUpdate()

Joystick.Cpp
#pragma comment(lib, "winmm.lib")

float axisarray[8];
unsigned char buttonarray[128];

int EJoyConnected(int index){
	return glfwGetJoystickParam( GLFW_JOYSTICK_1 + index, GLFW_PRESENT );
}

int EJoyAxes(int index){
	return glfwGetJoystickParam( GLFW_JOYSTICK_1 + index, GLFW_AXES );
}

int EJoyButtons(int index){
	return glfwGetJoystickParam( GLFW_JOYSTICK_1 + index, GLFW_BUTTONS );
}

void EJoyAxisStates(int index,int axes){
	glfwGetJoystickPos( GLFW_JOYSTICK_1 + index, axisarray, axes);
	return;
}

void EJoyButtonStates(int index,int buttons){
	glfwGetJoystickButtons( GLFW_JOYSTICK_1 + index, buttonarray, buttons );
	return;
}

float EJoyAxisState(int axis){
	return axisarray[axis];
}

int EJoyButtonState(int button){
	return buttonarray[button];
}

//Based on code from https://github.com/fatty/glfw/blob/f84990bffd20d5663de1889c60ef4bf334e76fb7/src/win32_joystick.c
int EJoyHatState(int index){

	JOYCAPS jc;
    JOYINFOEX ji;
	joyGetDevCaps(index, &jc, sizeof(JOYCAPS));

    // Get joystick state
    ji.dwSize = sizeof(JOYINFOEX);
    ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
    joyGetPosEx(index, &ji);
	
	const int hats = (jc.wCaps & JOYCAPS_HASPOV) ? 1 : 0;
    if (hats > 0 )
    {
		if(ji.dwPOV>36000) return -1;
        return ji.dwPOV / 100;
    }
	return -1;
	
}


Joystick.Monkey
Import mojo
Import "joystick.cpp"

Extern

Function EJoyConnected:Int(index) = "EJoyConnected"
Function EJoyButtons:Int(index) = "EJoyButtons"
Function EJoyAxes:Int(index) = "EJoyAxes"
Function EJoyButtonStates:Int(index, buttons) = "EJoyButtonStates"
Function EJoyAxisStates:Int(index, axes) = "EJoyAxisStates"
Function EJoyButtonState:Int(button) = "EJoyButtonState"
Function EJoyAxisState:Float(axis) = "EJoyAxisState"
Function EJoyHatState:Int(index) = "EJoyHatState"

Public 

Const DeadZone:Float = 0.1

Class Joystick
	

	Global State:= New Joystick[16]

	Field Connected:Bool = False
	Field Axes:Float[]
	Field Buttons:Int[]
	Field Hat:int
		
End

Function EJoyAxis:Float(index, axis)
	If (index >= EJoyCount) Return 0
	If (Joystick.State[index].Axes.Length <= axis) Return 0
	Return Joystick.State[index].Axes[axis]
End

Function EJoyHat:Float(index)
	If (index >= EJoyCount) Return 0
	Return Joystick.State[index].Hat
End

Function EJoyX:Float(index)
	Return EJoyAxis(index, 0)
End

Function EJoyY:Float(index)
	Return EJoyAxis(index, 1)
End

Function EJoyZ:Float(index)
	Return EJoyAxis(index, 2)
End

Function EJoyHit(index, button)
	If (index >= EJoyCount) Return 0
	If (button >= Joystick.State[index].Buttons.Length) Return 0
	If Joystick.State[index].Buttons[button] = 1 Return 1
	Return 0
End

Function EJoyDown(index, button)
	If (index >= EJoyCount) Return 0
	If (button >= Joystick.State[index].Buttons.Length) Return 0
	If Joystick.State[index].Buttons[button] > 0 Return 1
	Return 0
End

Function EJoyInit()
	EJoyCount = 0
	For Local a = 0 To 15
		Joystick.State[a] = New Joystick()
		If (EJoyConnected(a))
			Joystick.State[a].Connected = True
			Joystick.State[a].Axes = New float[EJoyAxes(a)]
			Joystick.State[a].Buttons = New int[EJoyButtons(a)]
			Print "Axes" + EJoyAxes(a)
			Print "Buttons" + EJoyButtons(a)
			EJoyCount += 1
		EndIf
	Next
End

Function EJoyUpdate()

	For Local a = 0 To 15
		If (Joystick.State[a].Connected = True)
		
			EJoyAxisStates(a, Joystick.State[a].Axes.Length)
			EJoyButtonStates(a, Joystick.State[a].Buttons.Length)
			
			Joystick.State[a].Hat = EJoyHatState(a)
			
			For Local b = 0 To Joystick.State[a].Axes.Length - 1
				Joystick.State[a].Axes[b] = Min(Max(EJoyAxisState(b), -1.0), 1.0)
				If (Abs(Joystick.State[a].Axes[b]) < DeadZone)
					Joystick.State[a].Axes[b] = 0
				EndIf
			Next
			
			For Local b = 0 To Joystick.State[a].Buttons.Length - 1
				
				Select Joystick.State[a].Buttons[b]
					Case 0
						If EJoyButtonState(b) = 1 Then
							Joystick.State[a].Buttons[b] = 1
						EndIf
					Case 1
						Joystick.State[a].Buttons[b] = 2
					Case 2
						If EJoyButtonState(b) = 0 Then Joystick.State[a].Buttons[b] = 0
				End
			Next
		EndIf
	Next
End

Global EJoyCount



mr_twister(Posted 2014) [#2]
This is great!
I will not be using the module (as joystick support has improved quite a lot in Monkey lately) but there are a few ideas I will definitely borrow from you (like reading additional axes and getting info on the joystick). They will make nice additions to the handful of GLFW-specific enhancements I already have in my engine (checking if a joystick is connected was one of them)

Thanks :)


consty(Posted 2014) [#3]
Awesome work. Mark and his team should have a look at it if this is really good.