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.
459 lines
11 KiB
459 lines
11 KiB
// @doc
|
|
/**********************************************************************
|
|
*
|
|
* @module ForceFeatures.cpp |
|
|
*
|
|
* Implements CForceFeatures to use msgame's HID features.
|
|
*
|
|
* History
|
|
* ----------------------------------------------------------
|
|
* Mitchell Dernis Original
|
|
*
|
|
* (c) 1986-1998 Microsoft Corporation. All right reserved.
|
|
*
|
|
* @topic ForceFeatures |
|
|
* CForceFeatures opens a handle to msgame in the context of
|
|
* a particular device on construction.
|
|
* The public members expose the feature interface for msgame.
|
|
*
|
|
* Will work with NT5 as is. For Win98 we need a different
|
|
* scheme for getting HID path. DI promises to fix somehow.
|
|
**********************************************************************///
|
|
|
|
#include <windows.h>
|
|
#define DIRECTINPUT_VERSION 0x050a
|
|
#include <dinput.h>
|
|
#include <dinputd.h>
|
|
extern "C" {
|
|
#include <hidsdi.h>
|
|
}
|
|
#include "FFeature.h"
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** CForceFeatures::CForceFeatures(UINT uJoystickId)
|
|
**
|
|
** @mfunc C'tor gets Hid Path from Joystick and opens path to driver
|
|
**
|
|
** @rdesc None since this is c'tor. However at the end of this routine
|
|
** m_hDevice will contain a handle for the driver on success, or
|
|
** will contain NULL on failure. All routines will check the
|
|
** value of m_hDevice before proceeding.
|
|
**
|
|
*************************************************************************************/
|
|
CForceFeatures::CForceFeatures() :
|
|
m_hDevice(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** CForceFeatures::~CForceFeatures()
|
|
**
|
|
** @mfunc D'tor closes handle to driver, if it was open
|
|
**
|
|
*************************************************************************************/
|
|
CForceFeatures::~CForceFeatures()
|
|
{
|
|
if(m_hDevice)
|
|
{
|
|
CloseHandle(m_hDevice);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::Initialize(UINT uJoystickId, HINSTANCE hinstModule)
|
|
**
|
|
** @mfunc Calls to MsGame to GetId using MSGAME_FEATURE_GETID
|
|
**
|
|
** @rdesc S_OK on success
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::Initialize
|
|
(
|
|
UINT uJoystickId, //@parm Joystick Id as used by winmm
|
|
HINSTANCE hinstModule //@parm Instance of the DLL for Creating DirectInput
|
|
)
|
|
{
|
|
if (m_hDevice != NULL) {
|
|
return S_OK; // No need to reinitialize
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
//**
|
|
//** Get HidPath
|
|
//**
|
|
//**
|
|
|
|
//
|
|
// Get IDirectInput interface
|
|
//
|
|
IDirectInput *pDirectInput = NULL;
|
|
IDirectInputJoyConfig *pDirectInputJoyConfig = NULL;
|
|
hr = DirectInputCreate(
|
|
hinstModule,
|
|
DIRECTINPUT_VERSION,
|
|
&pDirectInput,
|
|
NULL
|
|
);
|
|
if( FAILED(hr) ) return hr;
|
|
|
|
//
|
|
// Get IDirectInputJoyConfig
|
|
//
|
|
hr=pDirectInput->QueryInterface(IID_IDirectInputJoyConfig, (LPVOID *)&pDirectInputJoyConfig);
|
|
if( FAILED(hr) )
|
|
{
|
|
pDirectInput->Release();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// GetConfig for JoyId
|
|
//
|
|
DIJOYCONFIG DiJoyConfig;
|
|
DiJoyConfig.dwSize=sizeof(DIJOYCONFIG);
|
|
hr = pDirectInputJoyConfig->GetConfig(
|
|
uJoystickId,
|
|
&DiJoyConfig,
|
|
DIJC_GUIDINSTANCE
|
|
);
|
|
//
|
|
// Done with pDirectInputJoyConfig
|
|
//
|
|
pDirectInputJoyConfig->Release();
|
|
pDirectInputJoyConfig = NULL;
|
|
if( FAILED(hr) )
|
|
{
|
|
pDirectInput->Release();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get IDirectInputDevice interface
|
|
//
|
|
IDirectInputDevice *pDirectInputDevice;
|
|
hr = pDirectInput->CreateDevice(DiJoyConfig.guidInstance, &pDirectInputDevice, NULL);
|
|
//
|
|
// Done pDirectInput
|
|
//
|
|
pDirectInput->Release();
|
|
pDirectInput = NULL;
|
|
if( FAILED(hr) ) return hr;
|
|
|
|
//
|
|
// Get HidPath
|
|
//
|
|
DIPROPGUIDANDPATH DiPropGuidAndPath;
|
|
DiPropGuidAndPath.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
|
|
DiPropGuidAndPath.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
DiPropGuidAndPath.diph.dwObj = 0;
|
|
DiPropGuidAndPath.diph.dwHow = DIPH_DEVICE;
|
|
hr=pDirectInputDevice->GetProperty( DIPROP_GUIDANDPATH, &DiPropGuidAndPath.diph);
|
|
|
|
//
|
|
// Done with pDirectInputDevice
|
|
//
|
|
pDirectInputDevice->Release();
|
|
pDirectInputDevice = NULL;
|
|
if( FAILED(hr) ) return hr;
|
|
|
|
//**
|
|
//** Open Path to Driver
|
|
//**
|
|
m_hDevice = CreateFileW(
|
|
DiPropGuidAndPath.wszPath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (m_hDevice == INVALID_HANDLE_VALUE)
|
|
{
|
|
m_hDevice = NULL;
|
|
}
|
|
if (m_hDevice == NULL)
|
|
{
|
|
DWORD err = ::GetLastError();
|
|
return E_FAIL;
|
|
}
|
|
|
|
PHIDP_PREPARSED_DATA pHidPreparsedData;
|
|
if (HidD_GetPreparsedData(m_hDevice, &pHidPreparsedData) == FALSE)
|
|
{
|
|
::CloseHandle(m_hDevice);
|
|
m_hDevice = NULL;
|
|
return E_FAIL;
|
|
}
|
|
HIDP_CAPS hidpCaps;
|
|
HidP_GetCaps(pHidPreparsedData, &hidpCaps);
|
|
m_uiMaxFeatureLength = hidpCaps.FeatureReportByteLength;
|
|
HidD_FreePreparsedData(pHidPreparsedData);
|
|
|
|
//
|
|
// On success, m_hDevice now contains a handle to the device
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::GetId(PRODUCT_ID_REPORT& rProductId)
|
|
**
|
|
** @mfunc Calls to MsGame to GetId using MSGAME_FEATURE_GETID
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::GetId
|
|
(
|
|
PRODUCT_ID_REPORT& rProductId // @parm Reference to PRODUCT_ID_REPORT to get from driver
|
|
)
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
rProductId.bReportId = MSGAME_FEATURE_GETID;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&rProductId), m_uiMaxFeatureLength);
|
|
|
|
// -- HIDPI.H
|
|
// HIDP_GetData(Report Type, Data, Lenght, Preparse Data, Report, ReportLength);
|
|
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::GetStatus(JOYCHANNELSTATUS_REPORT& rJoyChannelStatus)
|
|
**
|
|
** @mfunc Get the JoyChannel Status from msgame's MSGAME_FEATURE_GETSTATUS
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::GetStatus
|
|
(
|
|
JOYCHANNELSTATUS_REPORT& rJoyChannelStatus // @parm Reference to JOYCHANNELSTATUS_REPORT to be filled by driver
|
|
)
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
rJoyChannelStatus.bReportId = MSGAME_FEATURE_GETSTATUS;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&rJoyChannelStatus), m_uiMaxFeatureLength);
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
DWORD err = GetLastError();
|
|
return HRESULT_FROM_WIN32(err);
|
|
// return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::GetAckNak(ULONG_REPORT& rulAckNak)
|
|
**
|
|
** @mfunc Returns an AckNak by using msgame's GetAckNak Featue
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::GetAckNak
|
|
(
|
|
ULONG_REPORT& rulAckNak // @parm REFERENCE to ULONG_REPORT to be filled by driver with AckNak
|
|
)
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
rulAckNak.bReportId = MSGAME_FEATURE_GETACKNAK;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&rulAckNak), m_uiMaxFeatureLength);
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::GetAckNak(ULONG_REPORT& rulNakAck)
|
|
**
|
|
** @mfunc Returns an AckNak by using msgame's MSGAME_FEATURE_NAKACK
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::GetNakAck(
|
|
ULONG_REPORT& rulNakAck // @parm REFERENCE to ULONG_REPORT to be filled by driver with NakAck
|
|
)
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
rulNakAck.bReportId = MSGAME_FEATURE_GETACKNAK;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&rulNakAck), m_uiMaxFeatureLength);
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::GetSync(ULONG_REPORT& rulGameport)
|
|
**
|
|
** @mfunc Get Sync information from MSGAME's MSGAME_FEATURE_GETSYNC
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::GetSync
|
|
(
|
|
ULONG_REPORT& rulGameport // @parm REFERENCE to ULONG_REPORT to be filled by driver with Gameport
|
|
)
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
rulGameport.bReportId = MSGAME_FEATURE_GETACKNAK;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&rulGameport), m_uiMaxFeatureLength);
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************************
|
|
**
|
|
** HRESULT CForceFeatures::DoReset()
|
|
**
|
|
** @mfunc Does Reset via MSGAME's MSGAME_FEATURE_DORESET
|
|
**
|
|
** @rdesc S_OK on success
|
|
** ERROR_OPEN_FAILED if no drive connection
|
|
** E_FAIL for other problems
|
|
**
|
|
*************************************************************************************/
|
|
HRESULT CForceFeatures::DoReset()
|
|
{
|
|
if(!m_hDevice)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
|
|
}
|
|
|
|
BOOLEAN fSuccess;
|
|
//
|
|
// Fill in ReportID for feature
|
|
//
|
|
ULONG_REPORT ulBogus;
|
|
ulBogus.bReportId = MSGAME_FEATURE_DORESET;
|
|
|
|
//
|
|
// Call Get Feature on driver
|
|
//
|
|
fSuccess = HidD_GetFeature(m_hDevice, reinterpret_cast<PVOID>(&ulBogus), m_uiMaxFeatureLength);
|
|
|
|
//
|
|
// Return proper error code
|
|
//
|
|
if( !fSuccess )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|