0

当我注册 RawInput 时,我检查了函数的所有返回,一切都很好。但是,当我更新它时,它会阻塞我的第一个 CPU 内核的性能并且它不能正常工作(当我检查'M'按下按钮并让它创建一个消息框,它不仅会在我按下“M”时触发,而是在我按下任何东西或移动鼠标时触发。消息框也不会出现,还有只有哔声。)这是我用来初始化它的代码:

    const ushort usageTable[] = 
    {
        InputDeviceUsage::UsageMouse,
        InputDeviceUsage::UsageKeyboard,
        InputDeviceUsage::UsageGamepad,
    };

    const ulong flagsTable[] = 
    {
        mouseFlags,
        keyboardFlags,
        hidFlags
    };

    const List<SystemDevices>& systemDevices = EnumerateSystemDevices();

    List<String> deviceNames;
    List<InputDeviceInfo> deviceInfo;

    for(uint i = 0; i < systemDevices.Size(); i++)
    {
        deviceNames.Add(GetDeviceName(systemDevices[i].hDevice));
        deviceInfo.Add(GetDeviceInfo(systemDevices[i].hDevice));

        InputDevice device = 
        {
            InputDeviceUsagePage::UsagePageHID,
            usageTable[deviceInfo[i].dwType],
            flagsTable[deviceInfo[i].dwType],
            window
        };

        RegisteredDevices.Add(device);
        Devices[systemDevices[i].hDevice] = CreateDevice(deviceInfo[i].dwType);

其中 List 等效于std::vector<>,这些是涉及的 typedef 和定义:

enum InputDeviceUsagePage
{
    UsagePageHID = 0x01
};

enum InputDeviceUsage 
{
    UsageMouse = 0x02,
    UsageKeyboard = 0x06,
    UsageGamepad = 0x04
};

enum InputDeviceType
{
    TypeMouse = RIM_TYPEMOUSE,
    TypeKeyboard = RIM_TYPEKEYBOARD,
    TypeHID = RIM_TYPEHID
};

enum InputDeviceChangeBehavior
{
    Arrival = GIDC_ARRIVAL,
    Removal = GIDC_REMOVAL
};

enum InputDeviceDataRequest
{
    PreparseData =  RIDI_PREPARSEDDATA,
    Name =  RIDI_DEVICENAME,
    Info = RIDI_DEVICEINFO 
};

这是更新功能:

    try
    {
        InputData data;
        RawDevice::UpdateUnbuffered(reinterpret_cast<HRAWINPUT>(lparam), &data);

        DevicePtr it = Devices[data.header.hDevice];

        if(it == nullptr)
        {   
            DevicePtr newDevice = CreateDevice(data.header.dwType);

            Devices.Add(data.header.hDevice, newDevice);

            if(data.header.hDevice != null) 
            {
                it = newDevice;
            }
        }

        DevicePtr device = it;

        device->Read(data);

        switch(data.header.dwType) 
        {
            case InputDeviceType::TypeMouse:
                {
                    const RawMouse& mouse = static_cast<RawMouse&>(*device);

                    //TODO: add event handling here
                    break;
                }

            case InputDeviceType::TypeKeyboard:
                {
                    const RawKeyboard& keyboard = static_cast<RawKeyboard&>(*device);

                    //TODO: add event handling here
                    break;
                }

            case InputDeviceType::TypeHID:
                {
                    const RawHID& hid = static_cast<RawHID&>(*device);

                    //TODO: add event handling here
                    break;
                }

            default:
                {

                }
        }   
        return(exit_success);
    }
    catch(...)
    {
        return(DefWindowProc(window, message, wparam, lparam));
    }

因此,例如在有//TODO: 添加事件处理的地方我放了:

            case InputDeviceType::TypeKeyboard:
                {
                    const RawKeyboard& keyboard = static_cast<RawKeyboard&>(*device);

                    if(keyboard.KeyDown('M'))
                    {
                        MessageBox(window, L"Pressed key is 'M'", L"Input event", MB_OK);
                    }
                    break;
                }

每次按下鼠标上的任何键或任何按钮时都会发出哔声,不仅是 M,而且消息框也不显示,窗口只是哔哔声。CPU 内核被加载到最大值。这是KeyDown( )功能:

const bool RawKeyboard::KeyDown(ushort key) const
{
    if(_data.VKey == key && !(_data.Flags & KeyActions::KeyDown))
    {
        return(true);
    }
    {
        return(false);
    }
}

DevicePtr基本上是一个RawDevice*,它包含一个名称和DeviceInfo,并且从RawDevice继承RawMouseRawKeyboardRawHID,其中包含名为_data的RAWMOUSERAWKEYBOARDRAWHID成员。

编辑:只是添加调用更新的地方:

            case WM_INPUT:
                {
                    return(_input.Update(_mainWindow.GetHandle(), message, wparam, lparam));
                }
                break;

EDIT2:忘记添加 ReadUnbuffered 方法:

    void RawDevice::UpdateUnbuffered(const HRAWINPUT rawInput, RAWINPUT* data)
    {
        wint64 size(sizeof(RAWINPUT));

        boolresult = GetRawInputData(rawInput, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));

        if(result == false)
        {
            throw RawInputException(GetLastError(), L"GetRawInputData()");
        }
    }
4

1 回答 1

0

您的消息循环需要在更新您的应用程序之前处理队列中的所有消息。

听起来您正在弹出第一条消息,切换到您的应用程序。填充味精队列,收到一条消息,再填充队列......你明白了

于 2014-03-18T18:41:27.123 回答