test
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID || PACKAGE_DOCS_GENERATION
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine.InputSystem.Android.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace UnityEngine.InputSystem.Android.LowLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum used to identity the axis type in the Android motion input event. See <see cref="AndroidGameControllerState.axis"/>.
|
||||
/// See https://developer.android.com/reference/android/view/MotionEvent#constants_1 for more details.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags", Justification = "False positive")]
|
||||
public enum AndroidAxis
|
||||
{
|
||||
/// <summary>
|
||||
/// X axis of a motion event.
|
||||
/// </summary>
|
||||
X = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Y axis of a motion event.
|
||||
/// </summary>
|
||||
Y = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Pressure axis of a motion event.
|
||||
/// </summary>
|
||||
Pressure = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Size axis of a motion event.
|
||||
/// </summary>
|
||||
Size = 3,
|
||||
|
||||
/// <summary>
|
||||
/// TouchMajor axis of a motion event.
|
||||
/// </summary>
|
||||
TouchMajor = 4,
|
||||
|
||||
/// <summary>
|
||||
/// TouchMinor axis of a motion event.
|
||||
/// </summary>
|
||||
TouchMinor = 5,
|
||||
|
||||
/// <summary>
|
||||
/// ToolMajor axis of a motion event.
|
||||
/// </summary>
|
||||
ToolMajor = 6,
|
||||
|
||||
/// <summary>
|
||||
/// ToolMinor axis of a motion event.
|
||||
/// </summary>
|
||||
ToolMinor = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Orientation axis of a motion event.
|
||||
/// </summary>
|
||||
Orientation = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Vertical Scroll of a motion event.
|
||||
/// </summary>
|
||||
Vscroll = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal Scroll axis of a motion event.
|
||||
/// </summary>
|
||||
Hscroll = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Z axis of a motion event.
|
||||
/// </summary>
|
||||
Z = 11,
|
||||
|
||||
/// <summary>
|
||||
/// X Rotation axis of a motion event.
|
||||
/// </summary>
|
||||
Rx = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Y Rotation axis of a motion event.
|
||||
/// </summary>
|
||||
Ry = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Z Rotation axis of a motion event.
|
||||
/// </summary>
|
||||
Rz = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Hat X axis of a motion event.
|
||||
/// </summary>
|
||||
HatX = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Hat Y axis of a motion event.
|
||||
/// </summary>
|
||||
HatY = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Left Trigger axis of a motion event.
|
||||
/// </summary>
|
||||
Ltrigger = 17,
|
||||
|
||||
/// <summary>
|
||||
/// Right Trigger axis of a motion event.
|
||||
/// </summary>
|
||||
Rtrigger = 18,
|
||||
|
||||
/// <summary>
|
||||
/// Throttle axis of a motion event.
|
||||
/// </summary>
|
||||
Throttle = 19,
|
||||
|
||||
/// <summary>
|
||||
/// Rudder axis of a motion event.
|
||||
/// </summary>
|
||||
Rudder = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Wheel axis of a motion event.
|
||||
/// </summary>
|
||||
Wheel = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Gas axis of a motion event.
|
||||
/// </summary>
|
||||
Gas = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Break axis of a motion event.
|
||||
/// </summary>
|
||||
Brake = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Distance axis of a motion event.
|
||||
/// </summary>
|
||||
Distance = 24,
|
||||
|
||||
/// <summary>
|
||||
/// Tilt axis of a motion event.
|
||||
/// </summary>
|
||||
Tilt = 25,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 1 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic1 = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 2 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic2 = 33,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 3 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic3 = 34,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 4 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic4 = 35,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 5 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic5 = 36,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 6 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic6 = 37,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 7 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic7 = 38,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 8 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic8 = 39,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 9 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic9 = 40,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 10 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic10 = 41,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 11 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic11 = 42,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 12 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic12 = 43,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 13 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic13 = 44,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 14 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic14 = 45,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 15 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic15 = 46,
|
||||
|
||||
/// <summary>
|
||||
/// Generic 16 axis of a motion event.
|
||||
/// </summary>
|
||||
Generic16 = 47,
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR || UNITY_ANDROID
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15fa4fb6e47739e43b36a70fce024b6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,234 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID || PACKAGE_DOCS_GENERATION
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Android.LowLevel;
|
||||
using UnityEngine.InputSystem.DualShock;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace UnityEngine.InputSystem.Android.LowLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// Default state layout for Android game controller.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct AndroidGameControllerState : IInputStateTypeInfo
|
||||
{
|
||||
public const int MaxAxes = 48;
|
||||
public const int MaxButtons = 220;
|
||||
|
||||
public class Variants
|
||||
{
|
||||
public const string Gamepad = "Gamepad";
|
||||
public const string Joystick = "Joystick";
|
||||
public const string DPadAxes = "DpadAxes";
|
||||
public const string DPadButtons = "DpadButtons";
|
||||
}
|
||||
|
||||
internal const uint kAxisOffset = sizeof(uint) * (uint)((MaxButtons + 31) / 32);
|
||||
|
||||
public static FourCC kFormat = new FourCC('A', 'G', 'C', ' ');
|
||||
|
||||
[InputControl(name = "dpad", layout = "Dpad", bit = (uint)AndroidKeyCode.DpadUp, sizeInBits = 4, variants = Variants.DPadButtons)]
|
||||
[InputControl(name = "dpad/up", bit = (uint)AndroidKeyCode.DpadUp, variants = Variants.DPadButtons)]
|
||||
[InputControl(name = "dpad/down", bit = (uint)AndroidKeyCode.DpadDown, variants = Variants.DPadButtons)]
|
||||
[InputControl(name = "dpad/left", bit = (uint)AndroidKeyCode.DpadLeft, variants = Variants.DPadButtons)]
|
||||
[InputControl(name = "dpad/right", bit = (uint)AndroidKeyCode.DpadRight, variants = Variants.DPadButtons)]
|
||||
[InputControl(name = "buttonSouth", bit = (uint)AndroidKeyCode.ButtonA, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "buttonWest", bit = (uint)AndroidKeyCode.ButtonX, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "buttonNorth", bit = (uint)AndroidKeyCode.ButtonY, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "buttonEast", bit = (uint)AndroidKeyCode.ButtonB, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "leftStickPress", bit = (uint)AndroidKeyCode.ButtonThumbl, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "rightStickPress", bit = (uint)AndroidKeyCode.ButtonThumbr, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "leftShoulder", bit = (uint)AndroidKeyCode.ButtonL1, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "rightShoulder", bit = (uint)AndroidKeyCode.ButtonR1, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "start", bit = (uint)AndroidKeyCode.ButtonStart, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "select", bit = (uint)AndroidKeyCode.ButtonSelect, variants = Variants.Gamepad)]
|
||||
public fixed uint buttons[(MaxButtons + 31) / 32];
|
||||
|
||||
[InputControl(name = "dpad", layout = "Dpad", offset = (uint)AndroidAxis.HatX * sizeof(float) + kAxisOffset, format = "VEC2", sizeInBits = 64, variants = Variants.DPadAxes)]
|
||||
[InputControl(name = "dpad/right", offset = 0, bit = 0, sizeInBits = 32, format = "FLT", parameters = "clamp=3,clampConstant=0,clampMin=0,clampMax=1", variants = Variants.DPadAxes)]
|
||||
[InputControl(name = "dpad/left", offset = 0, bit = 0, sizeInBits = 32, format = "FLT", parameters = "clamp=3,clampConstant=0,clampMin=-1,clampMax=0,invert", variants = Variants.DPadAxes)]
|
||||
[InputControl(name = "dpad/down", offset = ((uint)AndroidAxis.HatY - (uint)AndroidAxis.HatX) * sizeof(float), bit = 0, sizeInBits = 32, format = "FLT", parameters = "clamp=3,clampConstant=0,clampMin=0,clampMax=1", variants = Variants.DPadAxes)]
|
||||
[InputControl(name = "dpad/up", offset = ((uint)AndroidAxis.HatY - (uint)AndroidAxis.HatX) * sizeof(float), bit = 0, sizeInBits = 32, format = "FLT", parameters = "clamp=3,clampConstant=0,clampMin=-1,clampMax=0,invert", variants = Variants.DPadAxes)]
|
||||
[InputControl(name = "leftTrigger", offset = (uint)AndroidAxis.Brake * sizeof(float) + kAxisOffset, parameters = "clamp=1,clampMin=0,clampMax=1.0", variants = Variants.Gamepad)]
|
||||
[InputControl(name = "rightTrigger", offset = (uint)AndroidAxis.Gas * sizeof(float) + kAxisOffset, parameters = "clamp=1,clampMin=0,clampMax=1.0", variants = Variants.Gamepad)]
|
||||
[InputControl(name = "leftStick", variants = Variants.Gamepad)]
|
||||
[InputControl(name = "leftStick/y", variants = Variants.Gamepad, parameters = "invert")]
|
||||
[InputControl(name = "leftStick/up", variants = Variants.Gamepad, parameters = "invert,clamp=1,clampMin=-1.0,clampMax=0.0")]
|
||||
[InputControl(name = "leftStick/down", variants = Variants.Gamepad, parameters = "invert=false,clamp=1,clampMin=0,clampMax=1.0")]
|
||||
////FIXME: state for this control is not contiguous
|
||||
[InputControl(name = "rightStick", offset = (uint)AndroidAxis.Z * sizeof(float) + kAxisOffset, sizeInBits = ((uint)AndroidAxis.Rz - (uint)AndroidAxis.Z + 1) * sizeof(float) * 8, variants = Variants.Gamepad)]
|
||||
[InputControl(name = "rightStick/x", variants = Variants.Gamepad)]
|
||||
[InputControl(name = "rightStick/y", offset = ((uint)AndroidAxis.Rz - (uint)AndroidAxis.Z) * sizeof(float), variants = Variants.Gamepad, parameters = "invert")]
|
||||
[InputControl(name = "rightStick/up", offset = ((uint)AndroidAxis.Rz - (uint)AndroidAxis.Z) * sizeof(float), variants = Variants.Gamepad, parameters = "invert,clamp=1,clampMin=-1.0,clampMax=0.0")]
|
||||
[InputControl(name = "rightStick/down", offset = ((uint)AndroidAxis.Rz - (uint)AndroidAxis.Z) * sizeof(float), variants = Variants.Gamepad, parameters = "invert=false,clamp=1,clampMin=0,clampMax=1.0")]
|
||||
public fixed float axis[MaxAxes];
|
||||
|
||||
public FourCC format
|
||||
{
|
||||
get { return kFormat; }
|
||||
}
|
||||
|
||||
public AndroidGameControllerState WithButton(AndroidKeyCode code, bool value = true)
|
||||
{
|
||||
fixed(uint* buttonsPtr = buttons)
|
||||
{
|
||||
if (value)
|
||||
buttonsPtr[(int)code / 32] |= 1U << ((int)code % 32);
|
||||
else
|
||||
buttonsPtr[(int)code / 32] &= ~(1U << ((int)code % 32));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AndroidGameControllerState WithAxis(AndroidAxis axis, float value)
|
||||
{
|
||||
fixed(float* axisPtr = this.axis)
|
||||
{
|
||||
axisPtr[(int)axis] = value;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// See https://developer.android.com/reference/android/view/InputDevice.html for input source values
|
||||
internal enum AndroidInputSource
|
||||
{
|
||||
Keyboard = 257,
|
||||
Dpad = 513,
|
||||
Gamepad = 1025,
|
||||
Touchscreen = 4098,
|
||||
Mouse = 8194,
|
||||
Stylus = 16386,
|
||||
Trackball = 65540,
|
||||
Touchpad = 1048584,
|
||||
Joystick = 16777232
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal struct AndroidDeviceCapabilities
|
||||
{
|
||||
public string deviceDescriptor;
|
||||
public int productId;
|
||||
public int vendorId;
|
||||
public bool isVirtual;
|
||||
public AndroidAxis[] motionAxes;
|
||||
public AndroidInputSource inputSources;
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
return JsonUtility.ToJson(this);
|
||||
}
|
||||
|
||||
public static AndroidDeviceCapabilities FromJson(string json)
|
||||
{
|
||||
if (json == null)
|
||||
throw new ArgumentNullException(nameof(json));
|
||||
return JsonUtility.FromJson<AndroidDeviceCapabilities>(json);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$"deviceDescriptor = {deviceDescriptor}, productId = {productId}, vendorId = {vendorId}, isVirtual = {isVirtual}, motionAxes = {(motionAxes == null ? "<null>" : String.Join(",", motionAxes.Select(i => i.ToString()).ToArray()))}, inputSources = {inputSources}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace UnityEngine.InputSystem.Android
|
||||
{
|
||||
////FIXME: This is messy! Clean up!
|
||||
/// <summary>
|
||||
/// Gamepad on Android. Comprises all types of gamepads supported on Android.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Most of the gamepads:
|
||||
/// - ELAN PLAYSTATION(R)3 Controller
|
||||
/// - My-Power CO.,LTD. PS(R) Controller Adaptor
|
||||
/// (Following tested and work with: Nvidia Shield TV (OS 9); Galaxy Note 20 Ultra (OS 11); Galaxy S9+ (OS 10.0))
|
||||
/// - Sony Interactive Entertainment Wireless (PS4 DualShock) (Also tested and DOES NOT WORK with Galaxy S9 (OS 8.0); Galaxy S8 (OS 7.0); Xiaomi Mi Note2 (OS 8.0))
|
||||
/// - Xbox Wireless Controller (Xbox One) (Also tested and works on Samsung Galaxy S8 (OS 7.0); Xiaomi Mi Note2 (OS 8.0))
|
||||
/// - NVIDIA Controller v01.03/v01.04
|
||||
/// - (Add more)
|
||||
/// map buttons in the following way:
|
||||
/// Left Stick -> AXIS_X(0) / AXIS_Y(1)
|
||||
/// Right Stick -> AXIS_Z (11) / AXIS_RZ(14)
|
||||
/// Right Thumb -> KEYCODE_BUTTON_THUMBR(107)
|
||||
/// Left Thumb -> KEYCODE_BUTTON_THUMBL(106)
|
||||
/// L1 (Left shoulder) -> KEYCODE_BUTTON_L1(102)
|
||||
/// R1 (Right shoulder) -> KEYCODE_BUTTON_R1(103)
|
||||
/// L2 (Left trigger) -> AXIS_BRAKE(23)
|
||||
/// R2 (Right trigger) -> AXIS_GAS(22)
|
||||
/// X -> KEYCODE_BUTTON_X(99)
|
||||
/// Y -> KEYCODE_BUTTON_Y(100)
|
||||
/// B -> KEYCODE_BUTTON_B(97)
|
||||
/// A -> KEYCODE_BUTTON_A(96)
|
||||
/// DPAD -> AXIS_HAT_X(15),AXIS_HAT_Y(16) or KEYCODE_DPAD_LEFT(21), KEYCODE_DPAD_RIGHT(22), KEYCODE_DPAD_UP(19), KEYCODE_DPAD_DOWN(20),
|
||||
/// Note: On Nvidia Shield Console, L2/R2 additionally invoke key events for AXIS_LTRIGGER, AXIS_RTRIGGER (in addition to AXIS_BRAKE, AXIS_GAS)
|
||||
/// If you connect gamepad to a phone for L2/R2 only AXIS_BRAKE/AXIS_GAS come. AXIS_LTRIGGER, AXIS_RTRIGGER are not invoked.
|
||||
/// That's why we map triggers only to AXIS_BRAKE/AXIS_GAS
|
||||
/// Nvidia Shield also reports KEYCODE_BACK instead of KEYCODE_BUTTON_SELECT, so Options(XboxOne Controller)/View(DualShock)/Select buttons do not work
|
||||
/// PS4 controller is officially supported from Android 10 and higher (https://playstation.com/en-us/support/hardware/ps4-pair-dualshock-4-wireless-with-sony-xperia-and-android)
|
||||
/// However, some devices with older OS have fixed PS4 controller support on their drivers this leads to following situation:
|
||||
/// Some gamepads on Android devices (with same Android number version) might have different mappings
|
||||
/// For ex., Dualshock, on NVidia Shield Console (OS 8.0) all buttons correctly map according to rules in AndroidGameControllerState
|
||||
/// when clicking left shoulder it will go to AndroidKeyCode.ButtonL1, rightShoulder -> AndroidKeyCode.ButtonR1, etc
|
||||
/// But, on Samsung Galaxy S9 (OS 8.0), the mapping is different (Same for Xiaomi Mi Note2 (OS 8.0), Samsung Galaxy S8 (OS 7.0))
|
||||
/// when clicking left shoulder it will go to AndroidKeyCode.ButtonY, rightShoulder -> AndroidKeyCode.ButtonZ, etc
|
||||
/// So even though Android version is 8.0 in both cases, Dualshock will only correctly work on NVidia Shield Console
|
||||
/// It's obvious that this depends on the driver and not Android OS, thus we can only assume Samsung in this case doesn't properly support Dualshock in their drivers
|
||||
/// While we can do custom mapping for Samsung, we can never now when will they try to update the driver for Dualshock or some other gamepad
|
||||
/// </remarks>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), variants = AndroidGameControllerState.Variants.Gamepad)]
|
||||
public class AndroidGamepad : Gamepad
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic controller with Dpad axes
|
||||
/// </summary>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), hideInUI = true,
|
||||
variants = AndroidGameControllerState.Variants.Gamepad + InputControlLayout.VariantSeparator + AndroidGameControllerState.Variants.DPadAxes)]
|
||||
public class AndroidGamepadWithDpadAxes : AndroidGamepad
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic controller with Dpad buttons
|
||||
/// </summary>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), hideInUI = true,
|
||||
variants = AndroidGameControllerState.Variants.Gamepad + InputControlLayout.VariantSeparator + AndroidGameControllerState.Variants.DPadButtons)]
|
||||
public class AndroidGamepadWithDpadButtons : AndroidGamepad
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joystick on Android.
|
||||
/// </summary>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), variants = AndroidGameControllerState.Variants.Joystick)]
|
||||
public class AndroidJoystick : Joystick
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A PlayStation DualShock 4 controller connected to an Android device.
|
||||
/// </summary>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), displayName = "Android DualShock 4 Gamepad",
|
||||
variants = AndroidGameControllerState.Variants.Gamepad + InputControlLayout.VariantSeparator + AndroidGameControllerState.Variants.DPadAxes)]
|
||||
public class DualShock4GamepadAndroid : DualShockGamepad
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A PlayStation DualShock 4 controller connected to an Android device.
|
||||
/// </summary>
|
||||
[InputControlLayout(stateType = typeof(AndroidGameControllerState), displayName = "Android Xbox One Controller",
|
||||
variants = AndroidGameControllerState.Variants.Gamepad + InputControlLayout.VariantSeparator + AndroidGameControllerState.Variants.DPadAxes)]
|
||||
public class XboxOneGamepadAndroid : XInput.XInputController
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR || UNITY_ANDROID
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c6472eb810ba445be34c69325e4fea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ede17f8b7e9dfcf42b560545a8102eeb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,293 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID || PACKAGE_DOCS_GENERATION
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine.InputSystem.Android.LowLevel;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.Processors;
|
||||
|
||||
////TODO: make all the sensor class types internal
|
||||
|
||||
namespace UnityEngine.InputSystem.Android.LowLevel
|
||||
{
|
||||
internal enum AndroidSensorType
|
||||
{
|
||||
None = 0,
|
||||
Accelerometer = 1,
|
||||
MagneticField = 2,
|
||||
Orientation = 3, // Was deprecated in API 8 https://developer.android.com/reference/android/hardware/Sensor#TYPE_ORIENTATION
|
||||
Gyroscope = 4,
|
||||
Light = 5,
|
||||
Pressure = 6,
|
||||
Temperature = 7, // Was deprecated in API 14 https://developer.android.com/reference/android/hardware/Sensor#TYPE_TEMPERATURE
|
||||
Proximity = 8,
|
||||
Gravity = 9,
|
||||
LinearAcceleration = 10,
|
||||
RotationVector = 11,
|
||||
RelativeHumidity = 12,
|
||||
AmbientTemperature = 13,
|
||||
MagneticFieldUncalibrated = 14,
|
||||
GameRotationVector = 15,
|
||||
GyroscopeUncalibrated = 16,
|
||||
SignificantMotion = 17,
|
||||
StepDetector = 18,
|
||||
StepCounter = 19,
|
||||
GeomagneticRotationVector = 20,
|
||||
HeartRate = 21,
|
||||
Pose6DOF = 28,
|
||||
StationaryDetect = 29,
|
||||
MotionDetect = 30,
|
||||
HeartBeat = 31,
|
||||
LowLatencyOffBodyDetect = 34,
|
||||
AccelerometerUncalibrated = 35,
|
||||
HingeAngle = 36
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal struct AndroidSensorCapabilities
|
||||
{
|
||||
public AndroidSensorType sensorType;
|
||||
|
||||
public string ToJson()
|
||||
{
|
||||
return JsonUtility.ToJson(this);
|
||||
}
|
||||
|
||||
public static AndroidSensorCapabilities FromJson(string json)
|
||||
{
|
||||
if (json == null)
|
||||
throw new ArgumentNullException(nameof(json));
|
||||
return JsonUtility.FromJson<AndroidSensorCapabilities>(json);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"type = {sensorType.ToString()}";
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe struct AndroidSensorState : IInputStateTypeInfo
|
||||
{
|
||||
public static FourCC kFormat = new FourCC('A', 'S', 'S', ' ');
|
||||
|
||||
////FIXME: Sensors to check if values matches old system
|
||||
// Accelerometer - OK
|
||||
// MagneticField - no alternative in old system
|
||||
// Gyroscope - OK
|
||||
// Light - no alternative in old system
|
||||
// Pressure - no alternative in old system
|
||||
// Proximity - no alternative in old system
|
||||
// Gravity - OK
|
||||
// LinearAcceleration - need to check
|
||||
// RotationVector - OK
|
||||
// RelativeHumidity - no alternative in old system
|
||||
// AmbientTemperature - no alternative in old system
|
||||
// GameRotationVector - no alternative in old system
|
||||
// StepCounter - no alternative in old system
|
||||
// GeomagneticRotationVector - no alternative in old system
|
||||
// HeartRate - no alternative in old system
|
||||
|
||||
[InputControl(name = "acceleration", layout = "Vector3", processors = "AndroidCompensateDirection", variants = "Accelerometer")]
|
||||
[InputControl(name = "magneticField", layout = "Vector3", variants = "MagneticField")]
|
||||
// Note: Using CompensateDirection instead of AndroidCompensateDirection, because we don't need to normalize velocity
|
||||
[InputControl(name = "angularVelocity", layout = "Vector3", processors = "CompensateDirection", variants = "Gyroscope")]
|
||||
[InputControl(name = "lightLevel", layout = "Axis", variants = "Light")]
|
||||
[InputControl(name = "atmosphericPressure", layout = "Axis", variants = "Pressure")]
|
||||
[InputControl(name = "distance", layout = "Axis", variants = "Proximity")]
|
||||
[InputControl(name = "gravity", layout = "Vector3", processors = "AndroidCompensateDirection", variants = "Gravity")]
|
||||
[InputControl(name = "acceleration", layout = "Vector3", processors = "AndroidCompensateDirection", variants = "LinearAcceleration")]
|
||||
[InputControl(name = "attitude", layout = "Quaternion", processors = "AndroidCompensateRotation", variants = "RotationVector")]
|
||||
[InputControl(name = "relativeHumidity", layout = "Axis", variants = "RelativeHumidity")]
|
||||
[InputControl(name = "ambientTemperature", layout = "Axis", variants = "AmbientTemperature")]
|
||||
[InputControl(name = "attitude", layout = "Quaternion", processors = "AndroidCompensateRotation", variants = "GameRotationVector")]
|
||||
[InputControl(name = "stepCounter", layout = "Integer", variants = "StepCounter")]
|
||||
[InputControl(name = "rotation", layout = "Quaternion", processors = "AndroidCompensateRotation", variants = "GeomagneticRotationVector")]
|
||||
[InputControl(name = "rate", layout = "Axis", variants = "HeartRate")]
|
||||
[InputControl(name = "angle", layout = "Axis", variants = nameof(AndroidSensorType.HingeAngle))]
|
||||
public fixed float data[16];
|
||||
|
||||
public AndroidSensorState WithData(params float[] data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
|
||||
for (var i = 0; i < data.Length && i < 16; i++)
|
||||
this.data[i] = data[i];
|
||||
|
||||
// Fill the rest with zeroes
|
||||
for (var i = data.Length; i < 16; i++)
|
||||
this.data[i] = 0.0f;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public FourCC format => kFormat;
|
||||
}
|
||||
|
||||
[DesignTimeVisible(false)]
|
||||
internal class AndroidCompensateDirectionProcessor : CompensateDirectionProcessor
|
||||
{
|
||||
// Taken from platforms\android-<API>\arch-arm\usr\include\android\sensor.h
|
||||
private const float kSensorStandardGravity = 9.80665f;
|
||||
|
||||
private const float kAccelerationMultiplier = -1.0f / kSensorStandardGravity;
|
||||
|
||||
public override Vector3 Process(Vector3 vector, InputControl control)
|
||||
{
|
||||
return base.Process(vector * kAccelerationMultiplier, control);
|
||||
}
|
||||
}
|
||||
|
||||
[DesignTimeVisible(false)]
|
||||
internal class AndroidCompensateRotationProcessor : CompensateRotationProcessor
|
||||
{
|
||||
public override Quaternion Process(Quaternion value, InputControl control)
|
||||
{
|
||||
// https://developer.android.com/reference/android/hardware/SensorEvent#values
|
||||
// "...The rotation vector represents the orientation of the device as a combination of an angle and an axis, in which the device has rotated through an angle theta around an axis <x, y, z>."
|
||||
// "...The three elements of the rotation vector are < x * sin(theta / 2), y* sin(theta / 2), z* sin(theta / 2)>, such that the magnitude of the rotation vector is equal to sin(theta / 2), and the direction of the rotation vector is equal to the direction of the axis of rotation."
|
||||
// "...The three elements of the rotation vector are equal to the last three components of a unit quaternion < cos(theta / 2), x* sin(theta/ 2), y* sin(theta / 2), z* sin(theta/ 2)>."
|
||||
//
|
||||
// In other words, axis + rotation is combined into Vector3, to recover the quaternion from it, we must compute 4th component as 1 - sqrt(x*x + y*y + z*z)
|
||||
var sinRho2 = value.x * value.x + value.y * value.y + value.z * value.z;
|
||||
value.w = (sinRho2 < 1.0f) ? Mathf.Sqrt(1.0f - sinRho2) : 0.0f;
|
||||
|
||||
return base.Process(value, control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace UnityEngine.InputSystem.Android
|
||||
{
|
||||
/// <summary>
|
||||
/// Accelerometer device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_ACCELEROMETER"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Accelerometer", hideInUI = true)]
|
||||
public class AndroidAccelerometer : Accelerometer
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Magnetic field sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_MAGNETIC_FIELD"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "MagneticField", hideInUI = true)]
|
||||
public class AndroidMagneticFieldSensor : MagneticFieldSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gyroscope device on android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_GYROSCOPE"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Gyroscope", hideInUI = true)]
|
||||
public class AndroidGyroscope : Gyroscope
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Light sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_LIGHT"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Light", hideInUI = true)]
|
||||
public class AndroidLightSensor : LightSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pressure sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_PRESSURE"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Pressure", hideInUI = true)]
|
||||
public class AndroidPressureSensor : PressureSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proximity sensor type on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_PROXIMITY"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Proximity", hideInUI = true)]
|
||||
public class AndroidProximity : ProximitySensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gravity sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_GRAVITY"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "Gravity", hideInUI = true)]
|
||||
public class AndroidGravitySensor : GravitySensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linear acceleration sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_LINEAR_ACCELERATION"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "LinearAcceleration", hideInUI = true)]
|
||||
public class AndroidLinearAccelerationSensor : LinearAccelerationSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotation vector sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_ROTATION_VECTOR"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "RotationVector", hideInUI = true)]
|
||||
public class AndroidRotationVector : AttitudeSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relative humidity sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_RELATIVE_HUMIDITY"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "RelativeHumidity", hideInUI = true)]
|
||||
public class AndroidRelativeHumidity : HumiditySensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ambient temperature sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_AMBIENT_TEMPERATURE"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "AmbientTemperature", hideInUI = true)]
|
||||
public class AndroidAmbientTemperature : AmbientTemperatureSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Game rotation vector sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_GAME_ROTATION_VECTOR"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "GameRotationVector", hideInUI = true)]
|
||||
public class AndroidGameRotationVector : AttitudeSensor
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step counter sensor device on Android.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_STEP_COUNTER"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = "StepCounter", hideInUI = true)]
|
||||
public class AndroidStepCounter : StepCounter
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hinge angle sensor device on Android.
|
||||
/// This sensor is usually available on foldable devices.
|
||||
/// </summary>
|
||||
/// <seealso href="https://developer.android.com/reference/android/hardware/Sensor#TYPE_HINGE_ANGLE"/>
|
||||
[InputControlLayout(stateType = typeof(AndroidSensorState), variants = nameof(AndroidSensorType.HingeAngle), hideInUI = true)]
|
||||
public class AndroidHingeAngle : HingeAngle
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 830105192d35a17469c56711468d1e8f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,174 @@
|
||||
#if UNITY_EDITOR || UNITY_ANDROID
|
||||
using System.Linq;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Android.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Android
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes custom android devices.
|
||||
/// You can use 'adb shell dumpsys input' from terminal to output information about all input devices.
|
||||
/// </summary>
|
||||
#if UNITY_DISABLE_DEFAULT_INPUT_PLUGIN_INITIALIZATION
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
class AndroidSupport
|
||||
{
|
||||
internal const string kAndroidInterface = "Android";
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
InputSystem.RegisterLayout<AndroidGamepad>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidGameController"));
|
||||
InputSystem.RegisterLayout<AndroidJoystick>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidGameController"));
|
||||
InputSystem.RegisterLayout<DualShock4GamepadAndroid>();
|
||||
InputSystem.RegisterLayout<XboxOneGamepadAndroid>();
|
||||
|
||||
////TODO: capability matching does not yet support bitmasking so these remain handled by OnFindLayoutForDevice for now
|
||||
InputSystem.RegisterLayout<AndroidGamepadWithDpadAxes>();
|
||||
InputSystem.RegisterLayout<AndroidGamepadWithDpadButtons>();
|
||||
|
||||
InputSystem.RegisterProcessor<AndroidCompensateDirectionProcessor>();
|
||||
InputSystem.RegisterProcessor<AndroidCompensateRotationProcessor>();
|
||||
|
||||
// Add sensors
|
||||
InputSystem.RegisterLayout<AndroidAccelerometer>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Accelerometer));
|
||||
InputSystem.RegisterLayout<AndroidMagneticFieldSensor>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.MagneticField));
|
||||
InputSystem.RegisterLayout<AndroidGyroscope>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Gyroscope));
|
||||
InputSystem.RegisterLayout<AndroidLightSensor>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Light));
|
||||
InputSystem.RegisterLayout<AndroidPressureSensor>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Pressure));
|
||||
InputSystem.RegisterLayout<AndroidProximity>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Proximity));
|
||||
InputSystem.RegisterLayout<AndroidGravitySensor>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.Gravity));
|
||||
InputSystem.RegisterLayout<AndroidLinearAccelerationSensor>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.LinearAcceleration));
|
||||
InputSystem.RegisterLayout<AndroidRotationVector>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.RotationVector));
|
||||
InputSystem.RegisterLayout<AndroidRelativeHumidity>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.RelativeHumidity));
|
||||
InputSystem.RegisterLayout<AndroidAmbientTemperature>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.AmbientTemperature));
|
||||
InputSystem.RegisterLayout<AndroidGameRotationVector>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.GameRotationVector));
|
||||
InputSystem.RegisterLayout<AndroidStepCounter>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.StepCounter));
|
||||
InputSystem.RegisterLayout<AndroidHingeAngle>(
|
||||
matches: new InputDeviceMatcher()
|
||||
.WithInterface(kAndroidInterface)
|
||||
.WithDeviceClass("AndroidSensor")
|
||||
.WithCapability("sensorType", AndroidSensorType.HingeAngle));
|
||||
|
||||
InputSystem.onFindLayoutForDevice += OnFindLayoutForDevice;
|
||||
}
|
||||
|
||||
internal static string OnFindLayoutForDevice(ref InputDeviceDescription description,
|
||||
string matchedLayout, InputDeviceExecuteCommandDelegate executeCommandDelegate)
|
||||
{
|
||||
// If we already have a matching layout, someone registered a better match.
|
||||
// We only want to act as a fallback.
|
||||
if (!string.IsNullOrEmpty(matchedLayout) && matchedLayout != "AndroidGamepad" && matchedLayout != "AndroidJoystick")
|
||||
return null;
|
||||
|
||||
if (description.interfaceName != "Android" || string.IsNullOrEmpty(description.capabilities))
|
||||
return null;
|
||||
|
||||
////TODO: these should just be Controller and Sensor; the interface is already Android
|
||||
switch (description.deviceClass)
|
||||
{
|
||||
case "AndroidGameController":
|
||||
{
|
||||
var caps = AndroidDeviceCapabilities.FromJson(description.capabilities);
|
||||
|
||||
// Note: Gamepads have both AndroidInputSource.Gamepad and AndroidInputSource.Joystick in input source, while
|
||||
// Joysticks don't have AndroidInputSource.Gamepad in their input source
|
||||
if ((caps.inputSources & AndroidInputSource.Gamepad) != AndroidInputSource.Gamepad)
|
||||
return "AndroidJoystick";
|
||||
|
||||
if (caps.motionAxes == null)
|
||||
return "AndroidGamepadWithDpadButtons";
|
||||
|
||||
// Vendor Ids, Product Ids can be found here http://www.linux-usb.org/usb.ids
|
||||
const int kVendorMicrosoft = 0x045e;
|
||||
const int kVendorSony = 0x054c;
|
||||
|
||||
// Tested with controllers: PS4 DualShock; XboxOne; Nvidia Shield
|
||||
// Tested on devices: Shield console Android 9; Galaxy s9+ Android 10
|
||||
if (caps.motionAxes.Contains(AndroidAxis.Z) &&
|
||||
caps.motionAxes.Contains(AndroidAxis.Rz) &&
|
||||
caps.motionAxes.Contains(AndroidAxis.HatX) &&
|
||||
caps.motionAxes.Contains(AndroidAxis.HatY))
|
||||
{
|
||||
if (caps.vendorId == kVendorMicrosoft)
|
||||
return "XboxOneGamepadAndroid";
|
||||
if (caps.vendorId == kVendorSony)
|
||||
return "DualShock4GamepadAndroid";
|
||||
}
|
||||
|
||||
|
||||
// Fallback to generic gamepads
|
||||
if (caps.motionAxes.Contains(AndroidAxis.HatX) &&
|
||||
caps.motionAxes.Contains(AndroidAxis.HatY))
|
||||
return "AndroidGamepadWithDpadAxes";
|
||||
|
||||
return "AndroidGamepadWithDpadButtons";
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR || UNITY_ANDROID
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c8442e8094ce974598eacc0302ddabb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user