|
|
/*****************************************************************************
* * DIHel.c * * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Hardware emulation layer for DirectInput. * * Contents: * * Hel_AcquireInstance * Hel_UnacquireInstance * Hel_SetBufferSize * Hel_DestroyInstance * * Hel_SetDataFormat * Hel_SetNotifyHandle * * Hel_Mouse_CreateInstance * Hel_Kbd_CreateInstance * Hel_Kbd_InitKeys * Hel_Joy_CreateInstance * Hel_Joy_Ping * Hel_Joy_GetInitParms * * IoctlHw * *****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
* * The sqiffle for this file. * *****************************************************************************/
#define sqfl sqflHel
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | IoctlHw | * * Send the IOCtl to the hardware device. * * @parm DWORD | ioctl | * * I/O control code. * * @parm IN LPVOID | pvIn | * * Optional input parameter. * * @parm DWORD | cbIn | * * Size of input buffer in bytes. * * @parm IN LPVOID | pvOut | * * Optional output parameter. * * @parm DWORD | cbOut | * * Size of output buffer in bytes. * * @returns * * <c S_OK> if the ioctl succeeded and returned the correct * number of bytes, else something based on the Win32 error code. * *****************************************************************************/
#ifndef WINNT
HRESULT EXTERNAL IoctlHw(DWORD ioctl, LPVOID pvIn, DWORD cbIn, LPVOID pvOut, DWORD cbOut) { HRESULT hres; DWORD cbRc;
if (g_hVxD != INVALID_HANDLE_VALUE) { if (DeviceIoControl(g_hVxD, ioctl, pvIn, cbIn, pvOut, cbOut, &cbRc, 0)) { if (cbRc == cbOut) { hres = S_OK; } else { SquirtSqflPtszV(sqfl, TEXT("Ioctl(%08x) returned wrong cbOut"), ioctl); hres = DIERR_BADDRIVERVER; } } else { SquirtSqflPtszV(sqfl | sqflError, TEXT("Ioctl(%08x) failed, error %d"), ioctl, GetLastError()); hres = hresLe(GetLastError()); } } else { hres = DIERR_BADDRIVERVER; } return hres; } #endif
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_IoctlChoose | * * Send the IOCtl to the hardware device if it is native, * or perform the operation through emulation if it is emulated. * * @parm PVXDINSTANCE | pvi | * * The device in question. * * @parm PFNHANDLER | pfn | * * The emulation function to call to carry out the operation. * * @parm DWORD | ioctl | * * I/O control code. * * @parm IN LPVOID | pvIn | * * Optional input parameter. * * @parm DWORD | cbIn | * * Size of input buffer in bytes. * *****************************************************************************/
typedef HRESULT (EXTERNAL *PFNHANDLER)(PV pv);
HRESULT INTERNAL Hel_IoctlChoose(PVXDINSTANCE pvi, PFNHANDLER pfn, DWORD ioctl, LPVOID pvIn, DWORD cbIn) { HRESULT hres; if (!(pvi->fl & VIFL_EMULATED)) { hres = IoctlHw(ioctl, pvIn, cbIn, 0, 0); } else { hres = pfn(pvIn); } return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_AcquireInstance | * * Attempt to acquire the device instance, using either the * device driver or emulation, whichever is appropriate. * * @parm PVXDINSTANCE | pvi | * * The instance to acquire. * *****************************************************************************/
HRESULT EXTERNAL Hel_AcquireInstance(PVXDINSTANCE pvi) { return Hel_IoctlChoose(pvi, CEm_AcquireInstance, IOCTL_ACQUIREINSTANCE, &pvi, cbX(pvi)); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_UnacquireInstance | * * Attempt to unacquire the device instance. * * @parm PVXDINSTANCE | pvi | * * The instance to unacquire. * *****************************************************************************/
HRESULT EXTERNAL Hel_UnacquireInstance(PVXDINSTANCE pvi) { return Hel_IoctlChoose(pvi, CEm_UnacquireInstance, IOCTL_UNACQUIREINSTANCE, &pvi, cbX(pvi)); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_SetBufferSize | * * Set the buffer size. * * @parm PVXDDWORDDATA | pvdd | * * Information about the buffer size. * *****************************************************************************/
HRESULT EXTERNAL Hel_SetBufferSize(PVXDDWORDDATA pvdd) { HRESULT hres; EnterProc(Hel_SetBufferSize, (_ "pxx", pvdd->pvi, pvdd->dw, pvdd->pvi->fl));
hres = Hel_IoctlChoose(pvdd->pvi, CEm_SetBufferSize, IOCTL_SETBUFFERSIZE, pvdd, cbX(*pvdd));
ExitOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_DestroyInstance | * * Destroy the device instance in the appropriate way. * * @parm PVXDINSTANCE | pvi | * * The instance. * *****************************************************************************/
HRESULT EXTERNAL Hel_DestroyInstance(PVXDINSTANCE pvi) { return Hel_IoctlChoose(pvi, CEm_DestroyInstance, IOCTL_DESTROYINSTANCE, &pvi, cbX(pvi)); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_SetDataFormat | * * Set the data format. * * @parm PVXDDATAFORMAT | pvdf | * * Information about the data format. * *****************************************************************************/
HRESULT EXTERNAL Hel_SetDataFormat(PVXDDATAFORMAT pvdf) { return Hel_IoctlChoose(pvdf->pvi, CEm_SetDataFormat, IOCTL_SETDATAFORMAT, pvdf, cbX(*pvdf)); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_SetNotifyHandle | * * Set the event handle for notification. * * @parm PVXDDWORDDATA | pvdd | * * 9x: dw = ring 0 handle. Dinput calls _OpenVxDHandle to get ring 0 handle. * NT: dw = ring 3 handle. DINPUT.SYS translates the handle to pointer. * *****************************************************************************/
HRESULT EXTERNAL Hel_SetNotifyHandle(PVXDDWORDDATA pvdd) { HRESULT hres; if (!(pvdd->pvi->fl & VIFL_EMULATED)) { #ifndef WINNT
AssertF(_OpenVxDHandle); if (pvdd->dw) { pvdd->dw = _OpenVxDHandle((HANDLE)pvdd->dw); } #endif
hres = IoctlHw(IOCTL_SETNOTIFYHANDLE, pvdd, cbX(*pvdd), 0, 0); } else { hres = S_OK; } return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @struct CREATEDEVICEINFO | * * Describes how to create the device either via the driver or * via emulation. * * @parm DWORD | dwIoctl | * * IOCtl code to try. * * @parm DWORD | flEmulation | * * Flag in registry that forces emulation. * * @parm EMULATIONCREATEPROC | pfnCreate | * * Function that creates emulation object. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
typedef HRESULT (EXTERNAL *EMULATIONCREATEPROC) (PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut);
typedef struct CREATEDEVICEINFO { DWORD dwIoctl; DWORD flEmulation; EMULATIONCREATEPROC pfnCreate; } CREATEDEVICEINFO, *PCREATEDEVICEINFO;
CREATEDEVICEINFO c_cdiMouse = { IOCTL_MOUSE_CREATEINSTANCE, DIEMFL_MOUSE, CEm_Mouse_CreateInstance, };
CREATEDEVICEINFO c_cdiKbd = { IOCTL_KBD_CREATEINSTANCE, DIEMFL_KBD | DIEMFL_KBD2, CEm_Kbd_CreateInstance, };
CREATEDEVICEINFO c_cdiJoy = { IOCTL_JOY_CREATEINSTANCE, DIEMFL_JOYSTICK, CEm_Joy_CreateInstance, };
#pragma END_CONST_DATA
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_CreateInstance | * * Attempt to create the device instance through the driver * with the specified IOCtl. * * If that is not possible, then use the emulation callback. * * @parm PCREATEDEVICEINFO | pcdi | * * Describes how to create the device. * * @parm PVXDDEVICEFORMAT | pdevf | * * Describes the device being created. * * @parm PVXDINSTANCE * | ppviOut | * * Receives created instance. * *****************************************************************************/
HRESULT EXTERNAL Hel_CreateInstance(PCREATEDEVICEINFO pcdi, PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut) { HRESULT hres;
pdevf->dwEmulation |= g_flEmulation; pdevf->dwEmulation &= pcdi->flEmulation;
if (pdevf->dwEmulation || (FAILED(hres = IoctlHw(pcdi->dwIoctl, pdevf, cbX(*pdevf), ppviOut, cbX(*ppviOut))))) { hres = pcdi->pfnCreate(pdevf, ppviOut); } return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Mouse_CreateInstance | * * Attempt to create the device instance through the driver. * If that is not possible, then use the emulation layer. * * @parm PVXDDEVICEFORMAT | pdevf | * * Describes the device being created. * * @parm PVXDINSTANCE * | ppviOut | * * Receives created instance. * *****************************************************************************/
HRESULT EXTERNAL Hel_Mouse_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut) { return Hel_CreateInstance(&c_cdiMouse, pdevf, ppviOut); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Kbd_CreateInstance | * * Attempt to create the device instance through the driver. * If that is not possible, then use the emulation layer. * * @parm PVXDDEVICEFORMAT | pdevf | * * Describes the device being created. * * @parm PVXDINSTANCE * | ppviOut | * * Receives created instance. * *****************************************************************************/
HRESULT EXTERNAL Hel_Kbd_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut) { return Hel_CreateInstance(&c_cdiKbd, pdevf, ppviOut); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Kbd_InitKeys | * * Tell the device driver (or emulation) about the key state. * * @parm PVXDDWORDDATA | pvdd | * * The instance and the key state. * *****************************************************************************/
HRESULT EXTERNAL Hel_Kbd_InitKeys(PVXDDWORDDATA pvdd) { return Hel_IoctlChoose(pvdd->pvi, CEm_Kbd_InitKeys, IOCTL_KBD_INITKEYS, pvdd, cbX(*pvdd)); }
#ifndef WINNT
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Joy_CreateInstance | * * Attempt to create the device instance through the driver. * If that is not possible, then use the emulation layer. * * @parm PVXDDEVICEFORMAT | pdevf | * * Describes the device being created. * * @parm PVXDINSTANCE * | ppviOut | * * Receives created instance. * *****************************************************************************/
HRESULT EXTERNAL Hel_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut) { return Hel_CreateInstance(&c_cdiJoy, pdevf, ppviOut); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Joy_Ping | * * Ask the device driver (or emulation) to get the joystick info. * * @parm PVXDDWORDDATA | pvdd | * * The instance and the key state. * *****************************************************************************/
HRESULT EXTERNAL Hel_Joy_Ping(PVXDINSTANCE pvi) { return Hel_IoctlChoose(pvi, CEm_Joy_Ping, IOCTL_JOY_PING8, &pvi, cbX(pvi)); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Joy_ConfigChanged | * * Tell vjoyd config has been changed. * *****************************************************************************/
HRESULT EXTERNAL Hel_Joy_ConfigChanged(DWORD dwFlags) { return IoctlHw(IOCTL_JOY_CONFIGCHANGED, &dwFlags, cbX(dwFlags), NULL, 0); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Joy_GetAxisCaps | * * Obtain a bitmask of the axes supported by the joystick. * If VJOYD won't tell us, then we figure it out from the * registry structure passed in. * * @parm DWORD | dwExternalID | * * The external joystick number. * * @parm PVXDAXISCAPS | pvac | * * Structure to receive the axis capabilities. * * @parm LPJOYREGHWCONFIG | phwc | * * The joystick settings as reported by the registry. * *****************************************************************************/
HRESULT EXTERNAL Hel_Joy_GetAxisCaps ( DWORD dwExternalID, PVXDAXISCAPS pvac, LPJOYREGHWCONFIG phwc ) { HRESULT hres; DWORD dwRegAxes;
/*
* Every joystick has an X and Y (no way to tell) * Mark as position axes or they won't count! */ dwRegAxes = JOYPF_X | JOYPF_Y | JOYPF_POSITION;
if (phwc->hws.dwFlags & JOY_HWS_HASZ) { dwRegAxes |= JOYPF_Z; }
if ( (phwc->hws.dwFlags & JOY_HWS_HASR) || (phwc->dwUsageSettings & JOY_US_HASRUDDER) ){ dwRegAxes |= JOYPF_R; }
if (phwc->hws.dwFlags & JOY_HWS_HASU) { dwRegAxes |= JOYPF_U; }
if (phwc->hws.dwFlags & JOY_HWS_HASV) { dwRegAxes |= JOYPF_V; }
if ((g_flEmulation & DIEMFL_JOYSTICK) || FAILED(hres = IoctlHw(IOCTL_JOY_GETAXES, &dwExternalID, cbX(dwExternalID), pvac, cbX(*pvac)))) {
/*
* If that didn't work, then just use the registry. */ if (phwc->hws.dwFlags & JOY_HWS_HASPOV) { pvac->dwPos |= JOYPF_POV0; }
/*
* Old VJOYD clients do not support velocity or any of the * other stuff. */ pvac->dwVel = 0; pvac->dwAccel = 0; pvac->dwForce = 0;
hres = S_OK; } else { /*
* ManBug 28971: Logitech drivers (and probably others) respond to * probing on axes for which they do not report data so set the * position axes to whatever is reported in the registry. * Note this still allows multiple POVs to be picked up as only one * POV is supported by the registry flags. */ pvac->dwPos &= ~JOYPF_ALLAXES; pvac->dwPos |= dwRegAxes; }
/*
* CJoy_InitRing3 assumes that this never fails. */ AssertF(SUCCEEDED(hres));
return hres; }
#endif //WINNT
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | Hel_Joy_GetInitParms | * * Ask the device driver (or emulation) for * VJOYD initialization parameters. * * In emulation, we assume the internal and external * IDs are equal (because they may as well be), * that no flags are set, and there are no versions. * * @parm DWORD | dwExternalID | * * The external joystick number. * * @parm PVXDINITPARMS | pvip | * * Receives assorted information. * *****************************************************************************/
HRESULT EXTERNAL Hel_Joy_GetInitParms(DWORD dwExternalID, PVXDINITPARMS pvip) { HRESULT hres;
if ((g_flEmulation & DIEMFL_JOYSTICK) || FAILED(hres = IoctlHw(IOCTL_JOY_GETINITPARMS, &dwExternalID, cbX(dwExternalID), pvip, cbX(*pvip))) || FAILED(hres = pvip->hres)) {
/*
* Do it the emulation way. */
ZeroX(*pvip); pvip->dwId = dwExternalID; hres = S_OK; }
return hres; }
|