我正在尝试实现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循环比人类释放按钮的反应更快,因此,单击将被视为保持事件。我通过更新全局布尔变量(即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();
}
此解决方案优于第一种方法,但仍然不一致,因为线程未同步。在某些时刻,当我只做一次点击时,检测到保持事件(即以毫秒为单位)。如何改进处理Hold Mouse Event的方法?
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;
}
mouse.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
mouse.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;
}
答案 0 :(得分:1)
为什么你不能获得m_isRightHold = true;
事件的高分辨率时间,并比较自那时起每个主循环迭代时间过去的时间段m_isRightHold
继续为true
customDate
确定鼠标按钮已被保持足够长的时间以考虑点击或保持发生?