我正在尝试实现 Mouse 类来处理与鼠标操作相关的任何问题。除了检测到鼠标按钮被按住外,一切正常。该库不为鼠标提供此功能,但有一个键盘事件选项(即通过 REPEAT 标志)。我必须手动实现它。第一种也是简单的方法是为按下和释放按钮设置一个标志
bool Mouse::isRightDown()
{
if (m_button == GLFW_MOUSE_BUTTON_RIGHT && m_action == GLFW_PRESS){
m_isRightHold = true;
...
}
bool Mouse::isRightUp()
{
if (m_button == GLFW_MOUSE_BUTTON_RIGHT && m_action == GLFW_RELEASE ){
m_isRightHold = false;
...
}
bool Mouse::isRightHold()
{
if ( g_RightFlag ){
...
return true;
}
return false;
}
现在在渲染循环中,我可以执行以下操作
while(!glfwWindowShouldClose(window)){
glfwPollEvents();
...
// Handle Right Button Mouse
if ( Mouse::Instance()->isRightHold() ){
std::cout << "Right Mouse Button is hold..." << std::endl;
}
...
glfwSwapBuffers(window);
}
但这种方法的问题在于,while 循环比人类释放按钮的 react 更快,因此,单击将被视为保持事件。我考虑过另一种方法,即更新全局 bool 变量(即 g_RightFlag
)。该变量将在独立线程中每 900 秒更新一次,如下所示
while (true){
//std::this_thread::sleep_for(delay);
std::chrono::duration<int, std::ratio<1, 1000>> delay(900);
bool sleep = true;
auto start = std::chrono::system_clock::now();
while(sleep)
{
auto end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if ( elapsed.count() > delay.count() ){
sleep = false;
}
}
mtx.lock();
g_RightFlag = m_isRightHold;
g_LefFlag = m_isLeftHold;
mtx.unlock();
}
此解决方案比第一种方法更好,但仍然不一致,因为线程不同步。在某些时候,当我只需单击一次时,就会检测到保持事件(即以毫秒为单位)。如何改进处理按住鼠标事件的方法?
main.cpp
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "mouse.h"
int main(void)
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(800,600,"LearnOpenGL",nullptr,nullptr);
if( window == nullptr ){
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if( glewInit() != GLEW_OK ){
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0,0, width, height);
// callback events
//Keyboard Event;
Mouse::Instance();
Mouse::Instance()->init(window);
while(!glfwWindowShouldClose(window)){
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Handle Right Button Mouse
if ( Mouse::Instance()->isRightDown() ){
std::cout << "Right Mouse Button is pressed..." << std::endl;
}
if ( Mouse::Instance()->isRightUp() ){
std::cout << "Right Mouse Button is released..." << std::endl;
}
if ( Mouse::Instance()->isRightHold() ){
std::cout << "Right Mouse Button is hold..." << std::endl;
}
// Handle Left Button Mouse
if ( Mouse::Instance()->isLeftDown() ){
std::cout << "Left Mouse Button is pressed..." << std::endl;
}
if ( Mouse::Instance()->isLeftUp() ){
std::cout << "Left Mouse Button is released..." << std::endl;
}
if ( Mouse::Instance()->isLeftHold() ){
std::cout << "Left Mouse Button is hold..." << std::endl;
}
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
鼠标.h
#ifndef MOUSE_H
#define MOUSE_H
#include <thread>
#include <atomic>
#include <chrono>
#include <GLFW/glfw3.h>
class Mouse
{
public:
static Mouse* Instance(){
if(s_pInstance == NULL)
s_pInstance = new Mouse;
return s_pInstance;
}
void init(GLFWwindow* window);
bool isRightDown();
bool isRightUp();
bool isRightHold();
bool isLeftDown();
bool isLeftUp();
bool isLeftHold();
std::atomic<int> m_button, m_action, m_mode;
private:
static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
bool m_isRightHold, m_isLeftHold;
GLFWwindow* m_pWindow;
Mouse();
static Mouse* s_pInstance;
std::thread m_OnHoldThread;
void initThread();
void updateThread();
void update(int b, int a, int m);
};
#endif
鼠标.cpp
#include "mouse.h"
#include <iostream>
#include <mutex> // std::mutex
std::mutex mtx;
Mouse* Mouse::s_pInstance = NULL;
bool g_LefFlag(false);
bool g_RightFlag(false);
Mouse::Mouse()
: m_button(-1), m_action(-1), m_mode(-1),
m_isRightHold(false), m_isLeftHold(false)
{
initThread();
}
void Mouse::init(GLFWwindow* window)
{
m_pWindow = window;
glfwSetMouseButtonCallback(window, mouse_button_callback);
}
void Mouse::mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
Mouse::Instance()->update(button, action, mods);
}
void Mouse::initThread()
{
m_OnHoldThread = std::thread(&Mouse::updateThread,this);
}
void Mouse::updateThread()
{
//std::chrono::milliseconds delay(1100);
while (true){
//std::this_thread::sleep_for(delay);
std::chrono::duration<int, std::ratio<1, 1000>> delay(900);
bool sleep = true;
auto start = std::chrono::system_clock::now();
while(sleep)
{
auto end = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if ( elapsed.count() > delay.count() ){
sleep = false;
}
}
mtx.lock();
g_RightFlag = m_isRightHold;
g_LefFlag = m_isLeftHold;
mtx.unlock();
}
}
bool Mouse::isRightDown()
{
if (m_button == GLFW_MOUSE_BUTTON_RIGHT && m_action == GLFW_PRESS){
m_isRightHold = true;
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
bool Mouse::isRightUp()
{
if (m_button == GLFW_MOUSE_BUTTON_RIGHT && m_action == GLFW_RELEASE ){
m_isRightHold = false;
mtx.lock();
g_RightFlag = m_isRightHold;
mtx.unlock();
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
bool Mouse::isRightHold()
{
if ( g_RightFlag ){
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
bool Mouse::isLeftDown()
{
if (m_button == GLFW_MOUSE_BUTTON_LEFT && m_action == GLFW_PRESS){
m_isLeftHold = true;
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
bool Mouse::isLeftUp()
{
if (m_button == GLFW_MOUSE_BUTTON_LEFT && m_action == GLFW_RELEASE ){
m_isLeftHold = false;
mtx.lock();
g_LefFlag = m_isLeftHold;
mtx.unlock();
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
bool Mouse::isLeftHold()
{
if ( g_LefFlag ){
m_button = -1;
m_action = -1;
m_mode = -1;
return true;
}
return false;
}
void Mouse::update(int b, int a, int m)
{
m_button = b;
m_action = a;
m_mode = m;
}
最佳答案
为什么不获取 m_isRightHold = true;
事件的高分辨率时间,并在 m_isRightHold
继续的每个主循环迭代中比较从那时起耗时段为 true
以确定鼠标按钮已按住足够长的时间以考虑单击或按住的发生?
关于c++ - 如何实现一致的方法来检测鼠标按钮是否被按住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44348886/