HidDevice.FromIdAsyn c () не может открыть устройство в режиме FileAccessMode :: ReadWrite в приложении Win32 - PullRequest
1 голос
/ 29 мая 2020

Я пытаюсь использовать Windows .Devices.HumanInterfaceDevice UWP API, чтобы открыть HID-устройство (в моем случае - геймпад) и отправить отчет о выходе HID. Но метод HidDevice.FromIdAsync() не может открыть устройство в режиме FileAccessMode::ReadWrite в моем классе c консольное приложение Win32:

enter image description here

Вот минимальный C ++ / WinRT Пример воспроизведения:

#include "pch.h"

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Devices.HumanInterfaceDevice.h>
#include <winrt/Windows.Storage.h>

#include <string>
#include <iostream>
#include <functional>

using namespace std;
using namespace winrt;
using namespace Windows::Devices::Enumeration;
using namespace Windows::Devices::HumanInterfaceDevice;
using namespace Windows::Storage;

void OnDeviceAdded(const winrt::Windows::Devices::Enumeration::DeviceInformation& deviceInformation)
{
    std::cout << "*****Device Init End*******" << std::endl;

    try {
        string id = to_string(deviceInformation.Id());
        string name = to_string(deviceInformation.Name());

        std::cout << "New HID device connected:" << std::endl;
        std::cout << "Id: " << id << std::endl;
        std::cout << "Name: " << name << std::endl;

        HidDevice m_Device = HidDevice::FromIdAsync(deviceInformation.Id(), FileAccessMode::ReadWrite).get();

        if (!m_Device)
        {
            std::cout << "Cannot open device for writing! Trying read-only..." << std::endl;
            m_Device = HidDevice::FromIdAsync(deviceInformation.Id(), FileAccessMode::Read).get();
        }

        if (!m_Device)
        {
            std::cout << "Cannot open device for reading!" << std::endl;
            throw;
        }

        uint16_t vendorId = m_Device.VendorId();
        uint16_t productId = m_Device.ProductId();
        uint16_t version = m_Device.Version();
        uint16_t usagePage = m_Device.UsagePage();
        uint16_t usageId = m_Device.UsageId();

        std::cout << "VendorId: " << vendorId << std::endl;
        std::cout << "ProductId: " << productId << std::endl;
        std::cout << "Version: " << version << std::endl;
        std::cout << "UsagePage: " << usagePage << std::endl;
        std::cout << "UsageId: " << usageId << std::endl;
    }
    catch (...)
    {
        std::cout << "Something went wrong while device init! :(" << std::endl;
    }

    std::cout << "*****Device Init End*******" << std::endl;
}

hstring hidDeviceSelector;
DeviceWatcher hidDeviceWatcher = nullptr;
event_token hidAddedToken;

int main()
{
    winrt::init_apartment();

    hidDeviceSelector = HidDevice::GetDeviceSelector(0x01 /*HID_USAGE_PAGE_GENERIC*/, 0x05 /*HID_USAGE_GENERIC_GAMEPAD*/);
    hidDeviceWatcher = DeviceInformation::CreateWatcher(hidDeviceSelector);
    hidAddedToken = hidDeviceWatcher.Added(std::bind(&OnDeviceAdded, std::placeholders::_2));
    hidDeviceWatcher.Start();

    while (true)
    {
        // wait
    }

    hidDeviceWatcher.Added(hidAddedToken);

    winrt::uninit_apartment();

    return 0;
}

Подобные вопросы относительно приложений UWP, в которых упоминается, что должно быть *.appxmanifest вроде этого:

 <Capabilities>
    <DeviceCapability Name="humaninterfacedevice">
      <!--SuperMutt Device-->
      <Device Id="vidpid:045E 0610">
        <Function Type="usage:FFAA 0001" />
      </Device>
    </DeviceCapability>
  </Capabilities>

Но, похоже, это необходимо только для приложений UWP.

Стоит упомянуть, что HidDevice Class имеет атрибут DualApiPartition и API должен быть разрешен для вызова из любого настольного приложения.

Это ошибка или я ' м что-то не хватает?

Мой код демонстрационного приложения C ++ / WinRT находится здесь: https://github.com/DJm00n/HidGamepadConsoleApp

...