'getrawinputdata within a simple main()

I am trying to read values from the joystick using simple C++ techniques and Windows. My aim is to write a program that sends a keyboard command whenever the joystick signal exceeds a predefined threshold. The keyboard command will be picked up by whichever window would be active at the time.

My C++ coding skills are limited so I wish to do this in the simplest way, preferably within one main().

Up to now I have managed to register the joystick.

But I stumbled across the first problem, which is how to use GetRawInputData(). I found a lot of examples about this within a win32 structure, but am struggling to translate this to a simple main().

My code till now is the following:

#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;

}

Can you help?

Thanks.

UPDATE

Following the suggestion to use joyGetInput(), here is the updated code:

#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;
}

My new question now is: How do you simulate a long key press? I would like the target window to behave just like a user kept pressing on the key. With the above code, the key is issued only once.



Solution 1:[1]

GetRawInputData() takes an HRAWINPUT handle as input. The only place you can get that handle is from the LPARAM parameter of the WM_INPUT window message.

Your main() function needs to use CreateWindow/Ex() to create a window (if you don't want the user to see it, consider making a message-only window), specify that window in the joystick's RAWINPUTDEVICE::hwndTarget field when you call RegisterRawInputDevices(), and then run a message loop so the window can receive messages. For example:

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

int main()
{
    WNDCLASSEX wx = {};
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = DefWindowProc;
    wx.hInstance = GetModuleHandle(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;
}

Alternatively:

#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 = GetModuleHandle(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;
}

I suggest you read the Raw Input documentation more carefully. This is all explained in detail. If you don't specify a window to RegisterRawInputDevices(), the OS will send the WM_INPUT messages to whichever window currently has the keyboard focus, which is not what you want.

That being said, if you want something simplier, you might consider using joyGetPosEx() instead of Raw Input.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 CristiFati