📄 hidjoy.c
字号:
DeviceExtension->AxisMap[RIS] = cAxisIndexTable[AxisMask];
}
}
}
if( dwFlags & JOY_HWS_HASPOV )
{
switch( dwFlags & ( JOY_HWS_POVISPOLL | JOY_HWS_POVISBUTTONCOMBOS ) )
{
case 0:
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: POV is not polled or button combo"));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
break;
case JOY_HWS_POVISBUTTONCOMBOS:
break;
case JOY_HWS_POVISPOLL:
AxisMask = ZLU[(dwFlags & POVMAPBITS) >> POVMAPSHFT];
if( AxisMask >= NA )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: POV axis mapping error dwFlags=0x%x",\
dwFlags));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
else
{
if( DeviceExtension->resistiveInputMask & AxisMask )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: POV axis mapped to same as Z or R axis") );
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
else
{
DeviceExtension->resistiveInputMask |= AxisMask;
DeviceExtension->povMap = cAxisIndexTable[AxisMask];
}
}
break;
case JOY_HWS_POVISPOLL | JOY_HWS_POVISBUTTONCOMBOS:
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: POV reports button combo and polled"));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
break;
}
}
else if( dwFlags & ( JOY_HWS_POVISPOLL | JOY_HWS_POVISBUTTONCOMBOS ) )
{
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: non-existant POV is polled or button combo"));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
AxisMask = XLU[( dwFlags & XMAPBITS ) >> XMAPSHFT];
if( AxisMask >= NA )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: X axis mapping error dwFlags=0x%x",\
dwFlags));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
else
{
if( DeviceExtension->resistiveInputMask & AxisMask )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_WARN,\
("HGM_MapAxesFromDevExt: X axis mapped to same as another axis") );
}
else
{
nAxis++;
DeviceExtension->resistiveInputMask |= AxisMask;
DeviceExtension->AxisMap[XIS] = cAxisIndexTable[AxisMask];
}
}
AxisMask = YLU[( dwFlags & YMAPBITS ) >> YMAPSHFT];
if( AxisMask >= NA )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: Y axis mapping error dwFlags=0x%x",\
dwFlags));
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
}
else
{
if( DeviceExtension->resistiveInputMask & AxisMask )
{
HGM_DBGPRINT( FILE_HIDJOY | HGM_WARN,\
("HGM_MapAxesFromDevExt: Y axis mapped to same as another axis") );
}
else
{
nAxis++;
DeviceExtension->resistiveInputMask |= AxisMask;
DeviceExtension->AxisMap[YIS] = cAxisIndexTable[AxisMask];
}
}
#undef XIS
#undef YIS
#undef ZIS
#undef RIS
#undef NA
/*
* Don't fail for this if CHANGE_DEVICE is defined because an exposed
* sibling will always have an nAxis of zero.
*/
#ifdef CHANGE_DEVICE
if( DeviceExtension->nAxes )
{
#endif /* CHANGE_DEVICE */
if( nAxis != DeviceExtension->nAxes )
{
ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR ;
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("HGM_MapAxesFromDevExt: nAxis(%d) != DeviceExtension->nAxes(%d)", \
nAxis, (int) DeviceExtension->nAxes));
}
#ifdef CHANGE_DEVICE
}
else
{
/*
* This must be an exposed sibling so store the calculated nAxis and
* a nButton just to look different.
*/
DeviceExtension->nAxes = (USHORT)nAxis;
DeviceExtension->nButtons = MAX_BUTTONS;
}
#endif /* CHANGE_DEVICE */
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE,\
("HGM_MapAxesFromDevExt: uResistiveInputMask=0x%x",\
DeviceExtension->resistiveInputMask) );
if( NT_SUCCESS(ntStatus) )
{
ntStatus = HGM_SetupButtons( DeviceExtension );
}
return( ntStatus );
} /* HGM_MapAxesFromDevExt */
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func NTSTATUS | HGM_GenerateReport |
*
* Generates a hid report descriptor for a n-axis, m-button joystick,
* depending on number of buttons and joy_hws_flags field.
*
* @parm IN PDEVICE_OBJECT | DeviceObject |
*
* Pointer to the device object
*
* @parm IN OUT UCHAR * | rgGameReport[MAXBYTES_GAME_REPORT] |
*
* Array that receives the HID report descriptor
*
* @parm OUT PUSHORT | pCbReport |
*
* Address of a short integer that receives size of
* HID report descriptor.
*
* @rvalue STATUS_SUCCESS | success
* @rvalue STATUS_BUFFER_TOO_SMALL | Need more memory for HID descriptor
*
*****************************************************************************/
NTSTATUS INTERNAL
HGM_GenerateReport
(
IN PDEVICE_OBJECT DeviceObject,
OUT UCHAR rgGameReport[MAXBYTES_GAME_REPORT],
OUT PUSHORT pCbReport
)
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION DeviceExtension;
UCHAR *pucReport;
int Idx;
int UsageIdx;
ULONG dwFlags;
POEMDATA OemData;
int InitialAxisMappings[MAX_AXES];
typedef struct _USAGES
{
UCHAR UsagePage;
UCHAR Usage;
} USAGES, *PUSAGE;
typedef struct _JOYCLASSPARAMS
{
UCHAR TopLevelUsage;
USAGES Usages[MAX_AXES];
} JOYCLASSPARAMS, *PJOYCLASSPARAMS;
PJOYCLASSPARAMS pJoyParams;
/*
* Canned parameters for devices
* The top-level usage must be either HID_USAGE_GENERIC_JOYSTICK or
* HID_USAGE_GENERIC_GAMEPAD in order for the device to be treated as a
* game controller.
* The poll limits are specified in uSecs so the value stored here is 1000000/x
*/
JOYCLASSPARAMS JoystickParams =
{
HID_USAGE_GENERIC_JOYSTICK,
{ { HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X} ,
{ HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_Y} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_THROTTLE} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_RUDDER} }
};
JOYCLASSPARAMS GamepadParams =
{
HID_USAGE_GENERIC_GAMEPAD,
{ { HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X} ,
{ HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_Y} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_THROTTLE} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_RUDDER} }
};
JOYCLASSPARAMS CarCtrlParams =
{
HID_USAGE_GENERIC_JOYSTICK,
{ { HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X} ,
{ HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_Y} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_THROTTLE} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_RUDDER} }
};
JOYCLASSPARAMS FlightYokeParams =
{
HID_USAGE_GENERIC_JOYSTICK,
{ { HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X} ,
{ HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_Y} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_THROTTLE} ,
{ HID_USAGE_PAGE_SIMULATION, HID_USAGE_SIMULATION_RUDDER} }
};
PAGED_CODE();
HGM_DBGPRINT( FILE_HIDJOY | HGM_FENTRY,\
("HGM_GenerateReport(ucIn=0x%x,DeviceObject=0x%x)",\
rgGameReport, DeviceObject) );
/*
* Get a pointer to the device extension
*/
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
/*
* Although the axes have already been validated and mapped in
* HGM_JoystickConfig this function destroys the mapping when it compacts
* the axes towards the start of the descriptor report. Since this
* function will be called once to find the descriptor length and then
* again to read the report, the mappings are regenerated again each
* time through. Although this results in the parameters being
* interpreted three times (for validation, descriptor size and
* descriptor content) it avoids the possibility of a discrepancy in
* implementation of separate functions.
*/
ntStatus = HGM_MapAxesFromDevExt( DeviceExtension );
ASSERTMSG( "HGM_GenerateReport:", ntStatus == STATUS_SUCCESS );
pucReport = rgGameReport;
dwFlags = DeviceExtension->HidGameOemData.OemData[(DeviceExtension->fSiblingFound!=0)].joy_hws_dwFlags;
/*
* What manner of beast have we ?
*/
if( dwFlags & JOY_HWS_ISGAMEPAD )
{
pJoyParams = &GamepadParams;
}
else if( dwFlags & JOY_HWS_ISYOKE )
{
pJoyParams = &FlightYokeParams;
}
else if( dwFlags & JOY_HWS_ISCARCTRL )
{
pJoyParams = &CarCtrlParams;
}
else
{
pJoyParams = &JoystickParams;
}
#define NEXT_BYTE( pReport, Data ) \
ASSERTMSG( "HGM_GenerateReport:", pReport+sizeof(UCHAR)-rgGameReport < MAXBYTES_GAME_REPORT ); \
*pReport++ = Data;
#define NEXT_LONG( pReport, Data ) \
ASSERTMSG( "HGM_GenerateReport:", pReport+sizeof(ULONG)-rgGameReport < MAXBYTES_GAME_REPORT); \
*(((LONG UNALIGNED*)(pReport))++) = Data;
#define ITEM_DEFAULT 0x00 /* Data, Array, Absolute, No Wrap, Linear, Preferred State, Has no NULL */
#define ITEM_VARIABLE 0x02 /* as ITEM_DEFAULT but value is a variable, not an array */
#define ITEM_HASNULL 0x40 /* as ITEM_DEFAULT but values out of range are considered NULL */
#define ITEM_ANALOG_AXIS ITEM_VARIABLE
#define ITEM_DIGITAL_POV (ITEM_VARIABLE|ITEM_HASNULL)
#define ITEM_BUTTON ITEM_VARIABLE
#define ITEM_PADDING 0x01 /* Constant (nothing else applies) */
/* USAGE_PAGE (Generic Desktop) */
NEXT_BYTE(pucReport, HIDP_GLOBAL_USAGE_PAGE_1);
NEXT_BYTE(pucReport, HID_USAGE_PAGE_GENERIC);
/* USAGE (Joystick | GamePad ) */
NEXT_BYTE(pucReport, HIDP_LOCAL_USAGE_1);
NEXT_BYTE(pucReport, pJoyParams->TopLevelUsage);
/* Logical Min is the smallest value that could be produced by a poll */
NEXT_BYTE(pucReport, HIDP_GLOBAL_LOG_MIN_4);
NEXT_LONG(pucReport, 0 );
/* Logical Max is the largest value that could be produced by a poll */
NEXT_BYTE(pucReport, HIDP_GLOBAL_LOG_MAX_4);
NEXT_LONG(pucReport, AXIS_FULL_SCALE );
/* Start a Linked collection */
/*
* Since this is a generic driver we know knothing about the physical
* distribution of controls on the device so we put everything in a
* single collection. If, for instance, we knew that some buttons were
* on the base and some on the stick we could better describe them by
* reporting them in separate collections.
*/
NEXT_BYTE(pucReport, HIDP_MAIN_COLLECTION);
NEXT_BYTE(pucReport, 0x0 );
/* Define one axis at a time */
NEXT_BYTE(pucReport, HIDP_GLOBAL_REPORT_COUNT_1);
NEXT_BYTE(pucReport, 0x1);
/* Each axis is a 32 bits value */
NEXT_BYTE(pucReport, HIDP_GLOBAL_REPORT_SIZE);
NEXT_BYTE(pucReport, 8 * sizeof(ULONG) );
/*
* Do the axis
* Although HID could cope with the "active" axes being mixed with the
* dummy ones, it makes life simpler to move them to the start.
* Pass through all the axis maps generated by HGM_JoystickConfig
* and map all the active ones into the descriptor, copying the usages
* appropriate for the type of device.
* Since a polled POV is nothing more than a different interpretation
* of axis data, this is added after any axes.
*/
C_ASSERT( sizeof( InitialAxisMappings ) == sizeof( DeviceExtension->AxisMap ) );
RtlCopyMemory( InitialAxisMappings, DeviceExtension->AxisMap, sizeof( InitialAxisMappings ) );
Idx = 0;
for( UsageIdx = 0; UsageIdx < MAX_AXES; UsageIdx++ )
{
if( InitialAxisMappings[UsageIdx] >= INVALID_INDEX )
{
continue;
}
DeviceExtension->AxisMap[Idx] = InitialAxisMappings[UsageIdx];
NEXT_BYTE(pucReport, HIDP_LOCAL_USAGE_4);
NEXT_BYTE(pucReport, pJoyParams->Usages[UsageIdx].Usage);
NEXT_BYTE(pucReport, 0x0);
NEXT_BYTE(pucReport, pJoyParams->Usages[UsageIdx].UsagePage);
NEXT_BYTE(pucReport, 0x0);
/* Data Field */
NEXT_BYTE(pucReport, HIDP_MAIN_INPUT_1);
NEXT_BYTE(pucReport, ITEM_ANALOG_AXIS);
HGM_DBGPRINT( FILE_HIDJOY | HGM_GEN_REPORT, \
("HGM_GenerateReport:Idx=%d, UsageIdx=%d, Mapping=%d, Usage=%02x, Page=%02x",\
Idx, UsageIdx, DeviceExtension->AxisMap[UsageIdx], \
pJoyParams->Usages[UsageIdx].Usage, pJoyParams->Usages[UsageIdx].UsagePage ) ) ;
Idx++;
}
if( dwFlags & JOY_HWS_POVISPOLL )
{
/*
* A polled POV is just the same as an axis.
* Note, we have already checked that there is an axis for use as the POV.
* Also, this type of POV can be distinguished from a digital POV by it's
* lack of a NULL value.
*/
NEXT_BYTE(pucReport, HIDP_LOCAL_USAGE_4);
NEXT_BYTE(pucReport, HID_USAGE_GENERIC_HATSWITCH);
NEXT_BYTE(pucReport, 0x0);
NEXT_BYTE(pucReport, HID_USAGE_PAGE_GENERIC);
NEXT_BYTE(pucReport, 0x0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -