Merge branch 'feat/steam-touch-controller' into local/touch-build

This commit is contained in:
x committed 2026-10-08 21:50:42 -04:00
commit bc0530463e
7 files changed
+21 -37

No files matched your search

@@ -147,7 +147,6 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private var onScreenControls: OnScreenControls? = null
/** Steam's touch controls (SteamTouchControls), made once the session offers the device. */
private var steamTouchControls: com.droiddeck.launcher.input.SteamTouchControls? = null
private var oscStyle by mutableStateOf(SessionPrefs.OSC_STYLE_DROIDDECK)
private var steamTouchAvailable by mutableStateOf(false)
private val steamTouchRetry = Runnable { updateOnScreenControls() }
/** While Steam's touch controls are up: how the game's touch config says touches outside them
@@ -571,16 +570,14 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
SessionPrefs.setBackActionsInverted(this@SessionActivity, inverted)
backActionsInverted = inverted
},
onOsc = { v -> SessionPrefs.setOscMode(this@SessionActivity, v); readPrefs(); updateOnScreenControls() },
oscStyle = if (SessionState.mode == SessionService.MODE_STEAM) oscStyle else null,
onOscStyle = { v ->
SessionPrefs.setOscStyle(this@SessionActivity, v)
onOsc = { v ->
SessionPrefs.setOscMode(this@SessionActivity, v)
readPrefs()
updateOnScreenControls()
if (v == SessionPrefs.OSC_STYLE_STEAM && com.droiddeck.launcher.input.SteamTouchDevice.current == null)
if (v == SessionPrefs.OSC_STEAM_TOUCH && com.droiddeck.launcher.input.SteamTouchDevice.current == null)
Toast.makeText(this@SessionActivity, R.string.osc_style_next_session, Toast.LENGTH_LONG).show()
},
onEditSteamTouch = if (steamTouchAvailable && oscStyle == SessionPrefs.OSC_STYLE_STEAM && onScreenButtonsVisible) ({
onEditSteamTouch = if (steamTouchAvailable && oscMode == SessionPrefs.OSC_STEAM_TOUCH && onScreenButtonsVisible) ({
drawerOpen = false
steamTouchControls?.startEditing()
}) else null,
@@ -824,7 +821,6 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
suspendPolicy = SessionPrefs.suspendPolicy(this, SessionState.mode)
steamDownloadsInBackground = SessionPrefs.steamDownloadsInBackground(this)
oscMode = SessionPrefs.oscMode(this)
oscStyle = SessionPrefs.oscStyle(this)
backActionsInverted = SessionPrefs.backActionsInverted(this)
}
@@ -1897,8 +1893,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
val buttonsOnly = forced == SessionPrefs.OSC_STEAM_QAM
// Steam's touch controller stands in for the app's pad, and is plugged into the client only
// while it is shown - as Steam Link withdraws its controls when a physical pad is in use.
val wantsSteam = !buttonsOnly && SessionState.mode == SessionService.MODE_STEAM &&
SessionPrefs.oscStyle(this) == SessionPrefs.OSC_STYLE_STEAM
val wantsSteam = forced == SessionPrefs.OSC_STEAM_TOUCH && SessionState.mode == SessionService.MODE_STEAM
val steam = if (wantsSteam) steamTouch() else null
// The service makes the device while the session starts, after this activity: the app's
// own pad until then, and another look in a moment.
@@ -1915,6 +1910,10 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
SessionPrefs.OSC_ALWAYS -> true
SessionPrefs.OSC_STEAM_QAM -> true
SessionPrefs.OSC_NEVER -> false
// Shown throughout a Steam session: a handheld's built-in pad would keep Auto off for good.
// Outside Steam it is Auto.
SessionPrefs.OSC_STEAM_TOUCH -> SessionState.mode == SessionService.MODE_STEAM ||
(!PadBridge.anyControllerConnected() && SessionState.mode != SessionService.MODE_DESKTOP)
// Auto: the touch pad when there is no controller - except on the desktop, where the
// screen is a touchpad for the pointer and a pad over it would be in the way. A game
// started from the rail, or Steam, gets it; the drawer turns it on anywhere.
@@ -22,9 +22,8 @@ object SessionPrefs {
const val OSC_ALWAYS = "always"
const val OSC_STEAM_QAM = "steam-qam"
const val OSC_NEVER = "never"
/** Whose on-screen controls: the app's own pad, or Steam's touch controller (SteamTouchControls). */
const val OSC_STYLE_DROIDDECK = "droiddeck"
const val OSC_STYLE_STEAM = "steam"
/** Steam's touch controller (SteamTouchControls) in place of the app's pad; Steam sessions only. */
const val OSC_STEAM_TOUCH = "steam-touch"
/** What Back does in a Steam session, first press then second: the labels of the two orders. */
val BACK_MENU_THEN_QAM = R.string.back_menu_then_qam
@@ -114,12 +113,6 @@ object SessionPrefs {
prefs(context).edit().putString("osc", mode).apply()
}
fun oscStyle(context: Context): String = prefs(context).getString("oscStyle", OSC_STYLE_DROIDDECK) ?: OSC_STYLE_DROIDDECK
fun setOscStyle(context: Context, style: String) {
prefs(context).edit().putString("oscStyle", style).apply()
}
/**
* The imported glibc Turnip every session draws with inside the runtime - Steam, its games and
* the desktop alike, as they run on the same GPU; "" = the driver built into the runtime.
@@ -43,7 +43,7 @@ private fun Swatch(color: Int) {
fun ColumnScope.ControllerRows(host: MenuHost, oscMode: String, c: ControllerPrefs.Settings, a: ControllerActions) {
ChoiceRow(
host, "controller-osc", stringResource(R.string.mode_osc), stringResource(R.string.ctrl_osc_hint),
listOf(SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto), SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always), SessionPrefs.OSC_STEAM_QAM to stringResource(R.string.mode_osc_qam), SessionPrefs.OSC_NEVER to stringResource(R.string.common_never)),
listOf(SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto), SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always), SessionPrefs.OSC_STEAM_TOUCH to stringResource(R.string.osc_steam_touch), SessionPrefs.OSC_STEAM_QAM to stringResource(R.string.mode_osc_qam), SessionPrefs.OSC_NEVER to stringResource(R.string.common_never)),
oscMode, note = stringResource(R.string.mode_osc_note), onPick = a.onOsc,
)
val tintOpen = host.open == "controller-tint"
@@ -270,6 +270,7 @@ fun ModeSettingsPage(s: ModeSettings, a: ModeSettingsActions) {
listOf(
SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto),
SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always),
SessionPrefs.OSC_STEAM_TOUCH to stringResource(R.string.osc_steam_touch),
SessionPrefs.OSC_STEAM_QAM to stringResource(R.string.mode_osc_qam),
SessionPrefs.OSC_NEVER to stringResource(R.string.common_never),
), s.oscMode,
@@ -217,9 +217,6 @@ class DrawerActions(
val onSteamMenu: (() -> Unit)?,
val onQam: (() -> Unit)?,
val onOsc: (String) -> Unit,
/** Whose on-screen controls (SessionPrefs.OSC_STYLE_*); null where Steam's are not offered. */
val oscStyle: String? = null,
val onOscStyle: (String) -> Unit = {},
/** Edits the Steam touch layout of the game in front, when Steam's controls are up. */
val onEditSteamTouch: (() -> Unit)? = null,
val controller: com.droiddeck.launcher.input.ControllerPrefs.Settings? = null,
@@ -423,14 +420,11 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
listOf(SessionPrefs.TOUCH_AUTO to stringResource(R.string.drawer_touch_auto, a.touchAuto), SessionPrefs.TOUCH_PAD to stringResource(R.string.mode_touch_touchpad), SessionPrefs.TOUCH_DIRECT to stringResource(R.string.mode_touch_direct), SessionPrefs.TOUCH_OFF to stringResource(R.string.widgets_off)),
a.touchMode, chipModifier = focus.track(page, "touch"), onPick = a.onTouch)
ChoiceRow(host, "osc", stringResource(R.string.mode_osc), null,
if (a.steam) listOf(SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto), SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always), SessionPrefs.OSC_STEAM_QAM to stringResource(R.string.mode_osc_qam), SessionPrefs.OSC_NEVER to stringResource(R.string.common_never))
if (a.steam) listOf(SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto), SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always), SessionPrefs.OSC_STEAM_TOUCH to stringResource(R.string.osc_steam_touch), SessionPrefs.OSC_STEAM_QAM to stringResource(R.string.mode_osc_qam), SessionPrefs.OSC_NEVER to stringResource(R.string.common_never))
else listOf(SessionPrefs.OSC_AUTO to stringResource(R.string.common_auto), SessionPrefs.OSC_ALWAYS to stringResource(R.string.common_always), SessionPrefs.OSC_NEVER to stringResource(R.string.common_never)),
a.oscMode, chipModifier = focus.track(page, "osc"), onPick = a.onOsc)
a.oscStyle?.let { style ->
ChoiceRow(host, "osc-style", stringResource(R.string.osc_style), stringResource(R.string.osc_style_hint),
listOf(SessionPrefs.OSC_STYLE_DROIDDECK to stringResource(R.string.osc_style_droiddeck), SessionPrefs.OSC_STYLE_STEAM to stringResource(R.string.osc_style_steam)),
style, chipModifier = focus.track(page, "osc-style"), onPick = a.onOscStyle)
}
// Steam's touch controller is Steam's alone; elsewhere that choice behaves as Auto.
if (!a.steam && a.oscMode == SessionPrefs.OSC_STEAM_TOUCH) SessionPrefs.OSC_AUTO else a.oscMode,
chipModifier = focus.track(page, "osc"), onPick = a.onOsc)
a.onEditSteamTouch?.let { edit ->
ActionRow(stringResource(R.string.osc_steam_layout), stringResource(R.string.osc_steam_layout_hint), stringResource(R.string.ctrl_edit), edit)
}
+1 -4
View File
@@ -257,10 +257,7 @@
<string name="mode_osc">On-screen controls</string>
<string name="mode_osc_qam">Steam + QAM</string>
<string name="mode_osc_note">Auto shows the controls when no controller is connected.</string>
<string name="osc_style">Touch controls</string>
<string name="osc_style_hint">DroidDeck\'s own pad, or Steam\'s touch controller: per-game layouts and configs from Steam</string>
<string name="osc_style_droiddeck">DroidDeck</string>
<string name="osc_style_steam">Steam (beta)</string>
<string name="osc_steam_touch">Steam touch (beta)</string>
<string name="osc_style_next_session">Steam\'s touch controls start with the next Steam session</string>
<string name="osc_steam_layout">Steam touch layout</string>
<string name="osc_steam_layout_hint">Move, resize or hide this game\'s touch controls; saved to Steam</string>
+3 -3
View File
@@ -1,6 +1,6 @@
# Steam's touch controls
Drawer → Controller → **Touch controls: Steam (beta)** replaces DroidDeck's own on-screen pad, in a
Drawer → Controller → **On-screen controls: Steam touch (beta)** replaces DroidDeck's own on-screen pad, in a
Steam session, with Steam's touch controller: the one the Steam Link apps use. Bindings, action
sets, per-game configs, Valve's touch templates, official and community touch configs and Steam
Cloud sync are all Steam's; DroidDeck draws the controls and turns touches into the controller's
@@ -35,8 +35,8 @@ SteamTouchConfig (Steam's configs) ←─── output reports ←── Ste
- **Output reports from the client:** 4 = app id and action set (decides which layout is shown),
5/6 = action set layer added/removed, 1 = rumble (also sent to the app's vibration like any
pad's), 3 = a setting. Feature report 2 is the battery.
- **Plugging.** The device is plugged in only while Steam's controls are shown: with Auto it steps
aside when a controller is connected, as Steam Link withdraws its touch controls. Unplugging
- **Plugging.** The device is plugged in only while Steam's controls are shown: always in a Steam
session with that choice, since a handheld's built-in pad would keep Auto off for good. Unplugging
ends the device's report stream (the client lets the controller go); either way libfakeinput
sends a udev event through `udevmon.c`'s stand-in monitor (`bl_udevmon_inject`), since the
sandbox gives the client no kernel uevents and its HID discovery would never look again.