Skip to content

Commit 2f045e3

Browse files
committed
fix: review fixes + dropped upstream improvements on the vibration path
Bot review (PR utkarshdalal#1214): - ContainerUtils.toContainerData / applyToContainer: normalize vibrationMode via PrefManager.normalizeVibrationModeInput and clamp vibrationIntensity to 0..100 at the read/write boundary. Stops a stale 'both' (or any other invalid value) carried over from the prior schema from propagating into ContainerData and back to disk. - ContainerData.Saver/restorer: same defence on the Compose Saver round-trip via a private VALID_RESTORED_VIBRATION_MODES whitelist plus an Int.coerceIn(0, 100) on intensity. Rebuilt invalid mode strings fall back to 'controller'. - WinHandler.startRumblePoller: re-check 'running' after acquiring rumbleNotifyLock so a stop() that runs between the outer while(running) check and the synchronized block is observed before the poller goes into wait(0). Without this, stop()'s notifyAll() is the only chance to wake the poller and a tight race could miss it. - WinHandler.rumbleViaVibratorManager: Arrays.sort(ids) instead of a two-element manual swap. Generalises the heavy/light motor selection to 3+ vibrator controllers (DualSense edition variants); 2-vibrator cases produce the same result as before. Broader review (dropped from upstream PR utkarshdalal#1261 when copying pre-cleanup's WinHandler wholesale): - WinHandler GET_GAMEPAD adoption: when no current controller is set, consult ControllerManager.getAssignedDeviceForSlot(0) instead of ExternalController.getController(0). The latter queries InputDevice ID 0 — an arbitrary number that rarely corresponds to the user's slot-0 assignment. - WinHandler.start(): call initializeAssignedControllers() so saved slot assignments are pre-registered before the first GET_GAMEPAD packet arrives. Pre-cleanup defined the method but never called it (dead code); upstream's PR called it from start(), and games that probe controllers at startup were depending on that pre-registration.
1 parent 315fe1f commit 2f045e3

3 files changed

Lines changed: 42 additions & 10 deletions

File tree

app/src/main/java/app/gamenative/utils/ContainerUtils.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,11 @@ object ContainerUtils {
325325
sharpnessEffect = container.getExtra("sharpnessEffect", "None"),
326326
sharpnessLevel = container.getExtra("sharpnessLevel", "100").toIntOrNull() ?: 100,
327327
sharpnessDenoise = container.getExtra("sharpnessDenoise", "100").toIntOrNull() ?: 100,
328-
vibrationMode = container.getExtra("vibrationMode", "controller"),
329-
vibrationIntensity = container.getExtra("vibrationIntensity", "100").toIntOrNull() ?: 100,
328+
vibrationMode = PrefManager.normalizeVibrationModeInput(
329+
container.getExtra("vibrationMode", "controller"),
330+
),
331+
vibrationIntensity = (container.getExtra("vibrationIntensity", "100").toIntOrNull() ?: 100)
332+
.coerceIn(0, 100),
330333
)
331334
}
332335

@@ -495,8 +498,14 @@ object ContainerUtils {
495498
container.putExtra("sharpnessEffect", containerData.sharpnessEffect)
496499
container.putExtra("sharpnessLevel", containerData.sharpnessLevel.toString())
497500
container.putExtra("sharpnessDenoise", containerData.sharpnessDenoise.toString())
498-
container.putExtra("vibrationMode", containerData.vibrationMode)
499-
container.putExtra("vibrationIntensity", containerData.vibrationIntensity.toString())
501+
container.putExtra(
502+
"vibrationMode",
503+
PrefManager.normalizeVibrationModeInput(containerData.vibrationMode),
504+
)
505+
container.putExtra(
506+
"vibrationIntensity",
507+
containerData.vibrationIntensity.coerceIn(0, 100).toString(),
508+
)
500509
try {
501510
container.language = containerData.language
502511
} catch (e: Exception) {

app/src/main/java/com/winlator/container/ContainerData.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ data class ContainerData(
104104
val sharpnessDenoise: Int = 100,
105105
) {
106106
companion object {
107+
private val VALID_RESTORED_VIBRATION_MODES = setOf("off", "controller", "device")
108+
107109
val Saver = mapSaver(
108110
save = { state ->
109111
mapOf(
@@ -188,8 +190,11 @@ data class ContainerData(
188190
executablePath = savedMap["executablePath"] as String,
189191
installPath = savedMap["installPath"] as String,
190192
showFPS = savedMap["showFPS"] as Boolean,
191-
vibrationMode = (savedMap["vibrationMode"] as? String) ?: "controller",
192-
vibrationIntensity = (savedMap["vibrationIntensity"] as? Int) ?: 100,
193+
vibrationMode = (savedMap["vibrationMode"] as? String)
194+
?.trim()?.lowercase()
195+
?.takeIf { it in VALID_RESTORED_VIBRATION_MODES }
196+
?: "controller",
197+
vibrationIntensity = ((savedMap["vibrationIntensity"] as? Int) ?: 100).coerceIn(0, 100),
193198
launchRealSteam = savedMap["launchRealSteam"] as Boolean,
194199
disableSteamOverlay = (savedMap["disableSteamOverlay"] as? Boolean) ?: true,
195200
sdkCloudSaveSubdir = (savedMap["sdkCloudSaveSubdir"] as? String) ?: "",

app/src/main/java/com/winlator/winhandler/WinHandler.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,14 @@ private void handleRequest(byte requestCode, final int port) throws IOException
511511
final boolean useVirtualGamepad = inputControlsView != null && profile != null && profile.isVirtualGamepad();
512512
int processId = this.receiveData.getInt();
513513
if (!useVirtualGamepad && ((externalController = this.currentController) == null || !externalController.isConnected())) {
514-
this.currentController = ExternalController.getController(0);
514+
// Use ControllerManager as the single source of truth for slot 0
515+
// rather than ExternalController.getController(0) which queries
516+
// InputDevice ID 0 — that ID is arbitrary and rarely matches the
517+
// user's slot-0 assignment.
518+
InputDevice p1Device = controllerManager.getAssignedDeviceForSlot(0);
519+
if (p1Device != null) {
520+
this.currentController = ExternalController.getController(p1Device.getId());
521+
}
515522
}
516523
boolean enabled2 = this.currentController != null || useVirtualGamepad;
517524
if (enabled2) {
@@ -672,6 +679,11 @@ public void start() {
672679
}
673680
this.running = true;
674681
startSendThread();
682+
683+
// Pre-register controllers from saved slot assignments so games that probe
684+
// for controllers at startup see them before the first input arrives.
685+
initializeAssignedControllers();
686+
675687
Executors.newSingleThreadExecutor().execute(() -> {
676688
try {
677689
DatagramSocket datagramSocket = new DatagramSocket((SocketAddress) null);
@@ -786,6 +798,11 @@ private void startRumblePoller() {
786798
if (waitMs <= 0) waitMs = 1; // never spin; ensure we yield to other threads
787799
try {
788800
synchronized (rumbleNotifyLock) {
801+
// Re-check running under the lock so a stop() that runs between the
802+
// outer while(running) check and this synchronized block is observed.
803+
// Without this, the poller would call wait(0) and miss the only
804+
// notify() the stop() path emits.
805+
if (!running) break;
789806
// wait(0) means indefinite; cap at keepalive interval when rumbling.
790807
rumbleNotifyLock.wait(waitMs == Long.MAX_VALUE ? 0 : waitMs);
791808
}
@@ -847,13 +864,14 @@ private boolean rumbleViaVibratorManager(VibratorManager vm, short lowFreq, shor
847864
int lowAmp = scaleAmplitude(lowFreq, vibrationIntensity);
848865
if (lowAmp == 0 && highAmp == 0) { vm.cancel(); return true; }
849866

850-
// Determine which ID drives the low-freq (heavy/left) motor and which drives
851-
// the high-freq (light/right) motor by sorting IDs ascending.
867+
// Sort IDs ascending so the low-freq (heavy/left) and high-freq (light/right)
868+
// selection is well-defined regardless of the order getVibratorIds() returned.
869+
// Manual two-element swap was correct for 2 IDs; sort generalises to 3+.
870+
Arrays.sort(ids);
852871
int lowMotorId = ids[0];
853872
int highMotorId = ids.length >= 2 ? ids[1] : ids[0];
854873

855874
if (ids.length >= 2) {
856-
if (ids[0] > ids[1]) { lowMotorId = ids[1]; highMotorId = ids[0]; }
857875
String motorKey = lowMotorId + "_" + highMotorId;
858876
if (loggedRumbleMotorIds.add(motorKey)) {
859877
Log.d(TAG, "Rumble motors: lowMotor=" + lowMotorId + " highMotor=" + highMotorId);

0 commit comments

Comments
 (0)