为什么有时不捕获输入事件,在 C++ 中
why input events are not being captured at sometimes, in c++
#include <Windows.h>
#include <vector>
using std::vector;
class event_handler{
private:
DWORD n_evnts_read=0,n_evnts=0,evnt_type=0,mode=0;
public:
int rec_indx = 0;
vector<INPUT_RECORD> inrec;
KEY_EVENT_RECORD kev;
MOUSE_EVENT_RECORD mev;
HANDLE hndlin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hndlout = GetStdHandle(STD_OUTPUT_HANDLE);
int cap_evnt_key(){
n_evnts_read = n_evnts = evnt_type = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts_read);
if (n_evnts_read){
inrec.resize(n_evnts_read);
ReadConsoleInput(hndlin, &inrec[0], inrec.size(), &n_evnts);
for(DWORD m = 0; m < n_evnts; m++)
if (inrec[m].EventType == KEY_EVENT)
{
kev = inrec[m].Event.KeyEvent;
fflush(stdin);
return 5;
}
}
return -1;
}
int cap_evnt_mouse(){
n_evnts_read = n_evnts = evnt_type = mode = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts_read);
if (n_evnts_read){
inrec.resize(n_evnts_read);
ReadConsoleInput(hndlin, &inrec[0], inrec.size(), &n_evnts);
for(DWORD m = 0; m < n_evnts; m++)
if (inrec[m].EventType == MOUSE_EVENT)
{
mev = inrec[m].Event.MouseEvent;
fflush(stdin);
return 5;
}
}
return -1;
}
DWORD key(){
if (!kev.bKeyDown)
return kev.wVirtualKeyCode;
else
return 0;
}
bool left_click(){
if (mev.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
return 1;
else
return 0;
}
} evnt_hndlr;
void test()
{
short n = 0;
COORD pos;
while (1)
{
if (evnt_hndlr.cap_evnt_key() == 5)
{
if (evnt_hndlr.key() == VK_RIGHT)
//do something
else if (evnt_hndlr.key() == VK_LEFT)
//do something
}
else if (evnt_hndlr.cap_evnt_mouse() == 5)
{
if (evnt_hndlr.left_click() == 1)
//do something
}
}
exit(0);
}
现在,当我在 main()
中 运行 test()
并尝试捕获一个 mouse/keyboard 事件时,有时它会给我一个信号,表明所需的事件已被捕获,但有时它会错过那个事件。
请给我一个可靠的捕获输入事件的方法(特别是当需要同时读取鼠标和键盘事件时),因为这个程序挂了(如果我没有使用错误的话)。另外,请向我解释为什么会出现此问题。这对用户来说确实很糟糕。
您没有处理读取的每个事件。您的代码有可能丢弃很多事件。每次调用 cap_evnt_...()
时,如果有任何新事件可供读取,则将已读取的所有事件丢弃到 vector
中但尚未处理。
尝试更像这样的东西:
#include <Windows.h>
#include <vector>
class event_handler{
private:
std::vector<INPUT_RECORD> evnts;
INPUT_RECORD inrec;
HANDLE hndlin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hndlout = GetStdHandle(STD_OUTPUT_HANDLE);
public:
int cap_evnt_read() {
if (evnts.empty()) {
DWORD n_evnts = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts);
if (n_evnts == 0) return -1;
evnts.resize(n_evnts);
ReadConsoleInput(hndlin, &evnts[0], n_evnts, &n_evnts);
}
inrec = evnts.front();
evnts.erase(events.begin());
return inrec.EventType;
}
DWORD key() const {
if (!inrec.Event.KeyEvent.bKeyDown)
return inrec.Event.KeyEvent.wVirtualKeyCode;
else
return 0;
}
bool left_click() const {
return (inrec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED);
}
}
evnt_hndlr;
void test()
{
while (true)
{
switch (evnt_hndlr.cap_evnt_read())
{
case KEY_EVENT:
{
if (evnt_hndlr.key() == VK_RIGHT)
// do something
else if (evnt_hndlr.key() == VK_LEFT)
// do something
break;
}
case MOUSE_EVENT:
{
if (evnt_hndlr.left_click())
// do something
break;
}
}
}
exit(0);
}
#include <Windows.h>
#include <vector>
using std::vector;
class event_handler{
private:
DWORD n_evnts_read=0,n_evnts=0,evnt_type=0,mode=0;
public:
int rec_indx = 0;
vector<INPUT_RECORD> inrec;
KEY_EVENT_RECORD kev;
MOUSE_EVENT_RECORD mev;
HANDLE hndlin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hndlout = GetStdHandle(STD_OUTPUT_HANDLE);
int cap_evnt_key(){
n_evnts_read = n_evnts = evnt_type = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts_read);
if (n_evnts_read){
inrec.resize(n_evnts_read);
ReadConsoleInput(hndlin, &inrec[0], inrec.size(), &n_evnts);
for(DWORD m = 0; m < n_evnts; m++)
if (inrec[m].EventType == KEY_EVENT)
{
kev = inrec[m].Event.KeyEvent;
fflush(stdin);
return 5;
}
}
return -1;
}
int cap_evnt_mouse(){
n_evnts_read = n_evnts = evnt_type = mode = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts_read);
if (n_evnts_read){
inrec.resize(n_evnts_read);
ReadConsoleInput(hndlin, &inrec[0], inrec.size(), &n_evnts);
for(DWORD m = 0; m < n_evnts; m++)
if (inrec[m].EventType == MOUSE_EVENT)
{
mev = inrec[m].Event.MouseEvent;
fflush(stdin);
return 5;
}
}
return -1;
}
DWORD key(){
if (!kev.bKeyDown)
return kev.wVirtualKeyCode;
else
return 0;
}
bool left_click(){
if (mev.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
return 1;
else
return 0;
}
} evnt_hndlr;
void test()
{
short n = 0;
COORD pos;
while (1)
{
if (evnt_hndlr.cap_evnt_key() == 5)
{
if (evnt_hndlr.key() == VK_RIGHT)
//do something
else if (evnt_hndlr.key() == VK_LEFT)
//do something
}
else if (evnt_hndlr.cap_evnt_mouse() == 5)
{
if (evnt_hndlr.left_click() == 1)
//do something
}
}
exit(0);
}
现在,当我在 main()
中 运行 test()
并尝试捕获一个 mouse/keyboard 事件时,有时它会给我一个信号,表明所需的事件已被捕获,但有时它会错过那个事件。
请给我一个可靠的捕获输入事件的方法(特别是当需要同时读取鼠标和键盘事件时),因为这个程序挂了(如果我没有使用错误的话)。另外,请向我解释为什么会出现此问题。这对用户来说确实很糟糕。
您没有处理读取的每个事件。您的代码有可能丢弃很多事件。每次调用 cap_evnt_...()
时,如果有任何新事件可供读取,则将已读取的所有事件丢弃到 vector
中但尚未处理。
尝试更像这样的东西:
#include <Windows.h>
#include <vector>
class event_handler{
private:
std::vector<INPUT_RECORD> evnts;
INPUT_RECORD inrec;
HANDLE hndlin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hndlout = GetStdHandle(STD_OUTPUT_HANDLE);
public:
int cap_evnt_read() {
if (evnts.empty()) {
DWORD n_evnts = 0;
GetNumberOfConsoleInputEvents(hndlin, &n_evnts);
if (n_evnts == 0) return -1;
evnts.resize(n_evnts);
ReadConsoleInput(hndlin, &evnts[0], n_evnts, &n_evnts);
}
inrec = evnts.front();
evnts.erase(events.begin());
return inrec.EventType;
}
DWORD key() const {
if (!inrec.Event.KeyEvent.bKeyDown)
return inrec.Event.KeyEvent.wVirtualKeyCode;
else
return 0;
}
bool left_click() const {
return (inrec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED);
}
}
evnt_hndlr;
void test()
{
while (true)
{
switch (evnt_hndlr.cap_evnt_read())
{
case KEY_EVENT:
{
if (evnt_hndlr.key() == VK_RIGHT)
// do something
else if (evnt_hndlr.key() == VK_LEFT)
// do something
break;
}
case MOUSE_EVENT:
{
if (evnt_hndlr.left_click())
// do something
break;
}
}
}
exit(0);
}