Skip to content

Commit 48a2b52

Browse files
bward-dev1claude
andcommitted
Park the Beta pointer instead of freezing it when there's nothing to solve
StateManager holds the last value written, so 'write nothing' reads as 'keep pointing there forever'. If the pointer got switched off, or its calibration was dropped by a presentation change, ingest simply stopped writing IR axes and the game's cursor stayed pegged wherever it last landed. Now it writes centre + hide once and remembers it did. Done on the CoreMotion queue rather than from the setter that turned the pointer off, because ciface::iOS::StateManager has no internal locking at all -- plain std::map writes, see StateManager.cpp -- so every Beta pointer write is kept on that one serial queue rather than adding a second writing thread. (The stock app already races StateManager between the main thread and TCDeviceMotion's queue; that's pre-existing and not something this branch should make worse.) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent cb9a291 commit 48a2b52

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

Source/iOS/App/Common/Controller/VirtualWiiRemote.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ import UIKit
5757
private let hideStateLock = NSLock()
5858
private var lastHidden = false
5959

60+
/// Whether a pointer position has been written since the last time it was parked. Touched only
61+
/// from the CoreMotion delivery queue, which is serial, so it needs no lock.
62+
private var wrotePointer = false
63+
6064
/// ciface::iOS::InputBackend::PopulateDevices registers eight Touchscreen devices: 0-3 are
6165
/// GameCube pads, 4-7 are Wii Remotes. So slots 1-4 are ports 4-7.
6266
@objc public init(slot: Int, presentation: WiiRemotePresentation) {
@@ -255,6 +259,7 @@ import UIKit
255259
/// horizontal one is not. This is the same trick TCWiiPad already uses when it writes
256260
/// `[y, y, x, x]` starting at wiiInfrared + 1 -- there, y arrives in UIKit's y-down space, so
257261
/// no negation is needed and none appears.
262+
///
258263
/// `overshoot` is PointerSolution.overshoot: 0 at the centre, 1 at an edge, more beyond.
259264
@objc public func submitPointer(x: Double, y: Double, overshoot: Double) {
260265
let horizontal = Float(x)
@@ -322,7 +327,23 @@ import UIKit
322327
submitIMU(motion, orientation: motionOrientation(for: snapshot))
323328

324329
if let solution = solution {
330+
wrotePointer = true
331+
325332
submitPointer(x: solution.x, y: solution.y, overshoot: solution.overshoot)
333+
} else if wrotePointer {
334+
// Nothing to solve any more -- the pointer was switched off, or the calibration was dropped
335+
// by a presentation change. Just stopping would leave the IR axes pegged wherever they last
336+
// landed, and the game's cursor stuck there: StateManager holds the last value written, so
337+
// "write nothing" reads as "keep pointing there forever". Park it at the centre and hide it
338+
// once instead.
339+
//
340+
// Done here, on the motion queue, rather than from the setter that turned the pointer off.
341+
// ciface::iOS::StateManager has no internal locking at all (see StateManager.cpp -- plain
342+
// std::map writes), so every Beta pointer write is kept on this one queue rather than adding
343+
// a second writing thread.
344+
wrotePointer = false
345+
346+
submitPointer(x: 0, y: 0, overshoot: .infinity)
326347
}
327348
}
328349

0 commit comments

Comments
 (0)