272 lines
7.6 KiB
C
272 lines
7.6 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* diqdevg.c
|
||
|
*
|
||
|
* Acquire an IDirectInputDevice as a generic device.
|
||
|
*
|
||
|
* We build a private data format with all the axes first, then
|
||
|
* all the buttons.
|
||
|
*
|
||
|
* We display the axes parenthesized, followed by a space-separated
|
||
|
* list of buttons.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "diquick.h"
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* DEVGINFO
|
||
|
*
|
||
|
* Structure used to track generic device state.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
typedef struct DEVGINFO {
|
||
|
DWORD cbState; /* Size of state buffer */
|
||
|
LPVOID pvState; /* State buffer */
|
||
|
int cAxes; /* Number of axes (start at offset 0) */
|
||
|
int cButtons; /* Number of buttons (start after axes) */
|
||
|
} DEVGINFO, *PDEVGINFO;
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Devg_UpdateStatus
|
||
|
*
|
||
|
* Warning! ptszBuf is only 256 characters long!
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
Devg_UpdateStatus(PDEVDLGINFO pddi, LPTSTR ptszBuf)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
PDEVGINFO pdevg = pddi->pvAcq;
|
||
|
IDirectInputDevice *pdev = pddi->pdid;
|
||
|
|
||
|
hres = IDirectInputDevice_GetDeviceState(pdev, pdevg->cbState,
|
||
|
pdevg->pvState);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
LPVOID pvData = pdevg->pvState;
|
||
|
int iButton;
|
||
|
|
||
|
if (pdevg->cAxes) {
|
||
|
int iAxis;
|
||
|
|
||
|
for (iAxis = 0; iAxis < pdevg->cAxes; iAxis++) {
|
||
|
LPLONG pl = pvData;
|
||
|
pvData = pvAddPvCb(pvData, sizeof(LONG));
|
||
|
ptszBuf += wsprintf(ptszBuf, iAxis == 0 ? TEXT("\050%d") :
|
||
|
TEXT(", %d"), *pl);
|
||
|
}
|
||
|
ptszBuf += wsprintf(ptszBuf, TEXT("\051"));
|
||
|
}
|
||
|
|
||
|
for (iButton = 0; iButton < pdevg->cButtons; iButton++) {
|
||
|
LPBYTE pb = pvData;
|
||
|
pvData = pvAddPvCb(pvData, sizeof(BYTE));
|
||
|
if (*pb & 0x80) {
|
||
|
ptszBuf += wsprintf(ptszBuf, TEXT(" %d"), iButton);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*ptszBuf = TEXT('\0');
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Devg_Destroy
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP_(void)
|
||
|
Devg_Destroy(PDEVDLGINFO pddi)
|
||
|
{
|
||
|
PDEVGINFO pdevg = pddi->pvAcq;
|
||
|
|
||
|
if (pdevg) {
|
||
|
if (pdevg->pvState) {
|
||
|
LocalFree(pdevg->pvState);
|
||
|
}
|
||
|
LocalFree(pdevg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Devg_DataFormatEnumProc
|
||
|
*
|
||
|
* Callback function for each object. If it's a button or axis,
|
||
|
* we put it in the data format. But only if it generates data!
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
typedef struct DEVGENUM {
|
||
|
DWORD dwNumObjs;
|
||
|
DIDATAFORMAT df;
|
||
|
PDEVGINFO pdevg;
|
||
|
PDEVDLGINFO pddi;
|
||
|
} DEVGENUM, *PDEVGENUM;
|
||
|
|
||
|
BOOL CALLBACK
|
||
|
Devg_DataFormatEnumProc(LPCDIDEVICEOBJECTINSTANCE pinst, LPVOID pv)
|
||
|
{
|
||
|
PDEVGENUM pge = pv;
|
||
|
LPDIOBJECTDATAFORMAT podf;
|
||
|
DIDEVICEOBJECTINSTANCE doi;
|
||
|
DWORD cbObj;
|
||
|
|
||
|
|
||
|
if( pge->df.dwNumObjs == pge->dwNumObjs -1 )
|
||
|
{
|
||
|
HLOCAL hloc;
|
||
|
pge->dwNumObjs *=2;
|
||
|
hloc = LocalReAlloc((HLOCAL)pge->df.rgodf, pge->dwNumObjs * pge->df.dwObjSize , LMEM_MOVEABLE+LMEM_ZEROINIT);
|
||
|
|
||
|
if(hloc)
|
||
|
{
|
||
|
pge->df.rgodf = hloc;
|
||
|
}else
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ConvertDoi(pge->pddi, &doi, pinst);
|
||
|
|
||
|
/*
|
||
|
* Ignore no-data elements.
|
||
|
*/
|
||
|
if (doi.dwType & DIDFT_NODATA) {
|
||
|
} else {
|
||
|
|
||
|
if (doi.dwType & (DIDFT_AXIS | DIDFT_POV)) {
|
||
|
pge->pdevg->cAxes++;
|
||
|
cbObj = cbX(LONG);
|
||
|
} else if (doi.dwType & DIDFT_BUTTON) {
|
||
|
pge->pdevg->cButtons++;
|
||
|
cbObj = cbX(BYTE);
|
||
|
} else {
|
||
|
/*
|
||
|
* Theoretical impossibility!
|
||
|
*/
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
podf = &pge->df.rgodf[pge->df.dwNumObjs];
|
||
|
|
||
|
podf->dwOfs = pge->df.dwDataSize;
|
||
|
#ifdef USE_HID_USAGE_DATA_FORMATS
|
||
|
if (doi.wUsagePage) {
|
||
|
podf->dwType = (doi.dwType &
|
||
|
(DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)) |
|
||
|
DIDFT_ANYINSTANCE;
|
||
|
podf->pguid = (PV)DIMAKEUSAGEDWORD(doi.wUsagePage, doi.wUsage);
|
||
|
podf->dwFlags |= DIDOI_GUIDISUSAGE;
|
||
|
} else {
|
||
|
podf->dwType = doi.dwType;
|
||
|
}
|
||
|
#else
|
||
|
podf->dwType = doi.dwType;
|
||
|
#endif
|
||
|
|
||
|
pge->df.dwDataSize += cbObj;
|
||
|
pge->df.dwNumObjs++;
|
||
|
}
|
||
|
|
||
|
done:;
|
||
|
return DIENUM_CONTINUE;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Devg_SetDataFormat
|
||
|
*
|
||
|
* Build a custom data format for the device.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP
|
||
|
Devg_SetDataFormat(PDEVDLGINFO pddi)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
DEVGENUM ge;
|
||
|
|
||
|
ge.pddi = pddi;
|
||
|
ge.pdevg = LocalAlloc(LPTR, cbX(DEVGINFO));
|
||
|
if (ge.pdevg) {
|
||
|
DIDEVCAPS_DX3 caps;
|
||
|
|
||
|
pddi->pvAcq = ge.pdevg;
|
||
|
|
||
|
/*
|
||
|
* Get worst-case axis and button count.
|
||
|
*/
|
||
|
caps.dwSize = cbX(caps);
|
||
|
hres = IDirectInputDevice_GetCapabilities(pddi->pdid,
|
||
|
(PV)&caps);
|
||
|
if (SUCCEEDED(hres)) {
|
||
|
|
||
|
ge.df.dwSize = cbX(ge.df);
|
||
|
ge.df.dwObjSize = cbX(DIOBJECTDATAFORMAT);
|
||
|
ge.df.dwFlags = 0;
|
||
|
ge.df.dwNumObjs = 0;
|
||
|
ge.df.dwDataSize = 0;
|
||
|
|
||
|
ge.dwNumObjs = caps.dwAxes + caps.dwPOVs + caps.dwButtons;
|
||
|
ge.df.rgodf = LocalAlloc(LPTR,
|
||
|
(caps.dwAxes + caps.dwPOVs + caps.dwButtons) *
|
||
|
ge.df.dwObjSize);
|
||
|
|
||
|
if (ge.df.rgodf) {
|
||
|
if (SUCCEEDED(hres =
|
||
|
IDirectInputDevice_EnumObjects(pddi->pdid,
|
||
|
Devg_DataFormatEnumProc, &ge,
|
||
|
DIDFT_AXIS | DIDFT_POV | DIDFT_ALIAS | DIDFT_VENDORDEFINED )) &&
|
||
|
SUCCEEDED(hres =
|
||
|
IDirectInputDevice_EnumObjects(pddi->pdid,
|
||
|
Devg_DataFormatEnumProc, &ge, DIDFT_BUTTON| DIDFT_ALIAS | DIDFT_VENDORDEFINED))) {
|
||
|
ge.df.dwDataSize = (ge.df.dwDataSize + 3) & ~3;
|
||
|
|
||
|
ge.pdevg->cbState = ge.df.dwDataSize;
|
||
|
ge.pdevg->pvState = LocalAlloc(LPTR, ge.pdevg->cbState);
|
||
|
|
||
|
if (ge.pdevg->pvState) {
|
||
|
hres = IDirectInputDevice_SetDataFormat(
|
||
|
pddi->pdid, &ge.df);
|
||
|
} else {
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree(ge.df.rgodf);
|
||
|
} else {
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
} else {
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* c_acqvtblDev
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#pragma BEGIN_CONST_DATA
|
||
|
|
||
|
ACQVTBL c_acqvtblDev = {
|
||
|
Devg_UpdateStatus,
|
||
|
Devg_SetDataFormat,
|
||
|
Devg_Destroy,
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
#pragma END_CONST_DATA
|