我想在OpenGL/GLUT窗口中实现自己的光标.通常的做法是冻结光标(因此无法触及屏幕边缘)并自行跟踪其位置.我可以使用屏幕上的光标隐藏
glutSetCursor(GLUT_CURSOR_NONE);
然后在我的glutPassiveMotionFunc回调内部使用指针移动指向窗口的中间位置
int centerX = (float)kWindowWidth / 2.0; int centerY = (float)kWindowHeight / 2.0; int deltaX = (x - centerX); int deltaY = (y - centerY); mouseX += deltaX / (float)kWindowWidth; mouseY -= deltaY / (float)kWindowHeight; glutWarpPointer( centerX, centerY );
这样可以保持指针卡在窗口中间.问题是,当我绘制'OpenGL'鼠标(在glutDisplayFunc()回调内部)时,它非常生涩.
我在网上看了一下,发现可能存在一个问题,即glutWarpPointer()导致再次调用glutPassiveMotionFunc回调,导致循环,但这似乎不会发生在这里.
我在Mac OS X上发现了一篇帖子,说CGDisplayMoveCursorToPoint更适合这个.调用CGDisplayMoveCursorToPoint可以工作,但运动仍然非常不稳定(我似乎得到很多事件,其中x和y都是0).在任何情况下,我都希望这能在Linux上运行,因此只有Mac的解决方案并不理想(但我不得不在不同的系统上做不同的事情).
我已将其缩减为测试用例.
#include#include #include int curX = 0; int curY = 0; void display() { glClearColor( 0.0, 0.0, 0.0, 1.0 ); glClear( GL_COLOR_BUFFER_BIT ); float vx = (float)curX / 300.0 + 0.5; float vy = (float)curY / 300.0 + 0.5; glColor3f( 1.0, 0.0, 0.0 ); glBegin( GL_POINTS ); glVertex3f( vx, vy, 0.0 ); glEnd(); glutSwapBuffers(); } void passivemotion( int x, int y ) { int centerX = 150; int centerY = 150; int deltaX = x - centerX; int deltaY = y - centerY; curX += deltaX; curY -= deltaY; glutWarpPointer( centerX, centerY ); } void timer( int val ) { glutTimerFunc( 16, &timer, 0); glutPostRedisplay(); } int main (int argc, char * argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(300,300); glutCreateWindow("FPS Mouse Sample"); glutDisplayFunc(&display); glutPassiveMotionFunc(&passivemotion); glutSetCursor( GLUT_CURSOR_NONE ); glutTimerFunc( 16, &timer, 0 ); glutMainLoop(); return 0; }
Steven Canfi.. 6
感谢aib的提示.你让我看着glutWarpPointer的反汇编,很明显发生了什么.调用glutWarpPointer CGPostMouseEvent导致一堆无意义的事件(并且没有任何方法可以跳过它们,因为每帧只获得一次鼠标事件,新的"真实"事件将会延迟).我发现的解决方案是只在指针位于屏幕边缘时才会扭曲(毕竟,点是假装点永远不会到达屏幕边缘).无论如何,这是代码.
int lastX = 150; int lastY = 150; void passivemotion( int x, int y ) { int deltaX = x - lastX; int deltaY = y - lastY; lastX = x; lastY = y; if( deltaX == 0 && deltaY == 0 ) return; int windowX = glutGet( GLUT_WINDOW_X ); int windowY = glutGet( GLUT_WINDOW_Y ); int screenWidth = glutGet( GLUT_SCREEN_WIDTH ); int screenHeight = glutGet( GLUT_SCREEN_HEIGHT ); int screenLeft = -windowX; int screenTop = -windowY; int screenRight = screenWidth - windowX; int screenBottom = screenHeight - windowY; if( x <= screenLeft+10 || (y) <= screenTop+10 || x >= screenRight-10 || y >= screenBottom - 10) { lastX = 150; lastY = 150; glutWarpPointer( lastX, lastY ); // If on Mac OS X, the following will also work (and CGwarpMouseCursorPosition seems faster than glutWarpPointer). // CGPoint centerPos = CGPointMake( windowX + lastX, windowY + lastY ); // CGWarpMouseCursorPosition( centerPos ); // Have to re-hide if the user touched any UI element with the invisible pointer, like the Dock. // CGDisplayHideCursor(kCGDirectMainDisplay); } curX += deltaX; curY -= deltaY; }
Nathan S... 5
我找到了一个更好的方法.发生了什么事情,操作系统在扭曲鼠标后抑制事件约0.25秒.所以,只需要打电话:
#ifdef __APPLE__ CGSetLocalEventsSuppressionInterval(0.0); #endif
然后一切都会顺利而没有任何口吃.
您可能需要包括:
#include
并将此框架添加到您的项目或编译器选项中.
请注意,您可能会收到鼠标移动到屏幕中心的事件,因此如果它位于屏幕中间,我只会忽略该事件.
感谢aib的提示.你让我看着glutWarpPointer的反汇编,很明显发生了什么.调用glutWarpPointer CGPostMouseEvent导致一堆无意义的事件(并且没有任何方法可以跳过它们,因为每帧只获得一次鼠标事件,新的"真实"事件将会延迟).我发现的解决方案是只在指针位于屏幕边缘时才会扭曲(毕竟,点是假装点永远不会到达屏幕边缘).无论如何,这是代码.
int lastX = 150; int lastY = 150; void passivemotion( int x, int y ) { int deltaX = x - lastX; int deltaY = y - lastY; lastX = x; lastY = y; if( deltaX == 0 && deltaY == 0 ) return; int windowX = glutGet( GLUT_WINDOW_X ); int windowY = glutGet( GLUT_WINDOW_Y ); int screenWidth = glutGet( GLUT_SCREEN_WIDTH ); int screenHeight = glutGet( GLUT_SCREEN_HEIGHT ); int screenLeft = -windowX; int screenTop = -windowY; int screenRight = screenWidth - windowX; int screenBottom = screenHeight - windowY; if( x <= screenLeft+10 || (y) <= screenTop+10 || x >= screenRight-10 || y >= screenBottom - 10) { lastX = 150; lastY = 150; glutWarpPointer( lastX, lastY ); // If on Mac OS X, the following will also work (and CGwarpMouseCursorPosition seems faster than glutWarpPointer). // CGPoint centerPos = CGPointMake( windowX + lastX, windowY + lastY ); // CGWarpMouseCursorPosition( centerPos ); // Have to re-hide if the user touched any UI element with the invisible pointer, like the Dock. // CGDisplayHideCursor(kCGDirectMainDisplay); } curX += deltaX; curY -= deltaY; }
我找到了一个更好的方法.发生了什么事情,操作系统在扭曲鼠标后抑制事件约0.25秒.所以,只需要打电话:
#ifdef __APPLE__ CGSetLocalEventsSuppressionInterval(0.0); #endif
然后一切都会顺利而没有任何口吃.
您可能需要包括:
#include
并将此框架添加到您的项目或编译器选项中.
请注意,您可能会收到鼠标移动到屏幕中心的事件,因此如果它位于屏幕中间,我只会忽略该事件.