2015-04-28 69 views
0

我想從PDCurses獲取鼠標位置數據,它通常工作。問題是,如果在事件檢查發生之前按下鼠標按鈕兩次,則只有一個事件會從隊列中彈出。這意味着第二次按下的事件仍然在隊列中,並且下次按下鼠標時,舊位置將彈出而不是最近的位置。如果這種情況持續發生,則隊列開始備份,並且報告的鼠標按下變得越來越近。因爲我使用getch的唯一的事情是鼠標事件(我使用Window的GetAsyncKeyState和我自己的鍵盤事件管理器),我認爲一個簡單的修復就是在閱讀完後清除事件隊列一個鼠標事件。有沒有辦法清除Curse的事件隊列?

不幸的是,它似乎並不那麼容易,因爲我找不到任何允許清除隊列的方法。

我能想到的唯一方法是使用nodelaygetch設置爲非阻塞,然後重複使用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

當然你想要最近的鼠標位置,而不是最近的?因此,您應該找到一種方法來讀取並放棄隊列中最後一次鼠標事件以外的所有事件。 – EJP

回答

2

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

此功能通過沿途設置在最詛咒實現的狀態。這裏是ncurses中的manual page的鏈接,這可能會有所幫助。

+0

謝謝。我看了很多普通的詛咒手冊。我很驚訝,我從來沒有見過它。我最終寫了一個while循環來彈出它們並返回最後一個事件。我很好奇性能差異會是什麼。 – Carcigenicate

+0

這是值得檢查。我沒有用過這個與PDCurses,但知道它在ncurses中的使用。 –

相關問題