1725 lines
52 KiB
C++
1725 lines
52 KiB
C++
|
//===========================================================================
|
||
|
// dmtinput.cpp
|
||
|
//
|
||
|
// DirectInput functionality
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History:
|
||
|
// 08/30/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
|
||
|
#include "dimaptst.h"
|
||
|
#include "dmtinput.h"
|
||
|
#include "dmttest.h"
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputCreateDeviceList
|
||
|
//
|
||
|
// Creates a linked list of DirectInputDevice8A objects. Either enumerates
|
||
|
// suitable or all joystick/gamepad devices.
|
||
|
//
|
||
|
// NOTE: The actual work of adding a node to the list is performed by the
|
||
|
// dmtinputEnumDevicesCallback() function. This function exists merely to
|
||
|
// present a consistant look & feel with the rest of the list creation
|
||
|
// functions used in this app.
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 08/27/1999 - davidkl - created
|
||
|
// 08/30/1999 - davidkl - moved & renamed
|
||
|
// 10/26/1999 - davidkl - added axis range setting
|
||
|
// 10/27/1999 - davidkl - house cleaning
|
||
|
// 02/21/2000 - davidkl - added hwnd and call to dmtinputGetRegisteredMapFile
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputCreateDeviceList(HWND hwnd,
|
||
|
BOOL fEnumSuitable,
|
||
|
DMTSUBGENRE_NODE *pdmtsg,
|
||
|
DMTDEVICE_NODE **ppdmtdList)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
DWORD dwActions = 0;
|
||
|
DWORD dwType = 0;
|
||
|
DMTDEVICE_NODE *pDevice = NULL;
|
||
|
DMTDEVICEOBJECT_NODE *pObject = NULL;
|
||
|
DMTACTION_NODE *pAction = NULL;
|
||
|
IDirectInput8A *pdi = NULL;
|
||
|
DIACTIONA *pdia = NULL;
|
||
|
DIACTIONFORMATA diaf;
|
||
|
DIPROPRANGE dipr;
|
||
|
|
||
|
// validate pdmtsg
|
||
|
//
|
||
|
// this only needs to be valid if fEnumSuitable == TRUE
|
||
|
// if(fEnumSuitable)
|
||
|
// {
|
||
|
DPF(4, "dmtinputCreateDeviceList - Enumerating for "
|
||
|
"suitable devices... validating pdmtsg");
|
||
|
|
||
|
if(IsBadReadPtr((void*)pdmtsg, sizeof(DMTSUBGENRE_NODE)))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - invalid pdmtsg (%016Xh)",
|
||
|
pdmtsg);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
// }
|
||
|
|
||
|
// validate ppdmtdList
|
||
|
//
|
||
|
// This validation will be performed by dmtinputEnumDevicesCallback
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// create the dinput object
|
||
|
hRes = dmtinputCreateDirectInput(ghinst,
|
||
|
&pdi);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - unable to create "
|
||
|
"DirectInput object (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
hRes = DMT_E_INPUT_CREATE_FAILED;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// enumerate devices
|
||
|
//
|
||
|
// NOTE: this will create the linked list we want
|
||
|
// however, it will not create the object list.
|
||
|
// if(fEnumSuitable)
|
||
|
// {
|
||
|
// count the actions
|
||
|
dwActions = 0;
|
||
|
pAction = pdmtsg->pActionList;
|
||
|
while(pAction)
|
||
|
{
|
||
|
dwActions++;
|
||
|
pAction = pAction->pNext;
|
||
|
}
|
||
|
|
||
|
// allocate the diaction array
|
||
|
pdia = (DIACTIONA*)LocalAlloc(LMEM_FIXED,
|
||
|
dwActions * sizeof(DIACTIONA));
|
||
|
if(!pdia)
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - unable to allocate "
|
||
|
"DIACTION array");
|
||
|
hRes = E_OUTOFMEMORY;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// fill the array with ALL of the actions
|
||
|
// for the selected subgenre
|
||
|
hRes = dmtinputPopulateActionArray(pdia,
|
||
|
(UINT)dwActions,
|
||
|
pdmtsg->pActionList);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - unable to populate "
|
||
|
"DIACTION array (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// build the diactionformat structure
|
||
|
ZeroMemory((void*)&diaf, sizeof(DIACTIONFORMATA));
|
||
|
diaf.dwSize = sizeof(DIACTIONFORMATA);
|
||
|
diaf.dwActionSize = sizeof(DIACTIONA);
|
||
|
diaf.dwNumActions = dwActions;
|
||
|
diaf.rgoAction = pdia;
|
||
|
diaf.dwDataSize = 4 * diaf.dwNumActions;
|
||
|
diaf.guidActionMap = GUID_DIMapTst;
|
||
|
diaf.dwGenre = pdmtsg->dwGenreId;
|
||
|
diaf.dwBufferSize = DMTINPUT_BUFFERSIZE;
|
||
|
lstrcpyA(diaf.tszActionMap, DMT_APP_CAPTION);
|
||
|
|
||
|
// now, enumerate for joystick devices
|
||
|
/*
|
||
|
hRes = pdi->EnumDevicesBySemantics((LPCSTR)NULL,
|
||
|
&diaf,
|
||
|
dmtinputEnumDevicesCallback,
|
||
|
(void*)ppdmtdList,
|
||
|
DIEDFL_ATTACHEDONLY);
|
||
|
*/
|
||
|
// }
|
||
|
// else
|
||
|
// {
|
||
|
DPF(0, "Calling EnumDevicesBySemantics");
|
||
|
// hRes = pdi->EnumDevicesBySemantics("TestMe",
|
||
|
hRes = pdi->EnumDevicesBySemantics((LPCSTR)NULL,
|
||
|
&diaf,
|
||
|
dmtinputEnumDevicesCallback,
|
||
|
(void*)ppdmtdList,
|
||
|
0);//JJFix 34616//DIEDBSFL_ATTACHEDONLY);
|
||
|
// }
|
||
|
DPF(0, "Returned from EnumDevicesBySemantics");
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - Enum%sDevices "
|
||
|
"failed (%s == %08Xh)",
|
||
|
fEnumSuitable ? "Suitable" : "",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// the device enumeration function does not create
|
||
|
// the object linked list, we will create it now
|
||
|
//
|
||
|
// steps to do this:
|
||
|
// * walk the list. for each node:
|
||
|
// ** call dmtinputCreateObjectList()
|
||
|
pDevice = *ppdmtdList;
|
||
|
while(pDevice)
|
||
|
{
|
||
|
// get a list of the device's objects
|
||
|
hRes = dmtinputCreateObjectList(pDevice->pdid,
|
||
|
pDevice->guidInstance,
|
||
|
&(pDevice->pObjectList));
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - failed to create "
|
||
|
"device %s object list (%s == %08Xh)",
|
||
|
pDevice->szName,
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
hRes = S_FALSE;
|
||
|
}
|
||
|
|
||
|
// get the registered map file name (if exists)
|
||
|
// ISSUE-2001/03/29-timgill possible S_FALSE hResult from previous call is ignored
|
||
|
// (previous call to dmtinputCreateObjectList)
|
||
|
hRes = dmtinputGetRegisteredMapFile(hwnd,
|
||
|
pDevice,
|
||
|
pDevice->szFilename,
|
||
|
sizeof(char) * MAX_PATH);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDeviceList - failed to retrieve "
|
||
|
"device %s mapfile name (%s == %08Xh)",
|
||
|
pDevice->szName,
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
hRes = S_FALSE;
|
||
|
}
|
||
|
|
||
|
// next device
|
||
|
pDevice = pDevice->pNext;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// free the action array
|
||
|
if(pdia)
|
||
|
{
|
||
|
if(LocalFree((HLOCAL)pdia))
|
||
|
{
|
||
|
// memory leak
|
||
|
DPF(0, "dmtinputCreateDeviceList - MEMORY LEAK - pdia");
|
||
|
pdia = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if something failed, cleanup the linked list
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
dmtinputFreeDeviceList(ppdmtdList);
|
||
|
}
|
||
|
|
||
|
// we don't need the dinput object any more
|
||
|
SAFE_RELEASE(pdi);
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputCreateDeviceList()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputFreeDeviceList
|
||
|
//
|
||
|
// Frees the linked list created by dmtinputCreateDeviceList
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 08/27/1999 - davidkl - created
|
||
|
// 08/30/1999 - davidkl - moved & renamed. added call to pdid->Release()
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputFreeDeviceList(DMTDEVICE_NODE **ppdmtdList)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
DMTDEVICE_NODE *pNode = NULL;
|
||
|
|
||
|
// validate ppdmtaList
|
||
|
if(IsBadWritePtr((void*)ppdmtdList, sizeof(DMTDEVICE_NODE*)))
|
||
|
{
|
||
|
DPF(0, "dmtFreeDeviceList - Invalid ppdmtaList (%016Xh)",
|
||
|
ppdmtdList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate *ppdmtdList
|
||
|
if(IsBadReadPtr((void*)*ppdmtdList, sizeof(DMTDEVICE_NODE)))
|
||
|
{
|
||
|
if(NULL != *ppdmtdList)
|
||
|
{
|
||
|
DPF(0, "dmtFreeDeviceList - Invalid *ppdmtdList (%016Xh)",
|
||
|
*ppdmtdList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if NULL, then return "did nothing"
|
||
|
DPF(3, "dmtFreeDeviceList - Nothing to do....");
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// walk the list and free each object
|
||
|
while(*ppdmtdList)
|
||
|
{
|
||
|
pNode = *ppdmtdList;
|
||
|
*ppdmtdList = (*ppdmtdList)->pNext;
|
||
|
|
||
|
// free the object list first
|
||
|
//
|
||
|
// no need to check error results here..
|
||
|
//
|
||
|
// error reporting is handled in dmtinputFreeObjectList
|
||
|
dmtinputFreeObjectList(&(pNode->pObjectList));
|
||
|
|
||
|
// release the device object
|
||
|
SAFE_RELEASE((pNode->pdid));
|
||
|
|
||
|
// delete the node
|
||
|
DPF(5, "dmtFreeDeviceList - deleting Node (%016Xh)", pNode);
|
||
|
if(LocalFree((HLOCAL)pNode))
|
||
|
{
|
||
|
DPF(0, "dmtFreeDeviceList - MEMORY LEAK - "
|
||
|
"LocalFree() failed (%d)...",
|
||
|
GetLastError());
|
||
|
hRes = DMT_S_MEMORYLEAK;
|
||
|
}
|
||
|
DPF(5, "dmtFreeDeviceList - Node deleted");
|
||
|
}
|
||
|
|
||
|
// make sure that we set *ppObjList to NULL
|
||
|
*ppdmtdList = NULL;
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputFreeDeviceList()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputCreateObjectList
|
||
|
//
|
||
|
// Creates a linked list of device's objects (axes, buttons, povs).
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 08/30/1999 - davidkl - created
|
||
|
// 09/01/1999 - dvaidkl - added pdid
|
||
|
// 02/18/2000 - davidkl - fixed object enumeration to filter anything not
|
||
|
// an axis, button or pov
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputCreateObjectList(IDirectInputDevice8A *pdid,
|
||
|
GUID guidInstance,
|
||
|
DMTDEVICEOBJECT_NODE **ppdmtoList)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
DMTDEVICEOBJECT_NODE *pObject = NULL;
|
||
|
|
||
|
// validate pdid
|
||
|
if(IsBadReadPtr((void*)pdid, sizeof(IDirectInputDevice8A)))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateObjectList - invalid pdid (%016Xh)",
|
||
|
pdid);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate ppdmtoList
|
||
|
if(IsBadReadPtr((void*)ppdmtoList, sizeof(DMTDEVICEOBJECT_NODE*)))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateObjectList - invalid ppdmtoList (%016Xh)",
|
||
|
ppdmtoList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate guidInstance
|
||
|
if(IsEqualGUID(GUID_NULL, guidInstance))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateObjectList - invalid guidInstance (GUID_NULL)");
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// enumerate device objects
|
||
|
//
|
||
|
// NOTE: this call will create the linked list we want
|
||
|
hRes = pdid->EnumObjects(dmtinputEnumDeviceObjectsCallback,
|
||
|
(void*)ppdmtoList,
|
||
|
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// walk the list and add the guidInstance of the device
|
||
|
pObject = *ppdmtoList;
|
||
|
while(pObject)
|
||
|
{
|
||
|
// copy the device's guidInstance
|
||
|
pObject->guidDeviceInstance = guidInstance;
|
||
|
|
||
|
// next object
|
||
|
pObject = pObject->pNext;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// if something failed, cleanup the linked list
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Needs error case handling
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputCreateObjectList()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputFreeObjectList
|
||
|
//
|
||
|
// Frees the linked list created by dmtinputCreateObjectList
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 08/30/1999 - davidkl - created
|
||
|
// 09/01/1999 - davidkl - implemented
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputFreeObjectList(DMTDEVICEOBJECT_NODE **ppdmtoList)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
DMTDEVICEOBJECT_NODE *pNode = NULL;
|
||
|
|
||
|
// validate ppdmtaList
|
||
|
if(IsBadWritePtr((void*)ppdmtoList, sizeof(DMTDEVICEOBJECT_NODE*)))
|
||
|
{
|
||
|
DPF(0, "dmtinputFreeObjectList - Invalid ppdmtoList (%016Xh)",
|
||
|
ppdmtoList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate *ppdmtdList
|
||
|
if(IsBadReadPtr((void*)*ppdmtoList, sizeof(DMTDEVICEOBJECT_NODE)))
|
||
|
{
|
||
|
if(NULL != *ppdmtoList)
|
||
|
{
|
||
|
DPF(0, "dmtinputFreeObjectList - Invalid *ppdmtdList (%016Xh)",
|
||
|
*ppdmtoList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if NULL, then return "did nothing"
|
||
|
DPF(3, "dmtinputFreeObjectList - Nothing to do....");
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// walk the list and free each object
|
||
|
while(*ppdmtoList)
|
||
|
{
|
||
|
pNode = *ppdmtoList;
|
||
|
*ppdmtoList = (*ppdmtoList)->pNext;
|
||
|
|
||
|
// delete the node
|
||
|
DPF(5, "dmtinputFreeObjectList - deleting Node (%016Xh)", pNode);
|
||
|
if(LocalFree((HLOCAL)pNode))
|
||
|
{
|
||
|
DPF(0, "dmtinputFreeObjectList - MEMORY LEAK - "
|
||
|
"LocalFree() failed (%d)...",
|
||
|
GetLastError());
|
||
|
hRes = DMT_S_MEMORYLEAK;
|
||
|
}
|
||
|
DPF(5, "dmtinputFreeObjectList - Node deleted");
|
||
|
}
|
||
|
|
||
|
// make sure that we set *ppObjList to NULL
|
||
|
*ppdmtoList = NULL;
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputFreeObjectList()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputEnumDevicesCallback
|
||
|
//
|
||
|
// Enumeration callback funtion called by DirectInput in response to an app
|
||
|
// calling IDirectInput#A::EnumDevices().
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCDIDEVICEINSTANCEA pddi - device instance data (ANSI version)
|
||
|
// void *pvData - app specific data
|
||
|
//
|
||
|
// Returns:
|
||
|
// BOOL : DIENUM_CONTINUE or DIENUM_STOP
|
||
|
//
|
||
|
// History:
|
||
|
// 08/30/1999 - davidkl - created
|
||
|
// 11/08/1999 - davidkl - added object counts
|
||
|
// 12/01/1999 - davidkl - now keeping product name
|
||
|
// 02/23/2000 - davidkl - updated to EnumDevicesBySemantic
|
||
|
//===========================================================================
|
||
|
BOOL CALLBACK dmtinputEnumDevicesCallback(LPCDIDEVICEINSTANCEA pddi,
|
||
|
IDirectInputDevice8A *pdid,
|
||
|
DWORD,
|
||
|
DWORD,
|
||
|
void *pvData)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
BOOL fDirective = DIENUM_CONTINUE;
|
||
|
DMTDEVICE_NODE **ppList = (DMTDEVICE_NODE**)pvData;
|
||
|
DMTDEVICE_NODE *pCurrent = NULL;
|
||
|
DMTDEVICE_NODE *pNew = NULL;
|
||
|
DIDEVCAPS didc;
|
||
|
DIPROPDWORD dipdw;
|
||
|
DPF(0, "dmtinputEnumDevicesCallback - IN");
|
||
|
|
||
|
// validate pddi
|
||
|
//
|
||
|
// NOTE: we are going to trust (for now) that DirectInput will
|
||
|
// pass us valid data
|
||
|
|
||
|
// validate pdid
|
||
|
//
|
||
|
// NOTE: we are going to trust (for now) that DirectInput will
|
||
|
// pass us valid data
|
||
|
|
||
|
// validate ppList
|
||
|
if(IsBadWritePtr((void*)ppList, sizeof(DMTDEVICE_NODE*)))
|
||
|
{
|
||
|
return DIENUM_STOP;
|
||
|
}
|
||
|
|
||
|
// validate *ppList
|
||
|
if(IsBadWritePtr((void*)*ppList, sizeof(DMTDEVICE_NODE)))
|
||
|
{
|
||
|
if(NULL != *ppList)
|
||
|
{
|
||
|
return DIENUM_STOP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// we are handed a mouse or keyboard
|
||
|
//
|
||
|
// skip to the next device
|
||
|
if((DI8DEVTYPE_MOUSE == DIDFT_GETTYPE(pddi->dwDevType)) ||
|
||
|
(DI8DEVTYPE_KEYBOARD == DIDFT_GETTYPE(pddi->dwDevType)))
|
||
|
{
|
||
|
DPF(2, "dmtinputEnumDevicesCallback - "
|
||
|
"Keyboard/Mouse found. Skipping.");
|
||
|
fDirective = DIENUM_CONTINUE;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
pCurrent = *ppList;
|
||
|
|
||
|
// default to "keep enumerating, unless there is nothing else to find"
|
||
|
fDirective = DIENUM_CONTINUE;
|
||
|
|
||
|
// get info regarding the device
|
||
|
ZeroMemory((void*)&didc, sizeof(DIDEVCAPS));
|
||
|
didc.dwSize = sizeof(DIDEVCAPS);
|
||
|
hRes = pdid->GetCapabilities(&didc);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
// unable to retrieve device info... this is bad
|
||
|
DPF(0, "dmtinputEnumDevicesCallback - failed to "
|
||
|
"retrieve dev caps (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
DebugBreak();
|
||
|
hRes = E_UNEXPECTED;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
DPF(3, "dmtinputEnumDevicesCallback - Device: %s",
|
||
|
pddi->tszProductName);
|
||
|
|
||
|
// allocate a new node
|
||
|
pNew = (DMTDEVICE_NODE*)LocalAlloc(LMEM_FIXED,
|
||
|
sizeof(DMTDEVICE_NODE));
|
||
|
if(!pNew)
|
||
|
{
|
||
|
DPF(1, "dmtinputEnumDevicesCallback - insufficient "
|
||
|
"memory to allocate device node");
|
||
|
fDirective = DIENUM_STOP;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// populate the new node
|
||
|
ZeroMemory((void*)pNew, sizeof(DMTDEVICE_NODE));
|
||
|
|
||
|
// name(s)
|
||
|
lstrcpyA(pNew->szName, pddi->tszInstanceName);
|
||
|
lstrcpyA(pNew->szProductName, pddi->tszProductName);
|
||
|
|
||
|
// instance guid
|
||
|
pNew->guidInstance = pddi->guidInstance;
|
||
|
|
||
|
// device type/subtype
|
||
|
pNew->dwDeviceType = pddi->dwDevType;
|
||
|
|
||
|
// # axes
|
||
|
pNew->dwAxes = didc.dwAxes;
|
||
|
|
||
|
// # buttons
|
||
|
pNew->dwButtons = didc.dwButtons;
|
||
|
|
||
|
// # povs
|
||
|
pNew->dwPovs = didc.dwPOVs;
|
||
|
|
||
|
// is this a polled device?
|
||
|
if(DIDC_POLLEDDEVICE & didc.dwFlags)
|
||
|
{
|
||
|
// yep,
|
||
|
//
|
||
|
// better make sure we call IDirectInputDevice8A::Poll
|
||
|
DPF(4, "dmttestGetInput - Polled device");
|
||
|
pNew->fPolled = TRUE;
|
||
|
}
|
||
|
|
||
|
// device object ptr
|
||
|
pNew->pdid = pdid;
|
||
|
pdid->AddRef();
|
||
|
|
||
|
// vendor id / product id
|
||
|
ZeroMemory((void*)&dipdw, sizeof(DIPROPDWORD));
|
||
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
||
|
hRes = (pNew->pdid)->GetProperty(DIPROP_VIDPID,
|
||
|
&(dipdw.diph));
|
||
|
if(SUCCEEDED(hRes))
|
||
|
{
|
||
|
// extract the VID and PID
|
||
|
pNew->wVendorId = LOWORD(dipdw.dwData);
|
||
|
pNew->wProductId = HIWORD(dipdw.dwData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// property call failed, assume no VID|PID
|
||
|
pNew->wVendorId = 0;
|
||
|
pNew->wProductId = 0;
|
||
|
|
||
|
// this property call is not critical
|
||
|
// it's ok to mask the failure
|
||
|
hRes = S_FALSE;
|
||
|
}
|
||
|
|
||
|
// filename
|
||
|
lstrcpyA(pNew->szFilename, "\0");
|
||
|
|
||
|
|
||
|
// append to the end of the list
|
||
|
if(!pCurrent)
|
||
|
{
|
||
|
// make sure we return the head
|
||
|
*ppList = pNew;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// walk to the end of the list
|
||
|
while(pCurrent->pNext)
|
||
|
{
|
||
|
pCurrent = pCurrent->pNext;
|
||
|
}
|
||
|
|
||
|
// add the node
|
||
|
pCurrent->pNext = pNew;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// general cleanup
|
||
|
|
||
|
// in failure case, free pNew
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(1, "dmtinputEnumDevicesCallback - something failed... ");
|
||
|
|
||
|
if(pNew)
|
||
|
{
|
||
|
DPF(1, "dmtinputEnumDevicesCallback - freeing new device node");
|
||
|
if(LocalFree((HLOCAL)pNew))
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Needs error case handling
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// continue enumerating
|
||
|
return fDirective;
|
||
|
|
||
|
} //*** end dmtinputEnumDevicesCallback()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputEnumDeviceObjectsCallback
|
||
|
//
|
||
|
// Enumeration callback funtion called by DirectInput in response to an app
|
||
|
// calling IDirectInpuDevice#A::EnumDevices()
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCDIDEVICEOBJECTINSTANCEA pddi - device object instance data
|
||
|
// (ANSI version)
|
||
|
// void *pvData - app specific data
|
||
|
//
|
||
|
// Returns:
|
||
|
// BOOL : DIENUM_CONTINUE or DIENUM_STOP
|
||
|
//
|
||
|
// History:
|
||
|
// 08/30/1999 - davidkl - created
|
||
|
// 10/21/1999 - davidkl - added object type filtering
|
||
|
//===========================================================================
|
||
|
BOOL CALLBACK dmtinputEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCEA pddoi,
|
||
|
void *pvData)
|
||
|
{
|
||
|
BOOL fDirective = DIENUM_CONTINUE;
|
||
|
WORD wOffset = 0;
|
||
|
DMTDEVICEOBJECT_NODE **ppList = (DMTDEVICEOBJECT_NODE**)pvData;
|
||
|
DMTDEVICEOBJECT_NODE *pCurrent = NULL;
|
||
|
DMTDEVICEOBJECT_NODE *pNew = NULL;
|
||
|
|
||
|
// validate ppList
|
||
|
if(IsBadWritePtr((void*)ppList, sizeof(DMTDEVICEOBJECT_NODE*)))
|
||
|
{
|
||
|
return DIENUM_STOP;
|
||
|
}
|
||
|
|
||
|
// validate *ppList
|
||
|
if(IsBadWritePtr((void*)*ppList, sizeof(DMTDEVICEOBJECT_NODE)))
|
||
|
{
|
||
|
if(NULL != *ppList)
|
||
|
{
|
||
|
return DIENUM_STOP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
pCurrent = *ppList;
|
||
|
|
||
|
// default to "keep enumerating, unless there is nothing else to find"
|
||
|
fDirective = DIENUM_CONTINUE;
|
||
|
|
||
|
/*
|
||
|
// filter HID collections
|
||
|
if(DIDFT_COLLECTION & (pddoi->dwType))
|
||
|
{
|
||
|
// skip this object
|
||
|
DPF(3, "dmtinputEnumDeviceObjectsCallback - "
|
||
|
"object is a collection... skipping");
|
||
|
__leave;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// allocate a new node
|
||
|
pNew = (DMTDEVICEOBJECT_NODE*)LocalAlloc(LMEM_FIXED,
|
||
|
sizeof(DMTDEVICEOBJECT_NODE));
|
||
|
if(!pNew)
|
||
|
{
|
||
|
fDirective = DIENUM_STOP;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// populate the new node
|
||
|
ZeroMemory((void*)pNew, sizeof(DMTDEVICEOBJECT_NODE));
|
||
|
|
||
|
// name
|
||
|
lstrcpyA(pNew->szName, (LPSTR)pddoi->tszName);
|
||
|
|
||
|
// object type
|
||
|
pNew->dwObjectType = pddoi->dwType;
|
||
|
|
||
|
// object offset
|
||
|
pNew->dwObjectOffset = pddoi->dwOfs;
|
||
|
|
||
|
// HID usage page
|
||
|
pNew->wUsagePage = pddoi->wUsagePage;
|
||
|
|
||
|
// HID usage
|
||
|
pNew->wUsage = pddoi->wUsage;
|
||
|
|
||
|
// control "identifier"
|
||
|
switch(DIDFT_GETTYPE(pddoi->dwType))
|
||
|
{
|
||
|
case DIDFT_AXIS:
|
||
|
case DIDFT_ABSAXIS:
|
||
|
case DIDFT_RELAXIS:
|
||
|
pNew->wCtrlId = IDC_AXIS_X + DIDFT_GETINSTANCE(pddoi->dwType);
|
||
|
break;
|
||
|
|
||
|
case DIDFT_BUTTON:
|
||
|
case DIDFT_PSHBUTTON:
|
||
|
case DIDFT_TGLBUTTON:
|
||
|
// this is a button, encode as follows:
|
||
|
// (BTN1 + (instance % NUM_DISPBTNS)) +
|
||
|
// (BTNS_1_32 + (instance / NUM_DISPBTNS))
|
||
|
wOffset = DIDFT_GETINSTANCE(pddoi->dwType) / NUM_DISPBTNS;
|
||
|
pNew->wCtrlId = (wOffset << 8) |
|
||
|
(DIDFT_GETINSTANCE(pddoi->dwType) % NUM_DISPBTNS);
|
||
|
break;
|
||
|
|
||
|
case DIDFT_POV:
|
||
|
pNew->wCtrlId = IDC_POV1 + DIDFT_GETINSTANCE(pddoi->dwType);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// we should never hit this
|
||
|
// as we filter out objects that are
|
||
|
// not one of the types we care about
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// append to the end of the list
|
||
|
if(!pCurrent)
|
||
|
{
|
||
|
// list head
|
||
|
pCurrent = pNew;
|
||
|
|
||
|
// make sure we return the head
|
||
|
*ppList = pCurrent;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// walk to the end of the list
|
||
|
while(pCurrent->pNext)
|
||
|
{
|
||
|
pCurrent = pCurrent->pNext;
|
||
|
}
|
||
|
|
||
|
// add the node
|
||
|
pCurrent->pNext = pNew;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Needs error case handling
|
||
|
// Needs some sort of error handling
|
||
|
}
|
||
|
|
||
|
// continue enumerating
|
||
|
return fDirective;
|
||
|
|
||
|
} //*** end dmtinputEnumDeviceObjectsCallback()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputPopulateActionArray
|
||
|
//
|
||
|
// Fills DIACTIONA array with data from the DMTACTION_NODE list
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 09/08/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputPopulateActionArray(DIACTIONA *pdia,
|
||
|
UINT uElements,
|
||
|
DMTACTION_NODE *pdmtaList)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
UINT u = 0;
|
||
|
|
||
|
// validate pdia
|
||
|
if(IsBadWritePtr((void*)pdia, uElements * sizeof(DIACTIONA)))
|
||
|
{
|
||
|
DPF(0, "dmtinputPopulateActionArray - invalid pdia (%016Xh)",
|
||
|
pdia);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate pdmtaList
|
||
|
if(IsBadReadPtr((void*)pdmtaList, sizeof(DMTACTION_NODE)))
|
||
|
{
|
||
|
DPF(0, "dmtinputPopulateActionArray - invalid pdmtaList (%016Xh)",
|
||
|
pdmtaList);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// first, flush whatever is currently in the array
|
||
|
ZeroMemory((void*)pdia, uElements * sizeof(DIACTIONA));
|
||
|
|
||
|
// next, copy the following DIACTION elements
|
||
|
// from the action list to the action array
|
||
|
//
|
||
|
// NOTE: All strings referenced in these structurs
|
||
|
// are ANSI strings (we are using DIACTIONA)
|
||
|
//
|
||
|
// DIACTION DMTACTION_NODE
|
||
|
// ======== ==============
|
||
|
// dwSemantic dwActionId
|
||
|
// lptszActionName szName
|
||
|
//
|
||
|
for(u = 0; u < uElements; u++)
|
||
|
{
|
||
|
// make sure there is some data to copy
|
||
|
if(!pdmtaList)
|
||
|
{
|
||
|
DPF(1, "dmtinputPopulateActionArray - Ran out of "
|
||
|
"list nodes before fully populating DIACTION array");
|
||
|
hRes = S_FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// copy the data
|
||
|
(pdia+u)->dwSemantic = pdmtaList->dwActionId;
|
||
|
(pdia+u)->lptszActionName = pdmtaList->szName;
|
||
|
|
||
|
// go to next list element
|
||
|
pdmtaList = pdmtaList->pNext;
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputPopulateActionArray()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputXlatDIDFTtoInternalType
|
||
|
//
|
||
|
// Converts from the DIDFT_* value (DIDEVICEOBJECTINSTANCE.dwType) to our
|
||
|
// internal control type value (DMTA_TYPE_*)
|
||
|
//
|
||
|
// Parameters:
|
||
|
// DWORD dwType - value of DIDEVICEOBJECTINSTANCE.dwType
|
||
|
// DWORD *pdwInternalType - ptr to recieve DMTA_TYPE_* value
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 09/09/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputXlatDIDFTtoInternalType(DWORD dwType,
|
||
|
DWORD *pdwInternalType)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
|
||
|
// validate pdwInternalType
|
||
|
if(IsBadWritePtr((void*)pdwInternalType, sizeof(DWORD)))
|
||
|
{
|
||
|
DPF(0, "dmtinputXlatDIDFTtoInternalType - invalid pdwInternalType "
|
||
|
"(%016Xh)", pdwInternalType);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// translate
|
||
|
//
|
||
|
// OR together axis, button and pov masks,
|
||
|
// AND that with the type passed in
|
||
|
//
|
||
|
switch((DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV) & dwType)
|
||
|
{
|
||
|
case DIDFT_AXIS:
|
||
|
case DIDFT_RELAXIS:
|
||
|
case DIDFT_ABSAXIS:
|
||
|
DPF(5, "dmtinputXlatDIDFTtoInternalType - AXIS");
|
||
|
*pdwInternalType = DMTA_TYPE_AXIS;
|
||
|
break;
|
||
|
|
||
|
case DIDFT_PSHBUTTON:
|
||
|
case DIDFT_TGLBUTTON:
|
||
|
case DIDFT_BUTTON:
|
||
|
DPF(5, "dmtinputXlatDIDFTtoInternalType - BUTTON");
|
||
|
*pdwInternalType = DMTA_TYPE_BUTTON;
|
||
|
break;
|
||
|
|
||
|
case DIDFT_POV:
|
||
|
DPF(5, "dmtinputXlatDIDFTtoInternalType - POV");
|
||
|
*pdwInternalType = DMTA_TYPE_POV;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DPF(5, "dmtinputXlatDIDFTtoInternalType - WHAT IS THIS?");
|
||
|
*pdwInternalType = DMTA_TYPE_UNKNOWN;
|
||
|
hRes = S_FALSE;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputXlatDIDFTtoInternalType()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputPrepDevice
|
||
|
//
|
||
|
// Prepares the device for data retrieval. Performs the following steps:
|
||
|
// * Set the cooperative level
|
||
|
// * Set the data format
|
||
|
// * Set the buffer size
|
||
|
//
|
||
|
// Parameters:
|
||
|
// HWND hwnd - handle of app window
|
||
|
// DWORD dwGenreId - identifier of genre to be tested
|
||
|
// IDirectInputDevice8A *pdid - ptr to device object
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 09/21/1999 - davidkl - created
|
||
|
// 10/07/1999 - davidkl - added Get/ApplyActionMap calls
|
||
|
// 10/27/1999 - davidkl - added uAppData to pdia, changed param list
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputPrepDevice(HWND hwnd,
|
||
|
DWORD dwGenreId,
|
||
|
DMTDEVICE_NODE *pDevice,
|
||
|
DWORD dwActions,
|
||
|
DIACTIONA *pdia)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
DWORD dw = 0;
|
||
|
IDirectInputDevice8A *pdid = NULL;
|
||
|
DMTDEVICEOBJECT_NODE *pObject = NULL;
|
||
|
DIACTIONFORMATA diaf;
|
||
|
DIPROPDWORD dipdw;
|
||
|
|
||
|
// validate pDevice
|
||
|
if(IsBadReadPtr((void*)pDevice, sizeof(DMTDEVICE_NODE)))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - invalid pDevice (%016Xh)",
|
||
|
pDevice);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate pdia
|
||
|
if(IsBadReadPtr((void*)pdia, dwActions * sizeof(DIACTIONA)))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - invalid pdia (%016Xh)",
|
||
|
pdia);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
|
||
|
// validate pDevice->pdid
|
||
|
if(IsBadReadPtr((void*)(pDevice->pdid), sizeof(IDirectInputDevice8A)))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - invalid pDevice->pdid (%016Xh)",
|
||
|
pDevice->pdid);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// save some typing
|
||
|
pdid = pDevice->pdid;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// set the cooperative level
|
||
|
hRes = pdid->SetCooperativeLevel(hwnd,
|
||
|
DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - SetCooperativeLevel(non-exclusive | "
|
||
|
"background) failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// set data buffer size
|
||
|
ZeroMemory((void*)&dipdw, sizeof(DIPROPDWORD));
|
||
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
||
|
dipdw.diph.dwObj = 0;
|
||
|
dipdw.dwData = DMTINPUT_BUFFERSIZE;
|
||
|
hRes = pdid->SetProperty(DIPROP_BUFFERSIZE,
|
||
|
&(dipdw.diph));
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - SetProperty(buffer size) "
|
||
|
"failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// populate the diactionformat structure
|
||
|
ZeroMemory((void*)&diaf, sizeof(DIACTIONFORMATA));
|
||
|
diaf.dwSize = sizeof(DIACTIONFORMATA);
|
||
|
diaf.dwActionSize = sizeof(DIACTIONA);
|
||
|
diaf.dwNumActions = dwActions;
|
||
|
diaf.rgoAction = pdia;
|
||
|
diaf.dwDataSize = 4 * diaf.dwNumActions;
|
||
|
diaf.guidActionMap = GUID_DIMapTst;
|
||
|
diaf.dwGenre = dwGenreId;
|
||
|
diaf.dwBufferSize = DMTINPUT_BUFFERSIZE;
|
||
|
lstrcpyA(diaf.tszActionMap, DMT_APP_CAPTION);
|
||
|
|
||
|
|
||
|
// get the action map for this genre (from the device)
|
||
|
hRes = pdid->BuildActionMap(&diaf,
|
||
|
(LPCSTR)NULL,
|
||
|
DIDBAM_HWDEFAULTS);
|
||
|
DPF(1, "dmtinputPrepDevice - GetActionMap returned %s (%08Xh)",
|
||
|
dmtxlatHRESULT, hRes);
|
||
|
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - GetActionMap failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// add the control id/type info to the
|
||
|
// action array
|
||
|
pObject = pDevice->pObjectList;
|
||
|
while(pObject)
|
||
|
{
|
||
|
// spin through the array
|
||
|
//
|
||
|
// look for matching elements
|
||
|
// (match == same guidInstance & same offset
|
||
|
for(dw = 0; dw < dwActions; dw++)
|
||
|
{
|
||
|
// first check the guid
|
||
|
if(IsEqualGUID(pObject->guidDeviceInstance, (pdia+dw)->guidInstance))
|
||
|
{
|
||
|
// then compare the offset
|
||
|
if((pdia+dw)->dwObjID == pObject->dwObjectType)
|
||
|
{
|
||
|
// store the CtrlId and Type
|
||
|
(pdia+dw)->uAppData = (DIDFT_GETTYPE(pObject->dwObjectType) << 16) |
|
||
|
(pObject->wCtrlId);
|
||
|
|
||
|
// skip out of the for loop
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// next object
|
||
|
pObject = pObject->pNext;
|
||
|
}
|
||
|
|
||
|
// apply the action map for this genre
|
||
|
//
|
||
|
// this accomplishes the same task as calling SetDataFormat
|
||
|
hRes = pdid->SetActionMap(&diaf,
|
||
|
NULL,
|
||
|
DIDSAM_DEFAULT);
|
||
|
DPF(1, "dmtinputPrepDevice - ApplyActionMap returned %s (%08Xh)",
|
||
|
dmtxlatHRESULT, hRes);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputPrepDevice - ApplyActionMap failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Needs error case handling
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputPrepDevice()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputGetActionPri
|
||
|
//
|
||
|
// Extracts the action priority from the DirectInput semantic
|
||
|
//
|
||
|
// Parameters:
|
||
|
// DWORD dwSemantic - DirectInput action semantic
|
||
|
//
|
||
|
// Returns: int (Action priority)
|
||
|
//
|
||
|
// History:
|
||
|
// 09/28/1999 - davidkl - created
|
||
|
// 10/27/1999 - davidkl - code review cleanup
|
||
|
//===========================================================================
|
||
|
DWORD dmtinputGetActionPri(DWORD dwSemantic)
|
||
|
{
|
||
|
|
||
|
// action priority is 0 based, we want to return
|
||
|
// priority 1 based for display purposes
|
||
|
return (DWORD)(DISEM_PRI_GET(dwSemantic) + 1);
|
||
|
|
||
|
} //*** end dmtinputGetActionPri()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputGetActionObjectType
|
||
|
//
|
||
|
// Extracts the object type from the DirectInput semantic and returns it
|
||
|
// as one of DIMapTst's internal object types.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// DWORD dwSemantic - DirectInput action semantic
|
||
|
//
|
||
|
// Returns: DWORD (internal object type)
|
||
|
//
|
||
|
// History:
|
||
|
// 09/28/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
DWORD dmtinputGetActionObjectType(DWORD dwSemantic)
|
||
|
{
|
||
|
DWORD dwObjType = DMTA_TYPE_UNKNOWN;
|
||
|
|
||
|
// we achieve our goal by:
|
||
|
// * extracting and shifting object typw with DISEM_TYPE_GET
|
||
|
// ** value becomes 1, 2, or 3 (DirectInput's system)
|
||
|
// * subtracting 1 to be 0 based
|
||
|
// ** value becomes 0, 1, or 2 (DIMapTst's system)
|
||
|
dwObjType = DISEM_TYPE_GET(dwSemantic) - 1;
|
||
|
|
||
|
// done
|
||
|
return dwObjType;
|
||
|
|
||
|
} //*** end dmtinputGetActionObjectType()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputCreateDirectInput
|
||
|
//
|
||
|
// Creates a DirectInpu8A object
|
||
|
//
|
||
|
// Parameters:
|
||
|
// IDirectInput8A **ppdi - ptr to directinput object ptr
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 10/06/1999 - davidkl - created
|
||
|
// 10/27/1999 - davidkl - house cleaning
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputCreateDirectInput(HINSTANCE hinst,
|
||
|
IDirectInput8A **ppdi)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
|
||
|
// validate ppdi
|
||
|
if(IsBadWritePtr((void*)ppdi, sizeof(IDirectInput8A*)))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDirectInput - invalid ppdi (%016Xh)",
|
||
|
ppdi);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// cocreate IDirectInput8A
|
||
|
hRes = CoCreateInstance(CLSID_DirectInput8,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
IID_IDirectInput8A,
|
||
|
(void**)ppdi);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDirectInput - "
|
||
|
"CoCreateInstance failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// initialize the new dinput object
|
||
|
hRes = (*ppdi)->Initialize(hinst,
|
||
|
DIRECTINPUT_VERSION);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputCreateDirectInput - IDirectInput8A::"
|
||
|
"Initialize failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// if something fails...
|
||
|
|
||
|
// release the device object
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
SAFE_RELEASE((*ppdi));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputCreateDirectInput()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputDeviceHasObject
|
||
|
//
|
||
|
// Determines (from a the supplied object list) whether or not a device
|
||
|
// reports as having at least one object of the specified type.
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: BOOL (FALSE if any invalid parameters)
|
||
|
//
|
||
|
// History:
|
||
|
// 10/28/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
BOOL dmtinputDeviceHasObject(DMTDEVICEOBJECT_NODE *pObjectList,
|
||
|
DWORD dwType)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
DWORD dwObjType = DMTA_TYPE_UNKNOWN;
|
||
|
DMTDEVICEOBJECT_NODE *pObject = NULL;
|
||
|
|
||
|
pObject = pObjectList;
|
||
|
while(pObject)
|
||
|
{
|
||
|
if(FAILED(dmtinputXlatDIDFTtoInternalType(pObject->dwObjectType,
|
||
|
&dwObjType)))
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Needs error case handling
|
||
|
}
|
||
|
DPF(3, "dmtinputDeviceHasObject - %s : DIDFT type %08Xh, internal type %d",
|
||
|
pObject->szName,
|
||
|
pObject->dwObjectType,
|
||
|
dwObjType);
|
||
|
|
||
|
if(dwType == dwObjType)
|
||
|
{
|
||
|
fRet = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// next object
|
||
|
pObject = pObject->pNext;
|
||
|
}
|
||
|
|
||
|
|
||
|
// done
|
||
|
return fRet;
|
||
|
|
||
|
} //*** end dmtinputDeviceHasObject()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputRegisterMapFile
|
||
|
//
|
||
|
// Queries DirectInput for the proper location and registers the map file
|
||
|
// for the specified device.
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 11/04/1999 - davidkl - created
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputRegisterMapFile(HWND hwnd,
|
||
|
DMTDEVICE_NODE *pDevice)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
LONG lRet = 0L;
|
||
|
HKEY hkType = NULL;
|
||
|
IDirectInput8A *pdi = NULL;
|
||
|
IDirectInputJoyConfig *pjoycfg = NULL;
|
||
|
DIPROPDWORD dipdw;
|
||
|
DIJOYCONFIG dijc;
|
||
|
|
||
|
// validate pDevice
|
||
|
if(IsBadReadPtr((void*)pDevice, sizeof(DMTDEVICE_NODE)))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - invalid pDevice (%016Xh)",
|
||
|
pDevice);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate pDevice->pdid
|
||
|
if(IsBadReadPtr((void*)(pDevice->pdid), sizeof(IDirectInputDevice8A)))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - invalid pDevice->pdid (%016Xh)",
|
||
|
pDevice->pdid);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// create a directinput object
|
||
|
hRes = dmtinputCreateDirectInput(ghinst,
|
||
|
&pdi);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - unable to create pdi (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// query for the joyconfig interface
|
||
|
hRes = pdi->QueryInterface(IID_IDirectInputJoyConfig8,
|
||
|
(void**)&pjoycfg);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - QI(JoyConfig) failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// get the device id
|
||
|
//
|
||
|
// use DIPROP_JOYSTICKID
|
||
|
ZeroMemory((void*)&dipdw, sizeof(DIPROPDWORD));
|
||
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
||
|
dipdw.diph.dwObj = 0;
|
||
|
hRes = (pDevice->pdid)->GetProperty(DIPROP_JOYSTICKID,
|
||
|
&(dipdw.diph));
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - GetProperty(joystick id) failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// prepare the config structure
|
||
|
ZeroMemory((void*)&dijc, sizeof(DIJOYCONFIG));
|
||
|
dijc.dwSize = sizeof(DIJOYCONFIG);
|
||
|
|
||
|
// set the joycfg cooperative level
|
||
|
hRes = pjoycfg->SetCooperativeLevel(hwnd,
|
||
|
DISCL_EXCLUSIVE | DISCL_BACKGROUND);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - SetCooperativeLevel failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// acquire joyconfig
|
||
|
hRes = pjoycfg->Acquire();
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - Acquire() failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
|
||
|
// retrieve the config data
|
||
|
hRes = pjoycfg->GetConfig((UINT)(dipdw.dwData),
|
||
|
&dijc,
|
||
|
DIJC_GUIDINSTANCE |
|
||
|
DIJC_REGHWCONFIGTYPE);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - GetConfig failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// open the type key
|
||
|
//
|
||
|
// we are opening for read as well as write so we can
|
||
|
// save the previous value
|
||
|
hRes = dmtOpenTypeKey(dijc.wszType,
|
||
|
KEY_READ|KEY_WRITE,
|
||
|
&hkType);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - OpenTypeKey failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// write the map file name
|
||
|
lRet = RegSetValueExA(hkType,
|
||
|
"OEMMapFile",
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(CONST BYTE*)(pDevice->szFilename),
|
||
|
sizeof(char) *
|
||
|
(lstrlenA(pDevice->szFilename) + 1));
|
||
|
if(ERROR_SUCCESS)
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - RegSetValueExA failed (%d)",
|
||
|
GetLastError());
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// notify dinput that we changed something
|
||
|
hRes = pjoycfg->SendNotify();
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputRegisterMapFile - SendNotify failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
hRes = S_FALSE;
|
||
|
__leave;
|
||
|
}
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// cleanup
|
||
|
if(pjoycfg)
|
||
|
{
|
||
|
pjoycfg->Unacquire();
|
||
|
}
|
||
|
|
||
|
SAFE_RELEASE(pjoycfg);
|
||
|
SAFE_RELEASE(pdi);
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputRegisterMapFile()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtinputGetRegisteredMapFile
|
||
|
//
|
||
|
// Retrieves the map file name for the specified device
|
||
|
//
|
||
|
// Parameters:
|
||
|
// HWND hwnd
|
||
|
// DMTDEVICE_NODE *pDevice
|
||
|
// PSTR pszFilename
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 12/01/1999 - davidkl - created
|
||
|
// 02/21/2000 - davidkl - initial implementation
|
||
|
//===========================================================================
|
||
|
HRESULT dmtinputGetRegisteredMapFile(HWND hwnd,
|
||
|
DMTDEVICE_NODE *pDevice,
|
||
|
PSTR pszFilename,
|
||
|
DWORD cbFilename)
|
||
|
{
|
||
|
HRESULT hRes = S_OK;
|
||
|
LONG lRet = 0L;
|
||
|
HKEY hkType = NULL;
|
||
|
HKEY hKey = NULL;
|
||
|
IDirectInput8A *pdi = NULL;
|
||
|
IDirectInputJoyConfig *pjoycfg = NULL;
|
||
|
DIPROPDWORD dipdw;
|
||
|
DIJOYCONFIG dijc;
|
||
|
|
||
|
|
||
|
// validate pDevice
|
||
|
if(IsBadReadPtr((void*)pDevice, sizeof(DMTDEVICE_NODE)))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - invalid pDevice (%016Xh)",
|
||
|
pDevice);
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// validate pDevice->pdid
|
||
|
if(IsBadReadPtr((void*)(pDevice->pdid), sizeof(IDirectInputDevice8A)))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - invalid pDevice->pdid (%016Xh)",
|
||
|
pDevice->pdid);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// create a directinput object
|
||
|
hRes = dmtinputCreateDirectInput(ghinst,
|
||
|
&pdi);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - unable to create pdi (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// query for the joyconfig interface
|
||
|
hRes = pdi->QueryInterface(IID_IDirectInputJoyConfig8,
|
||
|
(void**)&pjoycfg);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - QI(JoyConfig) failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// get the device id
|
||
|
//
|
||
|
// use DIPROP_JOYSTICKID
|
||
|
ZeroMemory((void*)&dipdw, sizeof(DIPROPDWORD));
|
||
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
||
|
dipdw.diph.dwObj = 0;
|
||
|
hRes = (pDevice->pdid)->GetProperty(DIPROP_JOYSTICKID,
|
||
|
&(dipdw.diph));
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - GetProperty(joystick id) failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// prepare the config structure
|
||
|
ZeroMemory((void*)&dijc, sizeof(DIJOYCONFIG));
|
||
|
dijc.dwSize = sizeof(DIJOYCONFIG);
|
||
|
|
||
|
// set the joycfg cooperative level
|
||
|
hRes = pjoycfg->SetCooperativeLevel(hwnd,
|
||
|
DISCL_EXCLUSIVE | DISCL_BACKGROUND);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - SetCooperativeLevel failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// acquire joyconfig
|
||
|
hRes = pjoycfg->Acquire();
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - Acquire() failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// retrieve the config data
|
||
|
hRes = pjoycfg->GetConfig((UINT)(dipdw.dwData),
|
||
|
&dijc,
|
||
|
DIJC_GUIDINSTANCE |
|
||
|
DIJC_REGHWCONFIGTYPE);
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - GetConfig failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
|
||
|
// open the type key
|
||
|
//
|
||
|
// we are opening for read as well as write so we can
|
||
|
// save the previous value
|
||
|
|
||
|
hRes = dmtOpenTypeKey(dijc.wszType,
|
||
|
KEY_ALL_ACCESS,
|
||
|
&hkType);
|
||
|
|
||
|
if(FAILED(hRes))
|
||
|
{
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - OpenTypeKey failed (%s == %08Xh)",
|
||
|
dmtxlatHRESULT(hRes), hRes);
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// read the value of OEMMapfile
|
||
|
lRet = RegQueryValueExA(hkType,
|
||
|
"OEMMapFile",
|
||
|
NULL,
|
||
|
NULL,
|
||
|
(BYTE*)pszFilename,
|
||
|
&cbFilename);
|
||
|
if(ERROR_SUCCESS != lRet)
|
||
|
{
|
||
|
// ISSUE-2001/03/29-timgill Need to determine what the error code means and translate -> HRESULT
|
||
|
hRes = S_FALSE;
|
||
|
DPF(0, "dmtinputGetRegisteredMapFile - RegQueryValueEx failed (%08Xh)",
|
||
|
lRet);
|
||
|
lstrcpyA(pszFilename, "");
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
// cleanup
|
||
|
if(pjoycfg)
|
||
|
{
|
||
|
pjoycfg->Unacquire();
|
||
|
}
|
||
|
|
||
|
SAFE_RELEASE(pjoycfg);
|
||
|
SAFE_RELEASE(pdi);
|
||
|
}
|
||
|
|
||
|
// done
|
||
|
return hRes;
|
||
|
|
||
|
} //*** end dmtinputGetRegisteredMapFile()
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
// dmtOpenTypeKey
|
||
|
//
|
||
|
// Opens the hard coded DInput registry key...replaces IDirectInputJoyConfig::OpenTypeKey
|
||
|
//
|
||
|
// Parameters:
|
||
|
// LPCWSTR wszType
|
||
|
// DWORD hKey
|
||
|
// PHKEY phKey
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History:
|
||
|
// 08/09/2000 - rossy - initial implementation
|
||
|
//===========================================================================
|
||
|
HRESULT dmtOpenTypeKey( LPCWSTR wszType, DWORD hKey, PHKEY phKey )
|
||
|
{
|
||
|
|
||
|
char szRegStr[200];
|
||
|
char* szReg = "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\DirectInput\\";
|
||
|
|
||
|
wsprintf(szRegStr, TEXT("%s%S"), szReg, wszType);
|
||
|
|
||
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegStr , 0, hKey, phKey))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
}//*** end dmtOpenTypeKey()
|
||
|
|
||
|
//===========================================================================
|
||
|
//===========================================================================
|
||
|
//===========================================================================
|
||
|
//===========================================================================
|
||
|
//===========================================================================
|
||
|
//===========================================================================
|