diff --git a/README-STEAM.md b/README-STEAM.md index f06f964..dd21a7b 100644 --- a/README-STEAM.md +++ b/README-STEAM.md @@ -136,9 +136,17 @@ gamepadAPI.setDebug(true); If Steam is still applying mouse emulation: 1. **Configure Steam Input per-game** (most reliable fix): - - In Steam, right-click Nebula → Properties → Controller - - Set **"Override for Nebula"** to **"Disable Steam Input"** - - This completely disables Steam's input emulation for this app + - **Windows / Desktop Steam UI**: + - Library → right-click Nebula → Properties → **Controller** + - Set **"Override for Nebula"** to **"Disable Steam Input"** + - **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 **don’t 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 Steam’s 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` 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 +#### 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): ```bash @@ -187,6 +209,16 @@ The solution is two-fold: 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 +### 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 ```bash diff --git a/main.js b/main.js index 31bc496..8c7c5d4 100644 --- a/main.js +++ b/main.js @@ -15,7 +15,10 @@ process.env.SDL_GAMECONTROLLERCONFIG = process.env.SDL_GAMECONTROLLERCONFIG || ' // Signal that this app handles gamepad input natively // 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 // 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 // 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 = '0'; -} +process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD = + process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD ?? '0'; // Hint that this is a game/controller-focused app 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 steamworksInitialized = false; let steamInput = null; +let steamworksModule = null; +let steamCallbacksInterval = null; function initializeSteamworks() { try { const steamworks = require('steamworks.js'); + steamworksModule = steamworks; // Initialize with Nebula's Steam App ID steamworksClient = steamworks.init(4290110); @@ -67,6 +72,27 @@ function initializeSteamworks() { steamInput = steamworksClient.input; if (steamInput) { 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 { @@ -101,6 +127,19 @@ function initializeSteamworks() { // This is critical for Steam Input to recognize native controller support 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 { autoUpdater } = require('electron-updater'); const { pathToFileURL } = require('url');