c++: window 使用全局鼠标钩子重新定位

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

我正在尝试开发类似桌面分隔线的应用程序。 我使用了全局鼠标钩子(低级鼠标钩子),因为当将 window 拖到特定位置后向上左键时,window 位于特定位置并调整大小。 首先,我尝试在按下左键时将 window 重新定位到桌面屏幕的左角。 我使用 SetWindowPos 方法重新定位和调整大小,但效果不佳。 当我释放左键时,window 位于特定位置,但它 returns 立即回到原来的位置。 在调试应用程序时,它很好地进入了屏幕的左角。 我不知道为什么会这样。 以下是我的代码。

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

}

并且这是安装了全局鼠标钩子的一部分

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
}

我能做什么?

拖动window时,系统会向window发送消息-WM_EXITSIZEMOVE。 释放鼠标左键后,我将 WM_EXITSIZEMOVE 消息发送到捕获鼠标左键事件的 window。 完成此消息的处理后,我使用 SetWindowPos 方法重新定位 window 并且效果很好。 就这些了。