调研一台电脑连接两个键盘如何区分遇到的问题及解决方法

2023-11-13

1.查找windows API 手册,调用GetRawInputData函数,可以获得按下的键值VKey以及唯一的句柄hDevice,但是hDevice并不能直观的对应不同键盘而且每当拔下键盘,重新插入的时候hDevice会发生变化。
2.继续查找发现可以通过GetRawInputDeviceInfo函数,找到按键所对应的具体来源。函数第一个参数是设备句柄,第二个参数根据想要获得的内容填写,一开始我在第二个参数填写的是RIDI_DEVICEINFO,发现获得数值无法区分不同设备。
3.后来经过测试,填写RIDI_DEVICENAME,即读取设备名,能找出不同设备的区别,后经过对应,得到的是设备管理器对应出的设备实例路径,由此确定了唯一,并且拔下键盘后再插上,deviceName没有发生改变。

附上代码
(获取按键同时得到的信息)

::GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawinputData, &uiSize, sizeof(RAWINPUTHEADER));
    if (RIM_TYPEKEYBOARD == rawinputData.header.dwType)
    {
        // WM_KEYDOWN --> 普通按键    WM_SYSKEYDOWN --> 系统按键(指的是ALT)
        if ((WM_KEYDOWN == rawinputData.data.keyboard.Message) ||
                (WM_SYSKEYDOWN == rawinputData.data.keyboard.Message))
        {
            qDebug() << "keyboard.VKey ==" << (QChar)rawinputData.data.keyboard.VKey;
            qDebug() << "header.hDevice" << rawinputData.header.hDevice;
            
            UINT bufferSize;//为键盘设备名准备缓冲区大小
            ::GetRawInputDeviceInfo(rawinputData.header.hDevice, RIDI_DEVICENAME, NULL, &bufferSize);
            WCHAR* RawDevName = new WCHAR[bufferSize];
            ::GetRawInputDeviceInfo(rawinputData.header.hDevice, RIDI_DEVICENAME, RawDevName, &bufferSize);//将设备名读入缓冲区RawDevName
            QString devName = QString::fromWCharArray(RawDevName);
            qDebug() << "dev ===" << devName;
            delete[] RawDevName;
            
            //            RID_DEVICE_INFO device_info;
            //            UINT info_size (sizeof (RID_DEVICE_INFO));
            //            if (GetRawInputDeviceInfo (rawinputData.header.hDevice,
            //                                       RIDI_DEVICEINFO, (LPVOID)&device_info, &info_size) == info_size)
            //            {
            //                DWORD errorCode1 = GetLastError();
            //                qDebug()<<"errorCode1 = "<<errorCode1;
            //                if (device_info.dwType == RIM_TYPEKEYBOARD)
            //                {
            //                    qDebug()<<"device_info dwType= "<<device_info.keyboard.dwType;
            //                }
            //            }
        }
    }

(获取所有设备详情)

int MainWindow::GetUSBDeviceInfos(QList<USB_INFO> &infos)
{
    infos.clear();

    bool ok;
    QString str;
    USB_INFO info;
    HDEVINFO hDevInfo;
    SP_DEVINFO_DATA DeviceInfoData;
    WCHAR buffer[INTERFACE_DETAIL_SIZE] = { 0 };

    if ((hDevInfo = SetupDiGetClassDevs(NULL, L"USB", 0, DIGCF_PRESENT | DIGCF_ALLCLASSES)) == INVALID_HANDLE_VALUE){
        // Insert error handling here.
        return 0;
    }

    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    // 设备序号=0,1,2... 逐一测试设备接口,到失败为止
    for (int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i,
                                          &DeviceInfoData); i++)
    {
        DWORD DataT;
        DWORD buffersize = 0;
        if(!SetupDiGetDeviceRegistryProperty(
                    hDevInfo,
                    &DeviceInfoData,
                    SPDRP_HARDWAREID,
                    &DataT,
                    (PBYTE)buffer,
                    INTERFACE_DETAIL_SIZE,
                    &buffersize))
        {
            continue;
        }

        str = QString::fromWCharArray(buffer, wcslen(buffer));
        info.vid = str.mid(str.indexOf("VID") + 4, 4).toULong(&ok, 16);
        info.pid = str.mid(str.indexOf("PID") + 4, 4).toULong(&ok, 16);

        memset(buffer, 0, INTERFACE_DETAIL_SIZE);
        if (!SetupDiGetDeviceRegistryProperty(
                    hDevInfo,
                    &DeviceInfoData,
                    SPDRP_DEVICEDESC,           // 设备描述信息
                    &DataT,
                    (PBYTE)buffer,
                    INTERFACE_DETAIL_SIZE,
                    &buffersize))
        {
            continue;
        }
        info.desc = QString::fromWCharArray(buffer);

        memset(buffer, 0, INTERFACE_DETAIL_SIZE);
        if (!SetupDiGetDeviceRegistryProperty(
                    hDevInfo,
                    &DeviceInfoData,
                    SPDRP_LOCATION_INFORMATION,          // LocationInformation (R/W)
                    &DataT,
                    (PBYTE)buffer,
                    INTERFACE_DETAIL_SIZE,
                    &buffersize))
        {
            continue;
        }
        info.locationInfo = QString::fromWCharArray(buffer);

        memset(buffer, 0, INTERFACE_DETAIL_SIZE);
        if (!SetupDiGetDeviceRegistryProperty(
                    hDevInfo,
                    &DeviceInfoData,
                    SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,          //  PhysicalDeviceObjectName (R)
                    &DataT,
                    (PBYTE)buffer,
                    INTERFACE_DETAIL_SIZE,
                    &buffersize))
        {
            continue;
        }
        info.devName = QString::fromWCharArray(buffer);

        memset(buffer, 0, INTERFACE_DETAIL_SIZE);
        if (!SetupDiGetDeviceRegistryProperty(
                    hDevInfo,
                    &DeviceInfoData,
                    SPDRP_CLASSGUID,         //  ClassGUID (R/W)
                    &DataT,
                    (PBYTE)buffer,
                    INTERFACE_DETAIL_SIZE,
                    &buffersize))
        {
            continue;
        }
        info.guid = QString::fromWCharArray(buffer);

        ULONG pulStatus;
        ULONG pulProblemNumber;
        CM_Get_DevNode_Status(&pulStatus, &pulProblemNumber, DeviceInfoData.DevInst, 0);

        if((pulStatus & DN_HAS_PROBLEM) && !(pulStatus & DN_DRIVER_LOADED))
        {
            info.enable = false;
        }else
        {
            info.enable = true;
        }

        qDebug() << "设备启用标志 ===="<< info.enable;
        qDebug() << "产品ID ===="<< info.vid;
        qDebug() << "厂商ID ===="<< info.pid;
        qDebug() << "设备描述信息 ===="<< info.desc;
        qDebug() << "LocationInformation ===="<< info.locationInfo;
        qDebug() << "PhysicalDeviceObjectName ==" << info.devName;
        qDebug() << "ClassGUID (R/W) ==" << info.guid;
        infos.append(info);
    }

    //  Cleanup
    SetupDiDestroyDeviceInfoList(hDevInfo);

    return 0;
}

将两段代码整合,通过设备实例ID部分内容对应

BOOL GetDeviceInstanceId(HDEVINFO hDevInfo, SP_DEVINFO_DATA* DeviceInfoData,PWSTR strID)
{
    DWORD iRequiredSize = 0;
    int iSize = 0;
    BOOL b = SetupDiGetDeviceInstanceId(hDevInfo, DeviceInfoData, strID, iSize, &iRequiredSize);

    iSize = iRequiredSize;

    b = SetupDiGetDeviceInstanceId(hDevInfo, DeviceInfoData, strID, iSize, &iRequiredSize);

    if (true == b)
    {
        return TRUE;
    }
    return FALSE;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调研一台电脑连接两个键盘如何区分遇到的问题及解决方法 的相关文章

  • .NET 或 Windows 同步原语性能规范

    我目前正在写一篇科学文章 我需要非常准确地引用 有人可以向我指出 MSDN MSDN 文章 一些已发表的文章来源或一本书 我可以在其中找到 Windows 或 NET 同步原语的性能比较 我知道这些是按性能降序排列的 互锁 API 关键部分
  • 有什么工具可以了解 Windows 中正在运行的进程的布局(段)?

    我一直很好奇 该进程在内存中到底是什么样子的 其中有哪些不同的部分 部分 程序 在磁盘上 和进程 在内存中 到底是如何相关的 我之前的问题 有关可执行程序 进程 的内存布局的更多信息 https stackoverflow com ques
  • 尝试使用 C++ 创建一个计划任务运行一次,win7 上的任务计划程序 1.0

    我正在尝试创建一个非常简单的程序 它将在两分钟后运行记事本 这些都经过简化以提出更清晰的问题 我尝试合并一些MSDN 的例子 http msdn microsoft com en us library windows desktop aa3
  • 批处理文件 - 读取特定行,并将该行中的特定字符串保存为变量

    有没有办法让 for f 循环 或其他任何东西 读取特定行 这是我到目前为止的代码 它读取每一行的第一个单词 echo off set file readtest txt for f tokens 1 delims A in file do
  • 使用 GDI+ 和 C++ 减少闪烁

    我在 C MFC 应用程序中使用 GDI 每当调整窗口大小时 我似乎都无法避免闪烁 我已经尝试过以下步骤 返回 TRUEOnEraseBkGnd 返回 NULLOnCtlColor 根据此代码使用双缓冲 void vwView OnDraw
  • 如何在以管理员身份运行模式下部署应用程序?

    如何部署应用程序 使其需要管理员权限 而无需最终用户手动执行此操作 我使用 Delphi 2009 来构建该应用程序 您可以使用以下命令通知 Windows 您的应用程序需要以管理员身份运行requestedExecutionLevel应用
  • 当前有哪些 USB 设备(友好名称)连接到 PC?

    我可以获得当前连接到计算机的设备列表吗 我检查了this https stackoverflow com q 3331043 75500 and this https stackoverflow com questions 3685615
  • 无法在 Eclipse 中运行 SDL 程序,但可以在 Windows 资源管理器中运行

    我已经安装并设置了 SDL 并设法获得了一个要构建的教程示例 教程代码来自http zamma co uk setup sdl2 eclipse windows http zamma co uk setup sdl2 eclipse win
  • xampp openssl 调用 openssl_pkey_new() 时出错;

    所以我试图让 openssl 在我的 Windows 安装的 xampp 1 7 3 上工作 它是用 OpenSSL 0 9 8l 构建的 这只是我第二次在 amp 安装上安装 openssl 但第一次进展顺利 这是在同一台机器上的 wam
  • 从具有不同活动 perl 版本的另一个 perl 脚本调用 perl 函数

    我们有两个版本的 Active perl 5 6 和 5 24 我们有必须在 Active perl 5 24 版本 采用 TLS 1 2 版本 上执行的 Web 服务 并且需要从 Active perl 5 6 版本调用 我们使用的是wi
  • C++中最大化窗口时的问题

    我的程序需要任意最大化当前桌面上的任何窗口 我通过调用来实现这一点ShowWindow hWnd SW MAXIMIZE 其中 hWnd 是HWND我想要最大化的窗口 当该行代码执行时 相关窗口 此处为记事本 如下所示 一切看起来都很好 除
  • 使用 DEF 文件而不是 LIB 文件链接到 DLL?

    我了解到你可以 将 DLL 文件转换为 DEF文件 其中包括其导出 编辑 这不适用于许多约定 转换一个 DEF文件转换为 LIB 文件 您可以使用该文件链接到 DLL 为什么 大多数 链接器不能链接到给定的 DLLonly DEF 文件 而
  • 谁能推荐适用于 Windows 的磁盘 I/O 基准测试软件?

    我想测试文件系统在不同条件下的性能 具体来说 我想在 普通硬盘 和 USB 磁盘上测试未压缩和压缩的 Windows 虚拟机的性能 因为确切了解差异是什么会很有趣 我需要的是一个可以测试文件系统不同方面的程序 随机访问 顺序读 写等 并制作
  • 从 Windows 命令行打印 PDF

    我正在尝试打印当前目录中的所有 pdf 文件 当我在 cmd 中调用这个 bash 脚本时 singlepdf sh C Program Files x86 Adobe Reader 10 0 Reader AcroRd32 exe t G
  • 如何在 Windows 中利用 RDMA

    如何使用 RDMA 将内存块从一台服务器复制到 Windows 下的另一台服务器 我们没有 infiniband 但我们有 10GB 网络交换机 我所需要的只是一个例子 但我在谷歌上运气不佳 EDIT 好吧 到目前为止还没有人回答我的问题
  • os.path.expanduser("~") 的替代方案?

    在Python 2 7 x中 os path expanduser Unicode 已损坏 这意味着如果 的扩展中包含非 ASCII 字符 则会出现异常 http bugs python org issue13207 http bugs p
  • 发送和接收 Windows 消息

    Windows 消息似乎是通知 Windows 操作系统上的应用程序的好方法 它实际上运作良好 但我想到了几个问题 How to指定结构化数据lparamSendMessage 例程 就像许多消息代码一样 我的意思是 参数当然是一个指针 但
  • Windows BlockInput 功能不起作用

    Why BlockInput不工作 include
  • 如何用 Java 制作 Windows 7 工具提示

    我一直在网上到处寻找 但没有找到这个小问题的答案 在 Windows 7 中 我认为在 Vista 中 您有一个漂亮的圆形银色工具提示 它看起来比旧的黄色盒装蹩脚工具提示要好得多 下面的 How do I make a Windows 7
  • Windows 程序如何临时更改其时区?

    我写了一个函数来返回time t与给定日期的午夜相对应的值 当给定日期没有午夜时 它返回最早可用的时间 例如 当埃及进入夏令时时 这种情况就可能发生 今年 时间更改于 4 月 29 日晚上午夜生效 因此时钟直接从 23 59 转到 01 0

随机推荐