-
Notifications
You must be signed in to change notification settings - Fork 0
System
Since v0.5.0. steam.system is the curated layer over ISteamUtils: the facts
about the machine and the Steam client this app runs under, plus the two
gamepad keyboards. It is called system because the generated ISteamUtils
class already owns steam.utils.
Everything here reads the running Steam client, so it answers right away. showGamepadTextInput is the one exception: it opens the Big Picture keyboard and resolves when the user is done with it.
Some methods come from a different interface. gameLanguage and
everything under the running app are ISteamApps reads,
because they answer questions about this process rather than about its DLC,
which is what DLC covers.
The System instance is created lazily and cached on the Steam object. The
overlay calls of ISteamUtils are on Overlay, and avatars have
their own decode in social.avatar; image here is the
generic form for any Steam image handle.
appId(): numberThe app id this process is running under, as Steam sees it. steam.appId is
the one init was given; this is Steam's answer, which is the better one to
trust when the app id came from steam_appid.txt.
isSteamDeck(): booleanWhether the app runs on a Steam Deck. Use it to switch to the controller-first UI and the larger text Valve's Deck Verified checks look for.
SDK 1.65 replaced the old IsSteamRunningOnSteamDeck with
IsRunningOnSteamHardware, which names the hardware instead of answering yes
or no, so this compares against k_ESteamHardwareTypeSteamDeck. It is false on
every other machine, Steam Machine and Steam Frame included. Read
steam.utils.IsRunningOnSteamHardware() directly when you care which one.
isBigPicture(): boolean
isVr(): boolean
isChinaLauncher(): booleanisBigPicture is Big Picture mode, which is also the mode a Steam Deck runs
in, and it is what gates the gamepad keyboards. isVr is whether Steam runs in
VR. isChinaLauncher is the Steam China build, which has its own rules for
anti-addiction and age checks, so an app that ships there must branch on it.
uiLanguage(): stringThe language the Steam client UI is in, as an API language code, for example
english or german.
gameLanguage(): stringThe language this app was launched in, same code format. This is the one to localize the game with: the user may run the client in one language and the game in another.
Since v0.6.0. The rest of this section is what ISteamApps says about the
process you are in: where it lives on disk, which build and branch it is, how
it was launched, and whose licence it runs under. All of it is a local read.
installDir(appId?: number): string | nullThe absolute install directory of an app, defaulting to the running one, or
null when Steam knows no path for that app id.
Steam also answers for an app the user owns but has not installed, with the path it would install to, so pair this with isAppInstalled before touching the files. The path is read into a 1024-byte buffer.
import { init } from 'steamwand.js';
const steam = init({ appId: 480 });
console.log(steam.system.installDir(), steam.system.buildId());
steam.close();isAppInstalled(appId: number): booleanWhether an app's files are on disk. Meant for the other app in a launcher or a bundle; DLC state is dlc.isInstalled.
buildId(): numberThe build id of the running app, or 0 when the app is not running under Steam. Steamworks assigns a new one on every upload, so this is the version number to put in a bug report or a crash log.
currentBeta(): string | nullThe beta branch the app is running from, or null on the default branch, which
is where a user without a beta opt-in is. null is the normal answer for a
shipped game.
listBetas(): BetaBranch[]The beta branches of the running app that this user may see, in Steam's order. Empty when the app has no branches.
Steam reports one flags field per branch; this spreads it into the five booleans of BetaBranch. Names are read into a 64-byte buffer and descriptions into a 256-byte one, and a branch Steam refuses at its index is skipped rather than pushed half-filled.
for (const beta of steam.system.listBetas()) {
console.log(beta.name, beta.buildId, beta.installed ? '(installed)' : '');
}setActiveBeta(name: string): voidSwitches the app to a beta branch. The empty string switches back to the default branch.
Steam only records the choice. The branch is downloaded and the app runs from it after the next restart through Steam, so nothing changes in the running process. A private branch has to be unlocked with its password in the Steam client first.
Throws Error: steamwand: SetActiveBeta returned false (...) for an unknown or
locked branch name.
launchCommandLine(): string
launchQueryParam(key: string): stringlaunchCommandLine is the arguments Steam launched this app with, or an empty
string when there were none. This is where a steam://run/<appid>//<params>
link ends up, and where a +connect string lands when a friend's invite
started the app rather than finding it running. It is read into a 1024-byte
buffer.
launchQueryParam is one parameter of a steam://run/<appid>//?key=value
link, already parsed, or an empty string when the app was not launched with it.
Pass the key with no leading ? or &.
onLaunchParameters(listener: () => void): () => voidSubscribes to new launch arguments arriving for the running app, and returns an unsubscribe function.
It fires when Steam passes a steam://run/<appid>//<params> link to an app
that is already up, which is how a second click on a store or web link reaches
it. The callback carries no payload: read the new arguments with
launchCommandLine or launchQueryParam.
const off = steam.system.onLaunchParameters(() => {
console.log(steam.system.launchCommandLine());
});
// later: off();appOwner(): bigint
isFamilyShared(): booleanappOwner is the Steam id of the account whose licence this app runs under,
which is the local user except under Family Sharing. isFamilyShared is the
same fact as a boolean.
A borrowed session ends the moment the owner starts playing, so a game that cares about long sessions should warn the player rather than lose their progress.
timedTrial(): { secondsAllowed: number; secondsPlayed: number } | nullThe trial budget for an app the user is only trying out, or null when this is
not a timed trial, which is the normal answer.
const trial = steam.system.timedTrial();
if (trial) console.log(trial.secondsAllowed - trial.secondsPlayed, 'seconds left');ipCountry(): stringThe two letter ISO 3166-1 country code Steam geolocated this user's IP to, for
example DE. It is a guess from the IP address, not the country on the
account, so treat it as a default for matchmaking or currency rather than a
fact.
serverTime(): DateSteam's own wall clock time, as a Date. Use it wherever a local clock could
be wrong or tampered with, for example a daily reward or an event window.
import { init } from 'steamwand.js';
const steam = init({ appId: 480 });
console.log(steam.system.serverTime().toISOString());
console.log(steam.system.gameLanguage(), steam.system.ipCountry());
steam.close();secondsSinceAppActive(): number
secondsSinceComputerActive(): numberSeconds since this app started, and seconds since the last user input anywhere on this computer. The second one is how you tell an idle machine from an idle game.
batteryPower(): number | 'ac'Remaining battery charge in percent on a laptop or a handheld, or the string
'ac' when the machine runs on mains power. Steam reports 255 for mains power;
this turns that into 'ac' so a plugged-in machine can never look like a
full battery.
const power = steam.system.batteryPower();
if (power !== 'ac' && power < 20) console.log('save the game');isOverlayEnabled(): booleanWhether the Steam overlay can render over this app. The same read as overlay.isEnabled, here because it is a fact about the client.
image(handle: number): SteamImage | nullOne Steam image by handle, as raw RGBA pixels. Handles come from other calls,
for example the avatar handles on ISteamFriends. Two flat calls under the
hood: GetImageSize for the dimensions, then GetImageRGBA into a buffer of
exactly that size.
Returns null when Steam does not know the handle, which includes handle 0.
Throws Error: steamwand: GetImageRGBA returned false (...) when the size was
known but the pixels could not be read.
showGamepadTextInput(options: GamepadTextInputOptions): Promise<string | null>Opens the full screen gamepad keyboard and resolves with what the user typed,
or null if they dismissed it without submitting.
It only shows up in Big Picture mode and on Steam Deck. Everywhere else the
show call fails and this rejects at once. The text is fetched with
GetEnteredGamepadTextInput inside the dismissal callback, the only moment
Steam still holds it.
const name = await steam.system.showGamepadTextInput({
description: 'Your name',
maxChars: 32,
});
if (name !== null) console.log(name);Throws Error: steamwand: ShowGamepadTextInput returned false (not in Big Picture mode?).
showFloatingGamepadTextInput(
mode: number, x: number, y: number, width: number, height: number,
): boolean
dismissFloatingGamepadTextInput(): booleanshowFloatingGamepadTextInput opens the floating keyboard over a text field,
given that field's rectangle in pixels from the top left of the window. mode
is an EFloatingGamepadTextInputMode: 0 single line, 1 multiple lines, 2
email, 3 numeric. It returns false outside Big Picture mode, and
dismissFloatingGamepadTextInput returns true when a keyboard was open and is
now closing.
Unlike showGamepadTextInput this pair does not return the text. Steam types into whatever field the app has focused, so the app reads its own field.
onIpCountryChanged(listener: () => void): () => voidSubscribes to the country changing under this user's IP, and returns an unsubscribe function. The callback carries no payload, so read the new value with ipCountry.
onLowBattery(listener: (minutesLeft: number) => void): () => voidSubscribes to Steam's low battery warning. Steam sends it once the battery drops under 10 percent, and again every minute after that, with the minutes it thinks are left. A good moment to autosave.
const off = steam.system.onLowBattery((minutes) => {
console.log(`${minutes} minutes left, saving`);
});
// later: off();Returned by image.
| Field | Type | Meaning |
|---|---|---|
width |
number |
Width in pixels. |
height |
number |
Height in pixels. |
rgba |
Buffer |
Raw pixels, 4 bytes each in RGBA order, width * height * 4 long. |
Since v0.6.0. One entry from listBetas. The five booleans are
Steam's EBetaBranchFlags bits, spread out.
| Field | Type | Meaning |
|---|---|---|
name |
string |
Branch name, the one setActiveBeta takes. |
description |
string |
Description the developer wrote, empty if there is none. |
buildId |
number |
Build id currently on that branch. |
lastUpdated |
number |
When the branch was last updated, as a Unix time in seconds. |
isDefault |
boolean |
The app's default branch, the one a user without an opt-in runs. |
available |
boolean |
The branch is available to this user. |
isPrivate |
boolean |
The branch needs a password to opt into. |
selected |
boolean |
The branch the user picked in the Steam client. |
installed |
boolean |
The branch that is installed right now. |
Taken by showGamepadTextInput. Only description is
required.
| Field | Type | Default | Meaning |
|---|---|---|---|
description |
string |
none | Prompt shown above the keyboard. |
mode |
number |
0 |
EGamepadTextInputMode: 0 normal, 1 password (the text is masked). |
lineMode |
number |
0 |
EGamepadTextInputLineMode: 0 single line, 1 multiple lines. |
maxChars |
number |
256 |
Maximum characters the user may enter. |
existingText |
string |
'' |
Text the field starts with. |
| Shape | When |
|---|---|
Error: steamwand: ShowGamepadTextInput returned false (not in Big Picture mode?) |
The keyboard could not be shown, which is the normal outcome outside Big Picture mode and Steam Deck. |
Error: steamwand: GetEnteredGamepadTextInput returned false (...) |
Steam had text but refused to copy it out. |
Error: steamwand: GetImageRGBA returned false (...) |
image read a size but not the pixels. |
Error: steamwand: SetActiveBeta returned false (...) |
setActiveBeta got an unknown branch name, or one the user has not unlocked. |
Nothing here throws SteamResultError: no method waits for a call result.
The ISteamApps calls this layer does not take are on DLC or on the raw
steam.apps; that page lists them. The rest of ISteamUtils is on the raw
generated steam.utils:
- The overlay calls, wrapped separately on Overlay:
SetOverlayNotificationPosition,SetOverlayNotificationInset,BOverlayNeedsPresent. - The call-result plumbing, which the dispatch pump owns:
IsAPICallCompleted,GetAPICallFailureReason,GetAPICallResult. -
IsRunningOnSteamHardwarein its raw form, when you need to tell a Steam Machine or a Steam Frame from a Deck, plusGetSteamHardwareDefaultConfig. -
IsRunningUnderProton,GetIPv6ConnectivityState,GetConnectedUniverse,GetIPCCallCountandCheckFileSignature. -
StartVRDashboard,IsVRHeadsetStreamingEnabled,SetVRHeadsetStreamingEnabledandSetGameLauncherMode. -
InitFilterTextandFilterText, Steam's profanity filter. -
DismissGamepadTextInput, which closes the full screen keyboard from code instead of waiting for the user.
Flat API explains the calling convention.
Next: Controllers, the other layer a Steam Deck build needs.