Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Lib/v2/WindowManager.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ WaitForProcess(processName, timeout := 30) {
}

GetMonitorAtPos(x, y, api := "") {
if !api
api := SystemWindowAPI()

count := api.MonitorGetCount()
count := IsObject(api) ? api.MonitorGetCount() : MonitorGetCount()
Loop count {
api.MonitorGet(A_Index, &l, &t, &r, &b)
if IsObject(api)
api.MonitorGet(A_Index, &l, &t, &r, &b)
else
MonitorGet(A_Index, &l, &t, &r, &b)
Comment on lines +50 to +55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation introduces redundant branching logic inside the loop and deviates from the dependency injection pattern used elsewhere in this file (e.g., ToggleFakeFullscreen on line 9). Reverting to the previous pattern of ensuring api is an object once at the start simplifies the code and maintains consistency.

    if !api
        api := SystemWindowAPI()

    count := api.MonitorGetCount()
    Loop count {
        api.MonitorGet(A_Index, &l, &t, &r, &b)


if (l <= x && x <= r && t <= y && y <= b)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The boundary check uses inclusive upper bounds (x <= r and y <= b), which means a point at the exact right or bottom edge of a monitor is considered inside it. In multi-monitor setups, this coordinate typically marks the start of the adjacent monitor. Standard hit testing uses inclusive lower bounds and exclusive upper bounds (l <= x < r and t <= y < b).

        if (l <= x && x < r && t <= y && y < b)

return A_Index
}
Expand Down
102 changes: 102 additions & 0 deletions tests/WindowManager_Test.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#Requires AutoHotkey v2.0
#SingleInstance Force

#Include %A_ScriptDir%\..\Lib\v2\AHK_Common.ahk
#Include %A_ScriptDir%\..\Lib\v2\WindowManager.ahk

InitScript(false, false, false) ; disable UIA, Admin, and optimization for the test

; Setup testing output
stdout := FileOpen("*", "w `n")
testsPassed := 0
testsFailed := 0

AssertEqual(expected, actual, context) {
global testsPassed, testsFailed, stdout
if (expected == actual) {
testsPassed++
stdout.WriteLine("PASS: " . context)
} else {
testsFailed++
stdout.WriteLine("FAIL: " . context . " - Expected '" . expected . "', but got '" . actual . "'")
}
}

class MockSystemWindowAPI {
__New(monitors) {
this.monitors := monitors
}

MonitorGetCount() {
return this.monitors.Length
}

MonitorGet(N, &Left, &Top, &Right, &Bottom) {
if (N < 1 || N > this.monitors.Length)
return false
mon := this.monitors[N]
Left := mon.l
Top := mon.t
Right := mon.r
Bottom := mon.b
return true
}
}

try {
stdout.WriteLine("Starting GetMonitorAtPos tests...")

; Test Set 1: Single Monitor (0,0 to 1920,1080)
mon1 := {l: 0, t: 0, r: 1920, b: 1080}
apiSingle := MockSystemWindowAPI([mon1])

AssertEqual(1, GetMonitorAtPos(960, 540, apiSingle), "Single monitor - Center")
AssertEqual(1, GetMonitorAtPos(0, 0, apiSingle), "Single monitor - Top Left edge")
AssertEqual(1, GetMonitorAtPos(1920, 1080, apiSingle), "Single monitor - Bottom Right edge")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test case expects the coordinate 1920, 1080 to be inside a 1920x1080 monitor. However, in a 0-indexed pixel grid, these coordinates are technically outside the monitor's bounds (0-1919, 0-1079). The test should be updated to reflect standard exclusive upper bounds.

    AssertEqual(-1, GetMonitorAtPos(1920, 1080, apiSingle), "Single monitor - Bottom Right edge (outside)")

AssertEqual(-1, GetMonitorAtPos(-1, 540, apiSingle), "Single monitor - Out of bounds Left")
AssertEqual(-1, GetMonitorAtPos(1921, 540, apiSingle), "Single monitor - Out of bounds Right")
AssertEqual(-1, GetMonitorAtPos(960, -1, apiSingle), "Single monitor - Out of bounds Top")
AssertEqual(-1, GetMonitorAtPos(960, 1081, apiSingle), "Single monitor - Out of bounds Bottom")
Comment on lines +53 to +59

; Test Set 2: Multiple Monitors
; Mon 1: Primary 1920x1080 (0,0 to 1920,1080)
; Mon 2: Left 1080x1920 (-1080,0 to 0,1920)
; Mon 3: Right 1920x1080 (1920,0 to 3840,1080)
; Mon 4: Top 1920x1080 (0,-1080 to 1920,0)
mon_multi_1 := {l: 0, t: 0, r: 1920, b: 1080}
mon_multi_2 := {l: -1080, t: 0, r: 0, b: 1920}
mon_multi_3 := {l: 1920, t: 0, r: 3840, b: 1080}
mon_multi_4 := {l: 0, t: -1080, r: 1920, b: 0}
apiMulti := MockSystemWindowAPI([mon_multi_1, mon_multi_2, mon_multi_3, mon_multi_4])

AssertEqual(1, GetMonitorAtPos(960, 540, apiMulti), "Multi monitor - Primary Center")
AssertEqual(2, GetMonitorAtPos(-500, 500, apiMulti), "Multi monitor - Left Monitor")
AssertEqual(3, GetMonitorAtPos(2500, 500, apiMulti), "Multi monitor - Right Monitor")
AssertEqual(4, GetMonitorAtPos(960, -500, apiMulti), "Multi monitor - Top Monitor")

; Edge case overlapping bounds (falls to first match)
AssertEqual(1, GetMonitorAtPos(0, 0, apiMulti), "Multi monitor - Origin overlapping")
AssertEqual(1, GetMonitorAtPos(1920, 500, apiMulti), "Multi monitor - Border overlapping Primary/Right")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the single monitor case, the coordinate 1920 should ideally be considered part of the monitor starting at 1920 (Monitor 3) rather than the one ending at 1920 (Monitor 1).

    AssertEqual(3, GetMonitorAtPos(1920, 500, apiMulti), "Multi monitor - Border overlapping Primary/Right (should be Mon 3)")


; Out of bounds in multi-monitor setup
AssertEqual(-1, GetMonitorAtPos(960, 2000, apiMulti), "Multi monitor - Out of bounds Bottom")
AssertEqual(-1, GetMonitorAtPos(-2000, 500, apiMulti), "Multi monitor - Out of bounds Far Left")
Comment on lines +77 to +83

; Test Set 3: Zero Monitors
apiZero := MockSystemWindowAPI([])
AssertEqual(-1, GetMonitorAtPos(0, 0, apiZero), "Zero monitors - Should return -1")

; Final Results
stdout.WriteLine("---")
stdout.WriteLine("Tests Passed: " . testsPassed)
stdout.WriteLine("Tests Failed: " . testsFailed)

} finally {
; No teardown needed
}

if (testsFailed > 0) {
ExitApp(1)
}

ExitApp(0)
Loading