2015-11-29 117 views
0

正如您从下面的代码片段中看到的,我已经实现了一种通过其客户区拖动Windows命令提示符的方法。使用ReadConsoleInput()拖动控制台窗口

这段代码的问题是,如果用户遵循下列步骤:

  1. 无焦点控制台窗口
  2. 焦点控制台窗口通过点击和拖动它(不释放)
  3. 拖动窗口,以便光标逃离窗口区域(这可能意味着移动光标太快,或超出设置范围(第二个显示器),或通过任务栏/其他永远在顶部的窗口)

控制台窗口将停在光标后面,直到它再次移动到窗口内。

事实上,当控制台窗口在步骤1已经处于对焦状态时,这种情况不会发生,这对我来说真的很奇怪。我已经试过调试了这么多个小时,现在我不能再做了。我会很感激这方面的帮助。

// Continuously read input 
while(ReadConsoleInput(hIn, &ir, 1, &nr)) 
{ 
    switch(ir.EventType) 
    { 
     // Left mouse button down that either focuses or unfocuses console window 
     case FOCUS_EVENT: 
      // Left mouse button down that focuses console window 
      if(ir.Event.FocusEvent.bSetFocus) 
      { 
       GetCursorPos(&firstPos); 
       ScreenToClient(hWnd, &firstPos); 
      } 
      break; 
     case MOUSE_EVENT: 
      // Mouse did something inside console window 
      switch(ir.Event.MouseEvent.dwButtonState) 
      { 
       // Left mouse button down or up 
       case FROM_LEFT_1ST_BUTTON_PRESSED: 
        // Left mouse down or up, no drag 
        if(!ir.Event.MouseEvent.dwEventFlags) 
        { 
         GetCursorPos(&firstPos); 
         ScreenToClient(hWnd, &firstPos); 
        } 
        // Left button down, and mouse move. -> drag 
        if(ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) 
        { 
         GetCursorPos(&currentRelativeToScreen); 

         // Calculate window position while dragging 
         // | 
         // v 
         if(currentRelativeToScreen.x - firstPos.x > scrnSz.right - ca.right) 
          wndPos.X = scrnSz.right - ca.right; 
         else if(currentRelativeToScreen.x - firstPos.x < 0) 
          wndPos.X = 0; 
         else 
          wndPos.X = currentRelativeToScreen.x - firstPos.x; 

         if(currentRelativeToScreen.y - firstPos.y > scrnSz.bottom - ca.bottom) 
          wndPos.Y = scrnSz.bottom - ca.bottom; 
         else if(currentRelativeToScreen.y - firstPos.y < 0) 
          wndPos.Y = 0; 
         else 
          wndPos.Y = currentRelativeToScreen.y - firstPos.y; 
         // End window position calculations 

         SetWindowPos(hWnd, 0, wndPos.X, wndPos.Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 
        } 
        break; 
       default: 
        break; 
      } 
      break; 
     default: 
      break; 
    } 

回答

1

拖动窗口,使光标逃逸窗口区域[...]控制台窗口将停止光标以下,直到它的移动是在窗口内试。

这是预期的行为,如在https://msdn.microsoft.com/en-us/library/windows/desktop/ms684239.aspx记录(着重添加)。

无论何时用户移动鼠标或按下或释放其中一个鼠标按钮,都会生成鼠标事件。 仅当控制台组具有键盘焦点时,才将鼠标事件放置在控制台的输入缓冲区中并且光标处于控制台窗口边框内


[编辑]回答这个后续评论。

这个当控制台窗口已经聚焦在步骤1

虽然没有从官方文档显然不会发生,点击后控制台窗口出现捕获鼠标(并由此跟踪它甚至在移到控制台窗口之外)只有如果在点击时它已经有焦点了。对于焦点不清的控制台窗口,第一次单击会将焦点(无需全局捕获鼠标,因此只在光标位于其客户区域内时才会收到MOUSE_MOVE通知),而第二次单击则进入独占捕捉模式(并全部接收MOUSE_MOVE通知与光标位置无关)。

这可以通过设置为快速编辑模式的标准控制台窗口进行验证。如果窗口具有输入焦点,则即使鼠标移动到窗口之外,单击并拖动选择控制台中的文本。但是,如果窗口没有焦点。第一次点击只是为它提供焦点,但不会进入任何捕捉模式,拖动也不会选择任何文本。

对鼠标移动
+0

你怎么又解释说,如果窗口有焦点的整个时间的鼠标事件产生,而光标仍在窗口边界之外?此外,即使这是预期的行为(我怀疑,从UX的角度来看,加上其他窗口的行为并没有这种方式),我仍然有兴趣提供一种方法来规避这种行为。 – user4780006

+0

我编辑了我的答案来覆盖那个部分。不知道有一种解决方法,因为控制台窗口本身是相当特殊的。 – dxiv

+0

很好的编辑,很好的解释。但我仍然在寻找(至少有点)理智的方式......我猜即使在第一次(聚焦)点击时,模拟全局捕获鼠标移动的命令提示符。我假设这会以某种方式手动跟踪鼠标。 – user4780006

0

做:

if(button==leftButton){ 
ReleaseCapture(); 
SenMessage(hWnd,WM_NCLBUTTON_DOWN,HTCAPTION,lParam); 
}