mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 05:00:08 +02:00
Pause Frametop for VR games
Frametop kept using the headset during games: with gaze mode off, our eye tracker still took about 60% of a core, remote desktop about 2 cores while on, and KWin kept drawing hidden screens because ft-screens sent their frame callbacks at 90 Hz. Pausing gives that back, and resuming brings back only what pausing stopped. It's also a way to keep the gaze service and our eye tracker off during games, which PR #13 asked for. Paused (input/game_pause.py, run by the input relay): - frametop-gaze stops (ft-eyegrab then idles by itself), and hand tracking and remote desktop stop if they run - the desktop hides and slows down: ft-screens "pause on" hides every panel and sends KWin a frame callback once a second; or, with pause_desktop "close", the desktop closes and starts again on resume - the relay lets go of the 3D mouse, typing goes to Steam, and mapped buttons and key combinations do only pause_toggle, steam_menu and commands Toggled by both thumbsticks clicked together twice (configurable), read passively from vrserver's web socket (input/vrws.py) so it works in games and takes nothing from them; by the new pause_toggle action; by input/ft-pause; and, with pause_auto (default on), by a VR game starting and ending, which the pointer helper now reports ("vrgame 1|0"). Frametop Input Settings has a Games page for it. update-check.py checks the web socket, and doesn't count a paused gaze service as failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7fbcd177d3
commit
8aaf7db05a
18 files changed
+1534
-41
No files matched your search
+137
-2
@@ -19,6 +19,7 @@ Kirigami.ApplicationWindow {
|
||||
Kirigami.Action { text: "Devices"; icon.name: "input-mouse"; onTriggered: root.show(devicesPage) },
|
||||
Kirigami.Action { text: "Buttons"; icon.name: "input-keyboard"; onTriggered: root.show(buttonsPage) },
|
||||
Kirigami.Action { text: "Controllers"; icon.name: "input-gamepad"; onTriggered: root.show(controllersPage) },
|
||||
Kirigami.Action { text: "Games"; icon.name: "applications-games"; onTriggered: root.show(gamesPage) },
|
||||
Kirigami.Action { text: "Keyboard"; icon.name: "input-keyboard-virtual"; onTriggered: root.show(keyboardPage) },
|
||||
Kirigami.Action { text: "Pointer"; icon.name: "transform-move"; onTriggered: root.show(pointerPage) },
|
||||
Kirigami.Action { text: "Ignored panels"; icon.name: "view-hidden"; onTriggered: root.show(ignorePage) },
|
||||
@@ -56,8 +57,8 @@ Kirigami.ApplicationWindow {
|
||||
pageStack.push(page)
|
||||
}
|
||||
|
||||
// FT_INPUT_PAGE=buttons|controllers|keyboard|pointer|ignore|gaze|bluetooth opens the app on that page.
|
||||
pageStack.initialPage: ({ buttons: buttonsPage, controllers: controllersPage, keyboard: keyboardPage,
|
||||
// FT_INPUT_PAGE=buttons|controllers|games|keyboard|pointer|ignore|gaze|bluetooth opens the app on that page.
|
||||
pageStack.initialPage: ({ buttons: buttonsPage, controllers: controllersPage, games: gamesPage, keyboard: keyboardPage,
|
||||
pointer: pointerPage, ignore: ignorePage, gaze: gazePage,
|
||||
bluetooth: bluetoothPage })[startPage] || devicesPage
|
||||
|
||||
@@ -826,6 +827,140 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Games
|
||||
Component {
|
||||
id: gamesPage
|
||||
Kirigami.ScrollablePage {
|
||||
id: gmpage
|
||||
title: "Games"
|
||||
property var st: backend.pauseStatus
|
||||
|
||||
// The gesture's boxes follow the saved gesture (which may tidy what was picked).
|
||||
function syncGesture() {
|
||||
const g = backend.pauseGesture
|
||||
firstBox.currentIndex = firstBox.indexOfValue(g.first)
|
||||
secondBox.currentIndex = secondBox.indexOfValue(g.second)
|
||||
pressBox.currentIndex = pressBox.indexOfValue(g.presses)
|
||||
}
|
||||
function saveGesture() {
|
||||
backend.setPauseGesture(firstBox.currentValue, secondBox.currentValue, pressBox.currentValue)
|
||||
}
|
||||
Component.onCompleted: syncGesture()
|
||||
Connections {
|
||||
target: backend
|
||||
function onMappingsChanged() { gmpage.syncGesture() }
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
visible: !gmpage.st.relay
|
||||
type: Kirigami.MessageType.Error
|
||||
text: gmpage.st.old
|
||||
? "The input relay that runs is older and can't pause. Restart it: "
|
||||
+ "systemctl --user restart frametop-input-relay"
|
||||
: "The input relay isn't answering (frametop-input-relay.service). It does the pausing."
|
||||
}
|
||||
|
||||
Kirigami.FormLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: "Frametop:"
|
||||
Controls.Label { text: gmpage.st.summary }
|
||||
Controls.Button {
|
||||
text: gmpage.st.paused ? "Resume" : "Pause now"
|
||||
icon.name: gmpage.st.paused ? "media-playback-start" : "media-playback-pause"
|
||||
enabled: gmpage.st.relay
|
||||
onClicked: backend.setPaused(!gmpage.st.paused)
|
||||
}
|
||||
}
|
||||
Controls.Switch {
|
||||
Kirigami.FormData.label: "VR games:"
|
||||
text: "Pause while a VR game runs, and resume when it ends"
|
||||
checked: backend.pauseAuto
|
||||
onToggled: backend.setPauseAuto(checked)
|
||||
}
|
||||
|
||||
Kirigami.Separator { Kirigami.FormData.isSection: true; Kirigami.FormData.label: "Controller gesture" }
|
||||
Controls.ComboBox {
|
||||
id: firstBox
|
||||
Kirigami.FormData.label: "Button:"
|
||||
model: backend.gestureButtons
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 10
|
||||
onActivated: gmpage.saveGesture()
|
||||
}
|
||||
Controls.ComboBox {
|
||||
id: secondBox
|
||||
Kirigami.FormData.label: "Together with:"
|
||||
model: backend.gestureButtons
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
enabled: firstBox.currentValue !== ""
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 10
|
||||
onActivated: gmpage.saveGesture()
|
||||
}
|
||||
Controls.ComboBox {
|
||||
id: pressBox
|
||||
Kirigami.FormData.label: "Pressed:"
|
||||
model: [{ value: 2, text: "Twice" }, { value: 1, text: "Once" }]
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
// One button pressed once would go off far too easily in games.
|
||||
enabled: firstBox.currentValue !== "" && secondBox.currentValue !== ""
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 10
|
||||
onActivated: gmpage.saveGesture()
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.Wrap
|
||||
opacity: 0.7
|
||||
text: (backend.pauseGesture.first === "" ? "No gesture: a mapped button, a key combination, or ft-pause still work."
|
||||
: "Pauses and resumes Frametop, in games too. The game still gets the presses, so pick buttons it "
|
||||
+ "doesn't use this way. Two buttons count as together when both go down within a third of a "
|
||||
+ "second, and twice means within 0.7 s.")
|
||||
+ (gmpage.st.relay && backend.pauseGesture.first !== "" && !gmpage.st.gestureReader
|
||||
? " Not reading the controllers right now (SteamVR isn't running?)." : "")
|
||||
}
|
||||
|
||||
Kirigami.Separator { Kirigami.FormData.isSection: true; Kirigami.FormData.label: "While paused" }
|
||||
Controls.ComboBox {
|
||||
Kirigami.FormData.label: "The desktop:"
|
||||
model: backend.pauseDesktopModes
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 20
|
||||
Component.onCompleted: currentIndex = indexOfValue(backend.pauseDesktop)
|
||||
onActivated: backend.setPauseDesktop(currentValue)
|
||||
}
|
||||
Controls.Switch {
|
||||
Kirigami.FormData.label: "Sound:"
|
||||
text: "Play a sound on pause and resume"
|
||||
checked: backend.pauseSound
|
||||
onToggled: backend.setPauseSound(checked)
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.Wrap
|
||||
opacity: 0.7
|
||||
text: "Paused, Frametop leaves the headset's CPU and GPU to the game. The gaze service and our eye "
|
||||
+ "tracker stop, and nothing reads SteamVR's eye tracking. Hand tracking and remote desktop stop "
|
||||
+ "if they run. The desktop hides and slows down, or closes, as chosen above. The 3D mouse lets go, "
|
||||
+ "so the mouse is a plain one for SteamVR. Mapped buttons and key combinations do nothing but "
|
||||
+ "pausing, the Steam menu, and your own commands. Resuming brings back what pausing stopped. "
|
||||
+ "Map \"Pause/resume Frametop\" to a button or key combination on the other pages, or run "
|
||||
+ "input/ft-pause."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Gaze
|
||||
Component {
|
||||
id: gazePage
|
||||
|
||||
Reference in new issue
Block a user