windows c++禁用/启动HID设备(鼠标、键盘、触摸屏等)

背景

要通过代码来控制触摸屏的触控功能的开关,由于触摸屏触摸功能是通过HID协议来实现的,故想通过HID协议相关库来启用/禁用设备管理器中的HID触摸屏设备。

折腾过程如下

  • 试图通过hidapi来实现,发现hidapi中只能读取或发送数据
  • 查找HID相关的库,找到一个libhid的库,但发现其也没有启用/禁用接口
  • 尝试使用windows api来控制,也就有了下面的内容

环境

Qt 5.12.2 mingw64位 windows11

主要函数介绍

注意:SetupDiChangeState接口中使用的句柄和设备信息必须是对应的,即下文的SP_DEVINFO_DATA 必须是由传入的句柄所得到的。具体可以点击上面的接口查看具体的传入参数。

代码设计思路与实现

获取HID devices class的句柄集

    // 获取HID设备类的GUID
    GUID guid;
    HidD_GetHidGuid(&guid);

    // 获取HID设备类的句柄集
    HID_CONTROL_HANDLE = SetupDiGetClassDevs(&guid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

遍历设备接口,根据vid, pid匹配对应的设备

// 循环查找目标设备
    unsigned i = 0;

    SP_DEVINFO_DATA devData;
    devData.cbSize = sizeof (SP_DEVINFO_DATA);
    while(1)
    {
        SP_DEVICE_INTERFACE_DATA devInterface;
        devInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        if( !SetupDiEnumDeviceInterfaces(handle, nullptr, &guid, i, &devInterface) )
        {
            DWORD error = GetLastError();
            if(i > 0 && error > 0 && error != 259){ // 259 代表没有更多数据

                qCritical() << "设备接口枚举失败!错误代码:" << error;
            }
            break;
        }
        ++i;

        // 获取设备细节结构体缓冲区的大小,同时获取设备信息SP_DEVINFO_DATA
        DWORD size;
        if( !SetupDiGetDeviceInterfaceDetail(handle, &devInterface, nullptr, 0, &size, &devData) && (122 != GetLastError()))
        {
            qCritical() << "获取设备细节结构体缓冲区大小失败!错误代码:" << GetLastError();
            break;
        }

        //  获取设备细节信息(其中仅包含设备实例路径, 设备实例路径是唯一的)
        auto_free<SP_DEVICE_INTERFACE_DETAIL_DATA> detail((SP_DEVICE_INTERFACE_DETAIL_DATA*)malloc(size));
        detail.get()->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
        if( !SetupDiGetDeviceInterfaceDetail(handle, &devInterface, detail.get(), size, nullptr, &devData) )
        {
            qCritical() << "获取设备实例路径失败!错误代码:" << GetLastError();
            break;
        }

        // 根据设备实例路径判断设备唯一性
        tstring str = tstring(detail->DevicePath);
        if(judgePath(detail->DevicePath, vid, pid)) 	//匹配vid, pid
        {
            DeviceInfo info;
            info.devInfoData = devData;
            info.devPath = stringFromTCHAR(detail->DevicePath);
            devInfos.push_back(info);
        }
    }

设备状态控制

 bool excuteStatus = false;
    if(!devices.empty())
    {
        foreach( auto device, devices){
            SP_PROPCHANGE_PARAMS propChange;
            propChange.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
            propChange.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
            propChange.Scope = DICS_FLAG_GLOBAL;
            propChange.StateChange = enable ? DICS_ENABLE : DICS_DISABLE;

            DeviceFeature feature = device->getDeviceFeature();
            if ( SetupDiSetClassInstallParams(HID_CONTROL_HANDLE, &feature.devInfoData, &propChange.ClassInstallHeader, sizeof (propChange) ) )
            {
                if (SetupDiChangeState(HID_CONTROL_HANDLE, &feature.devInfoData))
                {
                    excuteStatus = true;
                }
                else {
                    excuteStatus = false;
                    DWORD errror = GetLastError();
                    qCritical() << "状态改变执行失败!错误代码:" << errror;
                }
            }
            else
            {
                excuteStatus = false;
                DWORD error = GetLastError();
                qCritical() << "设置安装参数失败!错误代码:" << error;
            }
        }
    }
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值