使用GetCursorPosition很困难

时间:2015-04-27 01:44:22

标签: c++ event-handling

我正在创建一个带有几个函数的事件处理程序,并使用它们来处理事件(特别是键盘和鼠标)。我正在使用GetCursorPosition来获取鼠标单击事件中的当前鼠标位置,但它始终为坐标返回0和0;即使我正在检查以确保通话成功(通过返回值)。

据我所知,GetCursorPosition不需要任何初始化。我冒险进入(个人)未知领域,所以我想要一些帮助。

有问题的功能:

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

    for (char button : mButtonsToCheck) {
        if ( GetAsyncKeyState(button) ) {
            POINT p;
            if ( !GetCursorPos(&p) ) {
                throw std::runtime_error::runtime_error(
                    "Cannot get cursor position: " + GetLastError()
                );
            }
            mouseHandler(button, p.x, p.y);
        }
    }
}

在一个单独的线程中循环内部调用。

我知道检测到鼠标按下,因为点击后位置会立即从(0,0)变为(1,1)。无论出于何种原因,它都不会报告正确的位置。

班上其他人:

EventHandler.h:

#ifndef EVENT_HANDLER_H
#define EVENT_HANDLER_H

#include <vector>
#include <atomic>
#include <thread>
#include <functional>
#include <windows.h>
#include <WinUser.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();

};

#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) ) {
            keyHandler(key);
        }
    }

    for (char button : mButtonsToCheck) {
        if ( GetAsyncKeyState(button) ) {
            POINT p;
            if ( !GetCursorPos(&p) ) {
                throw std::runtime_error::runtime_error(
                    "Cannot get cursor position:" + GetLastError()
                );
            }
            mouseHandler(button, p.x, p.y);
        }
    }
}

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

我的(凌乱)测试主:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <thread>
#include <chrono>
#include <conio.h>
#include <windows.h>
#include <WinUser.h>
#include <memory>
#include <functional>

#include "Timer.h"
#include "Utils.h"
#include "curses.h"
#include "EventHandler.h"

int main() {
    using namespace std;

    int counter = 99;

    KeyHandler kbHandler([&](char c){
        switch (c) {
            case 'A': {
                counter += 1;
                break;
            }
            case 'B': {
                counter -= 1;

                break;
            }
            case 'C': {
                counter += 2;

                break;
            }
            case 'D': {
                counter -= 2;
                break;
            }
        }
    });

    bool mouseX = 0, mouseY = 0;

    MouseHandler mouseHandler([&](char c, long x, long y) {
        switch (c) {
            case LEFT_MOUSE: {
                mouseX = x;
                mouseY = y;
            }
        }
    });

    EventHandler eh;

    eh.setKeyHandler(kbHandler);
    eh.setMouseHandler(mouseHandler);

    eh.setKeysToListenOn(vector<char> {'A', 'B', 'C', 'D'});
    eh.setButtonsToListenOn(vector<char> { LEFT_MOUSE });

    eh.listenForPresses();

    while (true) {
        cout << counter << " " << "(" << mouseX << "," << mouseY << ")" << endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(333));
    }

}

我们将不胜感激。

1 个答案:

答案 0 :(得分:0)

哇,我很特别(而且不是很好)。

由于某些原因,mouseXmouseY的类型为bool,因此很明显,任何非零值都会缩短为1。

我将两者都更改为long s,并按预期工作。