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