// Copyright (c) 2024 Augie R. Maddox, Guavaman Enterprises. All rights reserved.
namespace Rewired.Demos.CustomPlatform {
///
/// An example custom input source for a custom platform.
/// This is for managing Joysticks.
/// Must implement .
/// This is an extremely simple implementation and only one of many possible approaches.
/// Real-world design depends on how the platform input API works as each work very differently.
/// (Polling vs event-based, separate input thread, etc.)
/// No function in this class should be called from a separate thread.
/// If multi-threaded input is required, input should be read on a separate thread, enqueued,
/// and consumed by the Joystick/Controller on Update in a thread-safe manner (mutex).
///
public sealed class MyPlatformInputSource : Rewired.Platforms.Custom.CustomPlatformInputSource {
///
/// Source of joysticks. This is just for this example.
/// This would be replaced by a system that interfaces with the platform input API.
///
private UnityInputJoystickSource _joystickInputSource = new UnityInputJoystickSource();
///
/// Prevents anything from being called until input source is initialized.
///
private bool _initialized;
///
/// Determines if the input source is ready.
/// Input source must be ready before it can be used.
///
public override bool isReady {
get {
return _initialized;
}
}
///
/// Constructor.
///
/// Custom platform configuration variables
public MyPlatformInputSource(Rewired.Platforms.Custom.CustomPlatformConfigVars configVars) :
base(
configVars,
new InitOptions() {
// Optionally create a custom keyboard source. If this is ommitted or set to null, UnityEngine.Input will be used for keyboard handling.
// configVars.useNativeKeyboard must also be set to true or this keyboard source will not be used.
unifiedKeyboardSource = new MyPlatformUnifiedKeyboardSource(),
// Optionally create a custom mouse source. If this is ommitted or set to null, UnityEngine.Input will be used for mouse handling.
// configVars.useNativeMouse must also be set to true or this mouse source will not be used.
unifiedMouseSource = new MyPlatformUnifiedMouseSource()
}
)
{
}
///
/// This is called once automatically during Rewired initialization.
///
protected override void OnInitialize() {
base.OnInitialize();
// Do any required platform initialization...
_initialized = true;
// Get joysticks on init so they are ready in Awake for scripts
MonitorDeviceChanges();
}
///
/// Called once per enabled update loop frame.
///
public override void Update() {
_joystickInputSource.Update();
// Handle device connection and disconnection
MonitorDeviceChanges();
}
///
/// Check to see if any devices have been connected or disconnected.
///
private void MonitorDeviceChanges() {
// Find joysticks on the system and add/remove them as necessary
// Get the current joystick list
var joysticks = GetJoysticks();
// Get the current system joystick list
var systemJoysticks = _joystickInputSource.GetJoysticks();
// Handle joystick disconnections first
// For each joystick already connected
// if system joystick list does not contain joystick, remove it
for (int i = joysticks.Count - 1; i >= 0; i--) { // iterate list backwards so items can be removed
var joystick = joysticks[i] as Joystick; // cast to local override Joystick type
if (ContainsSystemJoystickBySystemId(systemJoysticks, joystick.sourceJoystick.systemId)) continue;
// Found an orphaned joystick. Remove it.
RemoveJoystick(joystick); // remove it from the joystick list
}
// Handle new joystick connections
// For each joystick detected on system:
// if joysticks does not contain system joystick, add it
// if maintaining a joystick history, retrieve joystick from history, otherwise create new Joystick and add it
for (int i = 0; i < systemJoysticks.Count; i++) {
var systemJoystick = systemJoysticks[i];
if (ContainsJoystickBySystemId(joysticks, systemJoystick.systemId)) continue;
// Found a new joystick
Joystick newJoystick = new Joystick(systemJoystick); // create the joystick
// Add a custom controller extension if you have extra features you want to support through a Controller Extension
if (systemJoystick.vibrationMotorCount > 0) {
newJoystick.extension = new MyPlatformControllerExtension(newJoystick);
}
AddJoystick(newJoystick); // add it to the joystick list
}
}
#region IDisposable Implementation
private bool _disposed;
/* Uncomment if freeing native resources
~TestInputSource() {
Dispose(false);
}*/
protected override void Dispose(bool disposing) {
if (_disposed) return;
if (disposing) {
// free other managed objects that implement
// IDisposable only
}
// release any unmanaged objects
// set the object references to null
_disposed = true;
base.Dispose(disposing);
}
#endregion
///
/// Find the index of a joystick by system id.
///
/// The joysticks list.
/// The system id of the joystick.
/// True if found, false if not.
private static bool ContainsJoystickBySystemId(System.Collections.Generic.IList joysticks, long systemId) {
for (int i = 0; i < joysticks.Count; i++) {
if (joysticks[i].systemId == systemId) return true;
}
return false;
}
///
/// Find the index of a system joystick by system id.
///
/// The joysticks list.
/// The system id of the joystick.
/// True if found, false if not.
private static bool ContainsSystemJoystickBySystemId(System.Collections.Generic.IList systemJoysticks, long systemId) {
for (int i = 0; i < systemJoysticks.Count; i++) {
if (systemJoysticks[i].systemId == systemId) {
return true;
}
}
return false;
}
///
/// Example Joystick implementation that supports vibration.
///
new public sealed class Joystick : Rewired.Platforms.Custom.CustomPlatformInputSource.Joystick, Rewired.Interfaces.IControllerVibrator {
private UnityInputJoystickSource.Joystick _sourceJoystick;
public UnityInputJoystickSource.Joystick sourceJoystick { get { return _sourceJoystick; } }
///
/// Constructor.
///
/// The source joystick.
/// sourceJoystick is null.
public Joystick(UnityInputJoystickSource.Joystick sourceJoystick)
: base(sourceJoystick.deviceName, sourceJoystick.systemId, sourceJoystick.axisCount, sourceJoystick.buttonCount)
{
if (sourceJoystick == null) throw new System.ArgumentNullException("sourceJoystick");
_sourceJoystick = sourceJoystick;
customIdentifier = _sourceJoystick.identifier; // add additional identifying information for definition matching
deviceInstanceGuid = sourceJoystick.deviceInstanceGuid; // set persistent device identifier, if available. do not set this if a persistent unique identifier cannot be created or obtained on the current platform.
}
// Public Methods
///
/// Called once per frame. Used to update input values.
///
public override void Update() {
// Fill button values
for (int i = 0; i < buttonCount; i++) {
SetButtonValue(i, sourceJoystick.GetButtonValue(i));
//SetButtonFloatValue(i, sourceJoystick.GetButtonFloatValue(i)); // use if pressure-sensitive buttons
}
// Fill axis values
for (int i = 0; i < axisCount; i++) {
SetAxisValue(i, sourceJoystick.GetAxisValue(i));
}
}
// Implement IControllerVibrator interface so Rewired vibration works
public int vibrationMotorCount {
get {
return _sourceJoystick.vibrationMotorCount;
}
}
public void SetVibration(int motorIndex, float motorLevel) {
_sourceJoystick.SetVibration(motorIndex, motorLevel);
}
public void SetVibration(int motorIndex, float motorLevel, float duration) {
_sourceJoystick.SetVibration(motorIndex, motorLevel, duration);
}
public void SetVibration(int motorIndex, float motorLevel, bool stopOtherMotors) {
_sourceJoystick.SetVibration(motorIndex, motorLevel, stopOtherMotors);
}
public void SetVibration(int motorIndex, float motorLevel, float duration, bool stopOtherMotors) {
_sourceJoystick.SetVibration(motorIndex, motorLevel, duration, stopOtherMotors);
}
public float GetVibration(int motorIndex) {
return _sourceJoystick.GetVibration(motorIndex);
}
public void StopVibration() {
_sourceJoystick.StopVibration();
}
}
}
}