Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SpaceMouse Wireless device #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
10 changes: 9 additions & 1 deletion Editor/ViewportController.cs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,17 @@ static void Fly(SceneView sceneView, Vector3 translationInversion, Vector3 rotat
{
SyncRigWithScene();

var rotation = SpaceNavigatorHID.current.Rotation.ReadValue();

// Check to see if we need to swap rotation Y and Z for fly mode
if(Settings.FlySwapRotationAxesYAndZ)
{
rotation = new Vector3(rotation.x, rotation.z, rotation.y);
}

// Apply inversion of axes for fly/grabmove mode.
Vector3 translation = Vector3.Scale(SpaceNavigatorHID.current.Translation.ReadValue(), translationInversion);
Vector3 rotation = Vector3.Scale(SpaceNavigatorHID.current.Rotation.ReadValue(), rotationInversion);
rotation = Vector3.Scale(rotation, rotationInversion);

// Apply sensitivity
translation *= Settings.TransSens[Settings.CurrentGear];
Expand Down
5 changes: 5 additions & 0 deletions Runtime/Settings/Settings.cs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public static class Settings {
public static bool RuntimeEditorNav = true;
public static bool RuntimeEditorNavSuspendOnGameViewFocus;

public static bool FlySwapRotationAxesYAndZ;

// Inversion
public static Vector3 FlyInvertTranslation, FlyInvertRotation;
public static Vector3 OrbitInvertTranslation, OrbitInvertRotation;
Expand Down Expand Up @@ -238,6 +240,7 @@ public static void OnGUI() {
RuntimeEditorNav = GUILayout.Toggle(RuntimeEditorNav, "Runtime Editor Navigation");
EditorGUI.BeginDisabledGroup(!RuntimeEditorNav);
RuntimeEditorNavSuspendOnGameViewFocus = GUILayout.Toggle(RuntimeEditorNavSuspendOnGameViewFocus, "Suspend on GameView focus");
FlySwapRotationAxesYAndZ = GUILayout.Toggle(FlySwapRotationAxesYAndZ, "Swap Y and Z rotation axes in Fly mode");
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();

Expand Down Expand Up @@ -425,6 +428,7 @@ public static void Write() {
// Runtime Editor Navigation
PlayerPrefs.SetInt("RuntimeEditorNav", RuntimeEditorNav ? 1 : 0);
PlayerPrefs.SetInt("RuntimeEditorNavWithFocussedGameView", RuntimeEditorNavSuspendOnGameViewFocus ? 1 : 0);
PlayerPrefs.SetInt("FlySwapRotationAxesYAndZ", FlySwapRotationAxesYAndZ ? 1 : 0);
// Axis Inversions
WriteAxisInversions(FlyInvertTranslation, FlyInvertRotation, "Fly");
WriteAxisInversions(OrbitInvertTranslation, OrbitInvertRotation, "Orbit");
Expand Down Expand Up @@ -469,6 +473,7 @@ public static void Read() {
// Runtime Editor Navigation
RuntimeEditorNav = PlayerPrefs.GetInt("RuntimeEditorNav", 1) == 1;
RuntimeEditorNavSuspendOnGameViewFocus = PlayerPrefs.GetInt("RuntimeEditorNavWithFocussedGameView", 1) == 1;
FlySwapRotationAxesYAndZ = PlayerPrefs.GetInt("FlySwapRotationAxesYAndZ", 1) == 1;
// Axis Inversions
ReadAxisInversions(ref FlyInvertTranslation, ref FlyInvertRotation, "Fly");
ReadAxisInversions(ref OrbitInvertTranslation, ref OrbitInvertRotation, "Orbit");
Expand Down
101 changes: 101 additions & 0 deletions Runtime/SpaceMouseWirelessHID.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using UnityEditor;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Utilities;

namespace SpaceNavigatorDriver
{
struct SpaceMouseWirelessHIDState : IInputStateTypeInfo
{
public FourCC format => new FourCC('H', 'I', 'D');

public struct ReportFormat1
{
public Vector3 translation;
public Vector3 rotation;
}

public struct ReportFormat3
{
public byte buttons;
}

// 1st report
[InputControl(name = "translation", format = "VC3S", layout = "Vector3", displayName = "Translation")]
[InputControl(name = "translation/x", offset = 0, format = "SHRT", parameters = "scale=true, scaleFactor=10")]
[InputControl(name = "translation/y", offset = 4, format = "SHRT", parameters = "scale=true, scaleFactor=-10")]
[InputControl(name = "translation/z", offset = 2, format = "SHRT", parameters = "scale=true, scaleFactor=-10")]
[InputControl(name = "rotation", format = "VC3S", layout = "Vector3", displayName = "Rotation")]
[InputControl(name = "rotation/x", offset = 6, format = "SHRT", parameters = "scale=true, scaleFactor=-80")]
[InputControl(name = "rotation/y", offset = 8, format = "SHRT", parameters = "scale=true, scaleFactor=80")]
[InputControl(name = "rotation/z", offset = 10, format = "SHRT", parameters = "scale=true, scaleFactor=80")]
public ReportFormat1 report1;

// 3rd report
[InputControl(name = "button1", bit = 0, format = "BIT", layout = "Button", displayName = "Button 1")]
[InputControl(name = "button2", bit = 1, format = "BIT", layout = "Button", displayName = "Button 2")]
public ReportFormat3 report3;
}

#if UNITY_EDITOR
[InitializeOnLoad] // Make sure static constructor is called during startup.
#endif
[InputControlLayout(stateType = typeof(SpaceMouseWirelessHIDState))]
public class SpaceMouseWirelessHID : SpaceNavigatorHID
{
static SpaceMouseWirelessHID()
{
// Register a layout with product ID, so this layout will have a higher score than SpaceNavigatorHID
InputSystem.RegisterLayout<SpaceMouseWirelessHID>(
matches: new InputDeviceMatcher()
.WithInterface("HID")
.WithManufacturer("3Dconnexion.*")
.WithCapability("productId", 0xC62E));
DebugLog("SpaceMouseWirelessHID : Register layout for SpaceMouse Wireless productId:0xC62E");
}

// When one of our custom devices is removed, we want to make sure that if
// it is the '.current' device, we null out '.current'.
public override unsafe void OnStateEvent(InputEventPtr eventPtr)
{
// Refuse delta events.
if (eventPtr.IsA<DeltaStateEvent>())
return;

var stateEventPtr = StateEvent.From(eventPtr);
if (stateEventPtr->stateFormat != new FourCC('H', 'I', 'D'))
return;

var reportPtr = (byte*) stateEventPtr->state;
var reportId = *reportPtr;
var reportStatePtr = (reportPtr + 1); // or wherever the actual report starts.

// We have two options here. We can either use InputState.Change with a DeltaStateEvent that we set up
// from the event we have received (and simply update either report1 or report2 only) or we can merge
// our current state with the state we have just received. The latter is simpler so we do that here.

var newState = default(SpaceMouseWirelessHIDState);
// Can opt to only copy the state that we won't override. We don't bother here.
UnsafeUtility.MemCpy(&newState, (byte*) currentStatePtr + stateBlock.byteOffset, sizeof(SpaceMouseWirelessHIDState));

switch (reportId)
{
case 1:
UnsafeUtility.MemCpy(&newState.report1, reportStatePtr, sizeof(SpaceMouseWirelessHIDState.ReportFormat1));
DebugLog("SpaceMouseWirelessHID : Copied report1");
break;
case 3:
UnsafeUtility.MemCpy(&newState.report3, reportStatePtr, sizeof(SpaceMouseWirelessHIDState.ReportFormat3));
DebugLog("SpaceMouseWirelessHID : Copied report3");
break;
}

// Apply the state change. Don't simply MemCpy over currentStatePtr as that will lead to various
// malfunctions. The system needs to do the memcpy itself.
InputState.Change(this, newState, eventPtr: eventPtr);
}
}
}
11 changes: 11 additions & 0 deletions Runtime/SpaceMouseWirelessHID.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.