Search code examples
c++winapimouse-hook

c++: window re-position with global mouse hook


I'm trying to develop the app like desktop divider. I used global mouse hook (low level mouse hook) because when left button up after dragging window into specific position, the window located into specific position and resized. First, I've tried to re-position window into left corner of the desktop screen when left button up. I used SetWindowPos method to re-position and resize, it doesn't work well. When I released the left button, the window is located into specific position, but it returns back to original position immediately. While debugging the app, it goes into left corner of the screen well. I don't know exactly why this happens. The following is my code.

LRESULT CALLBACK LowLevelMouseProc(int code, WPARAM wParam, LPARAM lParam)
{
if ( code != HC_ACTION )
    return CallNextHookEx(hMouseHook, code, wParam, lParam);
switch (wParam)
{
    case WM_LBUTTONDOWN:
    {
        TRACE("Down\n");
        // To get window handle from current mouse position
        ::GetCursorPos(&mouse_pos);
        hCurrentWnd = ::WindowFromPoint(mouse_pos);

        LButton_Down = true;

        Window_Drag = false;    // Initialize Window_Drag variable
        Mouse_Drag = false;

        while (hCurrentWnd != 0)
        {
            style = ::GetWindowLong(hCurrentWnd, GWL_STYLE);
            const int x = style & (WS_POPUP | WS_CHILD);

            if ((x == WS_OVERLAPPED) || (x == WS_POPUP)) break;

            // we also want to manipulate mdi childs that
            // aren't maximized
            if ((!(style & WS_MAXIMIZE)) && (::GetWindowLong(hCurrentWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)) break;

            hCurrentWnd = ::GetParent(hCurrentWnd);
        }

        if (IgnoreWindow())
        {
            return CallNextHookEx(hMouseHook, code, wParam, lParam);
        }

        // check if the alt key is pressed while a mouse button is pressed
        // and switch to the appropriate mode
        switch (wParam)
        {
            case WM_LBUTTONDOWN:
                LButton_Down = true;
                break;
            default:
                return CallNextHookEx(hMouseHook, code, wParam, lParam);
        }

        if (hCurrentWnd == 0)
        {
            return CallNextHookEx(hMouseHook, code, wParam, lParam);
        }

        HWND parent = ::GetParent(hCurrentWnd);

        // remember the window size and position 
        ::GetWindowRect(hCurrentWnd, &rDown);
        if ( ( parent ) && ( ( style & WS_POPUP ) == 0 ) )
        {
            ::ScreenToClient(parent, (POINT*)&rDown.left);
            ::ScreenToClient(parent, (POINT*)&rDown.right);
        }

        // we're getting serious - capture the mouse
        SetCapture(hCurrentWnd);

        return CallNextHookEx(hMouseHook, code, wParam, lParam);
    }

    case WM_MOUSEMOVE:
    {
        TRACE("Move\n");

        if ( !LButton_Down )
        {
            return CallNextHookEx(hMouseHook, code, wParam, lParam);
        }
        else {
            Mouse_Drag = true;

            TRACE("Mouse Drag - True\n");

            ::GetWindowRect(hCurrentWnd, &rCurWdrag);
            if ((rDown.left == rCurWdrag.left) && (rDown.top == rCurWdrag.top))
            {
                Window_Drag = false;
                TRACE("Window Drag - False\n");
            }
            else {
                Window_Drag = true;
                TRACE("Window Drag - True\n");
            }
        }

        return CallNextHookEx( hMouseHook, code, wParam, lParam) ;
    }

    case WM_LBUTTONUP:
    {
        TRACE("Up\n");

        LButton_Down = false;

        if ( Window_Drag && Mouse_Drag )
        {
            Window_Drag = false;
            Mouse_Drag = false;
            ::SetWindowPos(hCurrentWnd, 0, 0, 0, 500, 500, SWP_ASYNCWINDOWPOS);
            TRACE("Window Drag - False\n");
            TRACE("Mouse Drag - False\n");
        }
        else
        {
            Window_Drag = false;
            Mouse_Drag = false;
            TRACE("Window Drag 1 - False\n");
            TRACE("Mouse Drag 1 - False\n");
        }
        ReleaseCapture();
        return CallNextHookEx(NULL, code, wParam, lParam);
    }

    default:
    {

        LButton_Down = false;
        Window_Drag = false;
        Mouse_Drag = false;

        return CallNextHookEx(hMouseHook, code, wParam, lParam);
    }
}

}

And This is installed part of global mouse hook

BOOL CMFCApplication4Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);         // Set big icon
SetIcon(m_hIcon, FALSE);        // Set small icon

// TODO: Add extra initialization here

LButton_Down = false;
Mouse_Drag = false;
Window_Drag = false;

hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)LowLevelMouseProc, NULL, (DWORD)NULL);


return TRUE;  // return TRUE  unless you set the focus to a control
}

What can I do?


Solution

  • When dragging the window, the system sends message - WM_EXITSIZEMOVE to the window. Once I released the left mouse button, I send the WM_EXITSIZEMOVE message to the window which captured the left mouse up event. After the process of this msg is done, I used the SetWindowPos method to reposition the window and that works well. That's all.