Scale the SDK 8-bit motor levels to SDL’s 16-bit range and use SDL’s maximum effect duration. Keep lookup and rumble under the controller lock so hot unplug cannot invalidate the SDL pointer.
Run() registers KytyClose with atexit(), but Execute() ends the process with
std::quick_exit(), which invokes at_quick_exit handlers only. Nothing registered
one, so the cleanup never ran and neither did the emergency shutdown handlers
that close open guest files and flush the log.
Register a quick-exit handler that runs the emergency shutdown. It deliberately
skips RuntimeLinker::Clear(): guest threads are still live at that point and
tearing the linker down there deadlocks against a thread parked in a condition
wait.