Something went wrong. Try again.
Steam Deck Doom modding setup automation for Doom Runner, UZDoom, Brutal Doom, and Project Brutality.
brutal-doom moddb python doom-runner linux-gaming project-brutality uzdoom doom steam-deck
Something went wrong. Try again.
15 kB · 329 lines
Python
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330"""Build DoomDeck's source-port and Steam Input control profiles."""from __future__ import annotations
from doomdeck.domain.control_mapping import ( ControlAction, ControlProfile, ControlScheme, ControlSchemeAlternative, KeyboardMouseOutput, PhysicalInput, SensitivitySettings, SourcePortAlias, SourcePortBinding, SourcePortControlProfile, SteamInputBinding,)
DOOMDECK_STEAM_INPUT_TITLE = "DoomDeck Hybrid KB/M"DOOMDECK_STEAM_INPUT_DESCRIPTION = ( "Steam Deck layout generated by DoomDeck for Doom Runner and UZDoom-family presets. " "It emits keyboard/mouse inputs, uses no gyro, and keeps quick load behind a long-press rear grip.")QUICKLOAD_LONG_PRESS_MS = 1500
def key(value: str, label: str) -> KeyboardMouseOutput: return KeyboardMouseOutput("key", value, label)
def mouse_button(value: str, label: str) -> KeyboardMouseOutput: return KeyboardMouseOutput("mouse_button", value, label)
def mouse_wheel(value: str, label: str) -> KeyboardMouseOutput: return KeyboardMouseOutput("mouse_wheel", value, label)
def build_default_control_scheme() -> ControlScheme: """Return the selected Steam Deck keyboard/mouse layout."""
bindings = ( SteamInputBinding(PhysicalInput.LEFT_STICK, ControlAction.MOVE, key("W", "Move forward"), input_slot="dpad_north"), SteamInputBinding(PhysicalInput.LEFT_STICK, ControlAction.MOVE, key("S", "Move back"), input_slot="dpad_south"), SteamInputBinding(PhysicalInput.LEFT_STICK, ControlAction.MOVE, key("D", "Strafe right"), input_slot="dpad_east"), SteamInputBinding(PhysicalInput.LEFT_STICK, ControlAction.MOVE, key("A", "Strafe left"), input_slot="dpad_west"), SteamInputBinding(PhysicalInput.LEFT_STICK, ControlAction.RUN_TOGGLE, key("CAPSLOCK", "Toggle run mode"), input_slot="click"), SteamInputBinding( PhysicalInput.RIGHT_TRACKPAD, ControlAction.AIM, KeyboardMouseOutput("mouse", "absolute_mouse", "Aim"), activation="Soft_Press", ), SteamInputBinding( PhysicalInput.RIGHT_TRACKPAD, ControlAction.FLASHLIGHT_OR_ZOOM, mouse_button("MIDDLE", "Zoom / center view"), activation="Soft_Press", input_slot="click", ), SteamInputBinding(PhysicalInput.RIGHT_STICK, ControlAction.AIM, KeyboardMouseOutput("mouse", "joystick_mouse", "Coarse aim")), SteamInputBinding( PhysicalInput.RIGHT_STICK, ControlAction.FLASHLIGHT_OR_ZOOM, mouse_button("MIDDLE", "Zoom / center view"), input_slot="click", ), SteamInputBinding(PhysicalInput.RIGHT_TRIGGER, ControlAction.FIRE, mouse_button("LEFT", "Fire"), input_slot="edge"), SteamInputBinding( PhysicalInput.LEFT_TRIGGER, ControlAction.ALT_FIRE, mouse_button("RIGHT", "Alt fire / ADS"), input_slot="edge", ), SteamInputBinding( PhysicalInput.LEFT_BUMPER, ControlAction.PREVIOUS_WEAPON, mouse_wheel("SCROLL_DOWN", "Previous weapon"), input_slot="left_bumper", ), SteamInputBinding( PhysicalInput.RIGHT_BUMPER, ControlAction.NEXT_WEAPON, mouse_wheel("SCROLL_UP", "Next weapon"), input_slot="right_bumper", ), SteamInputBinding(PhysicalInput.A, ControlAction.USE, key("E", "Use / confirm"), input_slot="button_a"), SteamInputBinding(PhysicalInput.B, ControlAction.CROUCH, key("LEFT_CONTROL", "Crouch / menu back"), input_slot="button_b"), SteamInputBinding(PhysicalInput.X, ControlAction.RELOAD, key("R", "Reload"), input_slot="button_x"), SteamInputBinding(PhysicalInput.Y, ControlAction.JUMP, key("SPACE", "Jump / use"), input_slot="button_y"), SteamInputBinding(PhysicalInput.DPAD, ControlAction.MENU_NAVIGATION, key("UP_ARROW", "Menu up"), input_slot="dpad_north"), SteamInputBinding(PhysicalInput.DPAD, ControlAction.MENU_NAVIGATION, key("DOWN_ARROW", "Menu down"), input_slot="dpad_south"), SteamInputBinding(PhysicalInput.DPAD, ControlAction.MENU_NAVIGATION, key("RIGHT_ARROW", "Menu right"), input_slot="dpad_east"), SteamInputBinding(PhysicalInput.DPAD, ControlAction.MENU_NAVIGATION, key("LEFT_ARROW", "Menu left"), input_slot="dpad_west"), SteamInputBinding(PhysicalInput.MENU, ControlAction.MENU, key("ESCAPE", "Menu / pause"), input_slot="button_escape"), SteamInputBinding(PhysicalInput.VIEW, ControlAction.AUTOMAP, key("TAB", "Automap"), input_slot="button_menu"), SteamInputBinding(PhysicalInput.L4, ControlAction.JUMP, key("SPACE", "L4 jump"), input_slot="button_back_left_upper"), SteamInputBinding( PhysicalInput.R4, ControlAction.CROUCH, key("LEFT_CONTROL", "R4 crouch"), input_slot="button_back_right_upper", ), SteamInputBinding(PhysicalInput.L5, ControlAction.QUICK_SAVE, key("F6", "L5 quick save"), input_slot="button_back_left"), SteamInputBinding( PhysicalInput.R5, ControlAction.QUICK_LOAD, key("F9", "R5 long-press quick load"), activation="Long_Press", long_press_ms=QUICKLOAD_LONG_PRESS_MS, note="Long press only; no base-layer F9 binding is emitted.", input_slot="button_back_right", ), SteamInputBinding(PhysicalInput.LEFT_TRACKPAD, ControlAction.DIRECT_WEAPON, KeyboardMouseOutput("radial_menu", "1-9,0", "Weapon wheel")), *( SteamInputBinding( PhysicalInput.LEFT_TRACKPAD, action, key(value, label), layer="radial", input_slot=f"touch_menu_button_{index}", ) for index, (value, label, action) in enumerate( [ *((str(slot), f"Weapon slot {slot}", ControlAction.DIRECT_WEAPON) for slot in range(1, 10)), ("0", "Weapon slot 10", ControlAction.DIRECT_WEAPON), ("Q", "Brutal/PB kick", ControlAction.MOD_ACTION), ("F", "Flashlight / zoom / mod utility", ControlAction.FLASHLIGHT_OR_ZOOM), ("G", "PB equipment", ControlAction.MOD_ACTION), ("U", "PB unload", ControlAction.MOD_ACTION), ("LEFT_ALT", "PB dash", ControlAction.MOD_ACTION), ("L", "PB clear debris", ControlAction.MOD_ACTION), ], start=1, ) ), ) return ControlScheme( name=DOOMDECK_STEAM_INPUT_TITLE, description=DOOMDECK_STEAM_INPUT_DESCRIPTION, bindings=bindings, sensitivity=SensitivitySettings(), alternatives=( ControlSchemeAlternative( "Console-like face buttons", "ABXY carries use/crouch/reload/jump with bumpers for weapon cycling.", "Comfortable and familiar, but jump/reload/use pull the right thumb off aim when gyro is disabled.", ), ControlSchemeAlternative( "PC-preserving combat layout", "Right trackpad/stick emit mouse, left stick emits WASD, and rear grips keep movement actions under fingers.", "Best combat feel, but needs a radial menu and a documented menu/utility plan.", ), ControlSchemeAlternative( "Safety/menu-first layout", "D-pad and face buttons prioritize launcher/menu navigation and move save/load to utility chords.", "Great for Doom Runner setup screens, but weaker during normal combat and weapon switching.", ), ), evidence=( "id Software DOOM m_misc.c defaults: Space use, Right Ctrl fire, Shift run/speed.", "GZDoom commonbinds/defbinds: WASD, E use, Mouse1 fire, Mouse2 alt-fire, wheel weapons, F6/F9 save/load.", "UZDoom defaults: Ctrl crouch, R reload, Mouse3 zoom, controller triggers/bumpers, rear paddles for secondary actions.", "Brutal Doom FAQ/ModDB: Right Mouse alt-fire/ADS, Q kick, WASD/E/Space/Ctrl conventions.", "Project Brutality KEYCONF: Q kick, F quick melee, G equipment, U unload, LeftAlt dash, L clear debris.", "Valve Steam Deck/Steam Input docs: keyboard/mouse outputs, trackpad mouse modes, action/chord style layouts, four grip buttons.", ), rationale=( "Hybrid PC-preserving controls best satisfy keyboard/mouse Steam Input, no gyro, and modern console Doom ergonomics: " "aim stays on the right trackpad/stick, triggers fire, bumpers cycle weapons, face buttons remain familiar, " "and rear grips cover jump/crouch/quicksave/long-press quickload." ), gyro_enabled=False, )
def build_uzdoom_control_profiles() -> tuple[SourcePortControlProfile, ...]: return ( build_uzdoom_control_profile(ControlProfile.CLASSIC), build_uzdoom_control_profile(ControlProfile.MODERN), build_uzdoom_control_profile(ControlProfile.BRUTAL_DOOM), build_uzdoom_control_profile(ControlProfile.PROJECT_BRUTALITY), )
def build_uzdoom_control_profile(profile: ControlProfile) -> SourcePortControlProfile: if profile == ControlProfile.CLASSIC: return _classic_profile() if profile == ControlProfile.MODERN: return _modern_profile(ControlProfile.MODERN, "Modern dual-stick/FPS-style behavior for UZDoom.", bind_q=True, bind_f=True) if profile == ControlProfile.BRUTAL_DOOM: return _modern_profile( ControlProfile.BRUTAL_DOOM, "Brutal Doom behavior; preserves Q for the mod's default kick binding.", bind_q=False, bind_f=True, ) return _modern_profile( ControlProfile.PROJECT_BRUTALITY, "Project Brutality behavior; preserves mod KEYCONF defaults for Q/F/G/U/Alt/L utilities.", bind_q=False, bind_f=False, )
def _common_aliases(*, crouch_back: bool) -> tuple[SourcePortAlias, ...]: aliases = [ SourcePortAlias("+deck_use_select", '"+use; menu_select"'), SourcePortAlias("-deck_use_select", '"-use"'), ] if crouch_back: aliases.extend( [ SourcePortAlias("+deck_crouch_back", '"+crouch; menu_back"'), SourcePortAlias("-deck_crouch_back", '"-crouch"'), ] ) else: aliases.extend( [ SourcePortAlias("+deck_menu_back", '"menu_back"'), SourcePortAlias("-deck_menu_back", '""'), ] ) return tuple(aliases)
def _base_bindings() -> list[SourcePortBinding]: return [ SourcePortBinding("w", "+forward"), SourcePortBinding("s", "+back"), SourcePortBinding("a", "+moveleft"), SourcePortBinding("d", "+moveright"), SourcePortBinding("uparrow", "menu_up"), SourcePortBinding("downarrow", "menu_down"), SourcePortBinding("leftarrow", "menu_left"), SourcePortBinding("rightarrow", "menu_right"), SourcePortBinding("mouse1", "+attack"), SourcePortBinding("mouse2", "+altattack"), SourcePortBinding("e", "+deck_use_select"), SourcePortBinding("capslock", '"toggle cl_run"'), SourcePortBinding("tab", "togglemap"), SourcePortBinding("F6", "quicksave"), SourcePortBinding("F9", "quickload"), SourcePortBinding("escape", "menu_main"), SourcePortBinding("enter", "menu_select"), SourcePortBinding("backspace", "menu_back"), SourcePortBinding("mwheelup", "weapnext"), SourcePortBinding("mwheeldown", "weapprev"), ]
def _weapon_slot_bindings() -> list[SourcePortBinding]: return [*(SourcePortBinding(str(slot), f"slot {slot}") for slot in range(1, 10)), SourcePortBinding("0", "slot 0")]
def _classic_profile() -> SourcePortControlProfile: bindings = _base_bindings() bindings.extend( [ SourcePortBinding("space", "+deck_use_select"), SourcePortBinding("leftctrl", "+deck_menu_back"), SourcePortBinding("RTrigger", "+attack"), SourcePortBinding("LTrigger", "+altattack"), SourcePortBinding("LShoulder", "weapprev"), SourcePortBinding("RShoulder", "weapnext"), SourcePortBinding("Pad_A", "+deck_use_select"), SourcePortBinding("Pad_B", "menu_back"), SourcePortBinding("Pad_Start", "menu_main"), SourcePortBinding("Pad_Back", "+showscores"), ] ) bindings.extend(_weapon_slot_bindings()) return SourcePortControlProfile( profile=ControlProfile.CLASSIC, description="Classic-style Doom behavior for UZDoom/GZDoom-family source ports.", cvars=( ("freelook", "false"), ("lookstrafe", "false"), ("m_pitch", "0"), ("sv_allowjump", "false"), ("sv_allowcrouch", "false"), ("cl_run", "true"), ("crosshair", "0"), ), aliases=_common_aliases(crouch_back=False), bindings=tuple(bindings), )
def _modern_profile(profile: ControlProfile, description: str, *, bind_q: bool, bind_f: bool) -> SourcePortControlProfile: bindings = _base_bindings() bindings.extend( [ SourcePortBinding("space", "+jump"), SourcePortBinding("leftctrl", "+deck_crouch_back"), SourcePortBinding("c", "+crouch"), SourcePortBinding("r", "+reload"), SourcePortBinding("Pad_A", "+deck_use_select"), SourcePortBinding("Pad_B", "+deck_crouch_back"), SourcePortBinding("Pad_X", "+reload"), SourcePortBinding("Pad_Y", "+jump"), SourcePortBinding("Pad_Start", "menu_main"), SourcePortBinding("Pad_Back", "+showscores"), SourcePortBinding("RTrigger", "+attack"), SourcePortBinding("LTrigger", "+altattack"), SourcePortBinding("LShoulder", "weapprev"), SourcePortBinding("RShoulder", "weapnext"), ] ) if bind_q: bindings.append(SourcePortBinding("q", "weapprev")) if bind_f: bindings.append(SourcePortBinding("f", "+zoom")) bindings.extend(_weapon_slot_bindings()) return SourcePortControlProfile( profile=profile, description=description, cvars=( ("freelook", "true"), ("lookstrafe", "false"), ("m_pitch", "1"), ("sv_allowjump", "true"), ("sv_allowcrouch", "true"), ("cl_run", "true"), ("crosshair", "1"), ), aliases=_common_aliases(crouch_back=True), bindings=tuple(bindings), )