Improve Steam Input handling and update documentation

Updated main.js to better manage Steam Input environment variables, explicitly initialize and shutdown Steam Input, and regularly pump Steam callbacks to ensure proper controller support. Enhanced README-STEAM.md with detailed instructions for configuring Steam Input on Windows, Linux, and Steam Deck, including guidance for software/app limitations and launch options.
This commit is contained in:
2025-12-31 23:58:38 +13:00
parent 3d07b85706
commit 72438af1b6
2 changed files with 78 additions and 7 deletions
+34 -2
View File
@@ -136,9 +136,17 @@ gamepadAPI.setDebug(true);
If Steam is still applying mouse emulation: If Steam is still applying mouse emulation:
1. **Configure Steam Input per-game** (most reliable fix): 1. **Configure Steam Input per-game** (most reliable fix):
- In Steam, right-click Nebula → Properties → Controller - **Windows / Desktop Steam UI**:
- Library → right-click Nebula → Properties → **Controller**
- Set **"Override for Nebula"** to **"Disable Steam Input"** - Set **"Override for Nebula"** to **"Disable Steam Input"**
- This completely disables Steam's input emulation for this app - **Steam Deck / SteamOS Gaming Mode**:
- Open Nebula → press the Steam button → **Controller Settings** (or the controller icon)
- Set the layout to a **Gamepad** template (not “Keyboard/Mouse”), or disable Steam Input if the toggle is available
- This stops Steam from translating controller input into keyboard/mouse events (“Desktop Layout” behavior).
If you **dont see a Controller tab** (common when the Steam entry is treated as an “application/tool”):
- Use **Big Picture / Gaming Mode** and edit the **Controller Layout** for that specific entry.
- Or change Steams global Desktop Layout: Steam → Settings → Controller → **Desktop Layout** → pick a gamepad-focused template or remove mouse/keyboard bindings.
2. **Verify gamepad polling is active**: Open DevTools (F12) and run `gamepadAPI.getState()` - check that `isPolling` is `true` 2. **Verify gamepad polling is active**: Open DevTools (F12) and run `gamepadAPI.getState()` - check that `isPolling` is `true`
3. **Check gamepad connection**: Run `gamepadAPI.getConnected()` to see detected gamepads 3. **Check gamepad connection**: Run `gamepadAPI.getConnected()` to see detected gamepads
@@ -148,6 +156,20 @@ If Steam is still applying mouse emulation:
### Steam Launch Options ### Steam Launch Options
#### Windows
The `VAR=value %command%` syntax does **not** work on Windows. Use the Steam UI instead:
1. **Library** → right-click Nebula → **Properties****Controller** → set to **"Disable Steam Input"**
2. If no Controller tab exists, open Steam in **Big Picture Mode** → Nebula → **Manage Game** (gear) → **Controller Options****Disable Steam Input**
If you must use launch options on Windows, use this wrapper syntax:
```bat
cmd /c "set SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD=0 && %command%"
```
#### Linux / SteamOS / Steam Deck
Add these to your Steam launch options (Right-click game → Properties → Launch Options): Add these to your Steam launch options (Right-click game → Properties → Launch Options):
```bash ```bash
@@ -187,6 +209,16 @@ The solution is two-fold:
1. **Environment variables** (`SDL_GAMECONTROLLER_*`) signal to Steam's SDL-based input layer early 1. **Environment variables** (`SDL_GAMECONTROLLER_*`) signal to Steam's SDL-based input layer early
2. **Steam Input settings** ("Disable Steam Input") bypasses the emulation entirely 2. **Steam Input settings** ("Disable Steam Input") bypasses the emulation entirely
### Shipping Defaults (Steamworks “Software/App” limitation)
If your Steamworks package is categorized as **Software/Application**, Steamworks may not expose per-title Steam Input configuration the way it does for games.
In that case:
- You generally **cannot force a global Steam Input toggle** for all users from Steamworks.
- The practical, shippable approach is to (a) **consume controller input natively** (Nebula does this via early Gamepad API polling) so Steam Deck/Game Mode backs off Desktop emulation, and (b) provide user-facing guidance for disabling Steam Input / choosing a Gamepad layout.
If you need Steam Input defaults controlled centrally, the usual path is to ask Valve Partner Support to enable the relevant Steam Input configuration for your App ID, or to re-categorize the title where appropriate.
### Force Big Picture Mode ### Force Big Picture Mode
```bash ```bash
+43 -4
View File
@@ -15,7 +15,10 @@ process.env.SDL_GAMECONTROLLERCONFIG = process.env.SDL_GAMECONTROLLERCONFIG || '
// Signal that this app handles gamepad input natively // Signal that this app handles gamepad input natively
// This prevents Steam from applying mouse emulation in Game Mode // This prevents Steam from applying mouse emulation in Game Mode
process.env.SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD = '1'; // IMPORTANT: set to 0 to avoid Steam's virtual gamepad layer when possible.
// Forcing this to 1 can keep Steam virtualization/emulation active.
process.env.SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD =
process.env.SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD ?? '0';
// Prevent Steam from remapping the controller to keyboard/mouse // Prevent Steam from remapping the controller to keyboard/mouse
// Setting to '1' tells Steam we want raw controller access // Setting to '1' tells Steam we want raw controller access
@@ -26,9 +29,8 @@ process.env.SteamNoOverlayUIDrawing = process.env.SteamNoOverlayUIDrawing || '0'
// Tell Steam Input we're a native controller app // Tell Steam Input we're a native controller app
// When STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD is 0, Steam won't virtualize the gamepad // When STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD is 0, Steam won't virtualize the gamepad
if (!process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD) { process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD =
process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD = '0'; process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD ?? '0';
}
// Hint that this is a game/controller-focused app // Hint that this is a game/controller-focused app
process.env.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = '1'; process.env.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = '1';
@@ -48,10 +50,13 @@ process.env.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = '1';
let steamworksClient = null; let steamworksClient = null;
let steamworksInitialized = false; let steamworksInitialized = false;
let steamInput = null; let steamInput = null;
let steamworksModule = null;
let steamCallbacksInterval = null;
function initializeSteamworks() { function initializeSteamworks() {
try { try {
const steamworks = require('steamworks.js'); const steamworks = require('steamworks.js');
steamworksModule = steamworks;
// Initialize with Nebula's Steam App ID // Initialize with Nebula's Steam App ID
steamworksClient = steamworks.init(4290110); steamworksClient = steamworks.init(4290110);
@@ -68,6 +73,27 @@ function initializeSteamworks() {
if (steamInput) { if (steamInput) {
console.log('[Steamworks] Steam Input API available - native controller mode enabled'); console.log('[Steamworks] Steam Input API available - native controller mode enabled');
// Explicitly initialize Steam Input.
// Also ensure Steam callbacks are pumped; Steamworks features (including input)
// depend on runCallbacks being called regularly.
try {
if (typeof steamInput.init === 'function') {
steamInput.init();
}
} catch (initErr) {
console.log('[Steamworks] Steam Input init failed:', initErr.message);
}
if (!steamCallbacksInterval && typeof steamworks.runCallbacks === 'function') {
steamCallbacksInterval = setInterval(() => {
try {
steamworks.runCallbacks();
} catch {
// Ignore callback pump errors to avoid crashing the app.
}
}, 100);
}
// Try to get connected controllers to verify input is working // Try to get connected controllers to verify input is working
try { try {
const controllers = steamInput.getControllers(); const controllers = steamInput.getControllers();
@@ -101,6 +127,19 @@ function initializeSteamworks() {
// This is critical for Steam Input to recognize native controller support // This is critical for Steam Input to recognize native controller support
initializeSteamworks(); initializeSteamworks();
// Cleanup Steam callback pump on exit
try {
app?.once?.('before-quit', () => {
if (steamCallbacksInterval) {
clearInterval(steamCallbacksInterval);
steamCallbacksInterval = null;
}
try {
steamInput?.shutdown?.();
} catch {}
});
} catch {}
const { app, BrowserWindow, ipcMain, session, screen, shell, dialog, Menu, clipboard, webContents } = require('electron'); const { app, BrowserWindow, ipcMain, session, screen, shell, dialog, Menu, clipboard, webContents } = require('electron');
const { autoUpdater } = require('electron-updater'); const { autoUpdater } = require('electron-updater');
const { pathToFileURL } = require('url'); const { pathToFileURL } = require('url');