Как получить ввод мыши и клавиатуры в Windows - PullRequest
0 голосов
/ 10 апреля 2020

Не совсем вопрос, но я не знал, как / где его опубликовать.

Я искал более свежий способ захвата ввода с клавиатуры и мыши в моей программе и наткнулся на множество наполовину решения и попробуйте эту ссылку и даже загляните в документы MSDN, что привело меня в уныние. Сырая клавиатура ввода, кажется, работает, но мышь не дает ничего очевидного с помощью щелчков мыши или движения. Я собираюсь рассказать о том, как использовать dinput для sh получения входных данных. ИМХО, это лучшее, потому что у него нет задержки удержания клавиш из настроек Windows, а dinput8 включен в Windows 10 SDK. Вот упрощенная версия моей программы, которая должна объяснить, что вам нужно делать. Этот API не работает с программированием на XBox, и есть XInput для всех других типов «игровых» устройств, которые вы, возможно, должны учитывать. Для клавиатуры и мыши используйте dinput8, поскольку он все еще работает через 20 лет.

Включите заголовок dinput C: \ Program Files (x86) \ Windows Kits \ 10 \ Include \ 10.0.18362.0 \ um

#include <dinput.h>

Библиотека находится в C: \ Program Files (x86) \ Windows Kits \ 10 \ Lib \ 10.0.18362.0 \ xm или x64 в зависимости от вашей сборки.

Вам потребуется настроить обратный вызов в вашем main.exe для перечисления устройств. Хотя ваш не будет выглядеть точно так же, как мой, вы получите представление о том, что вам нужно делать. По какой-то причине я получаю четыре предмета назад; две клавиатуры и две мыши. Я должен использовать generi c названные "Keyboard" и "Mouse". Я предполагаю, что это низкоуровневые Windows имена для двух устройств.

bool CALLBACK InputEnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{
    // making instance of an object that holds the device information.
    // items to note are the lpddi->guidInstance and the instance name.
    CDeviceInstance* deviceInstance = new CDeviceInstance((GUID*)&lpddi->guidInstance, lpddi->tszInstanceName);

    // need to save the device items to some kind of list
    globalObjects->inputDevice->devices->Add(deviceInstance, deviceInstance->instanceName->GetText());

    return true;
}

Затем вам нужно создать интерфейс для dinput

hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinput, nullptr);

Использовать этот ссылочный указатель перечислить подключенные устройства. Обратите внимание, что это то, что вызывает функцию обратного вызова, определенную ранее.

globalObjects->inputDevice->dinput->EnumDevices(DI8DEVCLASS_ALL, (LPDIENUMDEVICESCALLBACK)InputEnumCallback, nullptr, DIEDFL_ATTACHEDONLY);

Теперь создайте объекты мыши и клавиатуры.

// The mouse
void CMouseDevice::MakeMouse(const char* m)
{
    // searching the list from the enumeration
    CLinkListNode<CDeviceInstance>* lln = inputDevice->devices->Search(m);

    if (lln == nullptr)
    {
        return;
    }

    // creating the device from the guidInstance
    hr = inputDevice->dinput->CreateDevice(lln->element->guidInstance, &device, nullptr);

    if (hr < 0)
    {
        errorLog->WriteError("CMouseDevice::MakeMouse::CreateDevice:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    //  window->hWnd is the window handle
    hr = device->SetCooperativeLevel(window->hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);

    if (hr < 0)
    {
        errorLog->WriteError("CMouseDevice::MakeMouse::SetCooperativeLevel:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    hr = device->SetDataFormat(&c_dfDIMouse);

    if (hr < 0)
    {
        errorLog->WriteError("CMouseDevice::MakeMouse::SetDataFormat:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    hr = device->Acquire();

    if (hr < 0)
    {
        errorLog->WriteError("CMouseDevice::MakeMouse::Acquire:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }
}

// The keyboard - same idea as the mouse
void CKeyboardDevice::MakeKeyboard(const char* dn)
{
    CLinkListNode<CDeviceInstance>* lln = inputDevice->devices->Search(dn);

    if (lln == nullptr)
    {
        return;
    }

    hr = inputDevice->dinput->CreateDevice(lln->element->guidInstance, &device, nullptr);

    if (hr < 0)
    {
        errorLog->WriteError("CKeyboardDevice::MakeKeyboard::CreateDevice:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    hr = device->SetCooperativeLevel(window->hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);

    if (hr < 0)
    {
        errorLog->WriteError("CKeyboardDevice::MakeKeyboard::SetCooperativeLevel:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    hr = device->SetDataFormat(&c_dfDIKeyboard);

    if (hr < 0)
    {
        errorLog->WriteError("CKeyboardDevice::MakeKeyboard::SetDataFormat:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }

    hr = device->Acquire();

    if (hr < 0)
    {
        errorLog->WriteError("CKeyboardDevice::MakeKeyboard::Acquire:%s\n", errorLog->GetComErrorMessage(hr));

        return;
    }
}

И, наконец, вот как вы читаете мышь и клавиатуру. Поместите эти два вызова функций в верхней части основного l oop, чтобы вы могли захватить пользовательский ввод.

Мышь

// the mouse state
// the DIMOUSESTATE structure has the x,y position changes and z for the scroll wheel
// you can use x and y to help with camera rotations if you are doing 3d
hr = device->GetDeviceState(sizeof(DIMOUSESTATE), &state);

// loop through the state items to see what buttons on the mouse are down
// It will read all the buttons.  There is DIMOUSESTATE2 which holds eight buttons.
for (UINT k = 0; k < CMouseDevice::BUTTON_COUNT; k++)
{
    // is the mouse button down
    if (state.rgbButtons[k])
    {
        keyMap[k]->nbr = k;
        keyMap[k]->count++;
    }
    else
    {
        keyMap[k]->count = 0;
    }
}

Клавиатура

// the keyboard state - KEY_COUNT = 256
hr = device->GetDeviceState(CKeyboardDevice::KEY_COUNT, &keys);

// you can loop through your keys just like the mouse buttons
for (UINT k = 0;k < CKeyboardDevice::KEY_COUNT;k++)
{
    // is the key down
    if (keys[k])
    {
        keyMap[k]->nbr = k;
        keyMap[k]->count++;
    }
    else
    {
        keyMap[k]->count = 0;
    }
}

Указатель на ссылку на устройство является переменной-членом в объектах моих программ, поэтому убедитесь, что они уникальны в ваших. Мышь и клавиатура являются клавишами прямого ввода, а не виртуальными клавишами, поэтому при тестировании на нажатие клавиши обязательно используйте клавишу DIK_ (клавиша прямого ввода), определенную в dinput.h

Обязательно отпустите устройства, когда закрытие основной программы.

if (device)
{
    device->Release();
    device = 0;
}

Вот и все для dinput, и я надеюсь, что этот пост поможет всем, кто переживает нежелательные необработанные функции ввода для мыши и клавиатуры. Большое спасибо Microsoft за сохранение API dinput8.lib все эти годы, включая Windows 10.

Happy Coding!

...