Maelstrom: Detect Steam Remote Play to phones

From 162c698a9958f9488025ab4db90fe923e1c03eee Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 27 Mar 2026 20:17:40 -0700
Subject: [PATCH] Detect Steam Remote Play to phones

---
 game/game.cpp  |  5 +--
 game/steam.cpp | 88 +++++++++++++++++++++++++++++++++-----------------
 game/steam.h   |  1 +
 3 files changed, 62 insertions(+), 32 deletions(-)

diff --git a/game/game.cpp b/game/game.cpp
index dd8ff193..b7e6d4c9 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -520,7 +520,8 @@ GamePanelDelegate::HandleEvent(const SDL_Event &event)
 			m_touchControls->Show();
 		}
 	} else if (event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED ||
-	           event.type == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED) {
+	           event.type == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED ||
+	           event.type == SDL_EVENT_REMOTE_PLAYERS_CHANGED) {
 		UpdateZoom();
 	}
 	return false;
@@ -597,7 +598,7 @@ GamePanelDelegate::UpdateZoom()
 	// We can zoom if we're on a phone in landscape mode and not local multiplayer
 	bool zoom = false;
 
-	if (SDL_IsPhone() && rect.w > rect.h) {
+	if ((SDL_IsPhone() || SteamStreamingToPhone()) && rect.w > rect.h) {
 		int i;
 
 		int local_players = 0;
diff --git a/game/steam.cpp b/game/steam.cpp
index f0fa696f..ae931c79 100644
--- a/game/steam.cpp
+++ b/game/steam.cpp
@@ -44,6 +44,8 @@ class SteamInterface
 	bool Init();
 	void Quit();
 
+	bool StreamingToPhone();
+
 	void SetSteamTimelineMode(STEAM_TIMELINE_MODE mode);
 	void SetSteamTimelineLevelStarted(int level);
 	void AddSteamTimelineEvent(STEAM_TIMELINE_EVENT event);
@@ -128,6 +130,28 @@ void SteamInterface::Quit()
 	m_initialized = false;
 }
 
+bool SteamInterface::StreamingToPhone()
+{
+	if (!m_initialized) {
+		return false;
+	}
+
+	ISteamRemotePlay *pSteamRemotePlay = SteamRemotePlay();
+	for (uint32 i = 0; i < pSteamRemotePlay->GetSessionCount(); ++i) {
+		RemotePlaySessionID_t sessionID = pSteamRemotePlay->GetSessionID(i);
+
+		// Skip Remote Play Together sessions
+		if (pSteamRemotePlay->BSessionRemotePlayTogether(sessionID)) {
+			continue;
+		}
+
+		if (pSteamRemotePlay->GetSessionClientFormFactor(sessionID) == k_ESteamDeviceFormFactorPhone) {
+			return true;
+		}
+	}
+	return false;
+}
+
 void SteamInterface::SetSteamTimelineMode(STEAM_TIMELINE_MODE mode)
 {
 	if (!m_initialized) {
@@ -435,28 +459,25 @@ void SteamInterface::OnRemotePlaySessionConnected(SteamRemotePlaySessionConnecte
 {
 	RemotePlaySessionID_t sessionID = pParam->m_unSessionID;
 
-	if (!IsRemotePlayTogether(sessionID)) {
-		// Ignore this session, it'll control the local player
-		return;
-	}
-
-	RemoteSession_t *session = new RemoteSession_t;
-	session->id = sessionID;
-	session->steamID = SteamRemotePlay()->GetSessionSteamID(sessionID);
+	if (IsRemotePlayTogether(sessionID)) {
+		RemoteSession_t *session = new RemoteSession_t;
+		session->id = sessionID;
+		session->steamID = SteamRemotePlay()->GetSessionSteamID(sessionID);
 
-	if (session->steamID.IsValid()) {
-		session->name = SDL_strdup(SteamFriends()->GetFriendPersonaName(session->steamID));
-	} else {
-		uint32 unGuestID = SteamRemotePlay()->GetSessionGuestID(sessionID);
-		if (unGuestID) {
-			SDL_asprintf(&session->name, TEXT("Guest %u"), unGuestID);
+		if (session->steamID.IsValid()) {
+			session->name = SDL_strdup(SteamFriends()->GetFriendPersonaName(session->steamID));
 		} else {
-			session->name = NULL;
+			uint32 unGuestID = SteamRemotePlay()->GetSessionGuestID(sessionID);
+			if (unGuestID) {
+				SDL_asprintf(&session->name, TEXT("Guest %u"), unGuestID);
+			} else {
+				session->name = NULL;
+			}
 		}
-	}
-	SDL_zeroa(session->keystate);
+		SDL_zeroa(session->keystate);
 
-	m_sessions.add(session);
+		m_sessions.add(session);
+	}
 
 	UpdatePlayers();
 }
@@ -465,21 +486,18 @@ void SteamInterface::OnRemotePlaySessionDisconnected(SteamRemotePlaySessionDisco
 {
 	RemotePlaySessionID_t sessionID = pParam->m_unSessionID;
 	RemoteSession_t *session = GetSession(sessionID);
-	if (!session) {
-		return;
-	}
-
-	m_sessions.remove(session);
+	if (session) {
+		m_sessions.remove(session);
 
-	for (unsigned int i = 0; i < SDL_arraysize(m_players); ++i) {
-		if (session == m_players[i]) {
-			m_players[i] = nullptr;
-			break;
+		for (unsigned int i = 0; i < SDL_arraysize(m_players); ++i) {
+			if (session == m_players[i]) {
+				m_players[i] = nullptr;
+				break;
+			}
 		}
+		SDL_free(session->name);
+		delete session;
 	}
-	SDL_free(session->name);
-	delete session;
-
 	UpdatePlayers();
 }
 
@@ -489,6 +507,11 @@ bool InitSteam()
 	return steam.Init();
 }
 
+bool SteamStreamingToPhone()
+{
+	return steam.StreamingToPhone();
+}
+
 Uint32 GetRemoteSessionForGamepad(SDL_Gamepad *gamepad)
 {
 	return steam.GetRemoteSessionForGamepad(gamepad);
@@ -561,6 +584,11 @@ bool InitSteam()
 	return false;
 }
 
+bool SteamStreamingToPhone()
+{
+	return false;
+}
+
 RemotePlaySessionID_t GetRemoteSessionForGamepad(SDL_Gamepad* gamepad)
 {
 	return 0;
diff --git a/game/steam.h b/game/steam.h
index 6bc555d7..7d76b77e 100644
--- a/game/steam.h
+++ b/game/steam.h
@@ -45,6 +45,7 @@ enum STEAM_TIMELINE_EVENT
 typedef Uint32 RemotePlaySessionID_t;
 
 extern bool InitSteam();
+extern bool SteamStreamingToPhone();
 extern RemotePlaySessionID_t GetRemoteSessionForGamepad(SDL_Gamepad *gamepad);
 extern Uint8 GetRemoteSessionControl(RemotePlaySessionID_t sessionID);
 extern const char *GetRemotePlayerName(Uint8 controlType);