Sign in to follow this  
THACO

DInput Multiple Joysticks

Recommended Posts

Ok Im just learning DInput and I have had success with the keyboard. The problem for me is multiple joysticks / callback functions in general. I pretty much just used the code from the directX joystick tutorial. I modified the tutorial a little to have it get multiple joysticks, but it only chooses one of those to EnumObjects (get and set axis??). My problem when I try to bring code from the tutorial into my own project is moving the callback functions into a class. I get this error error C2664: 'IDirectInput8A::EnumDevices' : cannot convert parameter 2 from 'BOOL (const DIDEVICEINSTANCE *,void *)' to 'LPDIENUMDEVICESCALLBACKA' None of the functions with this name in scope match the target type I did some searching found some info about if a callback function is in a class it has to be static. I changed them to static but got more errors error C2227: left of '->CreateDevice' must point to class/struct/union type is '' below is the line inquestion from the error above hr = g_pDI->CreateDevice(pdidInstance->guidInstance, &g_pGamepads[numPads], NULL ); error C2597: illegal reference to non-static member 'CInput::numPads' error C2597: illegal reference to non-static member 'CInput::g_pGamepads' error C2597: illegal reference to non-static member 'CInput::numPads' this error also references the line of code abouve hr = g_pDI.... error C2568: '[' : unable to resolve function overload unable to recover from previous error(s); stopping compilation So mainly im stuck, are there any suggestions, other tutorials to look at. Thanks THAC0

Share this post


Link to post
Share on other sites
I'm still early in my DirectX adventures, but from looking at what you posted, you will need to have the Callback function be a static member function. But when you make the function static, it can not access any members from an object you created from that class. The only members it has access to are static members.


It looks like you are having trouble understanding static member functions and variables, so let me try to explain it. Think of your class as a cookie-cutter, and the objects you make from it as the cookies. Check out the following code:

// Cookies.h
class Cookies
{
public:
Cookies(void); // constructor
~Cookies(void); // deconstructor


static int ReturnNumOfCookies(void); // static function
private:
static int c_NumOfCookies; // static variable
string m_CookieColor; // non-static member variable
};








#include "Cookies.h"
// since static variables exist regardless of
// whether or not we have any objects of the
// class type, we need to initialize it somewhere.
// We initialize it here to 0
int Cookies::c_NumOfCookies = 0;

// constructor
Cookies::Cookies(void)
{
// instantiated members of a class
// can access static members. Here
// we increment how many cookies we
// created so far.
NumOfCookies++; // this is a static member

// Now lets set a variable specific to
// this object's instance. Each cookie has
// a color associated with it. If this
// were static, all cookies we made would
// have the same color.
m_CookieColor = "Green";
}

Cookies::~Cookies(void)
{
// One less Cookie object, so decrease our
// static variable that keeps track of
// how many cookies are left.
NumOfCookies--;
}

int Cookies::ReturnNumOfCookies(void) // static function
{

return NumOfCookies;

// this below would be illegal:
// m_CookieColor = "Blue"; // illegal!
// It is illegal because we don't know
// which cookie we are changing the color of

}








Hopefully the code above helps you understand what static/non-static functions and variables are. With that being said, the call back function has two paramenters. Since I can't see your code, I'll post my callback function ( EnumJoysticksCallback) for my "DIJoystickMgr" class. Note the 2nd parameter... It is a VOID*. This means that you can put a pointer to any object there, and the compiler won't complain.

This is important, because this VOID* can be a pointer to the specific object that called the function.

BOOL CALLBACK DIJoystickMgr::EnumJoysticksCallback(
const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)

So somewhere in my class I EnumDevices, and pass the this pointer to my static callback function.



void DIJoystickMgr::SomeFunction(void)
{
// snip!
hResult = m_pDInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback,
this /*here!*/ , DIEDFL_ATTACHEDONLY);
// snip!
}


BOOL CALLBACK DIJoystickMgr::EnumJoysticksCallback(
const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
{
// The "this" pointer gets past to this function
// as the second parameter "VOID* pContext"

// pointer to a DI8Device. Use in the CreateDevice
// function, and also our doorway to accessing
// properties of the specific joystick device.
// Since each joystick device will have
// one of these, you might want to make it a
// non-static member of your joystick class,
// and set it somewere during the callback function/
LPDIRECTINPUTDEVICE8 pDIDevice;

// a pointer to a DIJoystickMgr object
// doesn't pointer to any object in particular
// yet.
DIJoystickMgr* joystickMgr;

// Make sure we are actually passed a pointer
// to a DIJoystickMgr object. If the pointer
// doesn't point anywhere, tell EnumDevices
// to stop enumerating.
if( (DIJoystickMgr*)pContext == NULL)
{
return DIENUM_STOP;
}

// take the VOID* and cast it to the same type
// as our class
joystickMgr = (DIJoystickMgr*) pContext;

// Now that we know which object called
// the callback function we can now access
// the non-static variables.
hResult = joystickMgr->g_pDI->CreateDevice(
pdidInstance->guidInstance, &pDIDevice, NULL);

// might want to also add something like this...
// so each joystickMgr has it's own LPDIRECTINPUTDEVICE8
joystickMgr->DIDevice = pDIDevice;

// snip!
}







g_pDI is a member varible of the specific object joystickMgr points to. If it doesn't make sense, here is the same principle from our first example...


// we passed a pointer to a particular object
// so cast it to the correct object type
// (from VOID* to Cookies*)
Cookies* aCookie = (Cookies*) pContext;

// a particular cookies color.. non-static
aCookie->m_CookieColor = "Puce";










Hope that Helps

[Edited by - TheChronoTrigger on June 23, 2005 2:16:00 AM]

Share this post


Link to post
Share on other sites
OK, that helped a little but still some link errors now


if(FAILED( hr = g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL,
EnumJoysticksCallback,
this, DIEDFL_ATTACHEDONLY)))

//Now in the actual EnumDevice function
BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
VOID* pContext)
{
HRESULT hr;

CInput* anInput = (CInput*) pContext;

// Obtain an interface to the enumerated Joystick.
//hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
hr = anInput->g_pDI->CreateDevice( pdidInstance->guidInstance, &anInput->g_pGamepads[ainput->numPads], NULL );

// If it failed, then we can't use this Joystick. (Maybe the user unplugged
// it while we were in the middle of enumerating it.)
if( FAILED(hr) )
return DIENUM_CONTINUE;

// Stop enumeration. Note: we're just taking the first Joystick we get. You
// could store all the enumerated Joysticks and let the user pick.
//return DIENUM_STOP;
anInput->numPads++;
return DIENUM_CONTINUE;
}




I still get these Link errors.


Input.obj : error LNK2019: unresolved external symbol "public: static int __stdcall CInput::EnumObjectsCallback(struct DIDEVICEOBJECTINSTANCEA const *,void *)" (?EnumObjectsCallback@CInput@@SGHPBUDIDEVICEOBJECTINSTANCEA@@PAX@Z) referenced in function "public: long __thiscall CInput::CreateGamepads(struct HWND__ *)" (?CreateGamepads@CInput@@QAEJPAUHWND__@@@Z)
Input.obj : error LNK2019: unresolved external symbol "public: static int __stdcall CInput::EnumJoysticksCallback(struct DIDEVICEINSTANCEA const *,void *)" (?EnumJoysticksCallback@CInput@@SGHPBUDIDEVICEINSTANCEA@@PAX@Z) referenced in function "public: long __thiscall CInput::CreateGamepads(struct HWND__ *)" (?CreateGamepads@CInput@@QAEJPAUHWND__@@@Z)



Thanks for your first post it was very helpful, to bad i still have these link errors. I did look around to see about how to use callback in a class, but nothing was helpful except for yours so thanks a bunch.

Share this post


Link to post
Share on other sites
If this is really your code, then the code for your EnumJoysticksCallback function isn't in the same scope as your CInput class. I'm assuming the same goes for your EnumObjectsCallback function as well. You probably declared each in your header file, but in your cpp file you didn't put function as CInput::EnumObjectsCallback and CInput::EnumJoysticksCallback. You may have written the code for EnumJoysticksCallback, but it isn't a part of your CInput class and the compiler is complaining that you haven't implemented the two functions you declared in your header.

//Now in the actual EnumDevice function
// Note the "CInput::" part in the function name.
// It shows which class we are writing this function for
BOOL CALLBACK CInput::EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
VOID* pContext)
{
HRESULT hr;

CInput* anInput = (CInput*) pContext;

// Obtain an interface to the enumerated Joystick.
//hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
hr = anInput->g_pDI->CreateDevice( pdidInstance->guidInstance, &anInput->g_pGamepads[ainput->numPads], NULL );

// If it failed, then we can't use this Joystick. (Maybe the user unplugged
// it while we were in the middle of enumerating it.)
if( FAILED(hr) )
return DIENUM_CONTINUE;

// Stop enumeration. Note: we're just taking the first Joystick we get. You
// could store all the enumerated Joysticks and let the user pick.
//return DIENUM_STOP;
anInput->numPads++;
return DIENUM_CONTINUE;
}








I think that is your problem. If not, let me know and I'll take a closer look at your code.

Share this post


Link to post
Share on other sites
Im such an idiot!

Yes that ws my problem
I just forgot to put the CInput:: back infront. Like I said before, I was able to get it working but I had to make the callbacks and most of my varibles global, and while I moved everything back in the header, I forgot to do it in the source. Thanks a lot

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