#define __DEBUG_MODULE_IN_USE__ CIC_CONTROLITEMCOLLECTION_CPP #include "stdhdrs.h" // @doc /********************************************************************** * * @module ControlItemCollection.cpp | * * Implementation of CControlItemCollection implementation functions * * History * ---------------------------------------------------------- * Mitchell S. Dernis Original * * (c) 1986-1998 Microsoft Corporation. All right reserved. * * @topic ControlItemCollection | * This library encapsulates HID parsing and driver packet code. It is * used it both the driver and the control panel applet. * **********************************************************************/ /*********************************************************************************** ** ** CControlItemCollectionImpl::Init ** ** @mfunc Initialize collection by calling factory to get items ** ** @rdesc S_OK on success, S_FALSE if factory failed to support one or ** more of the items, E_FAIL if device not supported or error from factory ** *************************************************************************************/ HRESULT CControlItemCollectionImpl::Init( ULONG ulVidPid, //@parm [in] Vid in the high word, Pid in the low word PFNGENERICFACTORY pfnFactory, //@parm [in] pointer to function which acts // on pFactoryHandle PFNGENERICDELETEFUNC pfnDeleteFunc //@parm [in] delete function to used for control items ) { CIC_DBG_ENTRY_PRINT(("CControlItemCollectionImpl::Init(0x%0.8x, 0x%0.8x)\n", ulVidPid, pfnFactory)); HRESULT hr = S_OK; // // Walk the table devices and find a matching VidPid // ULONG ulDeviceIndex=0; // // Endless loop, you get out by breaking, or returning from the function. // while(1) { // // If we have reached the end of the table // if(0 == DeviceControlsDescList[ulDeviceIndex].ulVidPid ) { ASSERT(FALSE); //Should never get here. return E_FAIL; //BUGBUGBUG need more descriptive error code here } if(DeviceControlsDescList[ulDeviceIndex].ulVidPid == ulVidPid) { break; } ulDeviceIndex++; } m_ulDeviceIndex = ulDeviceIndex; // // Use the size argument to pre-allocate space for the list // hr = m_ObjectList.SetAllocSize(DeviceControlsDescList[m_ulDeviceIndex].ulControlItemCount, NonPagedPool); if( FAILED(hr) ) { return hr; } // // Set the delete function for the class // m_ObjectList.SetDeleteFunc(pfnDeleteFunc); // // Walk through the control item list and call the factory for each one // CONTROL_ITEM_DESC *pControlItems = reinterpret_cast(DeviceControlsDescList[m_ulDeviceIndex].pControlItems); PVOID pNewControlItem; HRESULT hrFactory; m_ulMaxXfers = 0; for( ULONG ulControlIndex = 0; ulControlIndex < DeviceControlsDescList[m_ulDeviceIndex].ulControlItemCount; ulControlIndex++ ) { // // Call factory to get new control item // hrFactory = pfnFactory(pControlItems[ulControlIndex].usType, &pControlItems[ulControlIndex], &pNewControlItem); // // If the factory fails mark an error // if( FAILED(hrFactory) ) { hr = hrFactory; continue; } // // If the factory does not support that control add a null to the list // to hold the index as taken // if( S_FALSE == hrFactory ) { pNewControlItem = NULL; } else //an Xfer would be needed to get the state. { m_ulMaxXfers++; } // // Add item (or NULL) to list of items in collection // hrFactory = m_ObjectList.Add(pNewControlItem); if( FAILED(hrFactory) ) { hr = hrFactory; } } // // Return error code // return hr; } /*********************************************************************************** ** ** HRESULT CControlItemCollectionImpl::GetNext ** ** @mfunc Gets the next item in list ** ** @rdesc S_OK on success, S_FALSE if no more items ** ************************************************************************************/ HRESULT CControlItemCollectionImpl::GetNext ( PVOID *ppControlItem, //@parm pointer to receive control item ULONG& rulCookie //@parm cookie to keep track of enumeration ) const { CIC_DBG_RT_ENTRY_PRINT(("CControlItemCollectionImpl::GetNext(0x%0.8x, 0x%0.8x)\n", ppControlItem, rulCookie)); if( rulCookie >= m_ObjectList.GetItemCount() ) { *ppControlItem = NULL; CIC_DBG_EXIT_PRINT(("Exit GetNext - no more items\n")); return S_FALSE; } else { *ppControlItem = m_ObjectList.Get( rulCookie ); rulCookie += 1; if(!*ppControlItem) { CIC_DBG_EXIT_PRINT(("Calling GetNext recursively\n")); return GetNext(ppControlItem, rulCookie); } CIC_DBG_RT_EXIT_PRINT(("Exit GetNext - *ppControlItem = 0x%0.8x\n", *ppControlItem)); return S_OK; } } /*********************************************************************************** ** ** PVOID CControlItemCollectionImpl::GetFromControlItemXfer ** ** @mfunc Returns item given CONTROL_ITEM_XFER ** ** @rdesc Pointer to item on success, NULL if not ** ************************************************************************************/ PVOID CControlItemCollectionImpl::GetFromControlItemXfer( const CONTROL_ITEM_XFER& crControlItemXfer //@parm [in] report selector to get object for ) { CIC_DBG_RT_ENTRY_PRINT(("CControlItemCollectionImpl::GetFromControlItemXfer\n")); ULONG ulListIndex = crControlItemXfer.ulItemIndex - 1; ASSERT( m_ObjectList.GetItemCount() > ulListIndex); if( m_ObjectList.GetItemCount() <= ulListIndex) { return NULL; } CIC_DBG_RT_EXIT_PRINT(("Exiting CControlItemCollectionImpl::GetFromControlItemXfer\n")); return m_ObjectList.Get(ulListIndex); } /*********************************************************************************** ** ** NTSTATUS CControlItemCollectionImpl::ReadFromReport ** ** @mfunc Recurses collection and asks each item to read its state. ** ** @rdesc Use NT_SUCCESS, NT_ERROR, SUCCEEDED, FAILED macros to parse. ** ************************************************************************************/ NTSTATUS CControlItemCollectionImpl::ReadFromReport ( PHIDP_PREPARSED_DATA pHidPPreparsedData, //@parm hid preparsed data PCHAR pcReport, //@parm report buffer LONG lReportLength, //@parm length of report buffer PFNGETCONTROLITEM GetControlFromPtr //@parm pointer to function to get CControlItem * ) { NTSTATUS NtStatus; NtStatus = ControlItemsFuncs::ReadModifiersFromReport( DeviceControlsDescList[m_ulDeviceIndex].pModifierDescTable, m_ulModifiers, pHidPPreparsedData, pcReport, lReportLength ); if( NT_ERROR(NtStatus) ) { CIC_DBG_ERROR_PRINT(("ReadModifiersFromReport returned 0x%0.8x\n", NtStatus)); // // Instead of returning, let's go on, the modifiers are important, but // not important enough to cripple everything else. NtStatus = S_OK; } // // Loop over all items and read them // ULONG ulCookie = 0; PVOID pvControlItem = NULL; CControlItem *pControlItem; HRESULT hr; hr = GetNext(&pvControlItem, ulCookie); while(S_OK == hr) { pControlItem = GetControlFromPtr(pvControlItem); NtStatus= pControlItem->ReadFromReport( pHidPPreparsedData, pcReport, lReportLength ); if( NT_ERROR(NtStatus) ) { CIC_DBG_ERROR_PRINT(("pControlItem->ReadFromReport returned 0x%0.8x, ulCookie = 0x%0.8x\n", NtStatus, ulCookie)); return NtStatus; } pControlItem->SetModifiers(m_ulModifiers); hr = GetNext(&pvControlItem, ulCookie); } return NtStatus; } /*********************************************************************************** ** ** NTSTATUS CControlItemCollectionImpl::WriteToReport ** ** @mfunc Recurses collection and asks each item to write its state to the report. ** ** @rdesc Use NT_SUCCESS, NT_ERROR, SUCCEEDED, FAILED macros to parse. ** ************************************************************************************/ NTSTATUS CControlItemCollectionImpl::WriteToReport ( PHIDP_PREPARSED_DATA pHidPPreparsedData, //@parm hid preparsed data PCHAR pcReport, //@parm report buffer LONG lReportLength, //@parm length of report buffer PFNGETCONTROLITEM GetControlFromPtr //@parm pointer to function to get CControlItem * ) const { // // Loop over all items and write to them // NTSTATUS NtStatus; ULONG ulCookie = 0; PVOID pvControlItem = NULL; CControlItem *pControlItem; HRESULT hr; hr = GetNext(&pvControlItem, ulCookie); while(S_OK == hr) { pControlItem = GetControlFromPtr(pvControlItem); NtStatus= pControlItem->WriteToReport( pHidPPreparsedData, pcReport, lReportLength ); if( NT_ERROR(NtStatus) ) { CIC_DBG_ERROR_PRINT(("pControlItem->WriteToReport returned 0x%0.8x, ulCookie = 0x%0.8x\n", NtStatus, ulCookie)); return NtStatus; } hr = GetNext(&pvControlItem, ulCookie); } if( FAILED(hr) ) { ASSERT(SUCCEEDED(hr)); return hr; } NtStatus = ControlItemsFuncs::WriteModifiersToReport( DeviceControlsDescList[m_ulDeviceIndex].pModifierDescTable, m_ulModifiers, pHidPPreparsedData, pcReport, lReportLength ); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS CControlItemCollectionImpl::WriteToReport ** ** @mfunc Recurses collection and asks each item to set its self to its default state. ** ** @rdesc Use NT_SUCCESS, NT_ERROR, SUCCEEDED, FAILED macros to parse. ** ************************************************************************************/ void CControlItemCollectionImpl::SetDefaultState ( PFNGETCONTROLITEM GetControlFromPtr //@parm pointer to function to get CControlItem * ) { ULONG ulCookie = 0; PVOID pvControlItem = NULL; CControlItem *pControlItem; HRESULT hr; hr = GetNext(&pvControlItem, ulCookie); while(S_OK == hr) { pControlItem = GetControlFromPtr(pvControlItem); pControlItem->SetDefaultState(); hr = GetNext(&pvControlItem, ulCookie); } m_ulModifiers=0; } /*********************************************************************************** ** ** HRESULT CControlItemCollectionImpl::GetState ** ** @mfunc Gets the state of each item in the collection and return it in the caller ** ** @rdesc S_OK on success, E_OUTOFMEMORY if buffer is not large enough ** *************************************************************************************/ HRESULT CControlItemCollectionImpl::GetState ( ULONG& ulXferCount, // @parm [in\out] specifies length of array on entry // and items used on exit PCONTROL_ITEM_XFER pControlItemXfers, // @parm [out] caller allocated buffer to hold packets PFNGETCONTROLITEM GetControlFromPtr // @parm [in] function to get CControlItem * ) { HRESULT hr = S_OK; ULONG ulCookie = 0; ULONG ulXferMax = ulXferCount; PVOID pvControlItem = NULL; CControlItem *pControlItem; ulXferCount = 0; hr = GetNext(&pvControlItem, ulCookie); while(S_OK == hr) { pControlItem = GetControlFromPtr(pvControlItem); if( !pControlItem->IsDefaultState() ) { if(ulXferCount >= ulXferMax) { hr = E_OUTOFMEMORY; } else { pControlItem->GetItemState(pControlItemXfers[ulXferCount]); pControlItemXfers[ulXferCount++].ulModifiers = m_ulModifiers; } } hr = GetNext(&pvControlItem, ulCookie); } return hr; } HRESULT CControlItemCollectionImpl::SetState ( ULONG ulXferCount, // @parm [in\out] specifies length of array on entry // and items used on exit PCONTROL_ITEM_XFER pControlItemXfers, // @parm [out] caller allocated buffer to hold packets PFNGETCONTROLITEM GetControlFromPtr // @parm [in] function to get CControlItem * ) { PVOID pvControlItem = NULL; CControlItem *pControlItem; while(ulXferCount--) { // // It is legit, that someone may have a keyboard Xfer mixed up in the // array, in which case we need to dismiss it. If someone further down // gets it, they will ASSERT. // if( NonGameDeviceXfer::IsKeyboardXfer(pControlItemXfers[ulXferCount]) ) { continue; } pvControlItem = GetFromControlItemXfer( pControlItemXfers[ulXferCount]); if(NULL == pvControlItem) continue; m_ulModifiers |= pControlItemXfers[ulXferCount].ulModifiers; pControlItem = GetControlFromPtr(pvControlItem); pControlItem->SetModifiers(pControlItemXfers[ulXferCount].ulModifiers); pControlItem->SetItemState( pControlItemXfers[ulXferCount]); } return S_OK; } void CControlItemCollectionImpl::SetStateOverlayMode( PFNGETCONTROLITEM GetControlFromPtr, BOOLEAN fEnable ) { ULONG ulCookie = 0; PVOID pvControlItem = NULL; CControlItem *pControlItem; HRESULT hr; hr = GetNext(&pvControlItem, ulCookie); while(S_OK == hr) { pControlItem = GetControlFromPtr(pvControlItem); pControlItem->SetStateOverlayMode(fEnable); hr = GetNext(&pvControlItem, ulCookie); } } /*********************************************************************************** ** ** HRESULT ControlItemDefaultFactory ** ** @func Factory for a default collection ** ** @rdesc S_OK if successful, S_FALSE if not supported, E_FAIL for any failure. ** ************************************************************************************/ HRESULT ControlItemDefaultFactory ( USHORT usType, //@parm [in] Type of object to create const CONTROL_ITEM_DESC* cpControlItemDesc, //@parm [in] Item descriptor data CControlItem **ppControlItem //@parm [out] CControlItem we created ) { HRESULT hr = S_OK; switch(usType) { case ControlItemConst::usAxes: *ppControlItem = new WDM_NON_PAGED_POOL CAxesItem(cpControlItemDesc); break; case ControlItemConst::usDPAD: *ppControlItem = new WDM_NON_PAGED_POOL CDPADItem(cpControlItemDesc); break; case ControlItemConst::usPropDPAD: *ppControlItem = new WDM_NON_PAGED_POOL CPropDPADItem(cpControlItemDesc); break; case ControlItemConst::usWheel: *ppControlItem= new WDM_NON_PAGED_POOL CWheelItem(cpControlItemDesc); break; case ControlItemConst::usPOV: *ppControlItem = new WDM_NON_PAGED_POOL CPOVItem(cpControlItemDesc); break; case ControlItemConst::usThrottle: *ppControlItem = new WDM_NON_PAGED_POOL CThrottleItem(cpControlItemDesc); break; case ControlItemConst::usRudder: *ppControlItem = new WDM_NON_PAGED_POOL CRudderItem(cpControlItemDesc); break; case ControlItemConst::usPedal: *ppControlItem = new WDM_NON_PAGED_POOL CPedalItem(cpControlItemDesc); break; case ControlItemConst::usButton: *ppControlItem = new WDM_NON_PAGED_POOL CButtonsItem(cpControlItemDesc); break; case ControlItemConst::usZoneIndicator: *ppControlItem = new WDM_NON_PAGED_POOL CZoneIndicatorItem(cpControlItemDesc); break; case ControlItemConst::usForceMap: *ppControlItem = new WDM_NON_PAGED_POOL CForceMapItem(cpControlItemDesc); break; case ControlItemConst::usDualZoneIndicator: *ppControlItem = new WDM_NON_PAGED_POOL CDualZoneIndicatorItem(cpControlItemDesc); break; default: *ppControlItem = NULL; return S_FALSE; } if(!*ppControlItem) { return E_FAIL; } return S_OK; }