使用ReadConsoleInput()拖动控制台窗口

时间:2015-11-29 04:07:30

标签: c++ c windows user-interface winapi

从下面的代码段中可以看出,我已经实现了一种通过客户区域拖动Windows命令提示符的方法。

此代码的问题在于,如果用户遵循以下步骤:

  1. 取消对焦控制台窗口
  2. 通过单击并拖动(不释放)
  3. 来聚焦控制台窗口
  4. 拖动窗口以使光标逃离窗口区域(这可能意味着移动光标太快,或者超出设置范围(第二个监视器),或者通过任务栏/其他始终在窗口上移动)
  5. 控制台窗口将停止跟随光标,直到它再次移动到窗口内。

    当控制台窗口在第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;
        }
    

2 个答案:

答案 0 :(得分:1)

  

拖动窗口,使光标逃离窗口区域[...]控制台窗口将停止跟随光标,直到它再次移动到窗口内。

这是预期的行为,如https://msdn.microsoft.com/en-us/library/windows/desktop/ms684239.aspx(强调添加)所述。

  

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

<小时/> [编辑]回答关于此的后续评论。

  

当控制台窗口已在步骤1中处于焦点时,不会发生这种情况

虽然官方文档中并不明显,但控制台窗口似乎在单击时捕获鼠标(因此即使在移出控制台窗口之外也会跟踪它)如果它已经在焦点位于点击的时间。对于没有焦点的控制台窗口,第一次单击使其成为焦点(没有全局捕获鼠标,因此它仅在光标位于其客户区域内时接收MOUSE_MOVE通知),而第二次单击进入独占捕获模式(并接收所有MOUSE_MOVE通知,无论光标位置如何)。

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

答案 1 :(得分:0)

鼠标移动

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