Files
gen1recomp/tests/drivers/gold_touch_controls.lua
bryanthaboi ae6cac89e1 G2 support
2026-08-11 11:53:30 -04:00

120 lines
5.3 KiB
Lua

-- The mobile on-screen pad, on Gold. Gen 1 has had it since #415
-- (src/core/TouchControls.lua, Xelu's CC0 art in assets/touch/); Gold drew
-- nothing at all, so a phone player without a controller had no way to press
-- anything. Same module, same art, same options.touchControls layout -- what
-- was missing was every seam in src/core/Game2.lua that has to reach it.
--
-- POKEPORT_TOUCH=1 POKEPORT_GAME=gold \
-- POKEPORT_DRIVER=tests/drivers/gold_touch_controls.lua love .
-- POKEPORT_SHOT_DIR=/tmp/gold-touch (default)
--
-- POKEPORT_TOUCH=1 is what forces the overlay onto a desktop, and main.lua
-- then routes the mouse into love.touch* as a stand-in finger, which is the
-- same path a real finger takes -- so driving Game2:touchpressed here exercises
-- exactly what a phone does.
--
-- 01-pad.png the pad over the overworld, nothing held
-- 02-pressed.png A and RIGHT held, both controls lit
--
-- The assertions are the half a picture cannot show: that a press on a control
-- actually reaches Input as a GB button under the overlay's own source name,
-- that the d-pad swaps direction on a slide without ever double-holding, that a
-- captured touch is NOT offered to the mod pointer hook, and that a controller
-- press puts the pad away.
local U = require("tests.drivers.util")
local Input = require("src.core.Input")
local TouchControls = require("src.core.TouchControls")
return function(game)
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-touch"
local failures = 0
local function ok(label, condition, detail)
if condition then
print("[touch] ok " .. label)
else
failures = failures + 1
print("[touch] FAIL " .. label .. " " .. tostring(detail))
end
end
U.wait(45)
assert(game.world and game.world.map, "gold world did not boot")
ok("Game2 owns the shared overlay", game.touchControls == TouchControls)
ok("POKEPORT_TOUCH=1 forces it on for this desktop run",
TouchControls.active == true)
ok("and it has art to draw", TouchControls:visible(),
tostring(TouchControls.img))
if not TouchControls:visible() then
print("FAIL gold_touch_controls (no overlay)")
love.event.quit(1)
return
end
local L = TouchControls:layout()
U.shot(game, out .. "/01-pad.png")
-- A: press, hold, release. The overlay presses GB buttons through
-- Input:overlayPressed rather than a keyboard alias, so isTouchDown is the
-- proof it went through the pad and not through some other source.
game:touchpressed("f1", L.a.cx, L.a.cy)
ok("a finger on A holds GB A", Input:isDown("a"))
ok("under the overlay's own input source", Input:isTouchDown("a"))
-- The d-pad, and the slide between directions the pad exists for.
game:touchpressed("f2", L.dpad.cx + L.dpad.w * 0.4, L.dpad.cy)
ok("a finger right of the d-pad centre holds RIGHT", Input:isDown("right"))
U.shot(game, out .. "/02-pressed.png")
game:touchmoved("f2", L.dpad.cx, L.dpad.cy - L.dpad.w * 0.4)
ok("sliding it up swaps the hold to UP", Input:isDown("up"))
ok("and RIGHT is no longer held", not Input:isDown("right"))
game:touchreleased("f2", L.dpad.cx, L.dpad.cy - L.dpad.w * 0.4)
ok("lifting it drops UP", not Input:isDown("up"))
ok("without dropping A, which another finger still owns", Input:isDown("a"))
game:touchreleased("f1", L.a.cx, L.a.cy)
ok("and lifting that finger drops A", not Input:isDown("a"))
-- Two fingers on one button: the second must not double-press it, and
-- lifting one must not release the other's hold (TouchControls.held counts).
game:touchpressed("f3", L.b.cx, L.b.cy)
game:touchpressed("f4", L.b.cx + 1, L.b.cy + 1)
game:touchreleased("f3", L.b.cx, L.b.cy)
ok("two fingers on B: lifting one keeps B held", Input:isDown("b"))
game:touchreleased("f4", L.b.cx + 1, L.b.cy + 1)
ok("lifting the second drops it", not Input:isDown("b"))
-- The pointer seam (#807): a touch the pad captured belongs to the pad for
-- its whole life and must never be offered to a mod.
game.modPointers = nil
game:touchpressed("f5", L.start.cx, L.start.cy)
ok("a captured touch never becomes a mod pointer",
game.modPointers == nil or game.modPointers.f5 == nil)
game:touchreleased("f5", L.start.cx, L.start.cy)
-- A controller press puts the pad away until the next screen touch. The
-- release matters: `a` is GB A on the pad map too, and a hold left standing
-- here would be indistinguishable from the overlay pressing it below.
game:gamepadpressed(nil, "a")
game:gamepadreleased(nil, "a")
ok("a controller press hides the pad", not TouchControls:visible())
game:touchpressed("f6", L.a.cx, L.a.cy)
ok("and the next touch only brings it back, it does not press",
TouchControls:visible() and not Input:isDown("a"))
game:touchreleased("f6", L.a.cx, L.a.cy)
-- SELECT on a controller. `back` is SDL's name for the PS CREATE/SHARE
-- button (and Xbox VIEW, and Switch MINUS); src/core/GamepadMap.lua maps it
-- to GB SELECT, and Game2 used to swallow it with love.event.quit().
game:gamepadpressed(nil, "back")
ok("the pad's back/CREATE button presses GB SELECT", Input:isDown("select"))
game:gamepadreleased(nil, "back")
ok("and releases it", not Input:isDown("select"))
print(failures == 0 and "PASS gold_touch_controls"
or ("FAIL gold_touch_controls (%d)"):format(failures))
love.event.quit(failures == 0 and 0 or 1)
end