Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions opennow-stable/src/main/gfn/cloudmatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ function buildSessionRequestBody(input: SessionCreateRequest, deviceHashId: stri
const bitDepth = colorQualityBitDepth(cq);
const chromaFormat = colorQualityChromaFormat(cq);
const accountLinked = input.accountLinked ?? true;
const sonyHidEnabled = input.settings.experimentalGamepadGyro === true;

return {
sessionRequestData: {
Expand Down Expand Up @@ -550,7 +551,7 @@ function buildSessionRequestBody(input: SessionCreateRequest, deviceHashId: stri
}
: null,
surroundAudioInfo: 0,
remoteControllersBitmap: 0,
remoteControllersBitmap: sonyHidEnabled ? 1 : 0,
clientTimezoneOffset: timezoneOffsetMs(),
enhancedStreamMode: 1,
appLaunchMode: 1,
Expand All @@ -566,7 +567,7 @@ function buildSessionRequestBody(input: SessionCreateRequest, deviceHashId: stri
enabledL4S: input.settings.enableL4S,
mouseMovementFlags: 0,
trueHdr: hdrEnabled,
supportedHidDevices: 0,
supportedHidDevices: sonyHidEnabled ? 3 : 0,
profile: 0,
fallbackToLogicalResolution: false,
hidDevices: null,
Expand Down
61 changes: 38 additions & 23 deletions opennow-stable/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ function registerIpcHandlers(): void {
});

ipcMain.handle(IPC_CHANNELS.SETTINGS_SET, async <K extends keyof Settings>(_event: Electron.IpcMainInvokeEvent, key: K, value: Settings[K]) => {
settingsManager.set(key, value);
settingsManager.set(key as keyof import("./settings").Settings, value as import("./settings").Settings[keyof import("./settings").Settings]);
// React to certain setting changes immediately in main process
try {
if (key === "autoCheckForUpdates") {
Expand Down Expand Up @@ -2272,18 +2272,24 @@ app.whenReady().then(async () => {
}

// Set up permission handlers for getUserMedia, fullscreen, pointer lock
const isExperimentalGamepadGyroEnabled = (): boolean => settingsManager.get("experimentalGamepadGyro") === true;
const allowedNonHidPermissions = new Set([
"media",
"microphone",
"fullscreen",
"automatic-fullscreen",
"pointerLock",
"keyboardLock",
"speaker-selection",
]);

session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
const allowedPermissions = new Set([
"media",
"microphone",
"fullscreen",
"automatic-fullscreen",
"pointerLock",
"keyboardLock",
"speaker-selection",
]);

if (allowedPermissions.has(permission)) {
if ((permission as string) === "hid") {
callback(isExperimentalGamepadGyroEnabled());
return;
}

if (allowedNonHidPermissions.has(permission)) {
callback(true);
return;
}
Expand All @@ -2292,17 +2298,26 @@ app.whenReady().then(async () => {
});

session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin) => {
const allowedPermissions = new Set([
"media",
"microphone",
"fullscreen",
"automatic-fullscreen",
"pointerLock",
"keyboardLock",
"speaker-selection",
]);

return allowedPermissions.has(permission);
if ((permission as string) === "hid") {
return isExperimentalGamepadGyroEnabled();
}

return allowedNonHidPermissions.has(permission);
});

session.defaultSession.setDevicePermissionHandler((details) => {
return isExperimentalGamepadGyroEnabled() && details.deviceType === "hid" && details.device.vendorId === 0x054c;
});

session.defaultSession.on("select-hid-device", (event, details, callback) => {
if (!isExperimentalGamepadGyroEnabled()) {
return;
}
const sonyDevice = details.deviceList.find((device) => device.vendorId === 0x054c);
if (sonyDevice) {
event.preventDefault();
callback(sonyDevice.deviceId);
}
});

registerOpenNowMediaProtocol();
Expand Down
3 changes: 3 additions & 0 deletions opennow-stable/src/main/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ export interface Settings {
enableL4S: boolean;
/** Request Cloud G-Sync / Variable Refresh Rate on new sessions */
enableCloudGsync: boolean;
/** Experimental Sony controller gyro support over WebHID */
experimentalGamepadGyro: boolean;
/** Show the currently streaming game as Discord Rich Presence activity */
discordRichPresence: boolean;
/** Automatically check GitHub Releases for app updates in the background */
Expand Down Expand Up @@ -187,6 +189,7 @@ const DEFAULT_SETTINGS: Settings = {
gameLanguage: "en_US",
enableL4S: false,
enableCloudGsync: false,
experimentalGamepadGyro: false,
discordRichPresence: false,
autoCheckForUpdates: true,
allowEscapeToExitFullscreen: false,
Expand Down
20 changes: 20 additions & 0 deletions opennow-stable/src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
type StreamDiagnostics,
type StreamTimeWarning,
} from "./gfn/webrtcClient";
import { requestSonyGamepadHidAccess } from "./gfn/gamepadMotion";
import { formatShortcutForDisplay, isShortcutMatch, normalizeShortcut } from "./shortcuts";
import { useControllerNavigation } from "./controllerNavigation";
import { useElapsedSeconds } from "./utils/useElapsedSeconds";
Expand Down Expand Up @@ -935,6 +936,7 @@ export function App(): JSX.Element {
gameLanguage: "en_US",
enableL4S: false,
enableCloudGsync: false,
experimentalGamepadGyro: false,
discordRichPresence: false,
autoCheckForUpdates: true,
});
Expand Down Expand Up @@ -2444,6 +2446,13 @@ export function App(): JSX.Element {
// Save settings when changed
const updateSetting = useCallback(async <K extends keyof Settings>(key: K, value: Settings[K]) => {
setSettings((prev) => ({ ...prev, [key]: value }));
if (key === "experimentalGamepadGyro" && value) {
try {
void requestSonyGamepadHidAccess((line) => console.log(`[WebHID] ${line}`));
} catch {
// ignore
}
}
if (settingsLoaded) {
await window.openNow.setSetting(key, value);
}
Expand Down Expand Up @@ -2476,6 +2485,13 @@ export function App(): JSX.Element {
// ignore
}
}
if (key === "experimentalGamepadGyro") {
try {
clientRef.current?.setExperimentalGamepadGyroEnabled(Boolean(value));
} catch {
// ignore
}
}
}, [settingsLoaded]);

const handleStreamVolumeChange = useCallback((v: number) => {
Expand Down Expand Up @@ -3025,6 +3041,7 @@ export function App(): JSX.Element {
gameLanguage: settings.gameLanguage,
enableL4S: settings.enableL4S,
enableCloudGsync: settings.enableCloudGsync,
experimentalGamepadGyro: settings.experimentalGamepadGyro,
},
});

Expand Down Expand Up @@ -3185,6 +3202,7 @@ export function App(): JSX.Element {
gameLanguage: settings.gameLanguage,
enableL4S: settings.enableL4S,
enableCloudGsync: settings.enableCloudGsync,
experimentalGamepadGyro: settings.experimentalGamepadGyro,
},
});
if (!isRecoveryGenerationCurrent(recoveryGeneration)) {
Expand Down Expand Up @@ -3301,6 +3319,7 @@ export function App(): JSX.Element {
microphoneDeviceId: settings.microphoneDeviceId || undefined,
mouseSensitivity: settings.mouseSensitivity,
mouseAcceleration: settings.mouseAcceleration,
experimentalGamepadGyro: settings.experimentalGamepadGyro,
onLog: (line: string) => console.log(`[WebRTC] ${line}`),
onStats: (stats) => diagnosticsStore.set(stats),
onTimeWarning: (warning) => {
Expand Down Expand Up @@ -3639,6 +3658,7 @@ export function App(): JSX.Element {
gameLanguage: settings.gameLanguage,
enableL4S: settings.enableL4S,
enableCloudGsync: settings.enableCloudGsync,
experimentalGamepadGyro: settings.experimentalGamepadGyro,
},
});

Expand Down
18 changes: 18 additions & 0 deletions opennow-stable/src/renderer/src/components/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,24 @@ export function SettingsPage({ settings, regions, onSettingChange, codecResults,
</label>
</div>

<div className="settings-row settings-row--top-aligned">
<label className="settings-label settings-label--wrap">
<span>
Experimental Gamepad Gyro
<span className="settings-inline-badge settings-inline-badge--beta">Beta</span>
</span>
<span className="settings-hint">Requires a Sony DualShock 4 or DualSense exposed through WebHID. Sends DS4-style HID motion packets to GFN when motion data is available.</span>
</label>
<label className="settings-toggle">
<input
type="checkbox"
checked={settings.experimentalGamepadGyro ?? false}
onChange={(e) => handleChange("experimentalGamepadGyro", e.target.checked)}
/>
<span className="settings-toggle-track" />
</label>
</div>

<div className="settings-row settings-row--top-aligned">
<label className="settings-label settings-label--wrap">
Keyboard Layout
Expand Down
Loading
Loading