Fixes broken input after returning from an exclusive OpenGamepadUI session: the OGPU session leaves InputPlumber intercepting the gamepad in Block mode, so Steam cannot read it. Restart InputPlumber before switching, and return to the session recorded by os-session-select instead of hardcoding 'steam' so the autologin config is preserved.
124 lines
4.1 KiB
GDScript
124 lines
4.1 KiB
GDScript
extends Plugin
|
|
|
|
## Adds a "Switch to Steam" button to the power menu on ChimeraOS and SteamOS.
|
|
##
|
|
## OpenGamepadUI's built-in ChimeraOS platform support adds a "Switch to
|
|
## Desktop" button but has no way to return to Steam game mode. This plugin
|
|
## adds that missing button so users can round-trip between an exclusive
|
|
## OpenGamepadUI session and Steam.
|
|
|
|
const SESSION_SELECT_PATH := "/usr/lib/os-session-select"
|
|
const POWER_MENU_GROUP := "power_menu"
|
|
const BUTTON_NAME := "SwitchToSteamButton"
|
|
const MAX_ATTEMPTS := 600
|
|
|
|
# ChimeraOS records the session that was active before OpenGamepadUI took over
|
|
# in this file when the OpenGamepadUI session is entered. We return to that
|
|
# session instead of hardcoding a name so the autologin config is not mangled.
|
|
const RETURN_SESSION_FILE := "/.config/chimeraos-session-return"
|
|
const DEFAULT_RETURN_SESSION := "gamescope-session-steam-plus"
|
|
|
|
# Sessions os-session-select can be told to return to (matching the values it
|
|
# writes to the return-session file).
|
|
const RETURN_SESSIONS := [
|
|
"gamescope-session-steam-plus",
|
|
"gamescope-session-steam",
|
|
"gamescope-session-opengamepadui",
|
|
]
|
|
|
|
|
|
func _ready() -> void:
|
|
logger = Log.get_logger("SessionSwitch", Log.LEVEL.INFO)
|
|
if not _has_session_switcher():
|
|
logger.info("No session switcher script detected: " + SESSION_SELECT_PATH)
|
|
return
|
|
_add_button_when_ready()
|
|
|
|
|
|
func _add_button_when_ready() -> void:
|
|
for i in MAX_ATTEMPTS:
|
|
if _try_add_button():
|
|
return
|
|
await get_tree().process_frame
|
|
logger.info("Power menu never became available. Skipping 'Switch to Steam' button.")
|
|
|
|
|
|
func _try_add_button() -> bool:
|
|
var power_menu := get_tree().get_first_node_in_group(POWER_MENU_GROUP)
|
|
if not power_menu:
|
|
return false
|
|
|
|
var exit_button = power_menu.get("exit_button")
|
|
if not exit_button:
|
|
return false
|
|
|
|
var container = exit_button.get_parent()
|
|
if not container:
|
|
return false
|
|
if container.has_node(BUTTON_NAME):
|
|
return true
|
|
|
|
var button_scene := load("res://core/ui/components/card_button.tscn") as PackedScene
|
|
if not button_scene:
|
|
logger.error("Unable to load card_button scene.")
|
|
return true
|
|
var button := button_scene.instantiate()
|
|
button.name = BUTTON_NAME
|
|
button.set("click_focuses", false)
|
|
button.set("text", "Switch to Steam")
|
|
button.pressed.connect(_switch_session)
|
|
|
|
container.add_child(button)
|
|
container.move_child(button, exit_button.get_index())
|
|
|
|
var focus_group = power_menu.get("focus_group")
|
|
if focus_group and focus_group.has_method("recalculate_focus"):
|
|
focus_group.recalculate_focus()
|
|
|
|
logger.info("Added 'Switch to Steam' button to the power menu.")
|
|
return true
|
|
|
|
|
|
## Returns true if the session switcher script is present.
|
|
func _has_session_switcher() -> bool:
|
|
return FileAccess.file_exists(SESSION_SELECT_PATH)
|
|
|
|
|
|
## Switches back to the session that was active before OpenGamepadUI took
|
|
## over, using the OS session switcher.
|
|
func _switch_session() -> void:
|
|
_restart_inputplumber()
|
|
var target := _get_return_session()
|
|
var out: Array = []
|
|
var code := OS.execute(SESSION_SELECT_PATH, [target], out)
|
|
if code != OK:
|
|
logger.error("Unable to switch sessions: " + _result_text(out))
|
|
|
|
|
|
## Restarts InputPlumber before switching back so the exclusive OpenGamepadUI
|
|
## session does not leave the gamepad intercepted (blocked) for Steam.
|
|
## ChimeraOS ships passwordless sudo for exactly this command in its default
|
|
## sudoers, so the switch itself remains non-interactive.
|
|
func _restart_inputplumber() -> void:
|
|
var out: Array = []
|
|
var code := OS.execute("sudo", ["-n", "systemctl", "restart", "inputplumber"], out)
|
|
if code != OK:
|
|
logger.warning("Unable to restart InputPlumber: " + _result_text(out))
|
|
|
|
|
|
## Returns the session recorded by os-session-select before OpenGamepadUI was
|
|
## entered, falling back to the ChimeraOS default Steam session.
|
|
func _get_return_session() -> String:
|
|
var home := OS.get_environment("HOME")
|
|
if home.is_empty():
|
|
return DEFAULT_RETURN_SESSION
|
|
var file := FileAccess.open(home + RETURN_SESSION_FILE, FileAccess.READ)
|
|
if file:
|
|
var session := file.get_as_text().strip_edges()
|
|
if session in RETURN_SESSIONS:
|
|
return session
|
|
return DEFAULT_RETURN_SESSION
|
|
|
|
|
|
func _result_text(out: Array) -> String:
|
|
return out[0] if not out.is_empty() else ""
|