Jan
07
2008
0

AGT: Using XBox360 Pad with XInput

XBox 360 ControllerFor my AGT assignment I’ve decided to use a XBox 360 pad for input since I found out it can be used in Windows. To do this requires use of the XInput library that comes with DirectX.

So after setting up my input manager which automatically updates all input devices (there can be a maximum of four pad devices, defined by the variable XUSER_MAX_COUNT in the XInput header), I began work on the controller class to manage the state information about the pad.

The following header is my source for this class, when a controller is created, an id is passed to it that is used as the pad index for XInput.

#ifndef CONTROLLER_H_INCLUDED
#define CONTROLLER_H_INCLUDED

// --- [ libraries ] ------------------------------------------
#pragma comment(lib, "XInput.lib")

// --- [ includes ] -------------------------------------------
#include <windows.h>
#include <XInput.h>

// --- [ class ] ----------------------------------------------
class Controller
{
//
public:
enum Button
{
kButton_DPad_Up = 0,
kButton_DPad_Down,
kButton_DPad_Left,
kButton_DPad_Right,
kButton_Start,
kButton_Back,
kButton_Thumb_Left,
kButton_Thumb_Right,
kButton_Shoulder_Left,
kButton_Shoulder_Right,
kButton_X,
kButton_Y,
kButton_A,
kButton_B
}

enum AxisType
{
kAxis_Left = 0,
kAxis_Right,
kNumAxisTypes
};

enum MotorType
{
kMotor_Left = 0,
kMotor_Right,
kNumMotorTypes
};

enum TriggerType
{
kTrigger_Left = 0,
kTrigger_Right,
kNumTriggerTypes
};

struct AxisData
{
double x;
double y;
};

// Attributes
private:
const unsigned int m_id;
bool m_isConnected;

unsigned int m_currentButtons;
unsigned int m_previousButtons;

AxisData m_axis[kNumAxisTypes];
float m_triggers[kNumTriggerTypes];
double m_motorSpeed[kNumMotorTypes];

// Functions
public:
// Constructor
Controller( const unsigned int inControllerId );

// Check button has just been pressed
bool IsButtonDown( const Button inButton ) const
{
return ( ~m_previousButtons & m_currentButtons ) & ( 1 << inButton );
}

// Check button has just been released
bool IsButtonUp( const Button inButton ) const
{
return ( m_previousButtons & ~m_currentButtons ) & ( 1 << inButton );
}

// Check button is pressed
bool IsButtonPressed( const Button inButton ) const
{
return m_currentButtons & ( 1 << inButton );
}

// Get Thumb Axis
void GetAxis( const AxisType inType, AxisData & outData ) const
{
outData = m_axis[inType];
}

// Get Trigger Values
float GetTrigger( const TriggerType inType ) const
{
return m_triggers[inType];
}

// Get Motor Speed
double GetMotorSpeed( const MotorType inType ) const
{
return m_motorSpeed[inType];
}

// Set MotorSpeed
void SetMotorSpeed( const MotorType inType, const double inValue );

// Check Controller is Connected
bool IsConnected() const
{
return m_isConnected;
}

// Get Controller Id
unsigned int GetId() const
{
return m_id;
}

// Update
void Update();

private:
// Update an Axis
void UpdateAxis( const AxisType inType, const short inX, const short inY );

// Update a Trigger
void UpdateTrigger( const TriggerType inType, const unsigned char inValue );
};

All values that are variable are values between 0.0 and 1.0 in the case of triggers and motor speeds, and -1.0 and 1.0 in the case of axis components. You may have noticed that there is only one function that can change values explicitly, SetMotorSpeed(), the only other way to change values is direct input from the controller, so Update() must be called every frame.

You may notice that the division used to normalise the speed is 0x7FFF instead of 0xFFFF, this is because the number is signed, not unsigned like the other values we normalise.

Calling Update() more than once will break the IsButtonUp() and IsButtonDown() calls to always return false since they are based on the previous button states gotten by an update call.

The following is the source code for the controller class source file.

// --- [ includes ] -------------------------------------------
#include "Controller.h"

// --- [ constructor / destructor ] ---------------------------
Controller::Controller( const unsigned int inControllerId )
:
m_id( inControllerId ),
m_isConnected( false ),
m_currentButtons( 0 ),
m_previousButtons( 0 )
{
for( unsigned int i = 0; i < kNumAxisTypes; ++i )
{
m_axis[i].x = 0.0;
m_axis[i].y = 0.0;
}

for( unsigned int i = 0; i < kNumTriggerTypes; ++i )
{
m_triggers[i] = 0.0f;
}

for( unsigned int i = 0; i < kNumMotorTypes; ++i )
{
m_motorSpeed[i] = 0.0f;
}
}

// --- [ functions ] ------------------------------------------
void Controller::Update()
{
XINPUT_STATE state;

// Get new controller state and check if it is connected
m_isConnected = XInputGetState( m_id, &state ) == ERROR_SUCCESS;
if( !m_isConnected )
{
return;
}

// Set New Axis Positions and normalise
UpdateAxis( kAxis_Left, state.Gamepad.sThumbLX, state.Gamepad.sThumbLY );
UpdateAxis( kAxis_Right, state.Gamepad.sThumbRX, state.Gamepad.sThumbRY );

// Set New Trigger Values and normalise
UpdateTrigger( kTrigger_Left, state.Gamepad.bLeftTrigger );
UpdateTrigger( kTrigger_Right, state.Gamepad.bRightTrigger );

// Set previous button states to m_currentButtons, and current button
// state to new button state.
m_previousButtons = m_currentButtons;
m_currentButtons = static_cast<unsigned int>( state.Gamepad.wButtons );
}

void Controller::SetMotorSpeed( const MotorType inType, const double inValue )
{
XINPUT_VIBRATION vibration;

m_motorSpeed[inType] = inValue;

vibration.wLeftMotorSpeed = static_cast<WORD>( 0xffff * m_motorSpeed[kMotor_Left] );
vibration.wRightMotorSpeed = static_cast<WORD>( 0xffff * m_motorSpeed[kMotor_Right] );

XInputSetState( m_id, &vibration );
}

void Controller::UpdateAxis( const AxisType inType, const short inX, const short inY )
{
const short kAxisDeadzones[kNumAxisTypes] =
{
XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
};

m_axis[inType].x = 0.0;
m_axis[inType].y = 0.0;

if( inX < -kAxisDeadzones[inType] || inX > kAxisDeadzones[inType] )
{
m_axis[inType].x = static_cast<double>( state.Gamepad.sThumbLX ) / static_cast<double>( 0x7fff );
}

if( inY < -kAxisDeadzones[inType] || inY > kAxisDeadzones[inType] )
{
m_axis[inType].y = static_cast<double>( state.Gamepad.sThumbLY ) / static_cast<double>( 0x7fff );
}
}

void Controller::UpdateTrigger( const TriggerType inType, const unsigned char inValue )
{
m_triggers[inType] = 0.0f;

if( inValue > XINPUT_GAMEPAD_TRIGGER_THRESHOLD )
{
m_triggers[inType] = static_cast<float>( inValue ) / static_cast<float>( 0xff );
}
}

And that is all that is required for getting state information from a XBox 360 pad.

Written by Kaluriel in: Code,Legend of Bob,Tutorials | Tags: , , , ,
Aug
02
2003
0

Simple C++ DLL for Visual Basic 6.0

For that past few month or so I have been learning to make DLLs to use with Visual Basic, and in the process learning C++. The benefits of using C++ over Visual Basic is that division and multiplication can be up to 28x faster than the default Visual Basic method.

So I decided to write up a tutorial for others to make their own Visual Basic DLLs. First of all you need to understand the type differences between Visual Basic and Visual C++. The following list has the Visual Basic variable types on the left, and their C++ variable type equivalents on the right.

Integer > short

Long > long

Single > float

Double > double

Byte > unsigned char

String > BSTR

A BStr is a special COM object, which starts with a 4 byte integer for the length, and ends with two terminal string characters. It should also be noted that C++ is case sensitive, so the variable types on the right are how they should be in C++.

Now to create the DLL, open up a copy of Microsoft Visual C++ and select “Win32 Dynamic Link Library” for a new project and call it “Example”. An “Empty Application” will do for what we’re making when the “AppWizard” pops up.

With this new project created, goto the Project menu and add a new file, we need a new source file, I called mine “Main.cpp” but anything will do. Fill the new source file with the following source code.

//
//
#include <windows.h>

//
//
long _stdcall Multiply( long A, long B )
{
 return A * B;
}

//
//
long _stdcall Divide( long A, long B )
{
 return A / B;
}

//
//
long _stdcall SumOf( long A, long B )
{
 return A + B;
}

We include the Windows header since we may want to use APIs and because the BSTR is defined in there. The “_stdcall” is used to tell the compiler we want the parameters of the function pushed onto the stack in left to right order.

Now add a new module definition file to the Visual C++ project, call it “Example.def“. This file will let the compiler know what functions we want available to external programs, so after LIBRARY we put the name of our DLL, and under the EXPORTS section we put our available functions, “Multiply”, “Divide” and “SumOf”.

LIBRARY "Example"
EXPORTS
Multiply
Divide
SumOf

Finally in your Visual Basic project in the Form_Load() function, we can declare the functions within our DLL and make a call to them. Below shows can example of using the Multiply() function and then outputting it using a message box.

Private Declare Function Multiply Lib "Example" (ByVal A As Long, ByVal B As Long) As Long
Private Declare Function Divide Lib "Example" (ByVal A As Long, ByVal B As Long) As Long
Private Declare Function SumOf Lib "Example" (ByVal A As Long, ByVal B As Long) As Long

Private Sub Form_Load()
 Dim i As Long
 i = Multiply(2, 6)
 MsgBox i, vkOkOnly, App.Title
End Sub

If all goes correctly, a message box should appear with the value “12″ shown.

That’s all for this tutorial, I hope you found it useful.

Written by Kaluriel in: Code,Tutorials | Tags: ,

Theme: TheBuckmaker.com Blog Themes | The best Webhosting Plans, Eigenes Internet Radio