Есть ли способ очистить очередь событий Curse?

Я пытаюсь получить данные о местоположении мыши из PDCurses, и это обычно работает. Проблема в том, что если дважды нажать кнопку мыши до того, как произойдет проверка события, из очереди будет извлечено только одно из событий. Это означает, что событие для второго нажатия все еще находится в очереди, и при следующем нажатии мыши будет выталкиваться старое место вместо самого последнего. Если это продолжается, очередь начинает резервироваться, и сообщаемые нажатия мыши становятся все реже и реже.

Так как единственное, что я использую getch for для событий мыши (я использую Window GetAsyncKeyState и мой собственный менеджер событий клавиатуры), я подумал, что проще всего будет очистить очередь событий после чтения события мыши.

К сожалению, кажется, это не так просто, так как я не могу найти какие-либо методы, которые позволяют очистить очередь.

Единственный способ, которым я мог придумать, это установить getch неблокировать с помощью nodelay, а затем повторно использовать getch, сохраняя последнее событие, которое выскочило. Это кажется неэффективным и неточным, хотя.

Поскольку это потенциально проблема XY, вот эта функция:

void EventHandler::getMousePos(int& x, int& y) {
MEVENT event;
if (nc_getmouse(&event) == OK) {
x = event.x, y = event.y;
}
}

EventHandler.h:

#ifndef EVENT_HANDLER_H
#define EVENT_HANDLER_H

#include <vector>
#include <atomic>
#include <thread>
#include <functional>
#include <windows.h>
#include <WinUser.h>
#include "curses.h"
#define LEFT_MOUSE VK_LBUTTON
#define RIGHT_MOUSE VK_RBUTTON
#define MIDDLE_MOUSE VK_MBUTTON

typedef std::function<void(char)> KeyHandler;
typedef std::function<void(char,long,long)> MouseHandler;

class EventHandler {

std::thread listeningThread;

std::atomic<bool> listening = false;

std::vector<char> keysToCheck;
std::vector<char> mButtonsToCheck;

KeyHandler keyHandler = KeyHandler();
MouseHandler mouseHandler = MouseHandler();

void actOnPressedKeys();

public:
EventHandler();

~EventHandler();

void setKeyHandler(KeyHandler);
void setMouseHandler(MouseHandler);

void setKeysToListenOn(std::vector<char>);
void setButtonsToListenOn(std::vector<char>);

void listenForPresses(int loopMSDelay = 100);
void stopListening();

static void getMousePos(int& x, int& y);

};

#endif

EventHandler.cpp:

#include "EventHandler.h"
#include <thread>
#include <stdexcept>
#include <cctype>

EventHandler::EventHandler() {

}

EventHandler::~EventHandler() {
stopListening();
if (listeningThread.joinable()) {
//May need to fix this. May cause the EventHandler to freeze
// on destruction if listeningThread can't join;
listeningThread.join();
}
}

void EventHandler::actOnPressedKeys() {
for (char key : keysToCheck) {
if (GetAsyncKeyState(key)) {
//pressedKeys.insert(key);
keyHandler(key);
}
}

for (char button : mButtonsToCheck) {
if ( GetAsyncKeyState(button) ) {

int x = 0, y = 0;
getMousePos(x, y);
mvprintw(y, x, "Button Press Detected");
mouseHandler(button, x, y);
}
}
}

/*void EventHandler::actOnPressedKeys() {
pressedKeys.forEach([](char key){
keyHandler(key);
});
}*/

void EventHandler::setKeyHandler(KeyHandler handler) {
keyHandler = handler;
}

void EventHandler::setMouseHandler(MouseHandler handler) {
mouseHandler = handler;
}

void EventHandler::setKeysToListenOn(std::vector<char> newListenKeys) {
if (listening) {
throw std::runtime_error::runtime_error(
"Cannot change the listened-on keys while listening");
//This could be changed to killing the thread by setting
// listening to false, changing the keys, then restarting
// the listening thread. I can't see that being necessary though.
}

//Untested
for (char& key : newListenKeys) {
if (key >= 'a' && key <= 'z') {
key += 32;
}
}

keysToCheck = newListenKeys;

}

void EventHandler::setButtonsToListenOn(std::vector<char> newListenButtons) {
if (listening) {
throw std::runtime_error::runtime_error(
"Cannot change the listened-on buttons while listening");
}

mButtonsToCheck = newListenButtons;
}

void EventHandler::listenForPresses(int loopMSDelay) {
listening = true;
listeningThread = std::thread ([=]{
do {
actOnPressedKeys();
std::this_thread::sleep_for(std::chrono::milliseconds(loopMSDelay));
} while (listening);

});
}

void EventHandler::stopListening() {
listening = false;
}

void EventHandler::getMousePos(int& x, int& y) {
MEVENT event;
if (nc_getmouse(&event) == OK) {
x = event.x, y = event.y;
}
}

0

Решение

PDCurses реализует flushinp, который должен делать то, что запрашивается. Комментарий и функция (например, для win32)

/* discard any pending keyboard or mouse input -- this is the core
routine for flushinp() */

void PDC_flushinp(void)
{
PDC_LOG(("PDC_flushinp() - called\n"));

FlushConsoleInputBuffer(pdc_con_in);
}

Эта функция, кстати, предоставляется в большинстве реализаций curses. Вот ссылка на страница справочника в курсах, которые могут быть полезны.

2

Другие решения


По вопросам рекламы [email protected]