Sign in to follow this  
CDTMD

DirectX Input With PS3 Controller?

Recommended Posts

Well to play some of my computer games I plug in my PS3 controller then use some six-axis program so my computer can recognize it. Since it works it means I should be able to do it too. So my question is: How do I get input from the controller?

Share this post


Link to post
Share on other sites
Thanks for you help Evil Steve. It can recognize it. I did some more researching and I was able to get something working.

I can get it to check correctly if a button is pressed.

But I am having problems with the sticks.

js.lX is supposed to be the X direction of the stick. However when I check the results it shows that it is some big number.

Shouldn't it be like 0 until I move it?

What am I doing wrong?

Share this post


Link to post
Share on other sites
In DirectInput during EnumerateObjects you get a struct with object infos (LPCDIDEVICEOBJECTINSTANCE).

Check the type for an axis (either DIDFT_ABSAXIS or DIDFT_RELAXIS). If it has one of those bits set you can check the ranges the device will report:


DIPROPRANGE diRange;

diRange.diph.dwSize = sizeof( diRange );
diRange.diph.dwHeaderSize = sizeof( DIPROPHEADER );
diRange.diph.dwHow = DIPH_BYID;
diRange.diph.dwObj = lpddoi->dwType;

HRESULT hRes = pDevice->GetProperty( DIPROP_RANGE, (LPDIPROPHEADER)&diRange );
if ( SUCCEEDED( hRes ) )
{
NewCtrl.m_iMin = diRange.lMin;
NewCtrl.m_iMax = diRange.lMax;
}



Compare the polled value to your min/max ranges (use some threshold value). Done.

Share this post


Link to post
Share on other sites
Sorry for the bump but I'm back after a lot of homework and being sick. I never got it to work though.

This is the code I'm using.

I made a class for it. These are the only two calls I make. I get input then I write the result to a file. (ignore the getX(). Its just a temp name for it)

ps3i->getInput();
out << ps3i->getX() << endl;

The getInput() function

void PS3Input::getInput()
{
PS3Device->Poll();
PS3Device->Acquire();
PS3Device->GetDeviceState(sizeof(DIJOYSTATE2), &js);
}

getX()

int PS3Input::getX()
{
return js.lX;
}

This is the enumObjectsCallback function

BOOL CALLBACK PS3Input::enumObjectsCallback( const DIDEVICEOBJECTINSTANCE* instance, VOID* context )
{
HWND hDlg = ( HWND )context;

static int nSliderCount = 0; // Number of returned slider controls
static int nPOVCount = 0; // Number of returned POV controls

// For axes that are returned, set the DIPROP_RANGE property for the
// enumerated axis in order to scale min/max values.
if( instance->dwType & DIDFT_AXIS )
{
DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof( DIPROPRANGE );
diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER );
diprg.diph.dwHow = DIPH_BYID;
diprg.diph.dwObj = instance->dwType; // Specify the enumerated axis
diprg.lMin = -1000;
diprg.lMax = +1000;

// Set the range for the axis
if( FAILED( PS3Device->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )
return DIENUM_STOP;
}
}


Wasn't I supposed to get values from -1000 to 1000?

These are the ones I get.

[Numbers too long, it pissed me off, deleted.]

[Edited by - CDTMD on December 4, 2009 11:48:24 PM]

Share this post


Link to post
Share on other sites
Looks right to me.
Subtract MAXWORD/2 (eg, the maximum value of a 16 bit unsigned integer, divided on two).

Being unsigned, it cannot represent negative numbers :)
What did you do when the value was 32768? was it perhaps idle? (hint hint)

Share this post


Link to post
Share on other sites
When I change it to: return (js.lX-(MAXWORD/2));
Now the value I get for no movement is -512

If it can't represent - numbers why set the range from -1000->1000?

Yes it was idle. Now instead of 32768 I get -512





From what I can understand aren't I supposed to just set a range

-5 to 5

Then for example if I wanted to move a char with it then I just get the value (ex: 5) and use that as the speed, correct?

So what's with all these large and strange numbers?

Share this post


Link to post
Share on other sites
Quote:
Original post by CDTMD
When I change it to: return (js.lX-(MAXWORD/2));
Now the value I get for no movement is -512
MAXWORD = 0xffff = 65535.
MAXWORD/2 = 32767
32768 - 32767 = 1, which is 0.1% above 0.

Where are you getting -512 from?

Share this post


Link to post
Share on other sites
I have no idea but it seems to random.....

These numbers are from starting it then holding the left stick up. I waited a few seconds before moving the stick.

[Numbers too long, it pissed me off, deleted.]

These numbers are from when I tried it but did not touch the controller at all...

[Numbers too long, it pissed me off, deleted.]

And these from when I changed it back to: return js.lX;

[Numbers too long, it pissed me off, deleted.]

And these from when I waited then moved the left stick to the left.

[Numbers too long, it pissed me off, deleted.]

Whats with all the random numbers? Shouldn't idle be a constant?

[Edited by - CDTMD on December 5, 2009 2:55:56 PM]

Share this post


Link to post
Share on other sites
The PS3 analog sticks are very sensitive. This is why most input managers implement a "dead zone" which is defined as the range in which physical input values are mapped as zero motion.

As Endurion said, you get the minimum and maximum points of the range from DI. The center of a given axis is the average of these values, not the constant zero as you seem to assume. The average is trivially found as (min+max)/2.

When the PS3 controller is connected, it performs an automatic calibration based on the current position of the analog controls (which usually are at center position during this time). DI adjusts the range automatically to take this into account. Therefore, you shouldn't assume that the range is exactly the same everytime you connect the controller.

Share this post


Link to post
Share on other sites
Ok but even then you can set the ranges. Even then the preset ranges should be similar.

so (-1000+1000)/2
= (0)/2
= 0

I also changed it to this.

HRESULT hRes = PS3Device->GetProperty( DIPROP_RANGE, (LPDIPROPHEADER)&diprg );
if ( SUCCEEDED( hRes ) )
{
outr<<diprg.lMin<<endl;
outr<<diprg.lMax<<endl;
}

So it should print out the preset min/max values. But the file is always blank.

Any way Endurion set it like this
NewCtrl.m_iMin = diprg.lMin;
NewCtrl.m_iMax = diprg.lMax;

What type is NewCtrl? He doesn't declare it in the code.

Share this post


Link to post
Share on other sites
Quote:
Original post by CDTMD
Ok but even then you can set the ranges. Even then the preset ranges should be similar.

so (-1000+1000)/2
= (0)/2
= 0

I also changed it to this.

HRESULT hRes = PS3Device->GetProperty( DIPROP_RANGE, (LPDIPROPHEADER)&diprg );
if ( SUCCEEDED( hRes ) )
{
outr<<diprg.lMin<<endl;
outr<<diprg.lMax<<endl;
}

So it should print out the preset min/max values. But the file is always blank.

What "file"? There is always some values in the structure, regardless of whether they are correct or not.

Quote:

Any way Endurion set it like this
NewCtrl.m_iMin = diprg.lMin;
NewCtrl.m_iMax = diprg.lMax;

What type is NewCtrl? He doesn't declare it in the code.


"Of what type is NewCtrl" is not the point. You can assign the values to anything you want, for further processing.

Share this post


Link to post
Share on other sites
By file I meant like output.txt. I am using ofstream to see the values.

I also did try using int to get the values but again the file showed nothing...

Share this post


Link to post
Share on other sites
Strange I think I just found the problem... I just tried and it wont output anything... It seems that the function: enumObjectsCallback() is not being called.... Why?

// Creates an Input Object for monitoring mouse input, and one for keyboard input.
bool PS3Input::init(HINSTANCE hInst, HWND wndHandle)
{
...
PS3Device->EnumObjects( enumObjCallback, NULL, DIDFT_ALL );

return true;
}

BOOL CALLBACK PS3Input::enumObjectsCallback( const DIDEVICEOBJECTINSTANCE* instance, VOID* context )
{
...
}

BOOL CALLBACK enumObjCallback( const DIDEVICEOBJECTINSTANCE* instance, VOID* context )
{
if (context != NULL) {
return ((PS3Input *)context)->enumObjectsCallback(instance, context);
} else {
return DIENUM_STOP;
}
}

Am I doing it wrong? It works for enumJoysticksCallback()

Share this post


Link to post
Share on other sites
Put a breakpoint to the first row of your enumObjCallback function, run the debugger to that point and observe the parameters. Optionally, step thru the rest of the function. Can you spot the mistake?

(Hint: you are supposed to supply the context for the callback).

Share this post


Link to post
Share on other sites
Awesome thanks! It works now. I now get values between 0-65535. I made a temporary dead zone by only checking for 0 or 65535. It works! I just have to mess with the dead zone so I can do x and y at the same time but other than that it works perfectly thank you!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this