简体   繁体   English

Win32检测窗口是否最大化/停靠到半屏(Win键+左/右)

[英]Win32 detect if window is maximized/docked to half screen (Win-key + Left/Right)

I have a classic Win32-API (C++) application and need to detect if the window is docked to the left/right half of the screen. 我有一个经典的Win32-API(C ++)应用程序,需要检测窗口是否停靠在屏幕的左/右一半。

Background of the question is that the window only sizes in grid steps, let's say 32 pixel. 问题的背景是,窗口仅以网格步长大小,例如32像素。 In full screen the program detects that state, allow size to match the full screen and pad the excess space. 在全屏模式下,程序会检测到该状态,允许大小与全屏匹配,并填充多余的空间。 With Windows 8 and later I would like to do the same instead of currently leaving borders (because the size snaps to a multiple of 32 pixel). 在Windows 8和更高版本中,我想做同样的事情,而不是当前保留边框(因为大小会捕捉到32像素的倍数)。

With the function GetWindowPlacement() you can retrieve the normal window rectangle, using the member rcNormalPosition of WINDOWPLACEMENT . 使用函数GetWindowPlacement()您可以使用WINDOWPLACEMENT的成员rcNormalPosition检索普通的窗口矩形。 Then compare the normal rectangle to the actual window rectangle. 然后将正常矩形与实际窗口矩形进行比较。 If they don't match the window is most likely in a docked state. 如果它们不匹配,则窗口很可能处于停靠状态。

Example: 例:

bool IsDockedToMonitor(HWND hWnd)
{
    WINDOWPLACEMENT placement = {sizeof(WINDOWPLACEMENT)};
    GetWindowPlacement(hWnd, &placement);
    RECT rc;
    GetWindowRect(hWnd, &rc);

    return placement.showCmd == SW_SHOWNORMAL
        && (rc.left != placement.rcNormalPosition.left ||
            rc.top != placement.rcNormalPosition.top ||
            rc.right != placement.rcNormalPosition.right ||
            rc.bottom != placement.rcNormalPosition.bottom);
}

Note that this solution is not reliable 100% of the time. 请注意,此解决方案在100%的时间内都不可靠。 There is a slim chance that the normal rectangle and current window rectangle could match even when the window is docked to the side of the monitor. 即使将窗口停靠在显示器侧面,正常矩形和当前窗口矩形也可能会匹配。

In addition to what IInspectable has already mentioned, there is another way to determine this information and act accordingly. 除了已经提到过的IInspectable,还有另一种方法来确定此信息并采取相应的措施。

  1. Wait for a WM_WINDOWPOSCHANGED message and read its x , y , cx , and cy values from the WINDOWPOS pointer stored in lParam . 等待WM_WINDOWPOSCHANGED消息,并从lParam存储的WINDOWPOS指针读取其xycxcy值。
  2. Get a handle to the current monitor on which the window is placed by calling MonitorFromWindow . 通过调用MonitorFromWindow放置窗口的当前监视器的句柄。
  3. Create a MONITORINFO variable and set its cbSize field to sizeof(MONITORINFO) . 创建一个MONITORINFO变量并将其cbSize字段设置为sizeof(MONITORINFO)
  4. Use the monitor handle and the address of your MONITORINFO variable to call GetMonitorInfo . 使用监视器句柄和MONITORINFO变量的地址来调用GetMonitorInfo
  5. Read the rcWork value from your MONITORINFO variable. MONITORINFO变量中读取rcWork值。
    • rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcWork.left == WINDOWPOS.x - the window is "docked" to the left rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcWork.left == WINDOWPOS.x窗口“停靠”在左侧
    • rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcwork.right == (WINDOWPOS.x + WINDOWPOS.cx) - the window is "docked" to the right rcWork.top == WINDOWPOS.y && rcWork.bottom == (WINDOWPOS.y + WINDOWPOS.cx) && rcwork.right == (WINDOWPOS.x + WINDOWPOS.cx) -窗口“停靠”在右边
    • rcWork.top == WINDOWPOS.y && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx) - the window is "docked" to the top rcWork.top == WINDOWPOS.y && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx) -窗口“停靠”到顶部
    • rcWork.top == (WINDOWPOS.y + WINDOWPOS.cy) && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx) - the window is "docked" to the bottom rcWork.top == (WINDOWPOS.y + WINDOWPOS.cy) && rcWork.left == WINDOWPOS.x && rcWork.right == (WINDOWPOS.x + WINDOWPOS.cx) -窗口“停靠”在底部

You say you already have logic to determine if the window is fullscreen (do you mean fullscreen or maximized?), but effective maximization can be determined if left == x && top == y && right == x + cx && bottom == y + cy . 您说您已经有逻辑来确定窗口是全屏显示(是指全屏显示还是最大化?),但是如果left == x && top == y && right == x + cx && bottom == y + cy可以确定有效的最大化。 left == x && top == y && right == x + cx && bottom == y + cy

Here is an MSDN example of something similar. 这是类似的MSDN示例。

Note that it may be more desirable to cache the MONITORINFO values so you don't need to call it every time the window is repositioned. 请注意,可能更希望缓存MONITORINFO值,这样就不必每次重新定位窗口时都调用它。


If you only want this to apply when a user does NOT manually resize the window, here is a contrived example of a possible way to do so: 如果你只希望这个应用在用户不手动调整窗口的大小,这里是一个可能的方式这样做一个人为的例子:

LRESULT CALLBACK windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  static bool userSizing = false;

  switch (msg)
  {
  // could also catch WM_ENTERSIZEMOVE here, but this will trigger on 
  // moves as well as sizes
  case WM_SIZING:
    userSizing = true;
    break;

  case WM_EXITSIZEMOVE:
    userSizing = false;
    break;

  case WM_WINDOWPOSCHANGED:
    if (userSizing)
    {
      break;
    }

    // do logic to check to see if the window is sized in a "docked"
    // manner here
    break;

  // handle other window messages ...

  }
}

The Aero Snap feature is built into the Shell, not the window manager. Aero Snap功能内置在命令行管理程序中,而不是窗口管理器中。 As such, there is no particular window style or flag that indicates the docked state. 因此,没有指示停靠状态的特定窗口样式或标志。 The Shell simply repositions windows in response to certain actions (and internally records the state). 命令行管理程序仅对窗口进行重新定位以响应某些操作(并在内部记录状态)。 It does so in a way that is indistinguishable from manually repositioning a window with the mouse or keyboard. 这样做的方式与使用鼠标或键盘手动重新定位窗口的方式没有区别。

You cannot reliably determine, whether a window is docked to the left or right of the screen. 您无法可靠地确定窗口是否停靠在屏幕的左侧或右侧。 There is no particular message sent by the Shell, nor is a window's size and position relative to the working area a sufficient property. Shell没有发送任何特定消息,窗口的大小和相对于工作区域的位置也不是足够的属性。

What you are trying to accomplish isn't possible. 您试图实现的目标是不可能的。 You will have to implement a solution, that doesn't require the information that isn't available. 您将必须实施一个解决方案,该解决方案不需要不可用的信息。 One such implementation would be to always use padding for window sizes, that don't allow the entire client area to be used. 一种这样的实现方式是始终对窗口大小使用填充,不允许使用整个客户区域。 Another solution would be to implement the opposite: Allow window resizing to any size, unless you know the user is manually resizing the window. 另一个解决方案是实施相反的操作:允许将窗口大小调整为任意大小,除非您知道用户正在手动调整窗口大小。 You can determine the latter by handling the WM_SIZING message. 您可以通过处理WM_SIZING消息来确定后者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM