d707ee4d4e
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
release / apple (push) Has been cancelled
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
The two touch clients had exactly complementary gaps: iOS forwarded fingers ONLY as raw wire touches (no way to drive the host cursor from the touch screen), Android had the two mouse modes but no passthrough. Both now share one three-way "Touch input" setting: Trackpad (default) / Direct pointer / Touch passthrough. iOS/iPadOS: Input/TouchMouse.swift ports the Android gesture engine 1:1 (same px-based acceleration curve; tap=click, two-finger tap=right-click, two-finger drag=scroll, tap-then-drag=held drag, three-finger tap=stats HUD via the shared hudEnabled default); direct-pointer mode maps through the aspect-fit letterbox; the previous always-on behavior lives on as the passthrough option. The mode latches per gesture (a Settings change never splits one gesture across models), touchesCancelled releases held state without synthesizing a click, and session stop flushes a mid-drag button. Settings picker on iPhone + iPad next to the iPad-only pointer-capture toggle. Deliberate default change: trackpad, not passthrough. Android: new nativeSendTouch JNI shim → wire TouchDown/Move/Up (the host already injects real touch on every backend — libei touchscreen, wlroots, KWin fake-input, SendInput); streamTouchPassthrough forwards every finger with stable ids and lifts still-held contacts on teardown; the trackpadMode Boolean becomes the TouchMode enum (old pref migrated on load, never rewritten) with a Settings dropdown. Verified: macOS swift build + full suite (incl. new TouchMouseTests), iOS Simulator Swift compile, cargo check/fmt/clippy on the native crate, Kotlin app+kit compile + unit tests. On-glass feel of the iOS ballistics and Android passthrough against a touch-aware app still pending. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
2.0 KiB
Swift
43 lines
2.0 KiB
Swift
#if os(iOS)
|
|
import XCTest
|
|
|
|
@testable import PunktfunkKit
|
|
|
|
/// Pins the touch-mouse tuning contract (ported 1:1 from the Android client's TouchInput.kt
|
|
/// so the two touch clients feel identical) and the mode parsing. The gesture state machine
|
|
/// itself needs UITouch instances and is validated on-glass.
|
|
final class TouchMouseTests: XCTestCase {
|
|
func testModeParsingDefaultsToTrackpad() {
|
|
XCTAssertEqual(TouchInputMode(rawValue: "trackpad"), .trackpad)
|
|
XCTAssertEqual(TouchInputMode(rawValue: "pointer"), .pointer)
|
|
XCTAssertEqual(TouchInputMode(rawValue: "touch"), .touch)
|
|
// Unknown/unset values must fall back to trackpad — never crash or go touch-silent.
|
|
XCTAssertNil(TouchInputMode(rawValue: "bogus"))
|
|
}
|
|
|
|
func testAccelerationCurve() {
|
|
// At or below the speed floor: no acceleration — slow drags stay precise.
|
|
XCTAssertEqual(TouchMouse.Tuning.accel(forSpeed: 0), 1)
|
|
XCTAssertEqual(TouchMouse.Tuning.accel(forSpeed: TouchMouse.Tuning.accelSpeedFloor), 1)
|
|
// Above the floor the gain ramps...
|
|
let mid = TouchMouse.Tuning.accel(forSpeed: 1.0)
|
|
XCTAssertGreaterThan(mid, 1)
|
|
XCTAssertLessThan(mid, TouchMouse.Tuning.accelMax)
|
|
// ...and a flick is capped so it can't fling the cursor uncontrollably.
|
|
XCTAssertEqual(TouchMouse.Tuning.accel(forSpeed: 100), TouchMouse.Tuning.accelMax)
|
|
// Monotonic in between.
|
|
XCTAssertLessThanOrEqual(
|
|
TouchMouse.Tuning.accel(forSpeed: 0.5), TouchMouse.Tuning.accel(forSpeed: 1.5))
|
|
}
|
|
|
|
func testTuningRelations() {
|
|
// The tap-drag window must be long enough to hit but short enough not to turn every
|
|
// second tap into a drag.
|
|
XCTAssertGreaterThan(TouchMouse.Tuning.tapDragWindow, 0.1)
|
|
XCTAssertLessThan(TouchMouse.Tuning.tapDragWindow, 0.5)
|
|
// A wheel notch per ~10 pt of two-finger pan (the indirect-trackpad path's feel).
|
|
XCTAssertGreaterThan(TouchMouse.Tuning.scrollNotchPt, 0)
|
|
}
|
|
}
|
|
#endif
|