You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
15 KiB
522 lines
15 KiB
#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<CONTROL_ITEM_DESC *>(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;
|
|
}
|
|
|