Controller-Fix: Joystick-Objekte wurden nach dem Namens-Auslesen freigegeben, dadurch lieferte SDL keine Events mehr. Jetzt offen halten + Hotplug. Neu: tools/controller_check.py zur Diagnose, Tests fuer Tastenbelegung (62).
This commit is contained in:
1 parent
a088c23a09
commit
5237b0a39c
7 files changed
+343
-17
No files matched your search
+24
-1
@@ -153,7 +153,30 @@ Spiel läuft dann mit der Tastatur weiter.
|
|||||||
* **Bluetooth:** Systemeinstellungen → Bluetooth → Controller koppeln. Geht,
|
* **Bluetooth:** Systemeinstellungen → Bluetooth → Controller koppeln. Geht,
|
||||||
ist am Stand aber störanfälliger (Akku, Reconnects).
|
ist am Stand aber störanfälliger (Akku, Reconnects).
|
||||||
* **Microsofts Xbox-Funk-Dongle** funktioniert auf macOS **nicht**.
|
* **Microsofts Xbox-Funk-Dongle** funktioniert auf macOS **nicht**.
|
||||||
* Der Name des erkannten Controllers steht nach dem Start im Terminal.
|
* Der Controller muss vor dem Spielstart verbunden sein. Wird er später
|
||||||
|
verbunden, erkennt das Spiel ihn automatisch und schreibt es ins Terminal
|
||||||
|
(`Controller: Xbox Series X Controller`).
|
||||||
|
|
||||||
|
### Wenn der Controller erkannt wird, aber keine Taste reagiert
|
||||||
|
|
||||||
|
Diagnose starten:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.venv/bin/python tools/controller_check.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Dann A, X, Y und das D-Pad drücken. Das Fenster zeigt jede Taste, die ankommt:
|
||||||
|
|
||||||
|
* **Es erscheinen Zeilen** wie `Taste 0 gedrückt` und `→ Spiel-Aktion: PRIMARY`
|
||||||
|
→ die Eingabe kommt an; dann bitte die Ausgabe melden, es liegt dann an der
|
||||||
|
Tastenbelegung.
|
||||||
|
* **Es erscheint gar nichts** → macOS reicht die Controller-Eingabe nicht an
|
||||||
|
das Terminal weiter. Prüfen unter *Systemeinstellungen → Datenschutz &
|
||||||
|
Sicherheit → Eingabeüberwachung* (bei älteren macOS-Versionen
|
||||||
|
*Bedienungshilfen*), ob **Terminal** (bzw. iTerm / VS Code) erlaubt ist –
|
||||||
|
danach das Terminal neu starten.
|
||||||
|
* Bei Bluetooth zusätzlich: Controller entkoppeln, neu verbinden, oder einfach
|
||||||
|
das USB-Kabel verwenden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ loader_game/
|
|||||||
menu.py Stufenauswahl
|
menu.py Stufenauswahl
|
||||||
intro.py Anleitungsbild (Tutorial) + Startsequenz (Ampel, Reissverschluss)
|
intro.py Anleitungsbild (Tutorial) + Startsequenz (Ampel, Reissverschluss)
|
||||||
game.py Zustandsmaschine einer Runde
|
game.py Zustandsmaschine einer Runde
|
||||||
tests/test_logic.py 56 Tests (ohne Fenster)
|
tests/test_logic.py 62 Tests (ohne Fenster)
|
||||||
|
tools/controller_check.py Diagnose: zeigt jede Controller-Eingabe
|
||||||
docs/ANALYSE.md Analyse Altstand + Fehlerliste
|
docs/ANALYSE.md Analyse Altstand + Fehlerliste
|
||||||
old_version/ eingefrorener Altstand (nicht versioniert)
|
old_version/ eingefrorener Altstand (nicht versioniert)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -143,3 +143,26 @@ argument 'slots'` ab.
|
|||||||
Support-Fällen.
|
Support-Fällen.
|
||||||
* Verifiziert mit echtem Python 3.9.25 + pygame 2.6.1: 57 Tests grün,
|
* Verifiziert mit echtem Python 3.9.25 + pygame 2.6.1: 57 Tests grün,
|
||||||
Selbsttest läuft durch.
|
Selbsttest läuft durch.
|
||||||
|
|
||||||
|
## 11. Controller wurde erkannt, reagierte aber nicht (v1.6)
|
||||||
|
|
||||||
|
Symptom auf dem MacBook: Im Start-Log stand `Controller: Xbox Series X Controller`,
|
||||||
|
aber keine Taste löste im Spiel etwas aus – mit Kabel und via Bluetooth.
|
||||||
|
|
||||||
|
Ursache: `connected_controllers()` öffnete den Joystick nur, um den Namen
|
||||||
|
auszulesen, und gab das Python-Objekt danach wieder frei. Damit schloss pygame
|
||||||
|
das Gerät, und SDL liefert für geschlossene Geräte **keine** Joystick-Events
|
||||||
|
mehr – die Tastatur funktionierte weiter, der Controller war stumm.
|
||||||
|
|
||||||
|
Behoben in `input_map.py`:
|
||||||
|
|
||||||
|
* Die Joystick-Objekte werden in `_OPEN_CONTROLLERS` offen gehalten
|
||||||
|
(`open_controllers()`), aufgerufen beim Start und bei
|
||||||
|
`JOYDEVICEADDED` / `JOYDEVICEREMOVED` (Hotplug).
|
||||||
|
* `open_controllers()` initialisiert das Joystick-Subsystem bei Bedarf selbst
|
||||||
|
und schluckt fehlende Geräte, statt abzubrechen.
|
||||||
|
* Neues Diagnose-Tool `tools/controller_check.py`: zeigt Name, Tasten-/
|
||||||
|
Achsen-/Hat-Anzahl, GUID und jedes eingehende Event samt abgeleiteter
|
||||||
|
Spiel-Aktion.
|
||||||
|
* Tests für die Tastenbelegung (Tasten 0–3, D-Pad als Hat, Stick mit
|
||||||
|
Deadzone), 62 Tests insgesamt.
|
||||||
+48
-14
@@ -56,6 +56,53 @@ HAT_ACTIONS: dict[tuple[int, int], Action] = {
|
|||||||
#: Analogstick: ab diesem Ausschlag gilt eine Richtung als gewollt
|
#: Analogstick: ab diesem Ausschlag gilt eine Richtung als gewollt
|
||||||
AXIS_DEADZONE = 0.6
|
AXIS_DEADZONE = 0.6
|
||||||
|
|
||||||
|
#: Offene Joystick-Objekte. Sie müssen am Leben bleiben: gibt Python das
|
||||||
|
#: Objekt frei, schliesst pygame das Gerät – und SDL liefert danach **keine**
|
||||||
|
#: Joystick-Events mehr. Genau das war der Grund, weshalb ein erkannter
|
||||||
|
#: Controller im Spiel nichts bewirkte.
|
||||||
|
_OPEN_CONTROLLERS: list[pygame.joystick.Joystick] = []
|
||||||
|
|
||||||
|
|
||||||
|
def open_controllers() -> list[str]:
|
||||||
|
"""Öffnet alle angeschlossenen Controller und hält sie offen.
|
||||||
|
|
||||||
|
Nach ``pygame.init()`` aufrufen, und erneut, wenn ein Controller an- oder
|
||||||
|
abgesteckt wird (``JOYDEVICEADDED`` / ``JOYDEVICEREMOVED``).
|
||||||
|
"""
|
||||||
|
_OPEN_CONTROLLERS.clear()
|
||||||
|
names: list[str] = []
|
||||||
|
if not pygame.joystick.get_init():
|
||||||
|
try:
|
||||||
|
pygame.joystick.init()
|
||||||
|
except pygame.error:
|
||||||
|
return names
|
||||||
|
try:
|
||||||
|
count = pygame.joystick.get_count()
|
||||||
|
except pygame.error:
|
||||||
|
return names
|
||||||
|
for index in range(count):
|
||||||
|
try:
|
||||||
|
stick = pygame.joystick.Joystick(index)
|
||||||
|
stick.init()
|
||||||
|
except pygame.error:
|
||||||
|
continue
|
||||||
|
_OPEN_CONTROLLERS.append(stick)
|
||||||
|
names.append(stick.get_name())
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def opened_controllers() -> list[pygame.joystick.Joystick]:
|
||||||
|
"""Die aktuell offenen Controller (für Diagnose-Tools)."""
|
||||||
|
return list(_OPEN_CONTROLLERS)
|
||||||
|
|
||||||
|
|
||||||
|
def controller_names() -> list[str]:
|
||||||
|
return [stick.get_name() for stick in _OPEN_CONTROLLERS]
|
||||||
|
|
||||||
|
|
||||||
|
def is_device_event(event: pygame.event.Event) -> bool:
|
||||||
|
return event.type in (pygame.JOYDEVICEADDED, pygame.JOYDEVICEREMOVED)
|
||||||
|
|
||||||
|
|
||||||
def actions_from_event(event: pygame.event.Event) -> list[Action]:
|
def actions_from_event(event: pygame.event.Event) -> list[Action]:
|
||||||
"""Übersetzt ein pygame-Event in null bis eine Aktion."""
|
"""Übersetzt ein pygame-Event in null bis eine Aktion."""
|
||||||
@@ -79,21 +126,8 @@ def actions_from_event(event: pygame.event.Event) -> list[Action]:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def connected_controllers() -> list[str]:
|
|
||||||
"""Namen aller angeschlossenen Controller (leer, wenn keiner da ist)."""
|
|
||||||
names = []
|
|
||||||
for index in range(pygame.joystick.get_count()):
|
|
||||||
try:
|
|
||||||
stick = pygame.joystick.Joystick(index)
|
|
||||||
stick.init()
|
|
||||||
names.append(stick.get_name())
|
|
||||||
except pygame.error:
|
|
||||||
continue
|
|
||||||
return names
|
|
||||||
|
|
||||||
|
|
||||||
def describe_controller_setup() -> str:
|
def describe_controller_setup() -> str:
|
||||||
names = connected_controllers()
|
names = controller_names()
|
||||||
if not names:
|
if not names:
|
||||||
return "Controller: keiner erkannt (Tastatur: Space=Snap, ←=Drehen, ↑=OnTop, Esc=Ende)"
|
return "Controller: keiner erkannt (Tastatur: Space=Snap, ←=Drehen, ↑=OnTop, Esc=Ende)"
|
||||||
return "Controller: " + ", ".join(names)
|
return "Controller: " + ", ".join(names)
|
||||||
|
|||||||
@@ -28,7 +28,14 @@ from loader_game import config
|
|||||||
from loader_game.assets import Assets
|
from loader_game.assets import Assets
|
||||||
from loader_game.difficulty import DEFAULT_DIFFICULTY, Difficulty
|
from loader_game.difficulty import DEFAULT_DIFFICULTY, Difficulty
|
||||||
from loader_game.game import Game, HandleResult, State
|
from loader_game.game import Game, HandleResult, State
|
||||||
from loader_game.input_map import Action, actions_from_event, controller_hint_lines
|
from loader_game.input_map import (
|
||||||
|
Action,
|
||||||
|
actions_from_event,
|
||||||
|
controller_hint_lines,
|
||||||
|
describe_controller_setup,
|
||||||
|
is_device_event,
|
||||||
|
open_controllers,
|
||||||
|
)
|
||||||
from loader_game.intro import StartSequence, Tutorial
|
from loader_game.intro import StartSequence, Tutorial
|
||||||
from loader_game.menu import DifficultyMenu
|
from loader_game.menu import DifficultyMenu
|
||||||
from loader_game.sequences import load_sequences
|
from loader_game.sequences import load_sequences
|
||||||
@@ -98,6 +105,9 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
pygame.display.set_caption(config.WINDOW_TITLE)
|
pygame.display.set_caption(config.WINDOW_TITLE)
|
||||||
screen = create_screen(fullscreen=args.fullscreen)
|
screen = create_screen(fullscreen=args.fullscreen)
|
||||||
|
|
||||||
|
# Controller öffnen und offen halten – sonst liefert SDL keine Events.
|
||||||
|
open_controllers()
|
||||||
|
|
||||||
assets = Assets()
|
assets = Assets()
|
||||||
assets.load()
|
assets.load()
|
||||||
|
|
||||||
@@ -216,6 +226,10 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
if event.type == pygame.KEYDOWN and event.key == pygame.K_F11:
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_F11:
|
||||||
pygame.display.toggle_fullscreen()
|
pygame.display.toggle_fullscreen()
|
||||||
continue
|
continue
|
||||||
|
if is_device_event(event):
|
||||||
|
print(describe_controller_setup())
|
||||||
|
open_controllers()
|
||||||
|
continue
|
||||||
for action in actions_from_event(event):
|
for action in actions_from_event(event):
|
||||||
if not apply_action(action):
|
if not apply_action(action):
|
||||||
running = False
|
running = False
|
||||||
|
|||||||
@@ -14,10 +14,13 @@ import unittest
|
|||||||
os.environ.setdefault("SDL_VIDEODRIVER", "dummy")
|
os.environ.setdefault("SDL_VIDEODRIVER", "dummy")
|
||||||
os.environ.setdefault("SDL_AUDIODRIVER", "dummy")
|
os.environ.setdefault("SDL_AUDIODRIVER", "dummy")
|
||||||
|
|
||||||
|
import pygame # noqa: E402 (muss nach den SDL-Variablen kommen)
|
||||||
|
|
||||||
from loader_game import config
|
from loader_game import config
|
||||||
from loader_game.case import Case
|
from loader_game.case import Case
|
||||||
from loader_game.difficulty import DEFAULT_DIFFICULTY, DIFFICULTIES, by_key
|
from loader_game.difficulty import DEFAULT_DIFFICULTY, DIFFICULTIES, by_key
|
||||||
from loader_game.game import Game, HandleResult, State
|
from loader_game.game import Game, HandleResult, State
|
||||||
|
from loader_game import input_map
|
||||||
from loader_game.input_map import Action
|
from loader_game.input_map import Action
|
||||||
from loader_game.intro import StartSequence, Tutorial
|
from loader_game.intro import StartSequence, Tutorial
|
||||||
from loader_game.menu import DifficultyMenu
|
from loader_game.menu import DifficultyMenu
|
||||||
@@ -493,6 +496,97 @@ class SequenceChoiceTests(unittest.TestCase):
|
|||||||
self.assertEqual(game.sequence_index, 0)
|
self.assertEqual(game.sequence_index, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerMappingTests(unittest.TestCase):
|
||||||
|
"""Controller-Events → Aktionen (ohne echtes Gerät)."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def event(**kwargs):
|
||||||
|
import types
|
||||||
|
|
||||||
|
return types.SimpleNamespace(**kwargs)
|
||||||
|
|
||||||
|
def test_keyboard(self) -> None:
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(self.event(type=pygame.KEYDOWN, key=pygame.K_SPACE)),
|
||||||
|
[Action.PRIMARY],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(self.event(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)),
|
||||||
|
[Action.BACK],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(self.event(type=pygame.KEYDOWN, key=pygame.K_a)), []
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_xbox_buttons(self) -> None:
|
||||||
|
for button, expected in (
|
||||||
|
(0, Action.PRIMARY),
|
||||||
|
(1, Action.BACK),
|
||||||
|
(2, Action.LEFT),
|
||||||
|
(3, Action.UP),
|
||||||
|
):
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYBUTTONDOWN, button=button, joy=0)
|
||||||
|
),
|
||||||
|
[expected],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYBUTTONDOWN, button=7, joy=0)
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_dpad_as_hat(self) -> None:
|
||||||
|
for value, expected in (
|
||||||
|
((-1, 0), Action.LEFT),
|
||||||
|
((1, 0), Action.RIGHT),
|
||||||
|
((0, -1), Action.UP),
|
||||||
|
((0, 1), Action.DOWN),
|
||||||
|
):
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYHATMOTION, hat=0, value=value, joy=0)
|
||||||
|
),
|
||||||
|
[expected],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYHATMOTION, hat=0, value=(0, 0), joy=0)
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_left_stick_with_deadzone(self) -> None:
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYAXISMOTION, axis=0, value=-0.9, joy=0)
|
||||||
|
),
|
||||||
|
[Action.LEFT],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYAXISMOTION, axis=1, value=0.9, joy=0)
|
||||||
|
),
|
||||||
|
[Action.DOWN],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
input_map.actions_from_event(
|
||||||
|
self.event(type=pygame.JOYAXISMOTION, axis=0, value=0.2, joy=0)
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_open_controllers_without_devices_does_not_crash(self) -> None:
|
||||||
|
# Im Testrechner ist kein Controller angeschlossen – das muss ruhig
|
||||||
|
# eine leere Liste ergeben (und darf keine Ausnahme werfen).
|
||||||
|
names = input_map.open_controllers()
|
||||||
|
self.assertIsInstance(names, list)
|
||||||
|
self.assertEqual(names, input_map.controller_names())
|
||||||
|
|
||||||
|
|
||||||
class RenderTests(unittest.TestCase):
|
class RenderTests(unittest.TestCase):
|
||||||
"""Rendert je ein Bild von Anleitung, Startsequenz, Menü und Spiel (ohne Fenster).
|
"""Rendert je ein Bild von Anleitung, Startsequenz, Menü und Spiel (ohne Fenster).
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Controller-Diagnose: zeigt, was pygame vom Gamepad sieht.
|
||||||
|
|
||||||
|
Aufruf im Projektordner::
|
||||||
|
|
||||||
|
.venv/bin/python tools/controller_check.py
|
||||||
|
|
||||||
|
Drücke ein paar Tasten und bewege das D-Pad. Was hier ankommt, kommt auch im
|
||||||
|
Spiel an. Beenden mit Esc oder durch Schliessen des Fensters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent))
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from loader_game import input_map
|
||||||
|
|
||||||
|
WIDTH, HEIGHT = 1000, 520
|
||||||
|
MAX_LINES = 12
|
||||||
|
|
||||||
|
|
||||||
|
def describe(stick: pygame.joystick.Joystick) -> str:
|
||||||
|
return (
|
||||||
|
f"{stick.get_name()} · Tasten {stick.get_numbuttons()}"
|
||||||
|
f" · Achsen {stick.get_numaxes()}"
|
||||||
|
f" · Hats {stick.get_numhats()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
pygame.init()
|
||||||
|
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||||
|
pygame.display.set_caption("Controller-Test – Esc beendet")
|
||||||
|
|
||||||
|
font = pygame.font.SysFont(None, 28)
|
||||||
|
small = pygame.font.SysFont(None, 22)
|
||||||
|
|
||||||
|
input_map.open_controllers()
|
||||||
|
names = input_map.controller_names()
|
||||||
|
print("Gefundene Controller:", names or "keiner")
|
||||||
|
for stick in input_map.opened_controllers():
|
||||||
|
print(" -", describe(stick))
|
||||||
|
print(" GUID:", stick.get_guid())
|
||||||
|
|
||||||
|
lines: list[str] = []
|
||||||
|
events_seen = 0
|
||||||
|
quiet = 0.0
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
running = True
|
||||||
|
|
||||||
|
while running:
|
||||||
|
quiet += clock.tick(60) / 1000.0
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
running = False
|
||||||
|
break
|
||||||
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
|
||||||
|
running = False
|
||||||
|
break
|
||||||
|
if input_map.is_device_event(event):
|
||||||
|
input_map.open_controllers()
|
||||||
|
text = "Controller-Wechsel: " + (", ".join(input_map.controller_names()) or "keiner mehr")
|
||||||
|
lines.append(text)
|
||||||
|
print(text)
|
||||||
|
quiet = 0.0
|
||||||
|
continue
|
||||||
|
|
||||||
|
if event.type == pygame.JOYBUTTONDOWN:
|
||||||
|
events_seen += 1
|
||||||
|
quiet = 0.0
|
||||||
|
text = f"Taste {event.button} gedrückt (joy={event.joy})"
|
||||||
|
lines.append(text)
|
||||||
|
print(text)
|
||||||
|
elif event.type == pygame.JOYHATMOTION:
|
||||||
|
events_seen += 1
|
||||||
|
quiet = 0.0
|
||||||
|
text = f"D-Pad/Hat {event.hat} = {event.value} (joy={event.joy})"
|
||||||
|
lines.append(text)
|
||||||
|
print(text)
|
||||||
|
elif event.type == pygame.JOYAXISMOTION and abs(event.value) > 0.5:
|
||||||
|
events_seen += 1
|
||||||
|
quiet = 0.0
|
||||||
|
text = f"Achse {event.axis} = {event.value:+.2f} (joy={event.joy})"
|
||||||
|
lines.append(text)
|
||||||
|
print(text)
|
||||||
|
|
||||||
|
for action in input_map.actions_from_event(event):
|
||||||
|
text = f" → Spiel-Aktion: {action.name}"
|
||||||
|
lines.append(text)
|
||||||
|
print(text)
|
||||||
|
|
||||||
|
lines = lines[-MAX_LINES:]
|
||||||
|
|
||||||
|
screen.fill((20, 20, 24))
|
||||||
|
screen.blit(font.render("Controller-Test", True, (255, 255, 255)), (24, 20))
|
||||||
|
|
||||||
|
current = input_map.controller_names()
|
||||||
|
if current:
|
||||||
|
for index, text in enumerate(current):
|
||||||
|
screen.blit(small.render("✓ " + describe_short(text, input_map), True, (120, 230, 120)), (24, 64 + index * 26))
|
||||||
|
else:
|
||||||
|
screen.blit(small.render("Kein Controller gefunden.", True, (240, 120, 120)), (24, 64))
|
||||||
|
|
||||||
|
y = 140
|
||||||
|
for text in lines:
|
||||||
|
screen.blit(small.render(text, True, (220, 220, 220)), (24, y))
|
||||||
|
y += 26
|
||||||
|
|
||||||
|
if quiet > 5.0 and events_seen == 0:
|
||||||
|
hint = "Noch keine Controller-Eingabe empfangen – Taste drücken oder Kabel prüfen."
|
||||||
|
screen.blit(small.render(hint, True, (240, 200, 80)), (24, HEIGHT - 40))
|
||||||
|
|
||||||
|
screen.blit(
|
||||||
|
small.render("Esc beendet den Test.", True, (150, 150, 150)),
|
||||||
|
(24, HEIGHT - 70),
|
||||||
|
)
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
pygame.quit()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def describe_short(name: str, module) -> str:
|
||||||
|
for stick in module.opened_controllers():
|
||||||
|
if stick.get_name() == name:
|
||||||
|
return describe(stick)
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in new issue
Block a user