You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

408 lines
8.3 KiB
Python

#!/usr/bin/env python3
import argparse
import sys
import sdl2
import sdl2.ext
import sdl2.sdlttf as ttf
WIDTH = 1280
HEIGHT = 720
FONT = "/usr/share/fonts/open-sans/OpenSans-Semibold.ttf"
def debug(msg, enabled):
if enabled:
print(f"[DEBUG] {msg}", file=sys.stderr)
class ControllerManager:
def __init__(self, ignore, debug_enabled):
self.ignore = ignore
self.debug_enabled = debug_enabled
self.controllers = {}
self.unsupported = {}
def scan(self):
self.controllers.clear()
self.unsupported.clear()
count = sdl2.SDL_NumJoysticks()
for i in range(count):
name_ptr = sdl2.SDL_JoystickNameForIndex(i)
name = (
name_ptr.decode()
if name_ptr else
"Unknown Device"
)
if sdl2.SDL_IsGameController(i):
if any(
x.lower() in name.lower()
for x in self.ignore
):
debug(
f"Ignoring {name}",
self.debug_enabled
)
continue
c = sdl2.SDL_GameControllerOpen(i)
if c:
joy = sdl2.SDL_GameControllerGetJoystick(c)
instance = sdl2.SDL_JoystickInstanceID(
joy
)
self.controllers[instance] = {
"name": name,
"controller": c
}
debug(
f"Added controller {name}",
self.debug_enabled
)
else:
self.unsupported[i] = name
debug(
f"Unsupported joystick {name}",
self.debug_enabled
)
def add(self, index):
name_ptr = sdl2.SDL_JoystickNameForIndex(index)
name = (
name_ptr.decode()
if name_ptr else
"Unknown Device"
)
if sdl2.SDL_IsGameController(index):
c = sdl2.SDL_GameControllerOpen(index)
if c:
joy = sdl2.SDL_GameControllerGetJoystick(c)
instance = sdl2.SDL_JoystickInstanceID(
joy
)
self.controllers[instance] = {
"name": name,
"controller": c
}
debug(
f"Hotplugged {name}",
self.debug_enabled
)
else:
self.unsupported[index] = name
debug(
f"Hotplugged unsupported {name}",
self.debug_enabled
)
def remove(self, instance):
if instance in self.controllers:
name = self.controllers[instance]["name"]
sdl2.SDL_GameControllerClose(
self.controllers[instance]["controller"]
)
del self.controllers[instance]
debug(
f"Removed {name}",
self.debug_enabled
)
def draw_text(renderer, font, text, x, y, color):
surface = ttf.TTF_RenderUTF8_Blended(
font,
text.encode("utf-8"),
color
)
if not surface:
print(
"TTF render failed: " +
ttf.TTF_GetError().decode(),
file=sys.stderr
)
return
texture = sdl2.SDL_CreateTextureFromSurface(
renderer,
surface
)
if not texture:
print(
"Texture creation failed: " +
sdl2.SDL_GetError().decode(),
file=sys.stderr
)
sdl2.SDL_FreeSurface(surface)
return
rect = sdl2.SDL_Rect()
rect.x = x
rect.y = y
rect.w = surface.contents.w
rect.h = surface.contents.h
result = sdl2.SDL_RenderCopy(
renderer,
texture,
None,
rect
)
if result != 0:
print(
"RenderCopy failed: " +
sdl2.SDL_GetError().decode(),
file=sys.stderr
)
sdl2.SDL_DestroyTexture(texture)
sdl2.SDL_FreeSurface(surface)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("question")
parser.add_argument(
"--ignore",
nargs="*",
default=[]
)
parser.add_argument(
"--debug",
action="store_true"
)
args = parser.parse_args()
sdl2.SDL_Init(
sdl2.SDL_INIT_VIDEO |
sdl2.SDL_INIT_GAMECONTROLLER |
sdl2.SDL_INIT_JOYSTICK
)
ttf.TTF_Init()
window = sdl2.SDL_CreateWindow(
args.question.encode(),
sdl2.SDL_WINDOWPOS_CENTERED,
sdl2.SDL_WINDOWPOS_CENTERED,
WIDTH,
HEIGHT,
sdl2.SDL_WINDOW_FULLSCREEN
)
renderer = sdl2.SDL_CreateRenderer(
window,
-1,
sdl2.SDL_RENDERER_ACCELERATED
)
info = sdl2.SDL_RendererInfo()
sdl2.SDL_GetRendererInfo(renderer, info)
print(
"Renderer:",
info.name.decode(),
file=sys.stderr
)
font = ttf.TTF_OpenFont(
FONT.encode(),
42
)
manager = ControllerManager(
args.ignore,
args.debug
)
manager.scan()
event = sdl2.SDL_Event()
running = True
selected_controller = None
selected_time = 0
while running:
while sdl2.SDL_PollEvent(event):
if event.type == sdl2.SDL_CONTROLLERDEVICEADDED:
manager.add(
event.cdevice.which
)
elif event.type == sdl2.SDL_JOYDEVICEADDED:
manager.add(
event.jdevice.which
)
elif event.type == sdl2.SDL_JOYDEVICEREMOVED:
manager.remove(
event.jdevice.which
)
elif event.type == sdl2.SDL_CONTROLLERBUTTONDOWN:
instance = event.cbutton.which
if instance in manager.controllers:
selected_controller = manager.controllers[instance]["name"]
debug(
f"Selected {selected_controller}",
args.debug
)
selected_time = sdl2.SDL_GetTicks()
# draw
sdl2.SDL_SetRenderDrawColor(
renderer,
0,
0,
0,
255
)
sdl2.SDL_RenderClear(renderer)
draw_text(
renderer,
font,
args.question,
50,
50,
sdl2.SDL_Color(255,255,255,255)
)
y = 150
for c in manager.controllers.values():
draw_text(
renderer,
font,
"" + c["name"],
100,
y,
sdl2.SDL_Color(255,255,255,255)
)
y += 60
for name in manager.unsupported.values():
draw_text(
renderer,
font,
"" + name,
100,
y,
sdl2.SDL_Color(100,100,100,255)
)
y += 60
if selected_controller:
elapsed = sdl2.SDL_GetTicks() - selected_time
draw_text(
renderer,
font,
"Selected:",
100,
550,
sdl2.SDL_Color(255,255,255,255)
)
draw_text(
renderer,
font,
selected_controller,
100,
610,
sdl2.SDL_Color(0,255,0,255)
)
sdl2.SDL_RenderPresent(renderer)
if elapsed > 2000:
print(selected_controller)
running = False
continue
else:
sdl2.SDL_RenderPresent(renderer)
# cleanup
for c in manager.controllers.values():
sdl2.SDL_GameControllerClose(
c["controller"]
)
ttf.TTF_CloseFont(font)
sdl2.SDL_DestroyRenderer(renderer)
sdl2.SDL_DestroyWindow(window)
ttf.TTF_Quit()
sdl2.SDL_Quit()
if __name__ == "__main__":
sys.exit(main())