miroir de https://git.suyu.dev/suyu/suyu.git
418 lignes
15 KiB
Kotlin
418 lignes
15 KiB
Kotlin
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
|
// SPDX-FileCopyrightText: 2024 suyu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
package dev.suyu.suyu_emu.features.input
|
|
|
|
import dev.suyu.suyu_emu.features.input.model.NativeButton
|
|
import dev.suyu.suyu_emu.features.input.model.NativeAnalog
|
|
import dev.suyu.suyu_emu.features.input.model.InputType
|
|
import dev.suyu.suyu_emu.features.input.model.ButtonName
|
|
import dev.suyu.suyu_emu.features.input.model.NpadStyleIndex
|
|
import dev.suyu.suyu_emu.utils.NativeConfig
|
|
import dev.suyu.suyu_emu.utils.ParamPackage
|
|
import android.view.InputDevice
|
|
|
|
object NativeInput {
|
|
/**
|
|
* Default controller id for each device
|
|
*/
|
|
const val Player1Device = 0
|
|
const val Player2Device = 1
|
|
const val Player3Device = 2
|
|
const val Player4Device = 3
|
|
const val Player5Device = 4
|
|
const val Player6Device = 5
|
|
const val Player7Device = 6
|
|
const val Player8Device = 7
|
|
const val ConsoleDevice = 8
|
|
|
|
/**
|
|
* Button states
|
|
*/
|
|
object ButtonState {
|
|
const val RELEASED = 0
|
|
const val PRESSED = 1
|
|
}
|
|
|
|
/**
|
|
* Returns true if pro controller isn't available and handheld is.
|
|
* Intended to check where the input overlay should direct its inputs.
|
|
*/
|
|
external fun isHandheldOnly(): Boolean
|
|
|
|
/**
|
|
* Handles button press events for a gamepad.
|
|
* @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
|
|
* @param port Port determined by controller connection order.
|
|
* @param buttonId The Android Keycode corresponding to this event.
|
|
* @param action Mask identifying which action is happening (button pressed down, or button released).
|
|
*/
|
|
external fun onGamePadButtonEvent(
|
|
guid: String,
|
|
port: Int,
|
|
buttonId: Int,
|
|
action: Int
|
|
)
|
|
|
|
/**
|
|
* Handles axis movement events.
|
|
* @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
|
|
* @param port Port determined by controller connection order.
|
|
* @param axis The axis ID.
|
|
* @param value Value along the given axis.
|
|
*/
|
|
external fun onGamePadAxisEvent(guid: String, port: Int, axis: Int, value: Float)
|
|
|
|
/**
|
|
* Handles motion events.
|
|
* @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
|
|
* @param port Port determined by controller connection order.
|
|
* @param deltaTimestamp The finger id corresponding to this event.
|
|
* @param xGyro The value of the x-axis for the gyroscope.
|
|
* @param yGyro The value of the y-axis for the gyroscope.
|
|
* @param zGyro The value of the z-axis for the gyroscope.
|
|
* @param xAccel The value of the x-axis for the accelerometer.
|
|
* @param yAccel The value of the y-axis for the accelerometer.
|
|
* @param zAccel The value of the z-axis for the accelerometer.
|
|
*/
|
|
external fun onGamePadMotionEvent(
|
|
guid: String,
|
|
port: Int,
|
|
deltaTimestamp: Long,
|
|
xGyro: Float,
|
|
yGyro: Float,
|
|
zGyro: Float,
|
|
xAccel: Float,
|
|
yAccel: Float,
|
|
zAccel: Float
|
|
)
|
|
|
|
/**
|
|
* Signals and load a nfc tag
|
|
* @param data Byte array containing all the data from a nfc tag.
|
|
*/
|
|
external fun onReadNfcTag(data: ByteArray?)
|
|
|
|
/**
|
|
* Removes current loaded nfc tag.
|
|
*/
|
|
external fun onRemoveNfcTag()
|
|
|
|
/**
|
|
* Handles touch press events.
|
|
* @param fingerId The finger id corresponding to this event.
|
|
* @param xAxis The value of the x-axis on the touchscreen.
|
|
* @param yAxis The value of the y-axis on the touchscreen.
|
|
*/
|
|
external fun onTouchPressed(fingerId: Int, xAxis: Float, yAxis: Float)
|
|
|
|
/**
|
|
* Handles touch movement.
|
|
* @param fingerId The finger id corresponding to this event.
|
|
* @param xAxis The value of the x-axis on the touchscreen.
|
|
* @param yAxis The value of the y-axis on the touchscreen.
|
|
*/
|
|
external fun onTouchMoved(fingerId: Int, xAxis: Float, yAxis: Float)
|
|
|
|
/**
|
|
* Handles touch release events.
|
|
* @param fingerId The finger id corresponding to this event
|
|
*/
|
|
external fun onTouchReleased(fingerId: Int)
|
|
|
|
/**
|
|
* Sends a button input to the global virtual controllers.
|
|
* @param port Port determined by controller connection order.
|
|
* @param button The [NativeButton] corresponding to this event.
|
|
* @param action Mask identifying which action is happening (button pressed down, or button released).
|
|
*/
|
|
fun onOverlayButtonEvent(port: Int, button: NativeButton, action: Int) =
|
|
onOverlayButtonEventImpl(port, button.int, action)
|
|
|
|
private external fun onOverlayButtonEventImpl(port: Int, buttonId: Int, action: Int)
|
|
|
|
/**
|
|
* Sends a joystick input to the global virtual controllers.
|
|
* @param port Port determined by controller connection order.
|
|
* @param stick The [NativeAnalog] corresponding to this event.
|
|
* @param xAxis Value along the X axis.
|
|
* @param yAxis Value along the Y axis.
|
|
*/
|
|
fun onOverlayJoystickEvent(port: Int, stick: NativeAnalog, xAxis: Float, yAxis: Float) =
|
|
onOverlayJoystickEventImpl(port, stick.int, xAxis, yAxis)
|
|
|
|
private external fun onOverlayJoystickEventImpl(
|
|
port: Int,
|
|
stickId: Int,
|
|
xAxis: Float,
|
|
yAxis: Float
|
|
)
|
|
|
|
/**
|
|
* Handles motion events for the global virtual controllers.
|
|
* @param port Port determined by controller connection order
|
|
* @param deltaTimestamp The finger id corresponding to this event.
|
|
* @param xGyro The value of the x-axis for the gyroscope.
|
|
* @param yGyro The value of the y-axis for the gyroscope.
|
|
* @param zGyro The value of the z-axis for the gyroscope.
|
|
* @param xAccel The value of the x-axis for the accelerometer.
|
|
* @param yAccel The value of the y-axis for the accelerometer.
|
|
* @param zAccel The value of the z-axis for the accelerometer.
|
|
*/
|
|
external fun onDeviceMotionEvent(
|
|
port: Int,
|
|
deltaTimestamp: Long,
|
|
xGyro: Float,
|
|
yGyro: Float,
|
|
zGyro: Float,
|
|
xAccel: Float,
|
|
yAccel: Float,
|
|
zAccel: Float
|
|
)
|
|
|
|
/**
|
|
* Reloads all input devices from the currently loaded Settings::values.players into HID Core
|
|
*/
|
|
external fun reloadInputDevices()
|
|
|
|
/**
|
|
* Registers a controller to be used with mapping
|
|
* @param device An [InputDevice] or the input overlay wrapped with [SuyuInputDevice]
|
|
*/
|
|
external fun registerController(device: SuyuInputDevice)
|
|
|
|
/**
|
|
* Gets the names of input devices that have been registered with the input subsystem via [registerController]
|
|
*/
|
|
external fun getInputDevices(): Array<String>
|
|
|
|
/**
|
|
* Reads all input profiles from disk. Must be called before creating a profile picker.
|
|
*/
|
|
external fun loadInputProfiles()
|
|
|
|
/**
|
|
* Gets the names of each available input profile.
|
|
*/
|
|
external fun getInputProfileNames(): Array<String>
|
|
|
|
/**
|
|
* Checks if the user-provided name for an input profile is valid.
|
|
* @param name User-provided name for an input profile.
|
|
* @return Whether [name] is valid or not.
|
|
*/
|
|
external fun isProfileNameValid(name: String): Boolean
|
|
|
|
/**
|
|
* Creates a new input profile.
|
|
* @param name The new profile's name.
|
|
* @param playerIndex Index of the player that's currently being edited. Used to write the profile
|
|
* name to this player's config.
|
|
* @return Whether creating the profile was successful or not.
|
|
*/
|
|
external fun createProfile(name: String, playerIndex: Int): Boolean
|
|
|
|
/**
|
|
* Deletes an input profile.
|
|
* @param name Name of the profile to delete.
|
|
* @param playerIndex Index of the player that's currently being edited. Used to remove the profile
|
|
* name from this player's config if they have it loaded.
|
|
* @return Whether deleting this profile was successful or not.
|
|
*/
|
|
external fun deleteProfile(name: String, playerIndex: Int): Boolean
|
|
|
|
/**
|
|
* Loads an input profile.
|
|
* @param name Name of the input profile to load.
|
|
* @param playerIndex Index of the player that will have this profile loaded.
|
|
* @return Whether loading this profile was successful or not.
|
|
*/
|
|
external fun loadProfile(name: String, playerIndex: Int): Boolean
|
|
|
|
/**
|
|
* Saves an input profile.
|
|
* @param name Name of the profile to save.
|
|
* @param playerIndex Index of the player that's currently being edited. Used to write the profile
|
|
* name to this player's config.
|
|
* @return Whether saving the profile was successful or not.
|
|
*/
|
|
external fun saveProfile(name: String, playerIndex: Int): Boolean
|
|
|
|
/**
|
|
* Intended to be used immediately before a call to [NativeConfig.saveControlPlayerValues]
|
|
* Must be used while per-game config is loaded.
|
|
*/
|
|
external fun loadPerGameConfiguration(
|
|
playerIndex: Int,
|
|
selectedIndex: Int,
|
|
selectedProfileName: String
|
|
)
|
|
|
|
/**
|
|
* Tells the input subsystem to start listening for inputs to map.
|
|
* @param type Type of input to map as shown by the int property in each [InputType].
|
|
*/
|
|
external fun beginMapping(type: Int)
|
|
|
|
/**
|
|
* Gets an input's [ParamPackage] as a serialized string. Used for input verification before mapping.
|
|
* Must be run after [beginMapping] and before [stopMapping].
|
|
*/
|
|
external fun getNextInput(): String
|
|
|
|
/**
|
|
* Tells the input subsystem to stop listening for inputs to map.
|
|
*/
|
|
external fun stopMapping()
|
|
|
|
/**
|
|
* Updates a controller's mappings with auto-mapping params.
|
|
* @param playerIndex Index of the player to auto-map.
|
|
* @param deviceParams [ParamPackage] representing the device to auto-map as received
|
|
* from [getInputDevices].
|
|
* @param displayName Name of the device to auto-map as received from the "display" param in [deviceParams].
|
|
* Intended to be a way to provide a default name for a controller if the "display" param is empty.
|
|
*/
|
|
fun updateMappingsWithDefault(
|
|
playerIndex: Int,
|
|
deviceParams: ParamPackage,
|
|
displayName: String
|
|
) = updateMappingsWithDefaultImpl(playerIndex, deviceParams.serialize(), displayName)
|
|
|
|
private external fun updateMappingsWithDefaultImpl(
|
|
playerIndex: Int,
|
|
deviceParams: String,
|
|
displayName: String
|
|
)
|
|
|
|
/**
|
|
* Gets the params for a specific button.
|
|
* @param playerIndex Index of the player to get params from.
|
|
* @param button The [NativeButton] to get params for.
|
|
* @return A [ParamPackage] representing a player's specific button.
|
|
*/
|
|
fun getButtonParam(playerIndex: Int, button: NativeButton): ParamPackage =
|
|
ParamPackage(getButtonParamImpl(playerIndex, button.int))
|
|
|
|
private external fun getButtonParamImpl(playerIndex: Int, buttonId: Int): String
|
|
|
|
/**
|
|
* Sets the params for a specific button.
|
|
* @param playerIndex Index of the player to set params for.
|
|
* @param button The [NativeButton] to set params for.
|
|
* @param param A [ParamPackage] to set.
|
|
*/
|
|
fun setButtonParam(playerIndex: Int, button: NativeButton, param: ParamPackage) =
|
|
setButtonParamImpl(playerIndex, button.int, param.serialize())
|
|
|
|
private external fun setButtonParamImpl(playerIndex: Int, buttonId: Int, param: String)
|
|
|
|
/**
|
|
* Gets the params for a specific stick.
|
|
* @param playerIndex Index of the player to get params from.
|
|
* @param stick The [NativeAnalog] to get params for.
|
|
* @return A [ParamPackage] representing a player's specific stick.
|
|
*/
|
|
fun getStickParam(playerIndex: Int, stick: NativeAnalog): ParamPackage =
|
|
ParamPackage(getStickParamImpl(playerIndex, stick.int))
|
|
|
|
private external fun getStickParamImpl(playerIndex: Int, stickId: Int): String
|
|
|
|
/**
|
|
* Sets the params for a specific stick.
|
|
* @param playerIndex Index of the player to set params for.
|
|
* @param stick The [NativeAnalog] to set params for.
|
|
* @param param A [ParamPackage] to set.
|
|
*/
|
|
fun setStickParam(playerIndex: Int, stick: NativeAnalog, param: ParamPackage) =
|
|
setStickParamImpl(playerIndex, stick.int, param.serialize())
|
|
|
|
private external fun setStickParamImpl(playerIndex: Int, stickId: Int, param: String)
|
|
|
|
/**
|
|
* Gets the int representation of a [ButtonName]. Tells you what to show as the mapped input for
|
|
* a button/analog/other.
|
|
* @param param A [ParamPackage] that represents a specific button's params.
|
|
* @return The [ButtonName] for [param].
|
|
*/
|
|
fun getButtonName(param: ParamPackage): ButtonName =
|
|
ButtonName.from(getButtonNameImpl(param.serialize()))
|
|
|
|
private external fun getButtonNameImpl(param: String): Int
|
|
|
|
/**
|
|
* Gets each supported [NpadStyleIndex] for a given player.
|
|
* @param playerIndex Index of the player to get supported indexes for.
|
|
* @return List of each supported [NpadStyleIndex].
|
|
*/
|
|
fun getSupportedStyleTags(playerIndex: Int): List<NpadStyleIndex> =
|
|
getSupportedStyleTagsImpl(playerIndex).map { NpadStyleIndex.from(it) }
|
|
|
|
private external fun getSupportedStyleTagsImpl(playerIndex: Int): IntArray
|
|
|
|
/**
|
|
* Gets the [NpadStyleIndex] for a given player.
|
|
* @param playerIndex Index of the player to get an [NpadStyleIndex] from.
|
|
* @return The [NpadStyleIndex] for a given player.
|
|
*/
|
|
fun getStyleIndex(playerIndex: Int): NpadStyleIndex =
|
|
NpadStyleIndex.from(getStyleIndexImpl(playerIndex))
|
|
|
|
private external fun getStyleIndexImpl(playerIndex: Int): Int
|
|
|
|
/**
|
|
* Sets the [NpadStyleIndex] for a given player.
|
|
* @param playerIndex Index of the player to change.
|
|
* @param style The new style to set.
|
|
*/
|
|
fun setStyleIndex(playerIndex: Int, style: NpadStyleIndex) =
|
|
setStyleIndexImpl(playerIndex, style.int)
|
|
|
|
private external fun setStyleIndexImpl(playerIndex: Int, styleIndex: Int)
|
|
|
|
/**
|
|
* Checks if a device is a controller.
|
|
* @param params [ParamPackage] for an input device retrieved from [getInputDevices]
|
|
* @return Whether the device is a controller or not.
|
|
*/
|
|
fun isController(params: ParamPackage): Boolean = isControllerImpl(params.serialize())
|
|
|
|
private external fun isControllerImpl(params: String): Boolean
|
|
|
|
/**
|
|
* Checks if a controller is connected
|
|
* @param playerIndex Index of the player to check.
|
|
* @return Whether the player is connected or not.
|
|
*/
|
|
external fun getIsConnected(playerIndex: Int): Boolean
|
|
|
|
/**
|
|
* Connects/disconnects a controller and ensures that connection order stays in-tact.
|
|
* @param playerIndex Index of the player to connect/disconnect.
|
|
* @param connected Whether to connect or disconnect this controller.
|
|
*/
|
|
fun connectControllers(playerIndex: Int, connected: Boolean = true) {
|
|
val connectedControllers = mutableListOf<Boolean>().apply {
|
|
if (connected) {
|
|
for (i in 0 until 8) {
|
|
add(i <= playerIndex)
|
|
}
|
|
} else {
|
|
for (i in 0 until 8) {
|
|
add(i < playerIndex)
|
|
}
|
|
}
|
|
}
|
|
connectControllersImpl(connectedControllers.toBooleanArray())
|
|
}
|
|
|
|
private external fun connectControllersImpl(connected: BooleanArray)
|
|
|
|
/**
|
|
* Resets all of the button and analog mappings for a player.
|
|
* @param playerIndex Index of the player that will have its mappings reset.
|
|
*/
|
|
external fun resetControllerMappings(playerIndex: Int)
|
|
}
|