diff --git a/main.js b/main.js index 6041dea..31bc496 100644 --- a/main.js +++ b/main.js @@ -33,6 +33,74 @@ if (!process.env.STEAM_INPUT_ENABLE_VIRTUAL_GAMEPAD) { // Hint that this is a game/controller-focused app process.env.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = '1'; +// ============================================================================= +// STEAMWORKS API INTEGRATION +// ============================================================================= +// Initialize Steam API to properly signal to Steam that this app handles +// controller input natively. This is more reliable than environment variables +// alone for disabling Steam Input's mouse/keyboard emulation. +// +// NOTE: Since Nebula is categorized as Software (not a Game), we can't configure +// Steam Input settings in the Steamworks dashboard. Instead, we initialize the +// Steam Input API directly to signal native controller handling. +// ============================================================================= + +let steamworksClient = null; +let steamworksInitialized = false; +let steamInput = null; + +function initializeSteamworks() { + try { + const steamworks = require('steamworks.js'); + + // Initialize with Nebula's Steam App ID + steamworksClient = steamworks.init(4290110); + steamworksInitialized = true; + + // Log successful initialization + const playerName = steamworksClient.localplayer.getName(); + console.log(`[Steamworks] Initialized successfully for user: ${playerName}`); + + // Initialize Steam Input API - this tells Steam we handle controllers natively + // and should prevent mouse/keyboard emulation in Game Mode + try { + steamInput = steamworksClient.input; + if (steamInput) { + console.log('[Steamworks] Steam Input API available - native controller mode enabled'); + + // Try to get connected controllers to verify input is working + try { + const controllers = steamInput.getControllers(); + if (controllers && controllers.length > 0) { + console.log(`[Steamworks] Found ${controllers.length} connected controller(s)`); + } + } catch (inputErr) { + // Controller enumeration may not be available, that's OK + } + } + } catch (inputErr) { + console.log('[Steamworks] Steam Input API not fully available:', inputErr.message); + } + + return true; + } catch (e) { + // Not running through Steam, or steamworks.js not available + // This is fine - app works without Steam API + if (e.code === 'MODULE_NOT_FOUND') { + console.log('[Steamworks] steamworks.js not installed - running without Steam API'); + } else if (e.message && e.message.includes('Steam client')) { + console.log('[Steamworks] Steam client not running - running without Steam API'); + } else { + console.log('[Steamworks] Failed to initialize:', e.message || e); + } + return false; + } +} + +// Initialize Steamworks early (before app.ready) +// This is critical for Steam Input to recognize native controller support +initializeSteamworks(); + const { app, BrowserWindow, ipcMain, session, screen, shell, dialog, Menu, clipboard, webContents } = require('electron'); const { autoUpdater } = require('electron-updater'); const { pathToFileURL } = require('url'); diff --git a/package-lock.json b/package-lock.json index ca7627d..a2d8885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "dompurify": "^3.1.6", "electron-updater": "^6.6.2", "highlight.js": "^11.9.0", - "marked": "^12.0.2" + "marked": "^12.0.2", + "steamworks.js": "^0.3.2" }, "devDependencies": { "electron": "^39.2.7", @@ -313,7 +314,6 @@ "version": "22.16.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.3.tgz", "integrity": "sha512-sr4Xz74KOUeYadexo1r8imhRtlVXcs+j3XK3TcoiYk7B1t3YRVJgtaD3cwX73NYb71pmVuMLNRhJ9XKdoDB74g==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1907,6 +1907,14 @@ "node": ">= 6" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -3079,6 +3087,19 @@ "node": ">= 6" } }, + "node_modules/steamworks.js": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/steamworks.js/-/steamworks.js-0.3.2.tgz", + "integrity": "sha512-iuZdAHBktF/Ov7hYFApmM3tGaIi24hrmE84yzbBtd+E+2UX1ccFgINm5GIiAq8AEIA+BmXUXE9ezzEsXoOm1UA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "format": "^0.2.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3254,7 +3275,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/universalify": { diff --git a/package.json b/package.json index 2c339ed..962babb 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "dompurify": "^3.1.6", "electron-updater": "^6.6.2", "highlight.js": "^11.9.0", - "marked": "^12.0.2" + "marked": "^12.0.2", + "steamworks.js": "^0.3.2" }, "devDependencies": { "electron": "^39.2.7",