diff --git a/win/ahk/WinGetPosEx.ahk b/win/ahk/WinGetPosEx.ahk deleted file mode 100644 index 8320e7e..0000000 --- a/win/ahk/WinGetPosEx.ahk +++ /dev/null @@ -1,161 +0,0 @@ -;------------------------------ -; -; Function: WinGetPosEx -; -; Original author: jballi (https://autohotkey.com/boards/viewtopic.php?t=3392) -; -; Update author: RiseUp -; -; Description: -; -; Gets the position, size, and offset of a window. See the *Remarks* section -; for more information. -; -; Parameters: -; -; hWindow - Handle to the window. -; -; X, Y, Width, Height - Output variables. [Optional] If defined, these -; variables contain the coordinates of the window relative to the -; upper-left corner of the screen (X and Y), and the Width and Height of -; the window. -; -; Offset_Left, Offset_Top, Offset_Right, Offset_Bottom - Output variables. -; [Optional] Offset, in pixels, of the actual position of the window -; versus the position of the window as reported by GetWindowRect. If -; moving the window to specific coordinates, add these offset values to -; the appropriate coordinate (X and/or Y) to reflect the true size of the -; window. -; -; Returns: -; -; If successful, the address of a RECTPlus structure is returned. The first -; 16 bytes contains a RECT structure that contains the dimensions of the -; bounding rectangle of the specified window. The dimensions are given in -; screen coordinates that are relative to the upper-left corner of the screen. -; The next 16 bytes contain the offsets (4-byte integer for each of left, -; top, right, and bottom offsets). -; -; Also if successful (and if defined), the output variables (X, Y, Width, -; Height, Offset_Left, Offset_Top, Offset_Right, and Offset_Bottom) are -; updated. See the *Parameters* section for more more information. -; -; If not successful, FALSE is returned. -; -; Requirement: -; -; Windows 2000+ -; -; Remarks, Observations, and Changes: -; -; * Starting with Windows Vista, Microsoft includes the Desktop Window Manager -; (DWM) along with Aero-based themes that use DWM. Aero themes provide new -; features like a translucent glass design with subtle window animations. -; Unfortunately, the DWM doesn't always conform to the OS rules for size and -; positioning of windows. If using an Aero theme, many of the windows are -; actually larger than reported by Windows when using standard commands (Ex: -; WinGetPos, GetWindowRect, etc.) and because of that, are not positioned -; correctly when using standard commands (Ex: gui Show, WinMove, etc.). This -; function was created to 1) identify the true position and size of all -; windows regardless of the window attributes, desktop theme, or version of -; Windows and to 2) identify the appropriate offset that is needed to position -; the window if the window is a different size than reported. -; -; * The true size, position, and offset of a window cannot be determined until -; the window has been rendered. See the example script for an example of how -; to use this function to position a new window. -; -; * 20150906: The "dwmapi\DwmGetWindowAttribute" function can return odd errors -; if DWM is not enabled. One error I've discovered is a return code of -; 0x80070006 with a last error code of 6, i.e. ERROR_INVALID_HANDLE or "The -; handle is invalid." To keep the function operational during this types of -; conditions, the function has been modified to assume that all unexpected -; return codes mean that DWM is not available and continue to process without -; it. When DWM is a possibility (i.e. Vista+), a developer-friendly messsage -; will be dumped to the debugger when these errors occur. -; -; * 20171126: (RiseUp) Changed function to return 4 offset values instead of 2. -; Windows 10 has different offsets for the top versus the bottom of a window, -; so this function no longer assumes a symmetrical offset border around a -; given window. -; -; Credit: -; -; Idea and some code from *KaFu* (AutoIt forum) -; -;------------------------------------------------------------------------------- -WinGetPosEx(hWindow,ByRef X="",ByRef Y="",ByRef Width="",ByRef Height="" - ,ByRef Offset_Left="",ByRef Offset_Top="" - ,ByRef Offset_Right="",ByRef Offset_Bottom="") - { - Static Dummy5693 - ,RECTPlus - ,S_OK:=0x0 - ,DWMWA_EXTENDED_FRAME_BOUNDS:=9 - - ;-- Workaround for AutoHotkey Basic - PtrType:=(A_PtrSize=8) ? "Ptr":"UInt" - - ;-- Get the window's dimensions - ; Note: Only the first 16 bytes of the RECTPlus structure are used by the - ; DwmGetWindowAttribute and GetWindowRect functions. - VarSetCapacity(RECTPlus,32,0) - DWMRC:=DllCall("dwmapi\DwmGetWindowAttribute" - ,PtrType,hWindow ;-- hwnd - ,"UInt",DWMWA_EXTENDED_FRAME_BOUNDS ;-- dwAttribute - ,PtrType,&RECTPlus ;-- pvAttribute - ,"UInt",16) ;-- cbAttribute - - if (DWMRC<>S_OK) - { - if ErrorLevel in -3,-4 ;-- Dll or function not found (older than Vista) - { - ;-- Do nothing else (for now) - } - else - outputdebug, - (ltrim join`s - Function: %A_ThisFunc% - - Unknown error calling "dwmapi\DwmGetWindowAttribute". - RC=%DWMRC%, - ErrorLevel=%ErrorLevel%, - A_LastError=%A_LastError%. - "GetWindowRect" used instead. - ) - - ;-- Collect the position and size from "GetWindowRect" - DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus) - } - - ;-- Populate the output variables - X:=Left := NumGet(RECTPlus,0,"Int") - Y:=Top := NumGet(RECTPlus,4,"Int") - Right := NumGet(RECTPlus,8,"Int") - Bottom := NumGet(RECTPlus,12,"Int") - Width := Right-Left - Height := Bottom-Top - Offset_Left := 0 - Offset_Top := 0 - Offset_Right := 0 - Offset_Bottom := 0 - - ;-- If DWM is not used (older than Vista or DWM not enabled), we're done - if (DWMRC<>S_OK) - Return &RECTPlus - - ;-- Collect dimensions via GetWindowRect - VarSetCapacity(RECT,16,0) - DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECT) - GWR_Left := NumGet(RECT,0,"Int") - GWR_Top := NumGet(RECT,4,"Int") - GWR_Right := NumGet(RECT,8,"Int") - GWR_Bottom := NumGet(RECT,12,"Int") - - ;-- Calculate offsets and update output variables - NumPut(Offset_Left := Left - GWR_Left,RECTPlus,16,"Int") - NumPut(Offset_Top := Top - GWR_Top ,RECTPlus,20,"Int") - NumPut(Offset_Right := GWR_Right - Right ,RECTPlus,24,"Int") - NumPut(Offset_Bottom := GWR_Bottom - Bottom ,RECTPlus,28,"Int") - - Return &RECTPlus - } diff --git a/win/ahk/WindowManager.ahk b/win/ahk/WindowManager.ahk index 86ff71f..ab9c82b 100644 --- a/win/ahk/WindowManager.ahk +++ b/win/ahk/WindowManager.ahk @@ -32,7 +32,7 @@ InitWindowManager() { LogDebug("InitWindowManager") - global RATIO := 0.618 + ; global RATIO := 0.618 global RATIO := 0.382 global ID_SEEN := Object() global ARRANGEMENT := Object() @@ -64,12 +64,24 @@ FocusWinByPos(x, y) { GetCursorMonGeometry(ByRef x, ByRef y, ByRef w, ByRef h) { MouseGetPos, MouseX, MouseY + GetMonGeometryByPos(MouseX, MouseY, x, y, w, h) +} + +GetActiveWindowMonGeometry(ByRef x, ByRef y, ByRef w, ByRef h) { + WinGetPos, wx, wy, ww, wh, A + GetMonGeometryByPos(wx + ww / 2, wy + wh / 2, x, y, w, h) +} + +GetMonGeometryByPos(px, py, ByRef x, ByRef y, ByRef w, ByRef h) { + ; find monitor by position SysGet, mc, MonitorCount - ; find current monitor mi := 0 loop { + if (mi > mc) { + break + } SysGet, mon, MonitorWorkArea, %mi% - if (monLeft < MouseX and monRight > MouseX) { + if (monLeft < px and monRight > px and monTop < py and monBottom > py) { x := monLeft y := monTop w := monRight - monLeft @@ -77,11 +89,9 @@ GetCursorMonGeometry(ByRef x, ByRef y, ByRef w, ByRef h) { return } mi := mi + 1 - if (mi >= mc) { - MsgBox, "unable to find monitor under the cursor" - return - } } + msg := Format("unable to find monitor for pos {1}, {2}", px, py) + MsgBox, %msg% } FocusWinByDirection(direction) { @@ -94,6 +104,70 @@ FocusWinByDirection(direction) { FocusWinByPos(x + w * wf, y + h * hf) } +GetActiveWindowMargins(hwnd, monX, monY, monW, monH, ByRef l, ByRef t, ByRef r, ByRef b) { + Static Dummy5693 + ,RECTPlus + ,S_OK:=0x0 + ,DWMWA_EXTENDED_FRAME_BOUNDS:=9 + + ;-- Workaround for AutoHotkey Basic + PtrType:=(A_PtrSize=8) ? "Ptr":"UInt" + + ;-- Get the window's dimensions (excluding shadows) + ; Note: Only the first 16 bytes of the RECTPlus structure are used by the + ; DwmGetWindowAttribute and GetWindowRect functions. + VarSetCapacity(RECTPlus,32,0) + DWMRC:=DllCall("dwmapi\DwmGetWindowAttribute" + ,PtrType,hwnd ;-- hwnd + ,"UInt",DWMWA_EXTENDED_FRAME_BOUNDS ;-- dwAttribute + ,PtrType,&RECTPlus ;-- pvAttribute + ,"UInt",16) ;-- cbAttribute + + if (DWMRC<>S_OK) + { + if ErrorLevel in -3,-4 ;-- Dll or function not found (older than Vista) + { + ;-- Do nothing else (for now) + } + else + { + outputdebug, + (ltrim join`s + Function: %A_ThisFunc% - + Unknown error calling "dwmapi\DwmGetWindowAttribute". + RC=%DWMRC%, + ErrorLevel=%ErrorLevel%, + A_LastError=%A_LastError%. + "GetWindowRect" used instead. + ) + } + + ;-- Collect the position and size from "GetWindowRect" + DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus) + } + + ;-- Populate the output variables + x1 := NumGet(RECTPlus,0,"Int") + y1 := NumGet(RECTPlus,4,"Int") + x2 := NumGet(RECTPlus,8,"Int") + y2 := NumGet(RECTPlus,12,"Int") + + WinGetPos, winX, winY, winW, winH, A + ;-- Convert to scaled unit + scale := Round((x2 - x1) / winW*10)/10 + x1 := (x1 - monX) / scale + monX + y1 := (y1 - monY) / scale + monY + x2 := (x2 - monX) / scale + monX + y2 := (y2 - monY) / scale + monY + w := (x2 - x1) + h := (y2 - y1) + l := x1 - winX + t := y1 - winY + r := winX+winW-x2 + b := winY+winH-y2 + LogDebug("active window margins: {1} {2} {3} {4}", l, t, r, b) +} + MoveActiveWinByDirection(direction) { WinGet, isMax, MinMax, A if (isMax) { @@ -101,24 +175,36 @@ MoveActiveWinByDirection(direction) { } global RATIO global PADDING - GetCursorMonGeometry(x, y, w, h) activeWinId := WinExist("A") - WinGetPosEx(activeWinId, wx, wy, ww, wh, l, t, r, b) + GetActiveWindowMonGeometry(x, y, w, h) + GetActiveWindowMargins(activeWinId, x, y, w, h, l, t, r, b) + LogDebug("monitor geometry x: {1}, y: {2}, w: {3}, h: {4}", x, y, w, h) + ; left wx := x wy := y ww := floor(w * RATIO) wh := h + LogDebug("left geometry: x: {1}, y: {2}, w: {3}, h: {4}", wx, wy, ww, wh) + ; right if (direction = "right") { - wx := ww + floor(PADDING / 2) + wx := wx + ww ww := w - ww + LogDebug("right geometry: x: {1}, y: {2}, w: {3}, h: {4}", wx, wy, ww, wh) } else { wx := wx + PADDING } + ; adjust for aero margins + wx := wx - l + wy := wy - t + ww := ww + l + r + wh := wh + t + b + ; padding + wx := wx + floor(PADDING / 2) ww := ww - floor(PADDING * 1.5) wy := wy + PADDING wh := wh - PADDING * 2 - WinMove, A,, wx - l, wy - t, ww + l + r, wh + t + b - LogDebug("move {1} to {2}", activeWinId, direction) + WinMove, A,, wx, wy, ww, wh + LogDebug("move win to x: {1}, y: {2}, w: {3}, h: {4}", wx, wy, ww, wh) SaveActiveWindowDirection(direction) }