【问题标题】:getrawinputdata within a simple main()简单 main() 中的 getrawinputdata
【发布时间】:2018-03-30 09:46:44
【问题描述】:

我正在尝试使用简单的 C++ 技术和 Windows 从操纵杆中读取值。 我的目标是编写一个程序,只要操纵杆信号超过预定义的阈值,它就会发送键盘命令。键盘命令将被当时处于活动状态的任何窗口拾取。

我的 C++ 编码技能有限,所以我希望以最简单的方式完成此操作,最好在一个 main() 内完成。

到目前为止,我已经成功注册了操纵杆。​​p>

但我偶然发现了第一个问题,即如何使用 GetRawInputData()。我在 win32 结构中找到了很多关于此的示例,但我正在努力将其转换为简单的 main()。

到目前为止,我的代码如下:

#include <windows.h>
#include <iostream>

RAWINPUTDEVICE Rid[1];

int main()
{
    UINT      bufferSize;

    Rid[0].usUsagePage = 0x01;
    Rid[0].usUsage = 0x05;
    Rid[0].dwFlags = 0;
    Rid[0].hwndTarget = 0;

    if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE)
    {
        std::cout << "Registration failed" << std::endl;
        return 1;
    }
    else
    {
        std::cout << "Registration OK" << std::endl;

        while (1)
        {
            // This is the part in which I would like to read the joystick values
            // and determine whether to send a keyboard event or not.
        }


    }

    return 0;

}

你能帮忙吗?

谢谢。

更新

按照使用joyGetInput()的建议,这里是更新的代码:

#include<Windows.h>
#include<iostream>
#include<time.h>

using namespace std;

#define mid 32767
#define trig 1804
#define reset 1475

int main()
{

    JOYINFO pos;

    UINT result;
    SYSTEMTIME st;
    INPUT xi, yi, zi;

    int i = 0;
    int state[6] = { 0,0,0,0,0,0 };
    int uu = mid + trig;
    int ul = mid + reset;

    xi.type = INPUT_KEYBOARD;
    yi.type = INPUT_KEYBOARD;
    zi.type = INPUT_KEYBOARD;

    while (1)
    {
        result = joyGetPos(i, &pos);

        if (result != JOYERR_NOERROR)
        {
            cout << "JoyID " << i << " returned an error. Trying the next one." << endl;
            i++;
            if (i > 15)
            {
                cout << "Reached the maximum allowed attempts. Exiting." << endl;
                return 1;
            }               
        }
        else
        {
            //GetSystemTime(&st);

            //cout << st.wHour << ":" << st.wMinute << ":" << st.wSecond << ":" << st.wMilliseconds <<  "\tX: " << pos.wXpos << "\tY: " << pos.wYpos << "\tZ: " << pos.wZpos << endl;

            if (pos.wXpos > uu && state[0] == 0)
            {
                xi.ki.wVk = 0x30;
                xi.ki.dwFlags = 0;
                SendInput(1, &xi, sizeof(INPUT));
                state[0] = 1;
                GetSystemTime(&st);
                cout << "Key down - X axis" << endl;
                cout << st.wHour << ":" << st.wMinute << ":" << st.wSecond << ":" << st.wMilliseconds << "\tX: " << pos.wXpos << "\tY: " << pos.wYpos << "\tZ: " << pos.wZpos << endl;
            }
            if (pos.wXpos < ul && state[0] == 1)
            {
                xi.ki.wVk = 0x30;
                xi.ki.dwFlags = KEYEVENTF_KEYUP;
                SendInput(1, &xi, sizeof(INPUT));
                state[0] = 0;
                GetSystemTime(&st);
                cout << "Key up - X axis" << endl;
                cout << st.wHour << ":" << st.wMinute << ":" << st.wSecond << ":" << st.wMilliseconds << "\tX: " << pos.wXpos << "\tY: " << pos.wYpos << "\tZ: " << pos.wZpos << endl;
            }
        }
    }

    return 0;
}

我现在的新问题是: 你如何模拟长按键?我希望目标窗口的行为就像用户不断按下键一样。使用上面的代码,密钥只发出一次。

【问题讨论】:

  • 不需要导入整个std命名空间,这样你就可以在没有std::前缀的情况下使用cout

标签: c++ keyboard hid raw-input


【解决方案1】:

GetRawInputData()HRAWINPUT 句柄作为输入。唯一可以获得该句柄的地方是WM_INPUT 窗口消息的LPARAM 参数。

您的main() 函数需要使用CreateWindow/Ex() 创建一个窗口(如果您不希望用户看到它,请考虑创建一个message-only window),在操纵杆的RAWINPUTDEVICE::hwndTarget 字段中指定该窗口时你打电话给RegisterRawInputDevices(),然后运行一个消息循环,这样窗口就可以接收消息了。例如:

#include <windows.h>
#include <iostream>

int main()
{
    WNDCLASSEX wx = {};
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = DefWindowProc;
    wx.hInstance = GeteModuleHandle(NULL);
    wx.lpszClassName = TEXT("MyRawInputWndClass");

    if (!RegisterClassEx(&wx))
    {
        std::cout << "Window Class Registration failed" << std::endl;
        return 1;
    }

    HWND hWnd = CreateWindowEx(0, wx.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, wx.hInstance, NULL);
    if (!hWnd)
    {
        std::cout << "Window Creation failed" << std::endl;
        return 1;
    }

    RAWINPUTDEVICE Rid = {};
    Rid.usUsagePage = 0x01;
    Rid.usUsage = 0x05;
    Rid.dwFlags = 0;
    Rid.hwndTarget = hWnd;

    if (!RegisterRawInputDevices(&Rid, 1, sizeof(RAWINPUTDEVICE)))
    {
        std::cout << "Device Registration failed" << std::endl;
        return 1;
    }

    std::cout << "Device Registration OK" << std::endl;

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (msg.message == WM_INPUT)
        {
            HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(msg.lParam);
            // retrieve and process data from hRawInput as needed...
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return 0;
}

或者:

#include <windows.h>
#include <iostream>

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (Msg == WM_INPUT)
    {
        HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(lParam);
        // retrieve and process data from hRawInput as needed...
    }

    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

int main()
{
    WNDCLASSEX wx = {};
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = &MyWndProc;
    wx.hInstance = GeteModuleHandle(NULL);
    wx.lpszClassName = TEXT("MyRawInputWndClass");

    if (!RegisterClassEx(&wx))
    {
        std::cout << "Window Class Registration failed" << std::endl;
        return 1;
    }

    HWND hWnd = CreateWindowEx(0, wx.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, wx.hInstance, NULL);
    if (!hWnd)
    {
        std::cout << "Window Creation failed" << std::endl;
        return 1;
    }

    RAWINPUTDEVICE Rid = {};
    Rid.usUsagePage = 0x01;
    Rid.usUsage = 0x05;
    Rid.dwFlags = 0;
    Rid.hwndTarget = hWnd;

    if (!RegisterRawInputDevices(&Rid, 1, sizeof(RAWINPUTDEVICE)))
    {
        std::cout << "Device Registration failed" << std::endl;
        return 1;
    }

    std::cout << "Device Registration OK" << std::endl;

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

我建议你仔细阅读Raw Input documentation。这都是详细解释的。如果您没有为RegisterRawInputDevices() 指定一个窗口,则操作系统会将WM_INPUT 消息发送到当前具有键盘焦点的任何窗口,这不是您想要的。

话虽如此,如果您想要更简单的东西,您可以考虑使用joyGetPosEx() 而不是原始输入。

【讨论】:

  • 非常感谢您提出使用 joyGetPos() 的建议。它现在正在按我的意愿工作。新代码在我的原始帖子中更新。我现在的新问题是:如何模拟长按?
  • @JayD 只是在按下键和按下键之间延迟。
  • 嗨,再次感谢。延迟不起作用。它只会显示一次密钥。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2019-09-07
  • 2012-12-31
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多