hidjoy.c
来自「一个简单实现windows游戏杆的驱动示例-hidgame」· C语言 代码 · 共 1,675 行 · 第 1/4 页
C
1,675 行
{
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("HGM_InitDevice: JoystickConfig Failed"));
}
return( ntStatus );
} /* HGM_InitAnalog */
/*
* Change device sample only code
*/
#ifdef CHANGE_DEVICE
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func VOID | HGM_ChangeHandler |
*
* Use IOCTL_GAMEENUM_EXPOSE_SIBLING and IOCTL_GAMEENUM_REMOVE_SELF
* to change the attributes of the device.
*
* @parm IN OUT PDEVICE_EXTENSION | DeviceExtension |
*
* Pointer to the mini-driver device extension.
*
*****************************************************************************/
VOID
HGM_ChangeHandler
(
IN OUT PDEVICE_EXTENSION DeviceExtension
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
KEVENT IoctlCompleteEvent;
IO_STATUS_BLOCK IoStatus;
PIO_STACK_LOCATION irpStack, nextStack;
PIRP pIrp;
PVOID SiblingHandle;
GAMEENUM_EXPOSE_SIBLING ExposeSibling;
PAGED_CODE ();
HGM_DBGPRINT(FILE_HIDJOY | HGM_FENTRY,\
("HGM_ChangeHandler(DeviceExtension=0x%x)", DeviceExtension));
KeInitializeEvent(&IoctlCompleteEvent, NotificationEvent, FALSE);
pIrp = IoBuildDeviceIoControlRequest (
IOCTL_GAMEENUM_EXPOSE_SIBLING,
DeviceExtension->NextDeviceObject,
&ExposeSibling,
sizeof( ExposeSibling ),
&ExposeSibling,
sizeof( ExposeSibling ),
TRUE,
&IoctlCompleteEvent,
&IoStatus);
if( pIrp )
{
/*
* For demonstration purposes only, we don't actually change the
* device, we just re-expose the same one. If the device really
* needs to be changed, this would be signalled either by a
* change in the OemData on the newly exposed device or by using
* a specific HardwareID string.
* Note the nAxis and nButton fields will always be zero for an
* exposed sibling.
*/
RtlZeroMemory( &ExposeSibling, sizeof( ExposeSibling ) );
ExposeSibling.Size = sizeof( ExposeSibling );
ExposeSibling.HardwareHandle = &SiblingHandle;
C_ASSERT( sizeof( ExposeSibling.OemData ) == sizeof( DeviceExtension->HidGameOemData.Game_Oem_Data ) );
RtlCopyMemory(ExposeSibling.OemData, DeviceExtension->HidGameOemData.Game_Oem_Data, sizeof(ExposeSibling.OemData));
ASSERT( ExposeSibling.UnitID == 0 );
/*
* Setting a NULL pointer causes the HardwareID of this sibling to be used
*/
ExposeSibling.HardwareIDs = NULL;
/*
* issue a synchronous request to GameEnum to expose this new sibling
*/
ntStatus = IoCallDriver( DeviceExtension->NextDeviceObject, pIrp );
if( ntStatus == STATUS_PENDING )
{
ntStatus = KeWaitForSingleObject (&IoctlCompleteEvent, Executive, KernelMode, FALSE, NULL);
}
if( NT_SUCCESS(ntStatus) )
{
/*
* All went well so remove self
*/
HGM_DBGPRINT(FILE_HIDJOY | HGM_BABBLE, ("Sibling exposed!"));
pIrp = IoBuildDeviceIoControlRequest (
IOCTL_GAMEENUM_REMOVE_SELF,
DeviceExtension->NextDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&IoctlCompleteEvent,
&IoStatus);
if( pIrp )
{
/*
* issue a synchronous request to GameEnum to remove self
*/
ntStatus = IoCallDriver( DeviceExtension->NextDeviceObject, pIrp );
if( ntStatus == STATUS_PENDING )
{
ntStatus = KeWaitForSingleObject( &IoctlCompleteEvent, Executive, KernelMode, FALSE, NULL );
}
if( NT_SUCCESS(ntStatus) )
{
/*
* All done
*/
HGM_DBGPRINT(FILE_HIDJOY | HGM_BABBLE, ("Removed self!"));
}
else
{
/*
* Something bad happened but there's little we can do
*/
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR,\
("Failed to remove self with GameEnum error: 0x%08x", \
ntStatus));
}
}
else
{
ntStatus = STATUS_NO_MEMORY;
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR, \
("Failed to create IRP for remove self") );
}
}
else
{
/*
* Something bad happened so reset the flag and carry on
*/
DeviceExtension->fReplaced = FALSE;
HGM_DBGPRINT(FILE_HIDJOY | HGM_WARN,\
("Failed to expose sibling with GameEnum error: 0x%08x", ntStatus));
}
}
else
{
ntStatus = STATUS_NO_MEMORY;
DeviceExtension->fReplaced = FALSE;
HGM_DBGPRINT(FILE_HIDJOY | HGM_ERROR, \
("Failed to create IRP for expose sibling") );
}
/*
* We've finished touching the DeviceExtension now.
*/
HGM_DecRequestCount( DeviceExtension );
HGM_EXITPROC(FILE_HIDJOY|HGM_FEXIT_STATUSOK, "HGM_ChangeHandler", ntStatus);
return;
} /* HGM_ChangeHandler */
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func VOID | HGM_DeviceChanged |
*
* Start the process of changing the device attributes by stashing
* away all the data needed and then initializing and queuing a work
* item to call the IOCTL at the required PASSIVE_LEVEL.
*
* @parm IN OUT PDEVICE_EXTENSION | DeviceExtension |
*
* Pointer to the mini-driver device extension.
*
*****************************************************************************/
VOID
HGM_DeviceChanged
(
IN OUT PDEVICE_EXTENSION DeviceExtension
)
{
NTSTATUS ntStatus;
/*
* Since the work item will use the device extension, bump the usage
* count up one in case anyone tries to remove the device between
* now and when the work item gets to run. If that fails, forget it.
*/
ntStatus = HGM_IncRequestCount( DeviceExtension );
if( NT_SUCCESS(ntStatus) )
{
DeviceExtension->fReplaced = TRUE;
ExInitializeWorkItem( &DeviceExtension->WorkItem,
(PWORKER_THREAD_ROUTINE)HGM_ChangeHandler, DeviceExtension );
ExQueueWorkItem( &DeviceExtension->WorkItem, DelayedWorkQueue );
}
else
{
HGM_DBGPRINT(FILE_HIDJOY | HGM_WARN, ("Failed to change device") );
}
} /* HGM_DeviceChanged */
#endif /* CHANGE_DEVICE */
/*****************************************************************************
*
* @doc EXTERNAL
*
* @func VOID | HGM_Game2HID |
*
* Process the data returned from polling the gameport into values
* and buttons for returning to HID.
* <nl>The meaning of the data is interpreted according to the
* characteristics of the device described in the hardware settings
* flags.
*
* @parm IN PDEVICE_EXTENSION | DeviceExtension |
*
* Pointer to the mini-driver device extension.
*
* @parm IN OUT PUHIDGAME_INPUT_DATA | pHIDData |
*
* Pointer to the buffer into which the HID report should be written.
* This buffer must be assumed to be unaligned.
*
*****************************************************************************/
VOID
HGM_Game2HID
(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PUHIDGAME_INPUT_DATA pHIDData
)
{
LONG Idx;
/*
* Use a local buffer to assemble the report as the real buffer may not
* be aligned.
*/
HIDGAME_INPUT_DATA LocalBuffer;
RtlZeroMemory( &LocalBuffer, sizeof( LocalBuffer ) );
/*
* Remap axis
*/
for(Idx = 0x0; Idx < DeviceExtension->nAxes; Idx++ )
{
LocalBuffer.Axis[Idx] = DeviceExtension->LastGoodAxis[DeviceExtension->AxisMap[Idx]];
}
/*
* Copy buttons and remap any POVs
*/
if( DeviceExtension->fSiblingFound )
{
/*
* Simplest case, 2nd half poll must be 2A 2B
*/
LocalBuffer.Button[0] = DeviceExtension->LastGoodButton[2];
LocalBuffer.Button[1] = DeviceExtension->LastGoodButton[3];
}
else if( DeviceExtension->HidGameOemData.OemData[0].joy_hws_dwFlags & JOY_HWS_POVISBUTTONCOMBOS )
{
UCHAR Buttons = 0;
for( Idx = 3; Idx >=0; Idx-- )
{
Buttons <<= 1;
Buttons = (UCHAR)(Buttons + (UCHAR)(DeviceExtension->LastGoodButton[Idx] >> BUTTON_BIT));
}
if( DeviceExtension->HidGameOemData.OemData[0].joy_hws_dwFlags & JOY_HWS_HASPOV2 )
{
Idx = c2PComboLU[Buttons];
}
else
{
Idx = c1PComboLU[Buttons];
}
if( Idx >= P1_NULL )
{
if( Idx < P2_NULL )
{
LocalBuffer.hatswitch[0] = (UCHAR)(Idx & POV_MASK);
}
else
{
LocalBuffer.hatswitch[1] = (UCHAR)(Idx & POV_MASK);
}
}
else
{
#ifdef CHANGE_DEVICE
if( ( Idx >= DeviceExtension->nButtons ) && ( !DeviceExtension->fReplaced ) )
{
/*
* If a higher button was pressed than expected, use
* remove_self/expose_sibling to change expectations.
*/
HGM_DeviceChanged( DeviceExtension );
}
#endif /* CHANGE_DEVICE */
LocalBuffer.Button[Idx] = BUTTON_ON;
}
}
else
{
if( DeviceExtension->HidGameOemData.OemData[0].joy_hws_dwFlags & JOY_HWS_POVISPOLL )
{
/*
* Following the axis mapping loop, Idx is one larger than
* DeviceExtension->nAxes which is the correct index for a
* polled POV.
*/
LocalBuffer.Axis[Idx] = DeviceExtension->LastGoodAxis[DeviceExtension->povMap];
}
/*
* Check buttons on R and Z axes
*/
if( DeviceExtension->nButtons > 5 )
{
if( DeviceExtension->LastGoodAxis[3] > DeviceExtension->button6limit )
{
/*
* New max found so button is off
*/
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2, \
("HGM_Game2HID: Changing button 6 limit from %u to %u", \
DeviceExtension->button6limit, DeviceExtension->LastGoodAxis[3] ) ) ;
DeviceExtension->button6limit = DeviceExtension->LastGoodAxis[3];
}
else if( DeviceExtension->LastGoodAxis[3] < (DeviceExtension->button6limit>>1) )
{
LocalBuffer.Button[5] = BUTTON_ON;
}
}
if( DeviceExtension->nButtons > 4 )
{
Idx = 4;
if( DeviceExtension->LastGoodAxis[2] > DeviceExtension->button5limit )
{
/*
* New max found so button is off
*/
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2, \
("HGM_Game2HID: Changing button 5 limit from %u to %u", \
DeviceExtension->button5limit, DeviceExtension->LastGoodAxis[2] ) ) ;
DeviceExtension->button5limit = DeviceExtension->LastGoodAxis[2];
}
else if( DeviceExtension->LastGoodAxis[2] < (DeviceExtension->button5limit>>1) )
{
LocalBuffer.Button[4] = BUTTON_ON;
}
}
else
{
Idx = DeviceExtension->nButtons;
}
/*
* Copy all standard buttons
*/
while( Idx-- )
{
LocalBuffer.Button[Idx] = DeviceExtension->LastGoodButton[Idx];
}
}
C_ASSERT( sizeof( *pHIDData ) == sizeof( LocalBuffer ) );
RtlCopyMemory( pHIDData, &LocalBuffer, sizeof( LocalBuffer ) );
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2, \
("HGM_Game2HID: Axes: X: %08x Y: %08x Z: %08x R: %08x", \
LocalBuffer.Axis[0], LocalBuffer.Axis[1], LocalBuffer.Axis[2], LocalBuffer.Axis[3] ) ) ;
HGM_DBGPRINT( FILE_HIDJOY | HGM_BABBLE2, \
("HGM_Game2HID: P1: %d P2: %d Buttons %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", \
LocalBuffer.hatswitch[0], LocalBuffer.hatswitch[1], \
LocalBuffer.Button[0], LocalBuffer.Button[1], LocalBuffer.Button[2], LocalBuffer.Button[3], LocalBuffer.Button[4], \
LocalBuffer.Button[5], LocalBuffer.Button[6], LocalBuffer.Button[7], LocalBuffer.Button[8], LocalBuffer.Button[9] ) ) ;
} /* HGM_Game2HID */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?