windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dimapcfg/dmtinput.cpp
2020-09-26 16:20:57 +08:00

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()
//===========================================================================
//===========================================================================
//===========================================================================
//===========================================================================
//===========================================================================
//===========================================================================