1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Fix: Input processing on mobile devices with classic D-Pad control mode

This commit is contained in:
onebeastchris
2025-10-05 00:50:21 +02:00
parent 4297996d7a
commit 82fb2e4df1

View File

@@ -29,6 +29,7 @@ import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.protocol.bedrock.data.InputInteractionModel;
import org.cloudburstmc.protocol.bedrock.data.InputMode;
import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData;
import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket;
@@ -61,14 +62,54 @@ public final class InputCache {
var oldInputPacket = this.inputPacket;
this.inputMode = packet.getInputMode();
/*
Brief introduction to how Bedrock sends movement inputs! It's mainly based on the following:
(as of 1.21.111)
1. inputmode:
- MOUSE: same as Java edition; will send up/down/left/right inputs via input flags
- GAMEPAD: indicates the use of a controller with joysticks, sends an "analogue movement vector" instead
- TOUCH: see interaction model!
- MOTION_CONTROLLER: what even is this
2. Interaction model (here, only really relevant for us when the inputmode is "touch"):
- CLASSIC: shows "wasd" keys on the client; like input-mode MOUSE would, additionally up_left / up_right / down_left / down_right
- CROSSHAIR / TOUCH: NO wasd, analogue movement vector instead
Hence, we'll also need to check for this fun edge-case!
*/
boolean isMobileAndClassicMovement = inputMode == InputMode.TOUCH && packet.getInputInteractionModel() == InputInteractionModel.CLASSIC;
boolean up, down, left, right;
if (this.inputMode == InputMode.MOUSE) {
if (this.inputMode == InputMode.MOUSE || isMobileAndClassicMovement) {
up = bedrockInput.contains(PlayerAuthInputData.UP);
down = bedrockInput.contains(PlayerAuthInputData.DOWN);
left = bedrockInput.contains(PlayerAuthInputData.LEFT);
right = bedrockInput.contains(PlayerAuthInputData.RIGHT);
if (isMobileAndClassicMovement) {
// These are the buttons in the corners of the touch area
if (bedrockInput.contains(PlayerAuthInputData.UP_LEFT)) {
up = true;
left = true;
}
if (bedrockInput.contains(PlayerAuthInputData.UP_RIGHT)) {
up = true;
right = true;
}
if (bedrockInput.contains(PlayerAuthInputData.DOWN_LEFT)) {
down = true;
left = true;
}
if (bedrockInput.contains(PlayerAuthInputData.DOWN_RIGHT)) {
down = true;
right = true;
}
}
} else {
// The above flags don't fire TODO test console
// The above flags don't fire
Vector2f analogMovement = packet.getAnalogMoveVector();
up = analogMovement.getY() > 0;
down = analogMovement.getY() < 0;
@@ -78,7 +119,6 @@ public final class InputCache {
boolean sneaking = isSneaking(bedrockInput);
// TODO when is UP_LEFT, etc. used?
this.inputPacket = this.inputPacket
.withForward(up)
.withBackward(down)
@@ -133,7 +173,7 @@ public final class InputCache {
public boolean isSneaking(Set<PlayerAuthInputData> authInputData) {
// Flying doesn't send start / stop fly cases; might as well return early
if (session.isFlying()) {
// Of course e.g. mobile handles it differently with a descend case, while
// Of course e.g. mobile devices handle it differently with a descend case, while
// e.g. Win10 sends SNEAK_DOWN. Why? We'll never know.
return authInputData.contains(PlayerAuthInputData.DESCEND) || authInputData.contains(PlayerAuthInputData.SNEAK_DOWN);
}