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 + -
显示快捷键?