C GLFW鼠标事件滞后,窗口拖动

C GLFW鼠标事件滞后,窗口拖动,c,opengl,glfw,cursor-position,setwindowpos,C,Opengl,Glfw,Cursor Position,Setwindowpos,我试图在GLFW中拖动一个未装饰的窗口,但遇到了一些事件延迟,即使我使用的是glfwWaitEvents() 我有一个光标位置回调和一个简单的循环: // register a cursor position callback glfwSetCursorPosCallback(win, cursor_pos_callback); // then loop.. while(!glfwWindowShouldClose(win)) { glfwWaitEvents(); ... some

我试图在GLFW中拖动一个未装饰的窗口,但遇到了一些事件延迟,即使我使用的是
glfwWaitEvents()

我有一个光标位置回调和一个简单的循环:

// register a cursor position callback
glfwSetCursorPosCallback(win, cursor_pos_callback);

// then loop..
while(!glfwWindowShouldClose(win)) {
  glfwWaitEvents();
  ... some rendering...
  glfwSwapBuffers(win);
}
我的游标回调对delta进行一些简单的跟踪,并更新窗口位置

cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {
  // figure out delta_x and delta_y based on cursor previous position
  int delta_x, delta_y;

  // update window position
  if (window_drag_active) {
     int x,y;
     glfwGetWindowPos(window, &x, &y);
     glfwSetWindowPos(window, x + delta_x, y + delta_y);
  }
}
这是当我沿直线拖动时,三角洲的样子

delta_x:  10    delta_y:   0    |    xpos:   649    ypos: 55
delta_x:   5    delta_y:  -1    |    xpos:   654    ypos: 54
delta_x:   5    delta_y:   3    |    xpos:   659    ypos: 57
delta_x:   5    delta_y:   2    |    xpos:   664    ypos: 59
delta_x:  -5    delta_y:  -2    |    xpos:   659    ypos: 57
delta_x:   4    delta_y:   0    |    xpos:   663    ypos: 57
delta_x:   2    delta_y:   0    |    xpos:   665    ypos: 57
delta_x:  -3    delta_y:  -3    |    xpos:   662    ypos: 54
delta_x:   2    delta_y:   1    |    xpos:   664    ypos: 55
delta_x:   2    delta_y:   0    |    xpos:   666    ypos: 55
delta_x:   3    delta_y:   2    |    xpos:   669    ypos: 57
delta_x:   1    delta_y:  -1    |    xpos:   670    ypos: 56
delta_x:   2    delta_y:  -1    |    xpos:   672    ypos: 55
delta_x:   7    delta_y:   3    |    xpos:   679    ypos: 58
delta_x:   2    delta_y:  -1    |    xpos:   681    ypos: 57
delta_x:  -2    delta_y:  -3    |    xpos:   679    ypos: 54
delta_x:   0    delta_y:  -2    |    xpos:   679    ypos: 52
delta_x:   3    delta_y:   3    |    xpos:   682    ypos: 55
delta_x:  -5    delta_y:  -3    |    xpos:   677    ypos: 52
xpo
会按其应该的方式递增,然后每隔一段时间就会倒退一次(过时事件?)

可能我的窗口移动与光标不同步

结果是,当我拖动窗口时,它剧烈摇晃,我几乎无法将其移动到任何地方……


更新:我也尝试过将
glfwSetWindowPos
逻辑移动到主循环中,但没有成功——我仍然会得到同样的抖动和口吃


更新:当我注释掉
glfwSetWindowPos()
时,窗口不再移动(当然),但事件流现在是一致的


这让我想到,快速移动窗口会导致抖动(即向前2步,向后1步)。

我怀疑您的问题在于
光标位置回调
接收光标相对于窗口的位置,移动窗口会立即影响该位置

cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {
  // figure out delta_x and delta_y based on cursor previous position
  int delta_x, delta_y;

  // update window position
  if (window_drag_active) {
     int x,y;
     glfwGetWindowPos(window, &x, &y);
     glfwSetWindowPos(window, x + delta_x, y + delta_y);
  }
}
假设以恒定速率对角移动光标。如果光标在一个刻度上从相对位置(100100)移动到(105105),则计算
delta_x=5
delta_y=5
。然后你移动窗户。然后,移动窗口的过程会立即将相对坐标从(105105)更改回(100100),在下一个刻度上,即使您已移动到相对于原始窗口位置的位置(110110),您也仅处于相对于新窗口位置的相对位置(105105),因此,您可以从以前的位置(加上一些随机抖动噪声)计算
delta_x=0
delta_y=0
,即使您实际上沿每个轴移动了5个单位

相反,修改算法以保持恒定的相对光标位置。在拖动开始处,存储相对光标位置(例如(100100))。现在,在每个记号处,计算需要将窗口放置在何处,以将光标移回固定的相对位置。因此,如果光标已移动到(112108),则将窗口移动(+12,+8)以将光标放回(100100)。在稍后的勾选中,如果光标已移动到(108106),则不要尝试从(112108)计算增量;相反,将其与原始(100100)起点进行比较,并将窗口移动(+8,+6)。它将类似于以下内容:

cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {

  // update window position
  if (window_drag_active) {
     int delta_x = xpos - window_drag_starting_xpos;
     int delta_y = ypos - window_drag_starting_ypos;
     int x,y;
     glfwGetWindowPos(window, &x, &y);
     glfwSetWindowPos(window, x + delta_x, y + delta_y);
  }
}

我将另一个答案标记为可接受的解决方案,因为确实需要记录初始起始光标位置(相对于窗口),并使用该位置计算增量

然而,这样做只提供了一半的解决方案。 拖动时,我仍然会经历一些重大的跳跃和射击

最后,我发现这个同步问题来自于我设置新窗口位置的地方

cursor_pos_callback(GLFWwindow *win, double xpos, double ypos) {
  // figure out delta_x and delta_y based on cursor previous position
  int delta_x, delta_y;

  // update window position
  if (window_drag_active) {
     int x,y;
     glfwGetWindowPos(window, &x, &y);
     glfwSetWindowPos(window, x + delta_x, y + delta_y);
  }
}
要完全消除任何延迟,并确保窗口+光标同步,必须在渲染循环内部同时执行
glfwGetWindowPos()
glfwSetWindowPos()

在回调内部这样做将导致位置不同步的抖动。因此,我相信解决方案的一部分是确保窗口和光标尽可能保持同步

这是我想到的一个最小的例子(非常感谢K.a.布尔!)

#包括
#包括
#包括
#包括
静态双光标位置x=0;
静态双光标位置y=0;
静态双增量x=0;
静态双增量y=0;
静态int窗口拖动活动=0;
静态无效鼠标按钮回调(GLFWwindow*窗口、int按钮、int操作、,
int mods){
如果(按钮==GLFW\u鼠标按钮\u左&&action==GLFW\u按下){
窗口拖动活动=1;
双x,y;
glfwGetCursorPos(窗口、x和y);
光标位置x=楼层(x);
光标位置y=楼层(y);
}
如果(按钮==GLFW\U鼠标按钮\U左&&action==GLFW\U释放){
窗口拖动激活=0;
}
}
int main(){
glfwInit();
GLFWwindow*win=glfwCreateWindow(400500,“拖动示例”,NULL,NULL);
glfwSetMouseButtonCallback(赢,鼠标按钮回调);
glfwMakeContextCurrent(win);
而(!GLFWWindowsShouldClose(win)){
glfwaitevents();
如果(窗口\拖动\活动){
双XPO,YPO;
glfwGetCursorPos(win、xpos和YPO);
delta_x=xpos-光标_pos_x;
delta_y=ypos-光标位置y;
int x,y;
glfwGetWindowPos(win、x和y);
glfwSetWindowPos(win,x+delta_x,y+delta_y);
}
glfwSwapBuffers(win);
}
返回0;
}

谢谢您的详细回答!这无疑是解决问题的核心办法。然而,它只是部分修复了这个问题,抖动仍然存在,但至少它更好地跟踪了光标。