Leaked source code of windows server 2003
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

#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;
}