Skip to content

Gatilhos analógicos com o curso inteiro e jogador na primeira entrada do controle - #109

Merged
phforner0 merged 3 commits into
mainfrom
fix/controls
Nov 4, 2026
Merged

phforner0 merged 3 commits into
mainfrom
fix/controls

Conversation

@phforner0

@phforner0 phforner0 commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Corrige os bugs de controle relatados nas issues: gatilhos analógicos que viravam botão (#97, #104) e controles embutidos que o Android lista duas vezes, como os do AYN Thor (#76).

Gatilhos analógicos (#97, #104)

Os eixos dos gatilhos (LTRIGGER/BRAKE, RTRIGGER/GAS) chegavam ao jogo como botão a partir da metade, no P1 e no P2–P4, e o núcleo transformava um gatilho apertado em 255. Nos jogos de corrida não havia controle do acelerador nem do freio.

  • O gatilho agora manda o curso inteiro, como o byte 0–255 do Xbox 360, com zona morta de 0,02, e o núcleo repassa esse valor. Um toque digital (controles na tela ou tecla L2/R2) continua sendo gatilho cheio. É a mesma ideia do [Android] Support for multiple controllers and rumble rfandango/XenDroid#81, que não foi mergeado lá.
  • Nos keystrokes do jogo, o gatilho conta como apertado a partir do limiar do XInput (0x1F), como no driver SDL do Edge. O estado anterior só muda numa transição, para o primeiro aperto não sair como repetição. Segurar LT para a mira por giroscópio também conta a partir desse limiar.
  • Os eixos seguem o mapeamento de L2 e R2. Um controle em modo analógico não manda essas teclas, então:
    • mapeado para LT ou RT do jogo, o gatilho mantém o curso inteiro;
    • mapeado para outro botão, aperta esse botão a partir da metade;
    • sem mapeamento, não aciona nada.
  • Os eixos só mandam mudanças e nunca soltam o que não apertaram. Um gatilho parado não solta o LT segurado por uma tecla digital (como o ZL), nem o botão em que o mapeamento pôs o gatilho quando a própria tecla dele o segura.
  • A tela de mapeamento é um diálogo, e agora lê os eixos na janela dele: um gatilho empurrado além da metade conta como L2/R2. Na Analogue trigger support #97, o mapeamento nem via o gatilho.
  • Um controle que manda o gatilho como eixo e também como tecla tem a tecla, e a soltura dela, ignoradas depois que o eixo mexeu. Só o primeiro aperto ainda pode chegar antes da primeira amostra do eixo.

Jogador na primeira entrada (#76)

Cada controle pegava o próximo jogador na ordem em que o Android listava os dispositivos. Um portátil que lista os controles duas vezes, um dos dispositivos sem mandar nada, dava P1 ao mudo e P2 ao que de fato manda as entradas. No AYN Thor, o jogo ignorava os controles embutidos, e o teste de controles mostrava os dois conectados com só o P2 lendo.

  • Agora um controle pega um jogador na primeira tecla (menos Voltar), ou num empurrão deliberado de stick, gatilho ou hat: além da metade, como para tirar os controles da tela do caminho, então o drift de um stick gasto não conta. Fica com o mesmo jogador que tinha antes, se ainda estiver livre, ou com o menor livre.
  • O controle que joga vira P1, e um dispositivo que nunca manda nada não ocupa jogador.
  • Até lá, nada do que um controle manda vai para o jogo, porque os sticks parados dele soltariam os do P1.
  • Com os quatro jogadores ocupados, o próximo controle joga como P1, como antes.
  • A área de Controles e o teste de controles mostram os jogadores nessa ordem, a do primeiro aperto de cada controle no app. Num jogo, vale o primeiro aperto dentro do jogo. A introdução do teste de controles explica a regra, e o selo de cada controle mostra só o jogador.
  • Os docs e o simulador do site seguem a regra nova.

Não deu para ver a captura anexada na #76 daqui, então a regra não depende do nome nem dos IDs dos dispositivos do Thor.

O Edge não cobre isto: a entrada no Android é toda deste fork.

Testes

  • Build: ctlfix2, de d64f181d1: APK assinado, nenhum aviso de compilação nas linhas alteradas. O commit seguinte só mexe em website/.
  • Host: os 13 grupos de tools/test-native-logic.sh passam, com o NDK.
  • JVM: os testes dos pacotes gamepad e companion passam neste tip (29 classes, 142 testes), com os novos AnalogTriggersTest (5) e ControllerUseTest (2), e o SlotInputRouterTest (5) e o ControllerTestModelTest (4) atualizados para as regras novas.
  • Aparelho: no POCO F7, com o APK combinado. O Forza Horizon abriu no Turnip V38, chegou ao título em 37 s e entrou no jogo pelos controles na tela, a 29,6 fps e 7,5 ms de GPU, com a imagem certa.
    • Não testado no aparelho: o gatilho analógico, a captura do gatilho na tela de mapeamento e o jogador na primeira entrada. Não havia controle físico no teste, então essas partes têm só os testes JVM e a revisão, e ainda precisam de confirmação com um controle real.
  • Revisão independente: a primeira passada pediu mudanças, todas aplicadas: a captura do mapeamento não via o gatilho dentro do diálogo, os keystrokes viravam repetição, o drift de um stick pegava jogador, os eixos soltavam o LT segurado por outra tecla, e a soltura da tecla L2/R2 cortava o gatilho. A segunda passada aprovou. Ela pediu um ajuste médio, o selo de jogador comprido demais no teste de controles, e eu apliquei três baixos: o limiar do LT na mira por giroscópio, Voltar sem pegar jogador e as tags dos comentários, que colidiam com as do plano. Ficam para depois: soltar o gatilho quando abre um prompt do jogo, um estado de gatilho por dispositivo no P1, e o botão Guide pegando jogador.

Analog triggers stay analog in games, and handhelds whose built-in controls Android lists twice, such as the AYN Thor, play as P1.

  • Racing games get throttle and brake control from analog triggers.

🛠️ Fixed

  • Controller triggers reached games as buttons. They now send their whole travel, follow the L2/R2 key mapping, and the key mapping can capture a trigger that a controller sends only as an axis.
  • A controller takes a player when it's first used, not when it connects. On handhelds whose built-in controls Android lists twice, the controls that play are P1 instead of a silent duplicate.

Os gatilhos analógicos continuam analógicos nos jogos, e portáteis cujos controles embutidos o Android lista duas vezes, como o AYN Thor, jogam como P1.

  • Jogos de corrida ganham controle do acelerador e do freio pelos gatilhos analógicos.

🛠️ Corrigido

  • Os gatilhos dos controles chegavam aos jogos como botões. Agora mandam o curso inteiro, seguem o mapeamento de L2/R2, e o mapeamento consegue capturar um gatilho que o controle manda só como eixo.
  • Um controle pega um jogador quando é usado pela primeira vez, não quando conecta. Em portáteis cujos controles embutidos o Android lista duas vezes, os controles que jogam ficam como P1, e não uma cópia muda.

🤖 Generated with Claude Code

phforner0 and others added 2 commits November 3, 2026 20:31
…apping

The trigger axes (LTRIGGER/BRAKE, RTRIGGER/GAS) reached the guest as a
button past half way, on P1 and on P2-P4, and the core turned a pressed
trigger into 255: no throttle or brake control in racing games (#97,
#104). A trigger now sends its travel as the guest's 0-255 byte (dead
zone 0.02), and the core passes the value through; a digital press (the
touch controls, an L2/R2 key) is still full. Keystrokes see a trigger
pressed past XInput's threshold (> 0x1F, as Edge's SDL driver), and the
previous key state moves only on a transition, so a KEYDOWN isn't
flagged as a repeat. Holding LT for the gyro aim counts from that
threshold too. Following XenDroid's take on it (rfandango/XenDroid#81,
not merged there).

The axes follow the key mapping of L2 and R2, which a pad in analog mode
doesn't send as keys: on the guest's LT or RT they keep their travel, on
another button they press it past half way, and left unbound they drive
nothing. They send only changes and never release what they didn't
press, so a trigger at rest leaves alone LT held by a digital ZL key.
The key capture of the mapping screen, a dialog, takes a trigger pushed
past half in its own window as L2 or R2 (#97: the mapping didn't see the
trigger at all). A pad that sends a trigger both as an axis and as a key
past a point of its own has the key, and its release, ignored once the
axis has moved; the very first press can still get there before the
axis's first sample.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A controller took the next player as Android listed it. A handheld that
lists its controls twice, one device sending nothing (likely the raw
controls behind its own mapping service), gave that one P1 and the
device that does send input P2: on the AYN Thor the game ignored the
built-in controls, and the controller test showed both as connected with
only P2 reading input (#76).

A controller now takes a player with its first key press (Back aside),
or a deliberate push of a stick, trigger or hat (past half, as for
putting the touch controls aside, so a worn stick's drift doesn't take
one): the one it held before when still free, else the lowest free one.
The controls that play are P1, and a device that never sends input takes
none. Until then nothing it sends goes to the game, as its sticks at
rest would release P1's. Every player taken: it plays as P1, as before.
The Controls area and the controller test show players in that order
from the controllers' first press in the app; a game takes them by the
first press in the game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-11-04T03:01:26.035288Z
We couldn’t complete this review. Comment @codex review to try again.
d64f181 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

The simulator and the controls documentation still said players go in the
order the controllers connect. The simulator takes its English from the
app's own pt-BR and English pairs when the text is exactly the same, so
its texts that followed xd_ctl_who_order and ct_intro had lost their
English, and the site's strict build failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@phforner0
phforner0 merged commit a107faa into main Nov 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant