Eingabe-Eingebungen: Fokus doppelt gebunden ohne Modifikator-Prüfung, gehaltene Zeiger-Eingabe kann hängen bleiben #8

Open
opened 2026-08-29 01:41:08 +02:00 by G1LL1 · 3 comments
G1LL1 commented 2026-08-29 01:41:08 +02:00 (Migrated from gitlab.g1ll1.com)

Komponente: INPUT, GAME (boot)
Betroffene Version: main @ 238ed66, index.html Zeilen 2101–2131, 2177–2181, 2951–2955

Teil 1 – F/Shift ist doppelt gebunden, ohne Modifikatoren abzutrennen

Der Fokus wird an zwei unabhängigen Stellen behandelt:

// index.html:2101-2131  INPUT.init()
const KEYMAP = { ..., "f": "focus", "F": "focus", "Shift": "focus", "ShiftLeft": "focus", "ShiftRight": "focus" };
...
else if (act === "focus") { hooks.onGesture(); state.focusEdge = true; };   // focusEdge wird NIE gelesen
// index.html:2951-2955  GAME.boot()
window.addEventListener("keydown", function (ev) {
  if (ev.key === "f" || ev.key === "F" || ev.key === "Shift") tryFocus();
});
  • Die INPUT-Variante schreibt in ein totes Flag (state.focusEdge existiert nur hier und in der
    Deklaration Zeile 2059 – kein Leser).
  • Die tatsächlich wirkende Variante hat keine Modifikator-Prüfung und kein ev.repeat-Filter.

Folge: Strg+F / Cmd+F (Browser-Suche), Strg+S, F5-Verwechslungen u. ä. lösen
tryFocus() aus, solange der Fokus-Balken voll ist – inklusive Fokus-Sound und Bildschirm-Blitz.
Der andere Handler verhindert das nicht, weil preventDefault() nur für die
Pfeiltasten/Space-Codes gerufen wird (Zeile 2110).

Teil 2 – pointerleave hinterlässt gesetzte Halte-Zustände

// index.html:2170-2181
function up(ev) {                       // wird nur bei pointerup ausgeführt
  ...
  if (pt.side === "left") state.jumpHeld = false; else state.rollHeld = false;
  delete pointers[ev.pointerId];
  ...
}
canvas.addEventListener("pointerup", up, { passive: true });
canvas.addEventListener("pointercancel", function (ev) { delete pointers[ev.pointerId]; }, { passive: true });
canvas.addEventListener("pointerleave",  function (ev) { delete pointers[ev.pointerId]; }, { passive: true });

Wird der Zeiger nach einem Sprung gehalten, wandert vom Canvas weg und außerhalb losgelassen,
löscht pointerleave/pointercancel nur den Zeiger-Datensatz.
state.jumpHeld bleibt true, und damit bleibt der Sprunghalte-Auftrieb
(JUMP_HOLD_BOOST, MAX_JUMP_HOLD_TIME) für den nächsten Sprung aktiv, ohne dass der
Spieler die Taste hält. Aufgelöst wird es erst durch clearEdges() bei blur/Pause.

Reproduktion

Teil 1: Fokus-Balken voll (S.focusMeter = 1), dann Strg+F drücken → Fokus startet
(S.focusActive === true, AUDIO.focus(), Blitz).

Teil 2: Linken Bildschirmbereich gedrückt halten (Sprung mit Halteboost), Zeiger vom Canvas
ziehen, außerhalb loslassen, danach erneut springen → Sprunghöhe entspricht dem Halte- statt dem
Kurzhub.

Lösungsvorschlag

  • Eine einzige zentrale Tastaturbehandlung. INPUT setzt focusEdge, playerCmd/update
    verbrauchen es – oder der zweite Listener in boot() entfällt.
  • Modifikator- und Wiederholungsfilter vor allen Aktionen:
if (ev.repeat) return;
if (ev.ctrlKey || ev.metaKey || ev.altKey) return;
  • pointercancel/pointerleave wie up behandeln (Halte-Zustände zurücksetzen, ohne
    Tap-Aktion auszulösen), z. B. gemeinsame Funktion endPointer(ev, { fireTap: false }).
  • Tests: Strg+F löst keinen Fokus aus; gehaltener Linksklick + Loslassen außerhalb führt nicht
    zu einem Boost-Sprung.

Dokumentiert in gitlab-issues/08-eingabe-fokus-doppelt-und-zeiger-haengt.md (Commit 238ed66). Alle Befunde ausgeführt und gemessen; Repro-Schritte im Text.

**Komponente:** INPUT, GAME (`boot`) **Betroffene Version:** `main` @ `238ed66`, `index.html` Zeilen 2101–2131, 2177–2181, 2951–2955 ## Teil 1 – `F`/`Shift` ist doppelt gebunden, ohne Modifikatoren abzutrennen Der Fokus wird an zwei unabhängigen Stellen behandelt: ```js // index.html:2101-2131 INPUT.init() const KEYMAP = { ..., "f": "focus", "F": "focus", "Shift": "focus", "ShiftLeft": "focus", "ShiftRight": "focus" }; ... else if (act === "focus") { hooks.onGesture(); state.focusEdge = true; }; // focusEdge wird NIE gelesen ``` ```js // index.html:2951-2955 GAME.boot() window.addEventListener("keydown", function (ev) { if (ev.key === "f" || ev.key === "F" || ev.key === "Shift") tryFocus(); }); ``` * Die INPUT-Variante schreibt in ein totes Flag (`state.focusEdge` existiert nur hier und in der Deklaration Zeile 2059 – kein Leser). * Die tatsächlich wirkende Variante hat **keine Modifikator-Prüfung** und kein `ev.repeat`-Filter. Folge: `Strg+F` / `Cmd+F` (Browser-Suche), `Strg+S`, `F5`-Verwechslungen u. ä. lösen `tryFocus()` aus, solange der Fokus-Balken voll ist – inklusive Fokus-Sound und Bildschirm-Blitz. Der andere Handler verhindert das nicht, weil `preventDefault()` nur für die Pfeiltasten/`Space`-Codes gerufen wird (Zeile 2110). ## Teil 2 – `pointerleave` hinterlässt gesetzte Halte-Zustände ```js // index.html:2170-2181 function up(ev) { // wird nur bei pointerup ausgeführt ... if (pt.side === "left") state.jumpHeld = false; else state.rollHeld = false; delete pointers[ev.pointerId]; ... } canvas.addEventListener("pointerup", up, { passive: true }); canvas.addEventListener("pointercancel", function (ev) { delete pointers[ev.pointerId]; }, { passive: true }); canvas.addEventListener("pointerleave", function (ev) { delete pointers[ev.pointerId]; }, { passive: true }); ``` Wird der Zeiger nach einem Sprung gehalten, wandert vom Canvas weg und außerhalb losgelassen, löscht `pointerleave`/`pointercancel` nur den Zeiger-Datensatz. `state.jumpHeld` bleibt `true`, und damit bleibt der Sprunghalte-Auftrieb (`JUMP_HOLD_BOOST`, `MAX_JUMP_HOLD_TIME`) für den **nächsten** Sprung aktiv, ohne dass der Spieler die Taste hält. Aufgelöst wird es erst durch `clearEdges()` bei `blur`/Pause. ## Reproduktion Teil 1: Fokus-Balken voll (`S.focusMeter = 1`), dann `Strg+F` drücken → Fokus startet (`S.focusActive === true`, `AUDIO.focus()`, Blitz). Teil 2: Linken Bildschirmbereich gedrückt halten (Sprung mit Halteboost), Zeiger vom Canvas ziehen, außerhalb loslassen, danach erneut springen → Sprunghöhe entspricht dem Halte- statt dem Kurzhub. ## Lösungsvorschlag * Eine einzige zentrale Tastaturbehandlung. `INPUT` setzt `focusEdge`, `playerCmd`/`update` verbrauchen es – oder der zweite Listener in `boot()` entfällt. * Modifikator- und Wiederholungsfilter vor allen Aktionen: ```js if (ev.repeat) return; if (ev.ctrlKey || ev.metaKey || ev.altKey) return; ``` * `pointercancel`/`pointerleave` wie `up` behandeln (Halte-Zustände zurücksetzen, ohne Tap-Aktion auszulösen), z. B. gemeinsame Funktion `endPointer(ev, { fireTap: false })`. * Tests: `Strg+F` löst keinen Fokus aus; gehaltener Linksklick + Loslassen außerhalb führt nicht zu einem Boost-Sprung. --- *Dokumentiert in `gitlab-issues/08-eingabe-fokus-doppelt-und-zeiger-haengt.md` (Commit `238ed66`). Alle Befunde ausgeführt und gemessen; Repro-Schritte im Text.*
G1LL1 commented 2026-08-29 01:41:09 +02:00 (Migrated from gitlab.g1ll1.com)

mentioned in issue #9

mentioned in issue #9
G1LL1 commented 2026-08-29 01:45:26 +02:00 (Migrated from gitlab.g1ll1.com)

changed the description

changed the description
G1LL1 commented 2026-08-29 01:48:10 +02:00 (Migrated from gitlab.g1ll1.com)

changed the description

changed the description
Sign in to join this conversation.
No description provided.