Skip to content
Draft
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
1 change: 1 addition & 0 deletions game
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ButterscotchDroidRunner(
val logFile: File,
val osType: Int,
val enablePhysicalControllers: Boolean,
val physicalControllerSideways: Boolean,
val enablePhysicalKeyboard: Boolean,
var enableWidescreenHack: Boolean,
var postProcessing: GameEntry.PostProcessingSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class GameActivity : ComponentActivity() {
logsFile,
entry.runnerOs.nativeValue,
entry.enablePhysicalControllers,
entry.physicalControllerSideways,
entry.enablePhysicalKeyboard,
entry.enableWidescreenHack,
entry.postProcessing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class GamepadRouter(private val runner: ButterscotchDroidRunner) {
fun handleKeyEvent(event: KeyEvent): Boolean {
val slot = ensureSlot(event.deviceId, event.device)
if (slot < 0) return false
val button = keyCodeToButton(event.keyCode)
val button = keyCodeToButton(event.keyCode, runner)
if (button < 0) return false
when (event.action) {
// GML uses an edge model, so key-repeat (repeatCount > 0) is ignored: the button is
Expand All @@ -97,13 +97,56 @@ class GamepadRouter(private val runner: ButterscotchDroidRunner) {

// Analog sticks: forward raw, the runner deadzones on read. Left = X/Y, right = Z/RZ (the
// common Android mapping; controllers that expose the right stick on RX/RY won't drive it).
sendAxis(slot, state, AXIS_LH, event.getAxisValue(MotionEvent.AXIS_X))
sendAxis(slot, state, AXIS_LV, event.getAxisValue(MotionEvent.AXIS_Y))
sendAxis(slot, state, AXIS_RH, event.getAxisValue(MotionEvent.AXIS_Z))
sendAxis(slot, state, AXIS_RV, event.getAxisValue(MotionEvent.AXIS_RZ))
if (!runner.physicalControllerSideways){
sendAxis(slot, state, AXIS_LH, event.getAxisValue(MotionEvent.AXIS_X))
sendAxis(slot, state, AXIS_LV, event.getAxisValue(MotionEvent.AXIS_Y))
sendAxis(slot, state, AXIS_RH, event.getAxisValue(MotionEvent.AXIS_Z))
sendAxis(slot, state, AXIS_RV, event.getAxisValue(MotionEvent.AXIS_RZ))

// Many controllers report the dpad as a hat axis rather than dpad keycodes.
updateHat(slot, state, event.getAxisValue(MotionEvent.AXIS_HAT_X), event.getAxisValue(MotionEvent.AXIS_HAT_Y))

} else {
// Sideways controller movement
sendAxis(slot, state, AXIS_LH, event.getAxisValue(MotionEvent.AXIS_Y))
sendAxis(slot, state, AXIS_LV, -event.getAxisValue(MotionEvent.AXIS_X))
sendAxis(slot, state, AXIS_RH, event.getAxisValue(MotionEvent.AXIS_RZ))
sendAxis(slot, state, AXIS_RV, -event.getAxisValue(MotionEvent.AXIS_Z))

// Dpad as buttons
val xhat = signOf(event.getAxisValue(MotionEvent.AXIS_HAT_X))
val yhat = signOf(event.getAxisValue(MotionEvent.AXIS_HAT_Y))

if (xhat != state.lastHatX)
{
if(xhat < 0)
runner.onGamepadButton(slot, 0, true)
else if (state.lastHatX < 0)
runner.onGamepadButton(slot, 0, false)

if(xhat > 0)
runner.onGamepadButton(slot, 3, true)
else if (state.lastHatX > 0)
runner.onGamepadButton(slot, 3, false)
}

if(yhat != state.lastHatY)
{
if (yhat < 0)
runner.onGamepadButton(slot, 2, true)
else if(state.lastHatY < 0)
runner.onGamepadButton(slot, 2, false)

if (yhat > 0)
runner.onGamepadButton(slot, 1, true)
else if(state.lastHatY > 0)
runner.onGamepadButton(slot, 1, false)
}

state.lastHatX = xhat
state.lastHatY = yhat
}

// Many controllers report the dpad as a hat axis rather than dpad keycodes.
updateHat(slot, state, event.getAxisValue(MotionEvent.AXIS_HAT_X), event.getAxisValue(MotionEvent.AXIS_HAT_Y))

// Analog triggers -> digital L2/R2. Different controllers use LTRIGGER/RTRIGGER or BRAKE/GAS.
val left = maxOf(event.getAxisValue(MotionEvent.AXIS_LTRIGGER), event.getAxisValue(MotionEvent.AXIS_BRAKE))
Expand Down Expand Up @@ -184,7 +227,7 @@ class GamepadRouter(private val runner: ButterscotchDroidRunner) {
}

// Android KeyEvent keycode -> canonical button index, or -1 to leave the event alone.
private fun keyCodeToButton(keyCode: Int): Int = when (keyCode) {
private fun keyCodeToButton(keyCode: Int, runner: ButterscotchDroidRunner): Int = when (keyCode) {
KeyEvent.KEYCODE_BUTTON_A -> Gamepad.Button.FACE1.index
KeyEvent.KEYCODE_BUTTON_B -> Gamepad.Button.FACE2.index
KeyEvent.KEYCODE_BUTTON_X -> Gamepad.Button.FACE3.index
Expand All @@ -197,10 +240,10 @@ class GamepadRouter(private val runner: ButterscotchDroidRunner) {
KeyEvent.KEYCODE_BUTTON_START -> Gamepad.Button.START.index
KeyEvent.KEYCODE_BUTTON_THUMBL -> Gamepad.Button.STICK_L.index
KeyEvent.KEYCODE_BUTTON_THUMBR -> Gamepad.Button.STICK_R.index
KeyEvent.KEYCODE_DPAD_UP -> Gamepad.Button.DPAD_UP.index
KeyEvent.KEYCODE_DPAD_DOWN -> Gamepad.Button.DPAD_DOWN.index
KeyEvent.KEYCODE_DPAD_LEFT -> Gamepad.Button.DPAD_LEFT.index
KeyEvent.KEYCODE_DPAD_RIGHT -> Gamepad.Button.DPAD_RIGHT.index
KeyEvent.KEYCODE_DPAD_UP if !runner.physicalControllerSideways -> Gamepad.Button.DPAD_UP.index
KeyEvent.KEYCODE_DPAD_DOWN if !runner.physicalControllerSideways -> Gamepad.Button.DPAD_DOWN.index
KeyEvent.KEYCODE_DPAD_LEFT if !runner.physicalControllerSideways -> Gamepad.Button.DPAD_LEFT.index
KeyEvent.KEYCODE_DPAD_RIGHT if !runner.physicalControllerSideways -> Gamepad.Button.DPAD_RIGHT.index
KeyEvent.KEYCODE_BUTTON_MODE -> Gamepad.Button.HOME.index
else -> -1
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class GameMetadataFormState(
initialRunnerOs: GameEntry.RunnerOs,
initialEnablePhysicalControllers: Boolean,
initialEnablePhysicalKeyboard: Boolean,
initialPhysicalControllerSideways: Boolean,
initialEnableWidescreenHack: Boolean,
initialPostProcessing: GameEntry.PostProcessingSettings,
) {
Expand All @@ -34,6 +35,7 @@ class GameMetadataFormState(
var runnerOs by mutableStateOf(initialRunnerOs)
var enablePhysicalControllers by mutableStateOf(initialEnablePhysicalControllers)
var enablePhysicalKeyboard by mutableStateOf(initialEnablePhysicalKeyboard)
var physicalControllerSideways by mutableStateOf(initialPhysicalControllerSideways)
var enableWidescreenHack by mutableStateOf(initialEnableWidescreenHack)
var postProcessing by mutableStateOf(initialPostProcessing)

Expand All @@ -51,6 +53,7 @@ fun rememberGameMetadataFormState(
runnerOs: GameEntry.RunnerOs,
enablePhysicalControllers: Boolean,
enablePhysicalKeyboard: Boolean,
physicalControllerSideways: Boolean,
enableWidescreenHack: Boolean,
postProcessing: GameEntry.PostProcessingSettings = GameEntry.PostProcessingSettings()
): GameMetadataFormState = remember(key) {
Expand All @@ -61,6 +64,7 @@ fun rememberGameMetadataFormState(
initialLandscapeLayout = landscapeLayout,
initialRunnerOs = runnerOs,
initialEnablePhysicalControllers = enablePhysicalControllers,
initialPhysicalControllerSideways = physicalControllerSideways,
initialEnablePhysicalKeyboard = enablePhysicalKeyboard,
initialEnableWidescreenHack = enableWidescreenHack,
initialPostProcessing = postProcessing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,22 @@ fun MetadataForm(
subtitle = null,
checked = state.enablePhysicalControllers,
onChange = { state.enablePhysicalControllers = it },


)

Spacer(Modifier.height(16.dp))

if (state.enablePhysicalControllers)
InputToggle(
title = "Turn physical controllers sideways",
subtitle = "Useful for shmups",
checked = state.physicalControllerSideways,
onChange = {state.physicalControllerSideways = it},
)

Spacer(Modifier.height(16.dp))

InputToggle(
title = "Enable physical keyboard",
subtitle = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ data class GameEntry(
val runnerOs: RunnerOs = RunnerOs.WINDOWS,
/** When true, physical controllers (Bluetooth/USB gamepads) feed the GML gamepad_* builtins. Default on; turn off for games that misbehave with a controller attached. */
val enablePhysicalControllers: Boolean = true,
val physicalControllerSideways: Boolean = true,
/** When true, a physical (USB/Bluetooth) keyboard feeds the GML keyboard_* builtins. Default on; turn off for games that misbehave with a keyboard attached. */
val enablePhysicalKeyboard: Boolean = true,
val enableWidescreenHack: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class GameLibrary private constructor(
runnerOs: GameEntry.RunnerOs = GameEntry.RunnerOs.WINDOWS,
enablePhysicalControllers: Boolean = true,
enablePhysicalKeyboard: Boolean = true,
physicalControllerSideways: Boolean = true,
enableWidescreenHack: Boolean = false,
postProcessing: GameEntry.PostProcessingSettings = GameEntry.PostProcessingSettings()
) {
Expand All @@ -123,6 +124,7 @@ class GameLibrary private constructor(
landscapeLayout = landscapeLayout,
runnerOs = runnerOs,
enablePhysicalControllers = enablePhysicalControllers,
physicalControllerSideways = physicalControllerSideways,
enablePhysicalKeyboard = enablePhysicalKeyboard,
enableWidescreenHack = enableWidescreenHack,
postProcessing = postProcessing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fun GameSettingsScreen(
runnerOs = entry.runnerOs,
enablePhysicalControllers = entry.enablePhysicalControllers,
enablePhysicalKeyboard = entry.enablePhysicalKeyboard,
physicalControllerSideways = entry.physicalControllerSideways,
enableWidescreenHack = entry.enableWidescreenHack,
postProcessing = entry.postProcessing
)
Expand All @@ -63,6 +64,7 @@ fun GameSettingsScreen(
if (state.portraitLayout != entry.portraitLayout || state.landscapeLayout != entry.landscapeLayout) gameLibrary.update(entry.id) { it.copy(portraitLayout = state.portraitLayout, landscapeLayout = state.landscapeLayout) }
if (state.runnerOs != entry.runnerOs) gameLibrary.update(entry.id) { it.copy(runnerOs = state.runnerOs) }
if (state.enablePhysicalControllers != entry.enablePhysicalControllers) gameLibrary.update(entry.id) { it.copy(enablePhysicalControllers = state.enablePhysicalControllers) }
if (state.physicalControllerSideways != entry.physicalControllerSideways) gameLibrary.update(entry.id) {it.copy(physicalControllerSideways = state.physicalControllerSideways)}
if (state.enablePhysicalKeyboard != entry.enablePhysicalKeyboard) gameLibrary.update(entry.id) { it.copy(enablePhysicalKeyboard = state.enablePhysicalKeyboard) }
if (state.enableWidescreenHack != entry.enableWidescreenHack) gameLibrary.update(entry.id) { it.copy(enableWidescreenHack = state.enableWidescreenHack) }
if (state.postProcessing != entry.postProcessing) gameLibrary.update(entry.id) { it.copy(postProcessing = state.postProcessing) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,9 @@ private fun ConfigurePane(
landscapeLayout = LayoutLibrary.DEFAULT_LANDSCAPE_LAYOUT,
runnerOs = GameEntry.RunnerOs.WINDOWS,
enablePhysicalControllers = true,
physicalControllerSideways = false,
enablePhysicalKeyboard = true,
enableWidescreenHack = false
enableWidescreenHack = false,
)

MetadataForm(
Expand Down