#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);
}
Теперь, когда я запускаю test()
внутри main()
и пытаюсь перехватить событие мыши/клавиатуры, иногда он дает мне сигнал о том, что требуемое событие было перехвачено, но иногда это событие пропускается.
Пожалуйста, дайте мне надежный способ захвата событий ввода (особенно, когда события мыши и клавиатуры должны быть прочитаны одновременно), потому что эта процедура зависает (если я не использую неправильное слово). Кроме того, объясните мне, почему эта проблема происходит. Это действительно очень плохо для пользователей.
Как вы думаете, что происходит, когда вызывается
cap_evnt_key()
и в очереди есть события мыши? Ты выбросишь их! То же самое сcap_evnt_mouse()
с ключевыми событиями. Так что, конечно, вы иногда теряете события. Итак, вам нужно пересмотреть весь свой подход. Я бы предложил переместитьGetNumberOfConsoleInputEvents()
/ReadConsoleInput()
в другой метод, который перемещает ожидающие события в кеш, а затем иметь другой метод, который извлекает события из этого кеша, возвращаясь к консоли для кэширования новых событий всякий раз, когда кеш пуст.1: Это не проблема синхронизации консоли или что-то в этом роде? 2: Разве вектор
inrec
не может действовать как кеш-буфер? Я перемещаю события всякий раз, когда я нажимаю какую-либо клавишу на клавиатуре или мыши, вinrec
, а затем извлекаю требуемое после его захвата, а затем отбрасываю его, разве это не похоже на кеш? Или что-то еще нужно сделать и поддерживать?1: нет, потому что проблема в том, что ваша логика извлекает события и отбрасывает их. 2: может, если бы вы использовали его более эффективно. Например, всякий раз, когда вы вызываете
cap_evnt_...()
и доступны какие-либо новые события ввода, вы стираете текущее векторное содержимое и заполняете его только последними событиями, не проверяя, уже содержит более ранние интересующие вас события. Вам нужно добавить новые события к вектору, а не заменить его.int cap_evnt_key(){ n_evnts_read=n_evnts=evnt_type=0; GetNumberOfConsoleInputEvents(hndlin,&n_evnts_read); if(n_evnts_read){ inrec.resize(inrec.size()+n_evnts_read); ReadConsoleInput(hndlin,&inrec[inrec.size()-n_evnts_read],n_evnts_read,&n_evnts); for(int m=0;m<inrec.size();m++) if(inrec[m].EventType==KEY_EVENT) { kev=inrec[m].Event.KeyEvent; return 5; }}return -1;}
взгляните на мою модифицированную версию cap_evnt_key() согласно вашему совету.Я не удаляю содержимое
inrec
и продолжаю добавлять следующие события чтения, пока не будет выполнена желаемая работа. Как только это будет сделано, яresize()
обнулю его, это хороший способ сохранить кеш? Если нет, пожалуйста, объясните мне. Потому что проблема усугубилась (очевидно, по моей плохой логике :) )ваш новый код игнорирует существующие события в векторе, если нет доступных для чтения новых событий. Кроме того, вы не удаляете события из вектора по мере их обработки. И поскольку вы храните оба вида событий в одном векторе, изменение размера вектора до 0 приведет к потере ВСЕХ событий. Скажем, вы закончите обработку ключевых событий, вы потеряете события мыши. И наоборот. Я все еще думаю, что весь ваш подход неверен и должен быть переработан с нуля.
Давайте продолжим обсуждение в чате.