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

Posted

技术标签:

【中文标题】c++:使用全局鼠标钩子重新定位窗口【英文标题】:c++: window re-position with global mouse hook 【发布时间】:2017-08-31 03:54:28 【问题描述】:

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

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

我能做什么?

【问题讨论】:

如果您可以将问题减少到无法按预期工作的单个调用(或多行),它将帮助其他人帮助您。现在您的问题看起来像:“这是我的所有代码,但它不起作用”。 嗨,保罗,感谢您的友好回答。看来您有使用全局鼠标钩子的经验。你能帮帮我吗? 【参考方案1】:

拖动窗口时,系统向窗口发送消息-WM_EXITSIZEMOVE。 释放鼠标左键后,我将 WM_EXITSIZEMOVE 消息发送到捕获鼠标左键事件的窗口。 完成此消息的过程后,我使用 SetWindowPos 方法重新定位窗口,效果很好。 就是这样。

【讨论】:

以上是关于c++:使用全局鼠标钩子重新定位窗口的主要内容,如果未能解决你的问题,请参考以下文章

注册一个全局钩子来检测鼠标是不是拖动文件/文本

使用c#中的鼠标全局钩子获取leftclick状态的int

单击标题栏按钮时,全局低级鼠标钩子会导致冻结

钩子编程(HOOK) 屏蔽全部按键鼠标及系统功能键

dotnet C# 全局 Windows 鼠标钩子

dotnet C# 全局 Windows 鼠标钩子