user4780006
user4780006

Reputation: 137

Dragging the console window with ReadConsoleInput()

As you can see from the code snippet below, I've implemented a way to drag the Windows command prompt by its client area.

The problem with this code is that if the user follows these steps:

  1. Unfocus console window
  2. Focus console window by clicking and dragging it (without releasing)
  3. Drag the window so that the cursor escapes window area (this can mean moving the cursor too quickly, or out of the set bounds (second monitor), or over the taskbar/other always-on-top window)

The console window will stop following the cursor, until it's moved to be inside the window again.

The fact that this does not happen when the console window is already in-focus at step 1, is what's really weird to me. I've tried debugging this for so many hours now, I just can't do it anymore. I'd appreciate any help regarding this.

// 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;
    }

Upvotes: 0

Views: 484

Answers (2)

milevyo
milevyo

Reputation: 2180

on mouse move do:

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

Upvotes: 0

dxiv
dxiv

Reputation: 17628

Drag the window so that the cursor escapes window area [...] The console window will stop following the cursor, until it's moved to be inside the window again.

This is the expected behavior, as documented at https://msdn.microsoft.com/en-us/library/windows/desktop/ms684239.aspx (emphasis added).

Mouse events are generated whenever the user moves the mouse, or presses or releases one of the mouse buttons. Mouse events are placed in a console's input buffer only when the console group has the keyboard focus and the cursor is within the borders of the console's window.


[ EDIT] To answer the followup comment about this.

this does not happen when the console window is already in-focus at step 1

Though not obvious from the official documentation, the console window appears to capture the mouse when clicked (and thus track it even when moved outside the console window) only if it already had the focus at the time of the click. For a console window out of focus, the 1st click gives it the focus (without globally capturing the mouse, so it only receives MOUSE_MOVE notifications while the cursor is within its client area), while the 2nd click enters exclusive capture mode (and receives all MOUSE_MOVE notifications regardless of cursor position).

This can be verified with a standard console window set to quick-edit mode. If the window has the input focus, then click-and-drag selects text in the console, even if the mouse is moved outside the window. However, if the window does not have the focus. the 1st click just gives it the focus, but does not enter any capture mode and dragging does not select any text.

Upvotes: 1

Related Questions