Search code examples
c++winapiinputmouseevent

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

Now, when I run test() inside main() and try to capture a mouse/keyboard event, sometimes it gives me the signal that the required event was captured, but sometimes it misses that event.

Kindly give me a reliable way of capturing input events (especially when both mouse and keyboard events need to be read simultaneously), because this procedure is hanging (if I'm not using the wrong word). Also, explain to me why this problem is happening. It's very bad for users indeed.


Solution

  • You are not processing every event that is read. Your code has the potential to throw away a lot of events. Each time you call cap_evnt_...(), if there are any new events available to read, you throw away any events you have already read into the vector that have not been processed yet.

    Try something more like this instead:

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