c++ - 检测何时将任何应用程序窗口拖动到屏幕顶部
问题描述
在 Windows 10 上,我一直在尝试替换“Window snap”功能以更好地与超宽显示器配合使用。虽然捕获 Windows 键+箭头光标来处理键盘快捷键没有问题,但我现在想检测另一个应用程序窗口何时被拖到当前监视器的顶部/右侧/左侧/底部。
当前代码:
#include <iostream>
#include <Windows.h>
HHOOK _hook_keyboard;
KBDLLHOOKSTRUCT kbdStruct;
CONST int HORIZONTAL_SLOTS = 4;
CONST int VERTICAL_SLOTS = 1;
// horizontalPosition/verticalPosition specifies which "slot" starting at 0 to place Window in
// horizontalSlots/verticalSlots specifies how many slots to divide the screen into
void MoveAndResizeActiveWindow(int horizontalPosition, int verticalPosition, int horizontalSlots, int verticalSlots)
{
// get work area on primary monitor
HWND currentWindow = GetForegroundWindow();
if (currentWindow != NULL)
{
HMONITOR currentMonitor = MonitorFromWindow(currentWindow, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(currentMonitor, &monitorInfo))
{
long width = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
long height = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
long snappedWidth = width / horizontalSlots;
long snappedHeight = height / verticalSlots;
long snappedLeft = (snappedWidth * horizontalPosition) + monitorInfo.rcWork.left;
long snappedTop = (snappedHeight * verticalPosition) + monitorInfo.rcWork.top;
MoveWindow(currentWindow, snappedLeft, snappedTop, snappedWidth, snappedHeight, true);
}
}
}
LRESULT __stdcall HookCallbackKeyboard(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL bEatkeystroke = false;
short keyState;
if (nCode >= 0)
{
kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
switch (wParam)
{
case WM_KEYDOWN:
keyState = GetAsyncKeyState(VK_LWIN);
if (keyState)
{
switch (kbdStruct.vkCode)
{
case VK_LEFT:
bEatkeystroke = true;
break;
case VK_RIGHT:
bEatkeystroke = true;
break;
case VK_UP:
bEatkeystroke = true;
break;
case VK_DOWN:
bEatkeystroke = true;
break;
};
};
break;
case WM_KEYUP:
keyState = GetAsyncKeyState(VK_LWIN);
if (keyState)
{
switch (kbdStruct.vkCode)
{
case VK_LEFT:
MoveAndResizeActiveWindow(0, 0, 4, 1);
bEatkeystroke = true;
break;
case VK_RIGHT:
MoveAndResizeActiveWindow(3, 0, 4, 1);
bEatkeystroke = true;
break;
break;
case VK_UP:
MoveAndResizeActiveWindow(1, 0, 4, 1);
bEatkeystroke = true;
break;
case VK_DOWN:
MoveAndResizeActiveWindow(2, 0, 4, 1);
bEatkeystroke = true;
break;
};
}
break;
};
}
if (bEatkeystroke)
{
return 1;
}
else
{
return CallNextHookEx(_hook_keyboard, nCode, wParam, lParam);
}
}
void SetHook()
{
if (!(_hook_keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallbackKeyboard, NULL, 0)))
{
MessageBox(NULL, L"Failed to install hook on keyboard!", L"Error", MB_ICONERROR);
}
}
int main(int argc, char** argv[])
{
SetHook();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
有什么建议如何识别 Windows 何时被拖到屏幕上的特定位置?
根据对原始问题的答复中的建议,我已尝试将 SetWinEventHook 与以下代码一起使用,计划在正确的事件解决后限制 EVENT_MIN 和 EVENT_MAX。
g_hook_winevent = SetWinEventHook(
EVENT_MIN, EVENT_MAX,
NULL, // Handle to DLL.
HandleWinEvent, // The callback.
0, 0, // Process and thread IDs of interest (0 = all)
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // Flags.
}
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
LONG idObject, LONG idChild,
DWORD dwEventThread, DWORD dwmsEventTime)
{
// process event here
}
虽然这很容易使用 EVENT_SYSTEM_MOVESIZESTART 和 EVENT_SYSTEM_MOVESIZEEND 跟踪 Windows 移动的开始或结束,但我在这里看不到跟踪 EVENT_SYSTEM_MOVESIZEEND 之前的 Window 移动的事件。
虽然只有好的选择才会起作用,但理想情况下,我希望能够检测从 EVENT_SYSTEM_MOVESIZESTART 开始直到 EVENT_SYSTEM_MOVESIZEEND 完成的窗口位置。使用记事本进行测试,在移动期间引发的唯一事件是 EVENT_OBJECT_NAMECHANGE,它似乎在窗口移动期间不断触发,至少在记事本中是这样。但是,根据文档中的描述,我不确定这是否适合我的用例:“对象的名称属性已更改。系统为以下用户界面元素发送此事件:复选框、光标、列表视图控件、按钮、单选按钮、状态栏控件、树视图控件和窗口对象。服务器应用程序为它们的可访问对象发送此事件。
解决方案
推荐阅读
- reactjs - 使用 Graphql、React 映射函数
- visual-studio - svsnversion.exe 在 Visual Studio 中重新生成解决方案时引发错误
- codeigniter - 如何在codeigniter的输入类型文本框中显示Select - where条件值
- generics - Kotlin 泛型类型参数不匹配:推断类型为“非空”但预期为“可空”
- web-services - 执行 Web 服务时被禁止的错误 (403)
- php - 子视图在 Codeigniter 中呈现的 html 页面之前加载
- android - TextField On Tap 调用背景页面的 initState
- python - Google 语音识别 API 凭据错误
- odoo - 尝试从外部应用程序命中时禁用或绕过 odoo 登录
- regex - 提取特殊字符之间的数据