我正在尝试使用简单的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;
}
我现在的新问题是: 你如何模拟长按键?我希望目标窗口的行为就像用户按下按键一样。使用上面的代码,密钥只发出一次。
答案 0 :(得分:0)
GetRawInputData()
将HRAWINPUT
句柄作为输入。您可以获得该处理的唯一位置来自WM_INPUT
窗口消息的LPARAM
参数。
您的main()
函数需要使用CreateWindow/Ex()
来创建一个窗口(如果您不希望用户看到它,请考虑制作一个message-only window),在该窗口中指定该窗口当您调用RegisterRawInputDevices()
时,操纵杆的RAWINPUTDEVICE::hwndTarget
字段,然后运行消息循环,以便窗口可以接收消息。例如:
#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()
而不是原始输入。