Add SDL3-based controller input service
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.
This commit is contained in:
@@ -70,7 +70,7 @@ ApplicationWindow {
|
||||
window.handlePowerInput(action)
|
||||
return
|
||||
}
|
||||
if (action === InputRouter.Menu) {
|
||||
if (action === 7) {
|
||||
window.powerOverlayVisible = true
|
||||
return
|
||||
}
|
||||
@@ -120,16 +120,16 @@ ApplicationWindow {
|
||||
|
||||
function handlePowerInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Up:
|
||||
case 1:
|
||||
powerOverlay.moveFocus(-1)
|
||||
break
|
||||
case InputRouter.Down:
|
||||
case 2:
|
||||
powerOverlay.moveFocus(1)
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
case 5:
|
||||
powerOverlay.activateFocused()
|
||||
break
|
||||
case InputRouter.Back:
|
||||
case 6:
|
||||
window.powerOverlayVisible = false
|
||||
break
|
||||
default:
|
||||
|
||||
@@ -39,15 +39,18 @@ ColumnLayout {
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Left:
|
||||
case 3:
|
||||
rail.moveFocus(-1)
|
||||
break
|
||||
case InputRouter.Right:
|
||||
case 4:
|
||||
rail.moveFocus(1)
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
case 5:
|
||||
rail.activateFocused()
|
||||
break
|
||||
case 6:
|
||||
root.navigate("power")
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ ColumnLayout {
|
||||
]
|
||||
|
||||
property int focusIndex: 0
|
||||
property string statusText: "Mock entries for v0 — scanners and launchers come later."
|
||||
|
||||
spacing: 20
|
||||
|
||||
@@ -25,7 +26,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Mock entries for v0 — scanners and launchers come later."
|
||||
text: root.statusText
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
Layout.leftMargin: 40
|
||||
@@ -79,18 +80,19 @@ ColumnLayout {
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Up:
|
||||
case 1:
|
||||
focusIndex = Math.max(0, focusIndex - 1)
|
||||
list.currentIndex = focusIndex
|
||||
break
|
||||
case InputRouter.Down:
|
||||
case 2:
|
||||
focusIndex = Math.min(entries.length - 1, focusIndex + 1)
|
||||
list.currentIndex = focusIndex
|
||||
break
|
||||
case InputRouter.Back:
|
||||
case 6:
|
||||
root.goBack()
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
case 5:
|
||||
statusText = entries[focusIndex].title + " selected — launcher integration comes later."
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
@@ -17,6 +17,8 @@ ColumnLayout {
|
||||
|
||||
property int categoryIndex: 0
|
||||
property int itemIndex: 0
|
||||
readonly property int settingCount: 3
|
||||
property string statusText: "Choose a setting with Accept. Detailed controls come later."
|
||||
|
||||
spacing: 20
|
||||
|
||||
@@ -73,7 +75,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 3
|
||||
model: root.settingCount
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
@@ -93,26 +95,37 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.statusText
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Left:
|
||||
case 3:
|
||||
categoryIndex = Math.max(0, categoryIndex - 1)
|
||||
itemIndex = 0
|
||||
break
|
||||
case InputRouter.Right:
|
||||
case 4:
|
||||
categoryIndex = Math.min(categories.length - 1, categoryIndex + 1)
|
||||
itemIndex = 0
|
||||
break
|
||||
case InputRouter.Up:
|
||||
case 1:
|
||||
itemIndex = Math.max(0, itemIndex - 1)
|
||||
break
|
||||
case InputRouter.Down:
|
||||
itemIndex = Math.min(2, itemIndex + 1)
|
||||
case 2:
|
||||
itemIndex = Math.min(settingCount - 1, itemIndex + 1)
|
||||
break
|
||||
case InputRouter.Back:
|
||||
case 6:
|
||||
root.goBack()
|
||||
break
|
||||
case 5:
|
||||
statusText = categories[categoryIndex] + " setting " + (itemIndex + 1) + " selected."
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user