Skip to content

Commit

Permalink
Controller navigation fixes, part 1
Browse files Browse the repository at this point in the history
Navigating "over" selects now works

This is done by simulating Tab/Shift-Tab key presses when pressing the
respective buttons while focussing a MUI select element

I've gone ahead and removed our home-grown `GamepadInputEvent` type, as it's
just a lesser version of Electron's input events
  • Loading branch information
CommandMC committed Dec 1, 2024
1 parent 938ee99 commit 828571b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 28 deletions.
33 changes: 31 additions & 2 deletions src/backend/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
GameSettings,
DiskSpaceData,
StatusPromise,
GamepadInputEvent,
Runner
} from 'common/types'
import * as path from 'path'
Expand Down Expand Up @@ -1499,7 +1498,11 @@ ipcMain.handle('gamepadAction', async (event, args) => {
const mainWindow = getMainWindow()!

const { action, metadata } = args
const inputEvents: GamepadInputEvent[] = []
const inputEvents: (
| Electron.MouseInputEvent
| Electron.MouseWheelInputEvent
| Electron.KeyboardInputEvent
)[] = []

/*
* How to extend:
Expand Down Expand Up @@ -1585,6 +1588,32 @@ ipcMain.handle('gamepadAction', async (event, args) => {
keyCode: 'Esc'
})
break
case 'tab':
inputEvents.push(
{
type: 'keyDown',
keyCode: 'Tab'
},
{
type: 'keyUp',
keyCode: 'Tab'
}
)
break
case 'shiftTab':
inputEvents.push(
{
type: 'keyDown',
keyCode: 'Tab',
modifiers: ['shift']
},
{
type: 'keyUp',
keyCode: 'Tab',
modifiers: ['shift']
}
)
break
}

if (inputEvents.length) {
Expand Down
26 changes: 2 additions & 24 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,30 +346,6 @@ export interface GOGImportData {
dlcs: string[]
}

export type GamepadInputEvent =
| GamepadInputEventKey
| GamepadInputEventWheel
| GamepadInputEventMouse

interface GamepadInputEventKey {
type: 'keyDown' | 'keyUp' | 'char'
keyCode: string
}

interface GamepadInputEventWheel {
type: 'mouseWheel'
deltaY: number
x: number
y: number
}

interface GamepadInputEventMouse {
type: 'mouseDown' | 'mouseUp'
x: number
y: number
button: 'left' | 'middle' | 'right'
}

export interface SteamRuntime {
path: string
type: 'sniper' | 'scout' | 'soldier'
Expand Down Expand Up @@ -540,6 +516,8 @@ interface GamepadActionArgsWithoutMetadata {
| 'back'
| 'altAction'
| 'esc'
| 'tab'
| 'shiftTab'
metadata?: undefined
}

Expand Down
29 changes: 27 additions & 2 deletions src/frontend/helpers/gamepad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ export const initGamepad = () => {
altAction: { triggeredAt: {}, repeatDelay: false },
rightClick: { triggeredAt: {}, repeatDelay: false },
leftClick: { triggeredAt: {}, repeatDelay: false },
esc: { triggeredAt: {}, repeatDelay: false }
esc: { triggeredAt: {}, repeatDelay: false },
tab: { triggeredAt: {}, repeatDelay: false },
shiftTab: { triggeredAt: {}, repeatDelay: false }
}

// check if an action should be triggered
Expand Down Expand Up @@ -160,6 +162,22 @@ export const initGamepad = () => {
VirtualKeyboardController.backspace()
return
}
break
case 'padDown':
case 'leftStickDown':
// MUI Selects open on arrow down, which is usually not your intention
// when navigating down with the stick, so we change the action to tab
if (isMuiSelect()) {
action = 'tab'
}
break
case 'padUp':
case 'leftStickUp':
// Same as above
if (isMuiSelect()) {
action = 'shiftTab'
}
break
}

if (action === 'mainAction') {
Expand All @@ -185,7 +203,7 @@ export const initGamepad = () => {

const currentElement = () => document.querySelector<HTMLElement>(':focus')

const shouldSimulateClick = isSelect
const shouldSimulateClick = () => isSelect() || isMuiSelect()
function isSelect() {
const el = currentElement()
if (!el) return false
Expand Down Expand Up @@ -222,6 +240,13 @@ export const initGamepad = () => {
return parent.classList.contains('MuiMenu-list')
}

function isMuiSelect() {
const el = currentElement()
if (!el) return false

return el.classList.contains('MuiSelect-select')
}

function playable() {
const el = currentElement()
if (!el) return false
Expand Down

0 comments on commit 828571b

Please sign in to comment.