/***************************************************************************
 *
 *  Copyright (C) 1997 Microsoft Corporation.  All Rights Reserved.
 *
 *  File:       dihid.h
 *  Content:    DirectInput internal include file for HID
 *
 ***************************************************************************/

#ifndef _DIHID_H
#define _DIHID_H

/*
 *  Defines that should be in hidusage.h but are not yet
 */

#ifndef HID_USAGE_PAGE_PID
#define HID_USAGE_PAGE_PID      ( (USAGE) 0x0000f )
#endif

#ifndef HID_USAGE_PAGE_VENDOR
#define HID_USAGE_PAGE_VENDOR   ( (USAGE) 0xff00 )
#endif  

#ifndef HID_USAGE_SIMULATION_RUDDER
#define HID_USAGE_SIMULATION_RUDDER         ((USAGE) 0xBA)
#endif
#ifndef HID_USAGE_SIMULATION_THROTTLE
#define HID_USAGE_SIMULATION_THROTTLE       ((USAGE) 0xBB)
#endif
#ifndef HID_USAGE_SIMULATION_ACCELERATOR
#define HID_USAGE_SIMULATION_ACCELERATOR    ((USAGE) 0xC4)
#endif
#ifndef HID_USAGE_SIMULATION_BRAKE
#define HID_USAGE_SIMULATION_BRAKE          ((USAGE) 0xC5)
#endif
#ifndef HID_USAGE_SIMULATION_CLUTCH
#define HID_USAGE_SIMULATION_CLUTCH         ((USAGE) 0xC6)
#endif
#ifndef HID_USAGE_SIMULATION_SHIFTER
#define HID_USAGE_SIMULATION_SHIFTER        ((USAGE) 0xC7)
#endif
#ifndef HID_USAGE_SIMULATION_STEERING
#define	HID_USAGE_SIMULATION_STEERING		((USAGE) 0xC8)
#endif
#ifndef HID_USAGE_GAME_POV
#define HID_USAGE_GAME_POV                  ((USAGE) 0x20)
#endif


/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct HIDDEVICEINFO |
 *
 *          Records information about a single hid device.
 *
 *  @field  DIOBJECTSTATICDATA | osd |
 *
 *          Standard information that identifies the device crudely.
 *
 *          The <e DIOBJECTSTATICDATA.dwDevType> field contains the
 *          device type code, used by
 *          <f CDIDEnum_Next>.
 *
 *          If the device is a HID mouse, then the remaining fields
 *          are commandeered as follows:
 *
 *          The <e DIOBJECTSTATICDATA.pcguid> field is the number
 *          of buttons on the mouse.
 *
 *          The <e DIOBJECTSTATICDATA.CreateDcb> field is the number
 *          of axes on the mouse.
 *
 *          See <f DIHid_ProbeMouse> for an explanation of why we
 *          need to do this.
 *
 *  @field  PSP_DEVICE_INTERFACE_DETAIL_DATA | pdidd |
 *
 *          Pointer to name for device to be used in <f CreateFile>.
 *
 *  @field  HKEY | hk |
 *
 *          Registry key that contains configuration information.
 *          Sadly, we must keep it open because there is no way to
 *          obtain the name of the key, and the only way to open the
 *          key is inside an enumeration.
 *
 *  @field  HKEY | hkOld |
 *
 *          Registry key that contains configuration information.
 *          This key originally pointed to the registry used in Win2k Gold. 
 *          It is to maintain compatibiltiy with Win2k Gold.
 *
 *  @field  LPTSTR | ptszId |
 *
 *          Cached device ID that allows us to access other information
 *          about the device.
 *
 *  @field  GUID | guid |
 *
 *          The instance GUID for the device.
 *
 *  @field  GUID | guidProduct | 
 *
 *          The product GUID for the device.
 *
 *	@field	WORD | ProductID |
 *
 *			The PID for the device
 *
 *	@field	WORD | VendorID |
 *
 *			The VID for the device
 *
 *
 *****************************************************************************/

typedef struct HIDDEVICEINFO
{
    DIOBJECTSTATICDATA osd;
    PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
    HKEY hk;
    HKEY hkOld;
    LPTSTR ptszId;
    GUID guid;
    GUID guidProduct;
    int  idJoy;
	WORD ProductID;
	WORD VendorID;
    BOOL fAttached;
} HIDDEVICEINFO, *PHIDDEVICEINFO;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct HIDDEVICELIST |
 *
 *          Records information about all the HID devices.
 *
 *  @field  int | chdi |
 *
 *          Number of items in the list that are in use.
 *
 *  @field  int | chdiAlloc |
 *
 *          Number of items allocated in the list.
 *
 *  @field  HIDDEVICEINFO | rghdi[0] |
 *
 *          Variable-size array of device information structures.
 *
 *****************************************************************************/

typedef struct HIDDEVICELIST
{

    int chdi;
    int chdiAlloc;
    int idMaxJoy;
    HIDDEVICEINFO rghdi[0];

} HIDDEVICELIST, *PHIDDEVICELIST;

extern PHIDDEVICELIST g_phdl;

    #define cbHdlChdi(chdi)         FIELD_OFFSET(HIDDEVICELIST, rghdi[chdi])

/*
 *  We choose our starting point at 64 devices, since
 *  that's the maximum number of USB devices supported.  This
 *  avoids needless reallocs.
 */

    #define chdiMax                 64
    #define chdiInit                16

/*
 *  Tag for unused translation of object instance
 */
    #define NOREGTRANSLATION        (0x80000000)

/*
 *  VID/PID definitions used to handle analog devices
 */
    #define MSFT_SYSTEM_VID         (0x45E)
    #define MSFT_SYSTEM_PID         (0x100)
    #define ANALOG_ID_ROOT          TEXT("VID_045E&PID_01")

/*
 *  VID/PID template so that upper case hex is always used
 */
    #define VID_PID_TEMPLATE        TEXT("VID_%04X&PID_%04X")

/*
 *  Size of string in characters generated using VID_PID_TEMPLATE
 */
    #define cbszVIDPID              cA( VID_PID_TEMPLATE )


/*****************************************************************************
 *
 *      dihidenm.c - HID enumeration functions.
 *
 *****************************************************************************/

extern TCHAR g_tszIdLastRemoved[MAX_PATH]; //in dihidenm.c
extern DWORD g_tmLastRemoved;   //in dihinenm.c

STDMETHODIMP hresFindHIDInstanceGUID(PCGUID pguid, CREATEDCB *pcdcb);
STDMETHODIMP hresFindHIDDeviceInterface(LPCTSTR ptszPath, LPGUID pguidOut);

PHIDDEVICEINFO EXTERNAL phdiFindHIDInstanceGUID(PCGUID pguid);
PHIDDEVICEINFO EXTERNAL phdiFindHIDDeviceInterface(LPCTSTR ptszPath);

void EXTERNAL DIHid_BuildHidList(BOOL fForce);
void EXTERNAL DIHid_EmptyHidList(void);

BOOL EXTERNAL
    DIHid_GetDevicePath(HDEVINFO hdev,
                        PSP_DEVICE_INTERFACE_DATA pdid,
                        PSP_DEVICE_INTERFACE_DETAIL_DATA *ppdidd,
                        PSP_DEVINFO_DATA pdinf);


BOOL EXTERNAL
    DIHid_GetDeviceInstanceId(HDEVINFO hdev,
                              PSP_DEVINFO_DATA pdinf, 
                              LPTSTR *pptszId);

BOOL EXTERNAL
    DIHid_GetInstanceGUID(HKEY hk, LPGUID pguid);

    
/*****************************************************************************
 *
 *      diguid.c - GUID generation
 *
 *****************************************************************************/

void EXTERNAL DICreateGuid(LPGUID pguid);
void EXTERNAL DICreateStaticGuid(LPGUID pguid, WORD pid, WORD vid);

/*****************************************************************************
 *
 *      dihid.c
 *
 *****************************************************************************/

/*****************************************************************************
 *
 *          We will just use the HID item index as our DirectInput
 *          internal ID number, which is in turn an index into the
 *          <t DIOBJECTDATAFORMAT> array.
 *
 *          Keyboard support requires a translation table.
 *          Other devices also a translation table so that the external 
 *          instance numbers can be made compatible with legacy ones and 
 *          so that secondary aliases can be separated from primary ones.
 *
 *          Since HID restarts the item index counter at zero for
 *          each of input, feature, and output, we need to do some
 *          adjustment so there aren't any collisions.  So we
 *          shift the features to start after the inputs, and the
 *          outputs to start after the features.
 *
 *          The <e CHid.rgdwBase> array contains the amount by which
 *          each group of HID item indexes has been shifted.
 *
 *****************************************************************************/

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @func   BOOL | HidP_IsValidReportType |
 *
 *          For debugging only.  Check if a value is a valid
 *          <t HIDP_REPORT_TYPE>.
 *
 *          Note that we also create a "fake" report type in which
 *          to record our collections.
 *
 *  @field  HIDP_REPORT_TYPE | type |
 *
 *          One of the values
 *          <c HidP_Input>,
 *          <c HidP_Output>,
 *          or
 *          <c HidP_Feature>.  Hopefully.
 *
 *****************************************************************************/

    #define HidP_Max            (HidP_Feature + 1)
    #define HidP_Coll           HidP_Max
    #define HidP_MaxColl        (HidP_Coll + 1)

BOOL INLINE
    HidP_IsValidReportType(HIDP_REPORT_TYPE type)
{
    CAssertF(HidP_Input == 0);
    CAssertF(HidP_Output == 1);
    CAssertF(HidP_Feature == 2);
    return type < HidP_Max;
}

/*****************************************************************************
 *
 *          There are three (overlapping) classes of HID reports.
 *
 *          InputLike - HidP_Input and HidP_Feature
 *          OutputLike - HidP_Output and HidP_Feature
 *          NothingLike - HidP_Coll
 *
 *****************************************************************************/

BOOL INLINE
    HidP_IsInputLike(HIDP_REPORT_TYPE type)
{
    return type == HidP_Input || type == HidP_Feature;
}

BOOL INLINE
    HidP_IsOutputLike(HIDP_REPORT_TYPE type)
{
    return type == HidP_Output || type == HidP_Feature;
}

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct LMINMAX |
 *
 *          Min and max, that's all.  These are kept in structures
 *          to make logical-to-physical and physical-to-logical
 *          translations less gross.
 *
 *  @field  LONG | Min |
 *
 *          The minimum value.
 *
 *  @field  LONG | Max |
 *
 *          The maximum value.
 *
 *****************************************************************************/

typedef struct LMINMAX
{
    LONG Min;
    LONG Max;
} LMINMAX, *PLMINMAX;

typedef const LMINMAX *PCLMINMAX;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct HIDGROUPCAPS |
 *
 *          This structure unifies the various HID caps structures
 *          <t HIDP_BUTTON_CAPS> and
 *          <t HIDP_VALUE_CAPS>.
 *
 *  @field  HIDP_REPORT_TYPE | type |
 *
 *          One of the values
 *          <c HidP_Input>,
 *          <c HidP_Output>,
 *          or
 *          <c HidP_Feature>.
 *
 *  @field  UINT | cObj |
 *
 *          Number of objects in this group.
 *
 *  @field  USAGE | UsagePage |
 *
 *          Usage page for all usages in the group.
 *
 *  @field  USAGE | UsageMin |
 *
 *          First usage described by this group.  The remaining
 *          items are numbered consecutively starting from
 *          this value.
 *
 *  @field  USHORT | StringMin |
 *
 *          String for first usage described by this group.
 *          The remaining strings are numbered consecutively
 *          starting from this value, unless the string maximum
 *          is reached, in which case all subsequent objects
 *          share that last string.
 *
 *  @field  USHORT | StringMax |
 *
 *          Last string.
 *
 *  @field  USHORT | DesignatorMin |
 *
 *          Designator for first usage described by this group.
 *          The remaining designators are numbered consecutively
 *          starting from this value, unless the designator maximum
 *          is reached, in which case all subsequent objects
 *          share that last designator.
 *
 *  @field  USHORT | DesignatorMax |
 *
 *          Last designator.
 *
 *  @field  USHORT | DataIndexMin |
 *
 *          Data index for the first usage described by this group.
 *          The remaining data index values are numbered consecutively
 *          starting from this value.
 *
 *  @field  USHORT | usGranularity |
 *
 *          If object is a POV or wheel, then contains device granularity.
 *
 *  @field  LONG | lMask |
 *
 *          Mask bits used for sign extension.  For example, if the
 *          value is 8-bits, the mask will be 0xFFFFFF80, indicating
 *          that bit 7 (0x00000080) is extended to fill the remainder
 *          of the value.
 *
 *          This field is used only by values.
 *
 *  @field  USHORT | BitSize |
 *
 *          Number of bits devoted to this value, including the sign bit.
 *
 *          ISSUE-2001/03/29-timgill structure field probably not used anywhere.
 *
 *  @field  USHORT | LinkCollection |
 *
 *          HID link collection number.
 *
 *  @field  LMINMAX | Logical |
 *
 *          Logical minimum and maximum values.
 *          These are the extremes of raw values
 *          that can validly be received from the device.
 *
 *          This field is used only by values.
 *
 *  @field  LMINMAX | Physical |
 *
 *          Physical minimum and maximum values.
 *          This is the "actual" value
 *          that the logical minimum and maximum value corresponds to.
 *
 *          This field is used only by values, and is consulted
 *          only when converting between DirectInput calibration
 *          (which uses logical values) and VJOYD calibration
 *          (which uses physical values).
 *
 *  @field  LONG | Null |
 *
 *          The null value to be used for output.
 *
 *          This field is used only by values.
 *
 *  @field  ULONG | Units |
 *
 *          The HID units descriptor, if any.
 *
 *  @field  WORD | Exponent |
 *
 *          The HID unit exponent, if any.
 *
 *  @field  WORD | wReportId |
 *
 *          HID report Id
 *
 *  @field  BOOL | IsAbsolute |
 *
 *          Nonzero if the group describes absolute axes.
 *
 *          This field is used only by values.
 *
 *  @field  BOOL | IsValue |
 *
 *          Nonzero if the group describes a HID value.
 *
 *          Note that an analog pushbutton is reported by
 *          DirectInput as a <c DIDFT_BUTTON>, but is
 *          handled internally as a HID value.
 *
 *  @field  BOOL | IsAlias |
 *
 *          Nonzero if the group describes an alias.
 *
 *  @field  BOOL | IsSigned |
 *          
 *          The return data is signed. 
 *
 *  @field  BOOL | IsPolledPOV |
 *          
 *          TRUE if axis is a polled POV. 
 *
 *  @devnote New for DX6.1a
 *
 *****************************************************************************/

    #define HIDGROUPCAPS_SIGNATURE      0x47444948  /* HIDG */

typedef struct HIDGROUPCAPS
{

    D(DWORD dwSignature;)
    HIDP_REPORT_TYPE type;
    UINT    cObj;

    USAGE   UsagePage;
    USAGE   UsageMin;

    USHORT  StringMin,        StringMax;
    USHORT  DesignatorMin,    DesignatorMax;
    USHORT  DataIndexMin;

    USHORT  usGranularity;

    LONG    lMask;

    USHORT  BitSize;

    USHORT  LinkCollection;

    LMINMAX Logical;
    LMINMAX Physical;

    LONG    Null;

    ULONG   Units;
    WORD    Exponent;

    WORD    wReportId;
    BOOL    fReportDisabled;
    BOOL    Reserved;

    BOOL    IsAbsolute;
    BOOL    IsValue;
    BOOL    IsAlias;
    BOOL    IsSigned;
    
  #ifdef WINNT
    BOOL    IsPolledPOV;
  #endif

} HIDGROUPCAPS, *PHIDGROUPCAPS;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct HIDOBJCAPS |
 *
 *          This structure contains various cached pointers for each
 *          object on the device, allowing us to get at things like
 *          the group caps and the calibration information.
 *
 *  @field  PHIDGROUPCAPS | pcaps |
 *
 *          The <t PHIDGROUPCAPS> for the group the object belongs to.
 *
 *  @field  PJOYRANGECONVERT | pjrc |
 *
 *          If non-NULL, then points to the range conversion information
 *          for the object.
 *
 *  @field  int | idata |
 *
 *          Index into the <t HIDP_DATA> array for the corresponding
 *          output/feature report,
 *          or <c -1> if the item is not in the output/feature report.
 *
 *****************************************************************************/

typedef struct HIDOBJCAPS
{
    PHIDGROUPCAPS pcaps;
    PJOYRANGECONVERT pjrc;
    int idata;
} HIDOBJCAPS, *PHIDOBJCAPS;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct HIDREPORTINFO |
 *
 *          This structure contains information that is used for
 *          parsing HID reports.
 *
 *  @field  PHIDP_DATA | rgdata |
 *
 *          Array used when parsing reports via
 *          <f HidP_GetData> or <f HidP_SetData>.  This MUST be aligned 
 *          correctly on some architechtures.
 *
 *  @field  PV | pvReport |
 *
 *          The report itself.
 *
 *  @field  int | cdataMax |
 *
 *          Number of elements in the <e HIDREPORTINFO.rgdata> array.
 *
 *  @field  int | cdataUsed |
 *
 *          Number of elements in the <e HIDREPORTINFO.rgdata> array
 *          that are actually in use.
 *
 *  @field  ULONG | cbReport |
 *
 *          Number of bytes in the report.
 *
 *  @field  BOOL | fNeedClear |
 *
 *          Nonzero if the report needs to be zero'd out because we
 *          deleted something (most likely a button) from it.
 *          The only way to delete an item from a report is to zero
 *          out the entire report and then re-add everything back in.
 *
 *  @field  BOOL | fChanged |
 *
 *          Nonzero if an element in the report has changed.
 *
 *****************************************************************************/

typedef struct HIDREPORTINFO
{
    PHIDP_DATA rgdata;
    PV pvReport;
    int cdataMax;
    int cdataUsed;
    ULONG cbReport;
    BOOL fNeedClear;
    BOOL fChanged;
} HIDREPORTINFO, *PHIDREPORTINFO;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @struct CHid |
 *
 *          The <i IDirectInputDeviceCallback> object for HID devices.
 *
 *  @field  IDirectInputDeviceCalllback | didc |
 *
 *          The object (containing vtbl).
 *
 *  @field  PV | pvGroup2 |
 *
 *          Pointer to group 2 memory.  This field is a union with the 
 *          pointer to the first chunk of memory in the second memory group.
 *
 *  @field  HIDREPORTINFO | hriIn |
 *
 *          HID input report parsing and state.
 *
 *          This memory is the first chunk of group 2.
 *
 *  @field  HIDREPORTINFO | hriOut |
 *
 *          HID output report parsing and state.
 *
 *  @field  HIDREPORTINFO | hriFea |
 *
 *          HID feature report parsing and state.
 *
 *  @field  PV | pvPhys |
 *
 *          Pointer to physical device status information updated
 *          asynchronously by the data collection thread.
 *
 *  @field  PV | pvStage |
 *
 *          Staging area used when the HID report is parsed.
 *
 *          This memory is the last chunk of group 2.
 *
 *  @field  DWORD | cbPhys |
 *
 *          Size of the physical device state.
 *
 *  @field  VXDINSTANCE * | pvi |
 *
 *          The DirectInput instance handle.
 *
 *          HID devices always run through ring 3, which is misleadingly
 *          called "emulation".
 *
 *  @field  DWORD | dwDevType |
 *
 *          Device type code.
 *
 *  @field  LPTSTR | ptszId |
 *
 *          Setupapi device instance ID.  Used to obtain things
 *          like manufacturer name.
 *
 *  @field  LPTSTR | ptszPath |
 *
 *          Path to the device, for <f CreateFile>.
 *
 *  @field  UINT | dwAxes |
 *
 *          Number of axes on the device.
 *
 *  @field  UINT | dwButtons |
 *
 *          Number of buttons on the device.
 *
 *  @field  UINT | dwPOVs |
 *
 *          Number of POV controllers on the device.
 *
 *  @field  HANDLE | hdev |
 *
 *          Handle to the device itself.  This field is valid only
 *          while the device is acquired.
 *
 *  @field  HANDLE | hdevEm |
 *
 *          <f DuplicateHandle> of the <e CHid.hdev> which is used
 *          by the worker thread.  We need to keep this separate from
 *          the main copy to avoid race conditions between the main
 *          thread and the worker thread.
 *
 *  @field  HKEY | hkInstType |
 *
 *          Per-instance registry key that contains additional configuration
 *          information, equivalent to the joystick Type key.
 *
 *  @field  DWORD | rgdwBase[HidP_MaxColl] |
 *
 *          Array of base indices for the three HID usage classes:
 *          <c HidP_Input>, <c HidP_Output>, and <c HidP_Feature>.
 *          We hide the <c HidP_Collection> base index here, too.
 *
 *  @field  PHIDOBJCAPS | rghoc |
 *
 *          Pointer to array of
 *          <t PHIDOBJCAPS>, one for each object on the device,
 *          each of which in turn contains info about a single object.
 *
 *          This memory is allocated as part of the
 *          df.rgodf in the <t DIDATAFORMAT> structure
 *          hence should not be freed separately.
 *
 *  @field  DIDATAFORMAT | df |
 *
 *          The dynamically-generated data format based on the
 *          usages on the HID device.
 *
 *  @field  DWORD | ibButtonData |
 *
 *          The location of the button data inside the data format.
 *
 *  @field  DWORD | cbButtonData |
 *
 *          The number of bytes of button data inside the data format.
 *
 *  @field  PBYTE * | rgpbButtonMasks |
 *
 *          Pointer to a an array of pointers to byte strings to mask 
 *          the buttons relevant to a report.
 *
 *  @field  PHIDP_PREPARSED_DATA | ppd |
 *
 *          Preparsed data generated by the HID subsystem.
 *
 *  @field  PHIDGROUPCAPS | rgcaps |
 *
 *          Array of <t HIDGROUPCAPS> structures used to keep
 *          track of the various buttons, groups, and collections.
 *
 *  @field  UINT | ccaps |
 *
 *          Number of caps structures in the <e CHid.rgcaps> array.
 *
 *  @field  HIDP_CAPS | caps |
 *
 *          Cached HID caps.
 *
 *  @field  OVERLAPPED | o |
 *
 *          Overlapped I/O structure used by worker thread
 *          for reading.
 *
 *
 *  @field  PJOYRANGECONVERT | pjrcNext |
 *
 *          Pointer to the first <t JOYRANGECONVERT> structure
 *          (in a preallocated array) which has
 *          yet to be used.
 *          This structure is used for logical-to-physical
 *          range conversion (a.k.a. calibration).
 *
 *          This memory is allocated as part of the
 *          df.rgodf in the <t DIDATAFORMAT> structure
 *          hence should not be freed separately.
 *
 *          This field is used during device initialization to
 *          parcel out the <t JOYRANGECONVERT>s.  Afterwards,
 *          the field is <c NULL> if we did not create any
 *          conversion structures (hence do not need to subclass
 *          the cooperative window to catch recalibrations).
 *
 *  @field  PBYTE | rgbaxissemflags |
 *
 *          This points to an array which maps DirectInput axis 
 *          instance values to default semantic map flags.
 *
 *  @field  PINT | rgiobj |
 *
 *          This points to an array which maps DirectInput instance 
 *          values (DIDFT_GETINSTANCE) into object indices.
 *
 *  @field  PINT | rgipov |
 *
 *          If we are not a keyboard, then this is the first element in 
 *          the above array which maps povs.
 *
 *  @field  PINT | rgiaxis |
 *
 *          If we are not a keyboard, then this is the first element in 
 *          the above array which maps axes.
 *
 *  @field  PINT | rgicoll |
 *
 *          If we are not a keyboard, then this is the first element in 
 *          the above array which maps collections.
 *          //ISSUE-2001/03/29-timgill need to document keyboard case behaviour
 *
 *  @field  UINT | uiInstanceMax |
 *
 *          The number of elements in the above
 *          <f rgiobj> array.
 *
 *  @field  int | idJoy |
 *
 *          Joystick identifier for <f joyGetPosEx> and friends for
 *          legacy access.
 *
 *          This value starts out as -1, to meant that
 *          the corresponding legacy joystick is unknown.
 *          If we do something that requires the matched legacy
 *          joystick to be found, we check if the current value
 *          is still valid.  If not (either it is -1 or the cached
 *          value is stale), then we go hunt for the correct value.
 *
 *  @field  HKEY | hkType |
 *
 *          The joystick type key opened with <c MAXIMUM_ALLOWED> access.
 *          This is not per-instance; multiple instances of the same
 *          hardware share this key.
 *
 *  @field  USHORT | VendorID |
 *
 *          HID vendor ID for this device.
 *
 *  @field  USHORT | ProductID |
 *
 *          HID product ID for this device.
 *
 *  @field  HWND | hwnd |
 *
 *          The window which we have subclassed in order to watch
 *          for recalibration messages.
 *
 *  @field  BOOL | IsPolledInput |
 *
 *          Nonzero if the device has to be polled for Input data.
 *
 *  @field  BOOL | fPIDdevice |
 *
 *          Set to true if the device is found to support PID. 
 *
 *  @field  WORD | wMaxReportId | 
 *          
 *          The maximum (number) of ReportId used by the HID device.   
 *      
 *  @field  PUCHAR | pEnableReportId |
 *          
 *          Pointer to (wMaxReportId) bytes. If a reportID needs to be
 *          polled in order to get features / set Output, then that element
 *          of this array is set to 0x1.
 *
 *  @field HKEY | hkProp |
 *
 *          Extended properties for device type. Currently we keep dwFlags2 and
 *          OEMMapFile under this key.  
 *  
 *  @field  BOOL | fEnableInputReport |
 *
 *          True if Input report should be enabled for this device.
 *  
 *  @field  BOOL | fFlags2Checked |
 *
 *          True after we check the registry for Flags2 for disabling
 *          input reports.
 *
 *  @comm
 *
 *          It is the caller's responsibility to serialize access as
 *          necessary.
 *
 *****************************************************************************/

typedef struct CHid
{

    /* Supported interfaces */
    IDirectInputDeviceCallback dcb;

    union
    {
        PV            pvGroup2;
        HIDREPORTINFO hriIn;
    };

    HIDREPORTINFO hriOut;
    HIDREPORTINFO hriFea;

    PV       pvPhys;
    PV       pvStage;
    DWORD    cbPhys;

    VXDINSTANCE *pvi;

    DWORD    dwDevType;

    UINT     dwAxes;
    UINT     dwButtons;
    UINT     dwPOVs;
    UINT     dwCollections;

    HANDLE   hdev;
    HANDLE   hdevEm;

    DWORD    rgdwBase[HidP_MaxColl];
    PHIDOBJCAPS rghoc;
    DIDATAFORMAT df;

    DWORD    ibButtonData;
    DWORD    cbButtonData;
    PBYTE   *rgpbButtonMasks;

    PHIDP_PREPARSED_DATA ppd;
    PHIDGROUPCAPS rgcaps;

    PJOYRANGECONVERT pjrcNext;

    HIDP_CAPS caps;

    ED       ed;
    OVERLAPPED o;
    DWORD    dwStartRead;
    DWORD    dwStopRead;

    PBYTE    rgbaxissemflags;
    PINT     rgiobj;
    PINT     rgipov;
    PINT     rgiaxis;
    PINT     rgicoll;
    UINT     uiInstanceMax;

    LPTSTR   ptszId;
    LPTSTR   ptszPath;
    HKEY     hkInstType;
    UINT     ccaps;
    int      idJoy;

    HKEY     hkType;
    USHORT   VendorID;
    USHORT   ProductID;
    
    #define  FAILED_POLL_THRESHOLD   (0x4)
        
    HWND     hwnd;    
    
    BOOL     IsPolledInput;
    BOOL     fPIDdevice;  
    WORD     wMaxReportId[HidP_Max];
    PUCHAR   pEnableReportId[HidP_Max];

    DWORD    dwVersion;

    DIAPPHACKS  diHacks;

    HKEY     hkProp;

    BOOL     fEnableInputReport;
    BOOL     fFlags2Checked;

} CHid, CHID, *PCHID;

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @func   PCHID | pchidFromPo |
 *
 *          Given an interior pointer to an <t OVERLAPPED>, retrieve
 *          a pointer to the parent <t CHid>.
 *
 *  @parm   LPOVERLAPPED | po |
 *
 *          The pointer to convert.
 *
 *****************************************************************************/

PCHID INLINE
    pchidFromPo(LPOVERLAPPED po)
{
    return pvSubPvCb(po, FIELD_OFFSET(CHid, o));
}

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @func   PCHID | pchidFromPed |
 *
 *          Given an interior pointer to a <t CEd>, retrieve
 *          a pointer to the parent <t CHid>.
 *
 *  @parm   PED | ped |
 *
 *          The pointer to convert.
 *
 *****************************************************************************/

PCHID INLINE
    pchidFromPed(PED ped)
{
    return pvSubPvCb(ped, FIELD_OFFSET(CHid, ed));
}

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @func   PCHID | pchidFromPem |
 *
 *          Given a <t CEm>, wander back to the
 *          <t CHid> that spawned it.
 *
 *  @parm   PEM | pem |
 *
 *          The pointer at which to start.
 *
 *****************************************************************************/

PCHID INLINE
    pchidFromPem(PEM pem)
{
    PCHID pchid = pchidFromPed(pem->ped);
    AssertF(pemFromPvi(pchid->pvi) == pem);
    return pchid;
}

/*****************************************************************************
 *
 *  @doc    INTERNAL
 *
 *  @method UINT | CHid | ObjFromType |
 *
 *          Given a <p dwType>, extract the instance number
 *          and (if necessary) convert it to an object index.
 *          Note, the instance number will always be of the primary instance
 *          not an alias.
 *
 *  @parm   PCHID | this |
 *
 *          HID device object.
 *
 *  @parm   DWORD | dwType |
 *
 *          The type code to convert.
 *
 *  @returns
 *
 *          The object index, or an out-of-range value.
 *
 *****************************************************************************/

UINT INLINE
    CHid_ObjFromType(PCHID this, DWORD dwType)
{
    UINT uiObj = DIDFT_GETINSTANCE(dwType);

    // ISSUE-2001/03/29-timgill Range checks may be unnecessary
    // MarcAnd can we ever get the out of range value?
    //          if so, can we really run with it?
    //          if not, can these range checks be converted into Asserts?

    /*
     *  The range checking makes use of the fact that the translation 
     *  tables are taken from a contiguous memory allocation and that
     *  aliased collections are not distinguished.
     */
    if(this->rgiobj)
    {
        switch( DIDFT_GETTYPE(dwType) )
        {
        case DIDFT_RELAXIS:
        case DIDFT_ABSAXIS:
            if( &this->rgiaxis[uiObj] < this->rgicoll )
            {
                uiObj = this->rgiaxis[uiObj];
            } else
            {
                uiObj = 0xFFFFFFFF;
            }
            break;

        case DIDFT_PSHBUTTON:
        case DIDFT_TGLBUTTON:
            /*
             * If it is keyboard, this->rgiobj == this->rgipov (see CHid_MungeKeyboard).
             * So, we can't test &this->rgiobj[uiObj] < this->rgipov.
             */
            if( (GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_KEYBOARD &&
                 uiObj < this->uiInstanceMax ) ||
                &this->rgiobj[uiObj] < this->rgipov )
            {
                uiObj = this->rgiobj[uiObj];
            } else
            {
                uiObj = 0xFFFFFFFF;
            }
            break;

        case DIDFT_POV:
            if( &this->rgipov[uiObj] < this->rgiaxis )
            {
                uiObj = this->rgipov[uiObj];
            } else
            {
                uiObj = 0xFFFFFFFF;
            }
            break;
        case (DIDFT_COLLECTION | DIDFT_NODATA):
            if( &this->rgicoll[uiObj] <= &this->rgiobj[this->uiInstanceMax] )
            {
                uiObj = this->rgicoll[uiObj];
            } else
            {
                uiObj = 0xFFFFFFFF;
            }
            break;
        case DIDFT_NODATA:
            /*
             * So far, this TYPE only shows up on Keyboard (HID_USAGE_PAGE_LED).
             */
            if( GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_KEYBOARD &&
                 uiObj < this->uiInstanceMax )
            {
                uiObj = this->rgiobj[uiObj];
            }
            break;
        
        default:
            /*
             *  Hopefully this is just a vendor defined object but squirt
             *  in debug as these may cause problems.
             */
            SquirtSqflPtszV(sqflHidParse | sqflVerbose,
                            TEXT("CHid_ObjFromType: dwType 0x%08x not converted"),
                            dwType );                
            break;
        }
    }
    else
    {
        SquirtSqflPtszV(sqflHidParse | sqflError,
                        TEXT("CHid_ObjFromType: Translation array missing") );
    }

    return uiObj;
}

LONG EXTERNAL
    CHid_CoordinateTransform(PLMINMAX Dst, PLMINMAX Src, LONG lVal);

#ifndef WINNT
void EXTERNAL
    CHid_UpdateVjoydCalibration(PCHID this, UINT iobj);

void EXTERNAL
    CHid_UpdateCalibrationFromVjoyd(PCHID this, UINT iobj, LPDIOBJECTCALIBRATION pCal);
#endif

/*****************************************************************************
 *
 *      dihidini.c - Device callback initialization stuff
 *
 *****************************************************************************/

#define INITBUTTONFLAG     0x10000000

HRESULT EXTERNAL CHid_InitParseData(PCHID this);

HRESULT EXTERNAL CHid_Init(PCHID this, REFGUID rguid);

HANDLE EXTERNAL CHid_OpenDevicePath(PCHID this, DWORD dwAttributes );

UINT EXTERNAL CHid_LoadCalibrations(PCHID this);

BOOL EXTERNAL CHid_IsPolledDevice( HANDLE hdev );

/*****************************************************************************
 *
 *      dihiddat.c - HID data parsing/management
 *
 *****************************************************************************/

typedef HRESULT (FAR PASCAL * SENDHIDREPORT)(PCHID this, PHIDREPORTINFO phri);

void EXTERNAL CHid_ResetDeviceData(PCHID this, PHIDREPORTINFO phri,
                                   HIDP_REPORT_TYPE type);
HRESULT EXTERNAL CHid_AddDeviceData(PCHID this, UINT uiObj, DWORD dwData);
STDMETHODIMP CHid_PrepareDeviceData(PCHID this, PHIDREPORTINFO phri);
STDMETHODIMP CHid_SendHIDReport(PCHID this, PHIDREPORTINFO phri,
                                HIDP_REPORT_TYPE type, SENDHIDREPORT SendHIDReport);

NTSTATUS EXTERNAL
    CHid_ParseData(PCHID this, HIDP_REPORT_TYPE type, PHIDREPORTINFO phri);


HRESULT EXTERNAL
    DIHid_GetRegistryProperty(LPTSTR ptszId, DWORD dwProperty, LPDIPROPHEADER pdiph);

DWORD EXTERNAL DIHid_DetectHideAndRevealFlags( PCHID this );

/*****************************************************************************
 *
 *      diemh.c - HID "emulation"
 *
 *****************************************************************************/

void EXTERNAL CEm_HID_Sync(PLLTHREADSTATE plts, PEM pem);

BOOL EXTERNAL CEm_HID_IssueRead( PCHID pchid );

#endif /* _DIHID_H */