61c448eb00
Integrate SDL3 controller support and wire it into the InputRouter.
- Add ControllerInputService (src/ControllerInputService.{h,cpp}) to discover, poll and translate SDL3 gamepad events into InputRouter actions, with axis repeat handling and debouncing.
- Update CMakeLists to find or fetch SDL3, add the new source files to the target, link the SDL3 target, and copy runtime DLLs on Windows.
- Add triggerAction(Action) to InputRouter and use it from existing keyboard handling to centralize action dispatch.
- Instantiate ControllerInputService in main so controllers feed the InputRouter.
- Update QML views (ShellWindow, HomeView, LibraryView, SettingsView) to use numeric action IDs and add small UI/status text and navigation tweaks for controller-driven flows.
These changes enable gamepad/controller input for Bigscreen via SDL3 and adapt UI code to handle the mapped actions.
141 lines
3.1 KiB
QML
141 lines
3.1 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import Nebula.Bigscreen
|
|
|
|
ApplicationWindow {
|
|
id: window
|
|
|
|
width: 1280
|
|
height: 720
|
|
visible: true
|
|
title: "Nebula Bigscreen"
|
|
color: Theme.backgroundDeep
|
|
|
|
property string currentView: "home"
|
|
property bool powerOverlayVisible: false
|
|
property string signedInUser: "Player"
|
|
|
|
NebulaBackground {
|
|
anchors.fill: parent
|
|
}
|
|
|
|
Column {
|
|
anchors.fill: parent
|
|
spacing: 0
|
|
|
|
TopBar {
|
|
id: topBar
|
|
width: parent.width
|
|
userName: window.signedInUser
|
|
accentFocus: contentLoader.item && contentLoader.item.accentFocus !== undefined
|
|
? contentLoader.item.accentFocus()
|
|
: 0
|
|
}
|
|
|
|
Loader {
|
|
id: contentLoader
|
|
width: parent.width
|
|
height: parent.height - topBar.height
|
|
sourceComponent: viewComponentFor(window.currentView)
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: contentLoader.item
|
|
ignoreUnknownSignals: true
|
|
function onNavigate(route) {
|
|
window.onChildNavigate(route)
|
|
}
|
|
function onGoBack() {
|
|
window.onChildGoBack()
|
|
}
|
|
}
|
|
|
|
PowerOverlay {
|
|
id: powerOverlay
|
|
visible: window.powerOverlayVisible
|
|
z: 10
|
|
|
|
onDismissed: window.powerOverlayVisible = false
|
|
onActionChosen: function(actionId) {
|
|
console.log("Power action:", actionId)
|
|
window.powerOverlayVisible = false
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: InputRouter
|
|
function onActionTriggered(action) {
|
|
if (window.powerOverlayVisible) {
|
|
window.handlePowerInput(action)
|
|
return
|
|
}
|
|
if (action === 7) {
|
|
window.powerOverlayVisible = true
|
|
return
|
|
}
|
|
if (contentLoader.item && contentLoader.item.handleInput) {
|
|
contentLoader.item.handleInput(action)
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: homeComponent
|
|
HomeView {}
|
|
}
|
|
|
|
Component {
|
|
id: libraryComponent
|
|
LibraryView {}
|
|
}
|
|
|
|
Component {
|
|
id: settingsComponent
|
|
SettingsView {}
|
|
}
|
|
|
|
function viewComponentFor(viewId) {
|
|
switch (viewId) {
|
|
case "library":
|
|
return libraryComponent
|
|
case "settings":
|
|
return settingsComponent
|
|
default:
|
|
return homeComponent
|
|
}
|
|
}
|
|
|
|
function onChildNavigate(route) {
|
|
if (route === "power") {
|
|
window.powerOverlayVisible = true
|
|
return
|
|
}
|
|
window.currentView = route
|
|
}
|
|
|
|
function onChildGoBack() {
|
|
window.currentView = "home"
|
|
}
|
|
|
|
function handlePowerInput(action) {
|
|
switch (action) {
|
|
case 1:
|
|
powerOverlay.moveFocus(-1)
|
|
break
|
|
case 2:
|
|
powerOverlay.moveFocus(1)
|
|
break
|
|
case 5:
|
|
powerOverlay.activateFocused()
|
|
break
|
|
case 6:
|
|
window.powerOverlayVisible = false
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
}
|