Merge pull request #1787 from OpenSpace/feature/multiple-joysticks

Feature/multiple joysticks
This commit is contained in:
Malin E
2021-12-22 13:22:01 +01:00
committed by GitHub
33 changed files with 1022 additions and 488 deletions

View File

@@ -369,27 +369,34 @@ void mainPreSyncFunc() {
std::fill(state.axes.begin(), state.axes.end(), 0.f);
std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle);
// Check axes and buttons
glfwGetJoystickAxes(i, &state.nAxes);
if (state.nAxes > JoystickInputState::MaxAxes) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} axes, but only {} axes are supported. "
"All excess axes are ignored",
state.name, state.nAxes, JoystickInputState::MaxAxes
));
}
glfwGetJoystickButtons(i, &state.nButtons);
if (state.nButtons > JoystickInputState::MaxButtons) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} buttons, but only {} buttons are "
"supported. All excess buttons are ignored",
state.name, state.nButtons, JoystickInputState::MaxButtons
));
}
}
const float* axes = glfwGetJoystickAxes(i, &state.nAxes);
if (state.nAxes > JoystickInputState::MaxAxes) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} axes, but only {} axes are supported. "
"All excess axes are ignored",
state.name, state.nAxes, JoystickInputState::MaxAxes
));
state.nAxes = JoystickInputState::MaxAxes;
}
std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float));
const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons);
if (state.nButtons > JoystickInputState::MaxButtons) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} buttons, but only {} buttons are "
"supported. All excess buttons are ignored",
state.name, state.nButtons, JoystickInputState::MaxButtons
));
state.nButtons = JoystickInputState::MaxButtons;
}

View File

@@ -0,0 +1,90 @@
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
-- "Zoom" -- both in and out
-- "Zoom In"
-- "Zoom Out"
-- "LocalRoll X"
-- "LocalRoll Y"
-- "GlobalRoll X"
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- Seventh parameter is the sensitivity for the axis
-- Parameters for bindJoystickAxisProperty:
-- First - Name of the joystick that should be bound
-- Second - Which axis should be bound of this joystick
-- Third - The property uri
-- Fourth - (optional) The smallest value that you wnat to allow this property on the joystick
-- Fifth - (optional) The largest value that you wnat to allow this property on the joystick
-- Sixth - (optional) Determines whether the axis should be inverted
-- Seventh - (optional) Should this property change be sent to other connected remote sessions
local XBoxController = {
LeftThumbStick = { 0 , 1 },
RightThumbStick = { 2, 3 },
LeftTrigger = 4,
RightTrigger = 5,
A = 0,
B = 1,
X = 2,
Y = 3,
LB = 4,
RB = 5,
Select = 6,
Start = 7,
LeftStickButton = 8,
RightStickButton = 9,
DPad = {
Up = 10,
Right = 11,
Down = 12,
Left = 13
}
}
local freezeValue = function(name, axis, min, max)
return [[
local joystickType = openspace.navigation.joystickAxis(']] .. name .. "', " .. axis .. [[);
local isPropertyBound = true;
if joystickType == "None" then
isPropertyBound = false;
else
isPropertyBound = true;
end
if isPropertyBound then
openspace.navigation.bindJoystickAxis(']] .. name .. "', " .. axis .. [[, "None");
isPropertyBound = false;
else
openspace.navigation.bindJoystickAxisProperty(']] .. name .. "', " .. axis .. [[, 'Scene.Earth.Scale.Scale', ]] .. min ..", " .. max.. [[);
isPropertyBound = true;
end
]]
end
asset.onInitialize(function()
local controller = XBoxController;
local name = "Xbox Controller";
-- Bind Right trigger to Earth Scale
openspace.navigation.bindJoystickAxisProperty(name, controller.RightTrigger, "Scene.Earth.Scale.Scale", 0.1, 100);
-- Bind 'A' button to freeze current value
openspace.navigation.bindJoystickButton(
name,
controller.A,
freezeValue(name, controller.RightTrigger, 0.1, 100),
"Freeze current scale for Earth. Or release it to the trigger again."
)
end)

View File

@@ -4,58 +4,62 @@ Joystick.State = {}
Joystick.State.IsInRollMode = false
Joystick.State.Axis = {}
local bindLocalRoll = function(axis)
local bindLocalRoll = function(name, axis)
return [[
-- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup
if not Joystick.State.IsInRollMode then
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity = openspace.navigation.joystickAxis(]] .. axis .. [[)
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity, Joystick.State.Axis.PropertyUri, Joystick.State.Axis.MinValue, Joystick.State.Axis.MaxValue, Joystick.State.Axis.IsRemote = openspace.navigation.joystickAxis("]] .. name .. "\", " .. axis .. [[);
end
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "LocalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
openspace.navigation.bindJoystickAxis("]] .. name .. "\", " .. axis .. [[, "LocalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
Joystick.State.IsInRollMode = true
]]
end
local bindGlobalRoll = function(axis)
local bindGlobalRoll = function(name, axis)
return [[
-- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup
if not Joystick.State.IsInRollMode then
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity = openspace.navigation.joystickAxis(]] .. axis .. [[)
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity, Joystick.State.Axis.PropertyUri, Joystick.State.Axis.MinValue, Joystick.State.Axis.MaxValue, Joystick.State.Axis.IsRemote = openspace.navigation.joystickAxis("]] .. name .. "\", " .. axis .. [[);
end
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "GlobalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
openspace.navigation.bindJoystickAxis("]] .. name .. "\", " .. axis .. [[, "GlobalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
Joystick.State.IsInRollMode = true
]]
end
local permaBindLocalRoll = function(axis)
local permaBindLocalRoll = function(name, axis)
return [[
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity = openspace.navigation.joystickAxis(]] .. axis .. [[)
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity, Joystick.State.Axis.PropertyUri, Joystick.State.Axis.MinValue, Joystick.State.Axis.MaxValue, Joystick.State.Axis.IsRemote = openspace.navigation.joystickAxis("]] .. name .. "\", " .. axis .. [[);
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "LocalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
openspace.navigation.bindJoystickAxis("]] .. name .. "\", " .. axis .. [[, "LocalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
]]
end
local permaBindGlobalRoll = function(axis)
local permaBindGlobalRoll = function(name, axis)
return [[
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity = openspace.navigation.joystickAxis(]] .. axis .. [[)
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity, Joystick.State.Axis.PropertyUri, Joystick.State.Axis.MinValue, Joystick.State.Axis.MaxValue, Joystick.State.Axis.IsRemote = openspace.navigation.joystickAxis("]] .. name .. "\", " .. axis .. [[);
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "GlobalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
openspace.navigation.bindJoystickAxis("]] .. name .. "\", " .. axis .. [[, "GlobalRoll X", Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
]]
end
local unbindRoll = function(axis)
local unbindRoll = function(name, axis)
return [[
-- Reset previous state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
if(Joystick.State.Axis.Type == "Property") then
openspace.navigation.bindJoystickAxisProperty("]] .. name .. "\", " .. axis .. [[, Joystick.State.Axis.PropertyUri, Joystick.State.Axis.MinValue, Joystick.State.Axis.MaxValue, Joystick.State.Axis.Inverted, Joystick.State.Axis.IsRemote);
else
openspace.navigation.bindJoystickAxis("]] .. name .. "\", " .. axis .. [[, Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.JoystickType, Joystick.State.Axis.Sticky, Joystick.State.Axis.Sensitivity);
end
]]
end

View File

@@ -1,7 +1,7 @@
local propertyHelper = asset.require('../property_helper')
local joystickHelper = asset.require('./joystick_helper')
-- Allowed values for the second parameter of bindJoystickAxis:
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
@@ -14,13 +14,14 @@ local joystickHelper = asset.require('./joystick_helper')
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Third parameter determines whether the axis should be inverted
-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1]
-- Fifth parameters determins if the axis should be "Sticky" or not.
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- Sixth parameter is the sensitivity for the axis
-- Seventh parameter is the sensitivity for the axis
local PS4Controller = {
LeftThumbStick = { 0 , 1 },
@@ -49,59 +50,70 @@ local PS4Controller = {
asset.onInitialize(function()
local controller = PS4Controller;
local name = "Wireless Controller";
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.L2, 0.05)
openspace.navigation.setAxisDeadZone(name, controller.R2, 0.05)
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[2], "Pan Y", true);
openspace.navigation.bindJoystickAxis(controller.L2, "Zoom Out", false, true);
openspace.navigation.bindJoystickAxis(controller.R2, "Zoom In", false, true);
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[2], "Pan Y", true);
openspace.navigation.bindJoystickAxis(name, controller.L2, "Zoom Out", false, "TriggerLike");
openspace.navigation.bindJoystickAxis(name, controller.R2, "Zoom In", false, "TriggerLike");
openspace.navigation.bindJoystickButton(
name,
controller.L1,
joystickHelper.bindLocalRoll(controller.RightThumbStick[1]),
joystickHelper.bindLocalRoll(name, controller.RightThumbStick[1]),
"Switch to local roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.L1,
joystickHelper.unbindRoll(controller.RightThumbStick[1]),
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.R1,
joystickHelper.bindGlobalRoll(controller.RightThumbStick[1]),
joystickHelper.bindGlobalRoll(name, controller.RightThumbStick[1]),
"Switch to global roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.R1,
joystickHelper.unbindRoll(controller.RightThumbStick[1]),
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.Cross,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'),
"Toggle zoom friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.Circle,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'),
"Toggle rotational friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.DPad.Left,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction'),
"Toggle roll friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.Square,
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');" ..
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth');" ..
@@ -109,6 +121,7 @@ asset.onInitialize(function()
"Switch target to Earth"
)
openspace.navigation.bindJoystickButton(
name,
controller.Triangle,
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');" ..
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Mars');" ..

View File

@@ -1,7 +1,7 @@
local propertyHelper = asset.require('../property_helper')
local joystickHelper = asset.require('./joystick_helper')
-- Allowed values for the second parameter of bindJoystickAxis:
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
@@ -14,14 +14,15 @@ local joystickHelper = asset.require('./joystick_helper')
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Third parameter determines whether the axis should be inverted
-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1]
-- Fifth parameters determins if the axis should be "Sticky" or not.
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- This version of the SpaceMouse is NOT Sticky.
-- Sixth parameter is the sensitivity for the axis
-- Seventh parameter is the sensitivity for the axis
local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
@@ -33,23 +34,26 @@ local SpaceMouse = {
asset.onInitialize(function()
local controller = SpaceMouse;
local name = "SpaceNavigator";
openspace.navigation.bindJoystickAxis(controller.Push[1], "Orbit X", false);
openspace.navigation.bindJoystickAxis(controller.Push[2], "Orbit Y", false);
openspace.navigation.bindJoystickAxis(controller.Twist[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(controller.Tilt[2], "Pan Y", false);
openspace.navigation.bindJoystickAxis(controller.Push[3], "Zoom", false);
openspace.navigation.bindJoystickAxis(controller.Tilt[1], "LocalRoll X", false);
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y");
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y");
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom");
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X");
openspace.navigation.bindJoystickButton(
name,
controller.LeftButton,
joystickHelper.permaBindLocalRoll(controller.Tilt[1]),
joystickHelper.permaBindLocalRoll(name, controller.Tilt[1]),
"Switch to local roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.RightButton,
joystickHelper.permaBindGlobalRoll(controller.Tilt[1]),
joystickHelper.permaBindGlobalRoll(name, controller.Tilt[1]),
"Switch to global roll mode"
)
end)

View File

@@ -1,7 +1,7 @@
local propertyHelper = asset.require('../property_helper')
local joystickHelper = asset.require('./joystick_helper')
-- Allowed values for the second parameter of bindJoystickAxis:
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
@@ -14,14 +14,15 @@ local joystickHelper = asset.require('./joystick_helper')
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Third parameter determines whether the axis should be inverted
-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1]
-- Fifth parameters determins if the axis should be "Sticky" or not.
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- This version of the SpaceMouse IS Sticky.
-- Sixth parameter is the sensitivity for the axis
-- Seventh parameter is the sensitivity for the axis
local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
@@ -33,23 +34,26 @@ local SpaceMouse = {
asset.onInitialize(function()
local controller = SpaceMouse;
local name = "SpaceNavigator";
openspace.navigation.bindJoystickAxis(controller.Push[1], "Orbit X", false, false, true, 40.0);
openspace.navigation.bindJoystickAxis(controller.Push[2], "Orbit Y", false, false, true, 40.0);
openspace.navigation.bindJoystickAxis(controller.Twist[1], "Pan X", true, false, true, 40.0);
openspace.navigation.bindJoystickAxis(controller.Tilt[2], "Pan Y", false, false, true, 35.0);
openspace.navigation.bindJoystickAxis(controller.Push[3], "Zoom", false, false, true, 40.0);
openspace.navigation.bindJoystickAxis(controller.Tilt[1], "LocalRoll X", false, false, true, 35.0);
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y", false, "JoystickLike", true, 35.0);
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X", false, "JoystickLike", true, 35.0);
openspace.navigation.bindJoystickButton(
name,
controller.LeftButton,
joystickHelper.permaBindLocalRoll(controller.Tilt[1]),
joystickHelper.permaBindLocalRoll(name, controller.Tilt[1]),
"Switch to local roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.RightButton,
joystickHelper.permaBindGlobalRoll(controller.Tilt[1]),
joystickHelper.permaBindGlobalRoll(name, controller.Tilt[1]),
"Switch to global roll mode"
)
end)

View File

@@ -1,7 +1,7 @@
local propertyHelper = asset.require('../property_helper')
local joystickHelper = asset.require('./joystick_helper')
-- Allowed values for the second parameter of bindJoystickAxis:
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
@@ -14,13 +14,14 @@ local joystickHelper = asset.require('./joystick_helper')
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Third parameter determines whether the axis should be inverted
-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1]
-- Fifth parameters determins if the axis should be "Sticky" or not.
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- Sixth parameter is the sensitivity for the axis
-- Seventh parameter is the sensitivity for the axis
local XBoxController = {
LeftThumbStick = { 0 , 1 },
@@ -47,59 +48,70 @@ local XBoxController = {
asset.onInitialize(function()
local controller = XBoxController;
local name = "Xbox Controller";
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftTrigger, 0.05)
openspace.navigation.setAxisDeadZone(name, controller.RightTrigger, 0.05)
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[2], "Pan Y", true);
openspace.navigation.bindJoystickAxis(controller.LeftTrigger, "Zoom Out", false, true);
openspace.navigation.bindJoystickAxis(controller.RightTrigger, "Zoom In", false, true);
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[2], "Pan Y", true);
openspace.navigation.bindJoystickAxis(name, controller.LeftTrigger, "Zoom Out", false, "TriggerLike");
openspace.navigation.bindJoystickAxis(name, controller.RightTrigger, "Zoom In", false, "TriggerLike");
openspace.navigation.bindJoystickButton(
name,
controller.LB,
joystickHelper.bindLocalRoll(controller.RightThumbStick[1]),
joystickHelper.bindLocalRoll(name, controller.RightThumbStick[1]),
"Switch to local roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.LB,
joystickHelper.unbindRoll(controller.RightThumbStick[1]),
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.RB,
joystickHelper.bindGlobalRoll(controller.RightThumbStick[1]),
joystickHelper.bindGlobalRoll(name, controller.RightThumbStick[1]),
"Switch to global roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.RB,
joystickHelper.unbindRoll(controller.RightThumbStick[1]),
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.A,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'),
"Toggle zoom friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.B,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'),
"Toggle rotational friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.DPad.Left,
propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction'),
"Toggle roll friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.X,
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');" ..
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth');" ..
@@ -107,6 +119,7 @@ asset.onInitialize(function()
"Switch target to Earth"
)
openspace.navigation.bindJoystickButton(
name,
controller.Y,
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');" ..
"openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Mars');" ..

View File

@@ -30,8 +30,6 @@
namespace openspace::interaction {
class InputState;
class CameraInteractionStates {
public:
/**
@@ -42,8 +40,6 @@ public:
CameraInteractionStates(double sensitivity, double velocityScaleFactor);
virtual ~CameraInteractionStates() = default;
virtual void updateStateFromInput(const InputState& inputState, double deltaTime) = 0;
void setRotationalFriction(double friction);
void setHorizontalFriction(double friction);
void setVerticalFriction(double friction);

View File

@@ -49,17 +49,22 @@ public:
GlobalRollX,
GlobalRollY,
PanX,
PanY
PanY,
Property
};
enum class JoystickType {
JoystickLike,
TriggerLike
};
BooleanType(AxisInvert);
BooleanType(AxisNormalize);
BooleanType(ButtonCommandRemote);
struct AxisInformation {
AxisType type = AxisType::None;
AxisInvert invert = AxisInvert::No;
AxisNormalize normalize = AxisNormalize::No;
JoystickType joystickType = JoystickType::JoystickLike;
// The axis values can either go back to 0 when the joystick is released or it can
// stay at the value it was before the joystick was released.
@@ -70,49 +75,83 @@ public:
// Every axis can have their own sensitivity
double sensitivity = 0.0;
// The property info if the type is Property
std::string propertyUri;
float minValue = 0.f;
float maxValue = 1.f;
bool isRemote = true;
};
JoystickCameraStates(double sensitivity, double velocityScaleFactor);
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
void updateStateFromInput(
const JoystickInputStates& joystickInputStates, double deltaTime);
void setAxisMapping(int axis, AxisType mapping,
void setAxisMapping(std::string joystickName, int axis, AxisType mapping,
AxisInvert shouldInvert = AxisInvert::No,
AxisNormalize shouldNormalize = AxisNormalize::No,
JoystickType joystickType = JoystickType::JoystickLike,
bool isSticky = false, double sensitivity = 0.0
);
AxisInformation axisMapping(int axis) const;
void setAxisMappingProperty(std::string joystickName, int axis,
std::string propertyUri, float min = 0.f, float max = 1.f,
AxisInvert shouldInvert = AxisInvert::No, bool isRemote = true
);
void setDeadzone(int axis, float deadzone);
float deadzone(int axis) const;
AxisInformation axisMapping(const std::string& joystickName, int axis) const;
void setDeadzone(const std::string& joystickName, int axis, float deadzone);
float deadzone(const std::string& joystickName, int axis) const;
void bindButtonCommand(int button, std::string command, JoystickAction action,
ButtonCommandRemote remote, std::string documentation);
void clearButtonCommand(int button);
std::vector<std::string> buttonCommand(int button) const;
void bindButtonCommand(const std::string& joystickName, int button,
std::string command, JoystickAction action, ButtonCommandRemote remote,
std::string documentation);
void clearButtonCommand(const std::string& joystickName, int button);
std::vector<std::string> buttonCommand(const std::string& joystickName,
int button) const;
private:
// We use an array for the axes and a map for the buttons since the axis are going to
// be accessed much more often and thus have to be more efficient. And storing a few
// extra AxisInformation that are not used will not matter that much; finding an axis
// location in a potential map each frame, however, would
struct JoystickCameraState {
std::string joystickName;
std::array<AxisInformation, JoystickInputState::MaxAxes> _axisMapping;
// We use an array for the axes and a map for the buttons since the axis are going to
// be accessed much more often and thus have to be more efficient. And storing a few
// extra AxisInformation that are not used will not matter that much; finding an axis
// location in a potential map each frame, however, would
std::array<AxisInformation, JoystickInputState::MaxAxes> axisMapping;
// This array is used to store the old axis values from the previous frame,
// it is used to calculate the difference in the values in the case of a sticky axis
std::array<float, JoystickInputState::MaxAxes> _prevAxisValues;
// This array is used to store the old axis values from the previous frame,
// it is used to calculate the difference in the values in the case of a sticky axis
std::array<float, JoystickInputState::MaxAxes> prevAxisValues;
struct ButtonInformation {
std::string command;
JoystickAction action;
ButtonCommandRemote synchronization;
std::string documentation;
struct ButtonInformation {
// The script that is run when the button is activated
std::string command;
// When is the button considered activated
JoystickAction action;
// If the script should be syncronised to other remote sessions or not
ButtonCommandRemote synchronization;
// Short documentation on what the script of this button does
std::string documentation;
};
std::multimap<int, ButtonInformation> buttonMapping;
};
std::multimap<int, ButtonInformation> _buttonMapping;
std::vector<JoystickCameraState> _joystickCameraStates;
// Find the item in _joystickCameraStates that corresponds to the given joystickName
// return a pointer to the item, if not found then return nullptr
JoystickCameraState* joystickCameraState(const std::string& joystickName);
const JoystickCameraState* joystickCameraState(const std::string& joystickName) const;
// Ues getJoystickCameraState(name) to find the joystickCameraState that
// corresponds to the given joystickName. If not found then add a new item if possible
JoystickCameraState* findOrAddJoystickCameraState(const std::string& joystickName);
};
} // namespace openspace::interaction
@@ -137,6 +176,7 @@ inline std::string to_string(
case T::GlobalRollY: return "GlobalRoll Y";
case T::PanX: return "Pan X";
case T::PanY: return "Pan Y";
case T::Property: return "Property";
default: return "";
}
}
@@ -159,10 +199,35 @@ from_string(std::string_view string)
if (string == "GlobalRoll Y") { return T::GlobalRollY; }
if (string == "Pan X") { return T::PanX; }
if (string == "Pan Y") { return T::PanY; }
if (string == "Property") { return T::Property; }
throw RuntimeError("Unkonwn axis type '" + std::string(string) + "'");
}
template <>
inline std::string to_string(
const openspace::interaction::JoystickCameraStates::JoystickType& value)
{
using T = openspace::interaction::JoystickCameraStates::JoystickType;
switch (value) {
case T::JoystickLike: return "JoystickLike";
case T::TriggerLike: return "TriggerLike";
default: return "";
}
}
template <>
constexpr openspace::interaction::JoystickCameraStates::JoystickType
from_string(std::string_view string)
{
using T = openspace::interaction::JoystickCameraStates::JoystickType;
if (string == "JoystickLike") { return T::JoystickLike; }
if (string == "TriggerLike") { return T::TriggerLike; }
throw RuntimeError("Unkonwn joystick type '" + std::string(string) + "'");
}
} // namespace ghoul
#endif // __OPENSPACE_CORE___JOYSTICKCAMERASTATES___H__

View File

@@ -54,10 +54,11 @@ enum class JoystickAction : uint8_t {
* The input state of a single joystick.
*/
struct JoystickInputState {
/// These two are just randomly selected numbers that can be increased if needed
/// The maximum number of supported axes
static constexpr const int MaxAxes = 8;
/// The maximum number of supported buttons
static constexpr const int MaxButtons = 32;
static constexpr const int MaxButtons = 48;
/// Marks whether this joystick is connected. If this value is \c false, all other
/// members of this struct are undefined
@@ -72,11 +73,6 @@ struct JoystickInputState {
/// \c nAxes values are defined values, the rest are undefined
std::array<float, MaxAxes> axes;
/// The axis values can either go back to 0 when the joystick is released or it can
/// stay at the value it was before the joystick was released.
/// The latter is called a sticky axis, when the values don't go back to 0.
bool isSticky = false;
/// The number of buttons that this joystick possesses
int nButtons = 0;
/// The status of each button. Only the first \c nButtons values are defined, the rest
@@ -88,6 +84,10 @@ struct JoystickInputState {
/// derived from the available GLFW constants
constexpr const int MaxJoysticks = 16;
struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks> {
/// The maximum number of joysticks that are supported by this system. This number is
/// derived from the available GLFW constants
static constexpr const int MaxNumJoysticks = 16;
/**
* This function adds the contributions of all connected joysticks for the provided
* \p axis. After adding each joysticks contribution, the result is clamped to [-1,1].
@@ -99,7 +99,7 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
*
* \pre \p axis must be 0 or positive
*/
float axis(int axis) const;
float axis(const std::string& joystickName, int axis) const;
/**
* This functions checks whether any connected joystick has its \p button in the
@@ -113,7 +113,7 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
*
* \pre \p button must be 0 or positive
*/
bool button(int button, JoystickAction action) const;
bool button(const std::string& joystickName, int button, JoystickAction action) const;
};
} // namespace openspace::interaction

View File

@@ -0,0 +1,51 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___KEYBOARDINPUTSTATE___H__
#define __OPENSPACE_CORE___KEYBOARDINPUTSTATE___H__
#include <openspace/util/keys.h>
#include <vector>
namespace openspace::interaction {
// This class represents the global input state of interaction devices
class KeyboardInputState {
public:
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
// Accessors
const std::vector<std::pair<Key, KeyModifier>>& pressedKeys() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
bool isKeyPressed(Key key) const;
private:
// Input from keyboard
std::vector<std::pair<Key, KeyModifier>> _keysDown;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___KEYBOARDINPUTSTATE___H__

View File

@@ -29,11 +29,15 @@
namespace openspace::interaction {
class MouseInputState;
class KeyboardInputState;
class MouseCameraStates : public CameraInteractionStates {
public:
MouseCameraStates(double sensitivity, double velocityScaleFactor);
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
void updateStateFromInput(const MouseInputState& mouseinputState,
const KeyboardInputState& keyboardinputState, double deltaTime);
void setInvertMouseButton(bool value);

View File

@@ -22,52 +22,30 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___INPUTSTATE___H__
#define __OPENSPACE_CORE___INPUTSTATE___H__
#ifndef __OPENSPACE_CORE___MOUSEINPUTSTATE___H__
#define __OPENSPACE_CORE___MOUSEINPUTSTATE___H__
#include <openspace/interaction/websocketinputstate.h>
#include <openspace/util/keys.h>
#include <openspace/util/mouse.h>
#include <ghoul/glm.h>
#include <vector>
namespace openspace::interaction {
struct JoystickInputStates;
struct WebsocketInputStates;
// This class represents the global input state of interaction devices
class InputState {
class MouseInputState {
public:
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double mouseX, double mouseY);
void mouseScrollWheelCallback(double mouseScrollDelta);
// Accessors
const std::vector<std::pair<Key, KeyModifier>>& pressedKeys() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
bool isKeyPressed(Key key) const;
const std::vector<MouseButton>& pressedMouseButtons() const;
glm::dvec2 mousePosition() const;
double mouseScrollDelta() const;
bool isMouseButtonPressed(MouseButton mouseButton) const;
float joystickAxis(int i) const;
bool joystickButton(int i) const;
WebsocketInputStates& websocketInputStates();
float websocketAxis(int i) const;
bool websocketButton(int i) const;
bool hasWebsocketStates() const;
void resetWebsockets();
private:
// Input from keyboard
std::vector<std::pair<Key, KeyModifier>> _keysDown;
// Input from mouse
std::vector<MouseButton> _mouseButtonsDown;
glm::dvec2 _mousePosition = glm::dvec2(0.0);
@@ -76,4 +54,4 @@ private:
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___INPUTSTATE___H__
#endif // __OPENSPACE_CORE___MOUSEINPUTSTATE___H__

View File

@@ -33,7 +33,7 @@ class ScriptCameraStates : public CameraInteractionStates {
public:
ScriptCameraStates();
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
void updateStateFromInput(double deltaTime);
void addLocalRotation(const glm::dvec2& delta);
void addGlobalRotation(const glm::dvec2& delta);

View File

@@ -65,7 +65,8 @@ public:
WebsocketCameraStates(double sensitivity, double velocityScaleFactor);
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
void updateStateFromInput(
const WebsocketInputStates& websocketInputStates, double deltaTime);
void setAxisMapping(int axis, AxisType mapping,
AxisInvert shouldInvert = AxisInvert::No,

View File

@@ -26,8 +26,9 @@
#define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
#include <openspace/documentation/documentation.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/interaction/keyboardinputstate.h>
#include <openspace/interaction/mouseinputstate.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/navigation/navigationstate.h>
@@ -81,7 +82,8 @@ public:
// Accessors
Camera* camera() const;
const SceneGraphNode* anchorNode() const;
const InputState& inputState() const;
const MouseInputState& mouseInputState() const;
const KeyboardInputState& keyboardInputState() const;
const OrbitalNavigator& orbitalNavigator() const;
OrbitalNavigator& orbitalNavigator();
KeyframeNavigator& keyframeNavigator();
@@ -96,24 +98,36 @@ public:
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
void setJoystickAxisMapping(int axis, JoystickCameraStates::AxisType mapping,
void setJoystickAxisMapping(std::string joystickName,
int axis, JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert =
JoystickCameraStates::AxisInvert::No,
JoystickCameraStates::AxisNormalize shouldNormalize =
JoystickCameraStates::AxisNormalize::No,
JoystickCameraStates::JoystickType joystickType =
JoystickCameraStates::JoystickType::JoystickLike,
bool isSticky = false, double sensitivity = 0.0
);
JoystickCameraStates::AxisInformation joystickAxisMapping(int axis) const;
void setJoystickAxisMappingProperty(std::string joystickName,
int axis, std::string propertyUri,
float min = 0.f, float max = 1.f,
JoystickCameraStates::AxisInvert shouldInvert =
JoystickCameraStates::AxisInvert::No, bool isRemote = true
);
void setJoystickAxisDeadzone(int axis, float deadzone);
float joystickAxisDeadzone(int axis) const;
JoystickCameraStates::AxisInformation joystickAxisMapping(
const std::string& joystickName, int axis) const;
void bindJoystickButtonCommand(int button, std::string command, JoystickAction action,
void setJoystickAxisDeadzone(const std::string& joystickName, int axis,
float deadzone);
float joystickAxisDeadzone(const std::string& joystickName, int axis) const;
void bindJoystickButtonCommand(const std::string& joystickName, int button,
std::string command, JoystickAction action,
JoystickCameraStates::ButtonCommandRemote remote, std::string documentation);
void clearJoystickButtonCommand(int button);
std::vector<std::string> joystickButtonCommand(int button) const;
void clearJoystickButtonCommand(const std::string& joystickName, int button);
std::vector<std::string> joystickButtonCommand(const std::string& joystickName,
int button) const;
// Websockets
void setWebsocketAxisMapping(int axis, WebsocketCameraStates::AxisType mapping,
@@ -144,7 +158,8 @@ private:
bool _playbackModeEnabled = false;
InputState _inputState;
MouseInputState _mouseInputState;
KeyboardInputState _keyboardInputState;
Camera* _camera = nullptr;
std::function<void()> _playbackEndCallback;

View File

@@ -41,7 +41,6 @@
#include <openspace/properties/triggerproperty.h>
#include <ghoul/glm.h>
#include <glm/gtx/quaternion.hpp>
#include <optional>
namespace openspace {
@@ -53,13 +52,15 @@ namespace openspace {
namespace openspace::interaction {
class InputState;
class MouseInputState;
class KeyboardInputState;
class OrbitalNavigator : public properties::PropertyOwner {
public:
OrbitalNavigator();
void updateStatesFromInput(const InputState& inputState, double deltaTime);
void updateStatesFromInput(const MouseInputState& mouseInputState,
const KeyboardInputState& keyboardInputState, double deltaTime);
void updateCameraStateFromStates(double deltaTime);
void updateCameraScalingFromAnchor(double deltaTime);
void resetVelocities();

View File

@@ -26,7 +26,6 @@
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickinputstate.h>
namespace {
@@ -86,7 +85,7 @@ void GuiJoystickComponent::render() {
ImGui::Text("%s", "Summed contributions");
ImGui::Text("%s", "Axes");
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
float f = global::joystickInputStates->axis(i);
float f = global::joystickInputStates->axis("", i);
ImGui::SliderFloat(
std::to_string(i).c_str(),
&f,
@@ -98,8 +97,8 @@ void GuiJoystickComponent::render() {
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
ImGui::RadioButton(
std::to_string(i).c_str(),
global::joystickInputStates->button(i, JoystickAction::Press) ||
global::joystickInputStates->button(i, JoystickAction::Repeat)
global::joystickInputStates->button("", i, JoystickAction::Press) ||
global::joystickInputStates->button("", i, JoystickAction::Repeat)
);
}

View File

@@ -30,7 +30,6 @@
#include <openspace/interaction/websocketinputstate.h>
namespace openspace::interaction {
struct WebsocketInputStates;
struct WebsocketInputState;
}

View File

@@ -27,7 +27,6 @@
#include <modules/server/include/connection.h>
#include <modules/server/include/jsonconverters.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/interaction/websocketinputstate.h>
#include <openspace/navigation/navigationhandler.h>

View File

@@ -28,8 +28,8 @@
#include <openspace/engine/globalscallbacks.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/interactionmonitor.h>
#include <openspace/interaction/keyboardinputstate.h>
#include <openspace/navigation/navigationhandler.h>
#include <ghoul/logging/logmanager.h>
#include <fmt/format.h>
@@ -462,7 +462,7 @@ CefTouchEvent EventHandler::touchEvent(const TouchInput& input,
event.y = windowPos.y;
event.type = eventType;
const std::vector<std::pair<Key, KeyModifier>>& keyMods =
global::navigationHandler->inputState().pressedKeys();
global::navigationHandler->keyboardInputState().pressedKeys();
for (const std::pair<Key, KeyModifier>& p : keyMods) {
const KeyModifier mods = p.second;
event.modifiers |= static_cast<uint32_t>(mapToCefModifiers(mods));

View File

@@ -50,11 +50,12 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/interactionmonitor.cpp
${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/mouseinputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/joystickinputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/joystickcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/keyboardinputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/scriptcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
@@ -232,13 +233,14 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/camerainteractionstates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/inputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mouseinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionmonitor.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyboardinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/externinteraction.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h

View File

@@ -24,8 +24,6 @@
#include <openspace/interaction/camerainteractionstates.h>
#include <openspace/interaction/inputstate.h>
namespace openspace::interaction {
CameraInteractionStates::InteractionState::InteractionState(double scaleFactor)

View File

@@ -25,19 +25,24 @@
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/exception.h>
#include <cmath>
#include <utility>
namespace {
constexpr const char* _loggerCat = "JoystickCameraStates";
} // namespace
namespace openspace::interaction {
JoystickCameraStates::JoystickCameraStates(double sensitivity, double velocityScaleFactor)
: CameraInteractionStates(sensitivity, velocityScaleFactor)
{}
void JoystickCameraStates::updateStateFromInput(const InputState& inputState,
void JoystickCameraStates::updateStateFromInput(
const JoystickInputStates& joystickInputStates,
double deltaTime)
{
std::pair<bool, glm::dvec2> globalRotation = { false, glm::dvec2(0.0) };
@@ -46,83 +51,132 @@ void JoystickCameraStates::updateStateFromInput(const InputState& inputState,
std::pair<bool, glm::dvec2> globalRoll = { false, glm::dvec2(0.0) };
std::pair<bool, glm::dvec2> localRotation = { false, glm::dvec2(0.0) };
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
AxisInformation t = _axisMapping[i];
if (t.type == AxisType::None) {
for (const JoystickInputState& joystickInputState : joystickInputStates) {
if (joystickInputState.name.empty()) {
continue;
}
float rawValue = inputState.joystickAxis(i);
float value = rawValue;
JoystickCameraState* joystick = joystickCameraState(joystickInputState.name);
if (t.isSticky) {
value = rawValue - _prevAxisValues[i];
_prevAxisValues[i] = rawValue;
}
if (std::fabs(value) <= t.deadzone) {
if (!joystick) {
continue;
}
if (t.normalize) {
value = (value + 1.f) / 2.f;
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
AxisInformation t = joystick->axisMapping[i];
if (t.type == AxisType::None) {
continue;
}
float rawValue = joystickInputStates.axis(joystickInputState.name, i);
float value = rawValue;
if (t.isSticky) {
value = rawValue - joystick->prevAxisValues[i];
joystick->prevAxisValues[i] = rawValue;
}
if ((t.joystickType == JoystickType::JoystickLike &&
std::abs(value) <= t.deadzone) ||
(t.joystickType == JoystickType::TriggerLike && value <= -1.f + t.deadzone))
{
continue;
}
if (t.invert) {
value *= -1.f;
}
if (t.joystickType == JoystickType::TriggerLike ||
t.type == AxisType::Property)
{
value = (value + 1.f) / 2.f;
}
if (t.type == AxisType::Property) {
value = value * (t.maxValue - t.minValue) + t.minValue;
}
else {
if (std::abs(t.sensitivity) > std::numeric_limits<double>::epsilon()) {
value = static_cast<float>(value * t.sensitivity * _sensitivity);
}
else {
value = static_cast<float>(value * _sensitivity);
}
}
switch (t.type) {
case AxisType::None:
break;
case AxisType::OrbitX:
globalRotation.first = true;
globalRotation.second.x += value;
break;
case AxisType::OrbitY:
globalRotation.first = true;
globalRotation.second.y += value;
break;
case AxisType::Zoom:
case AxisType::ZoomIn:
zoom.first = true;
zoom.second += value;
break;
case AxisType::ZoomOut:
zoom.first = true;
zoom.second -= value;
break;
case AxisType::LocalRollX:
localRoll.first = true;
localRoll.second.x += value;
break;
case AxisType::LocalRollY:
localRoll.first = true;
localRoll.second.y += value;
break;
case AxisType::GlobalRollX:
globalRoll.first = true;
globalRoll.second.x += value;
break;
case AxisType::GlobalRollY:
globalRoll.first = true;
globalRoll.second.y += value;
break;
case AxisType::PanX:
localRotation.first = true;
localRotation.second.x += value;
break;
case AxisType::PanY:
localRotation.first = true;
localRotation.second.y += value;
break;
case AxisType::Property:
std::string script = fmt::format("openspace.setPropertyValue('{}', {});",
t.propertyUri, value);
global::scriptEngine->queueScript(
script,
scripting::ScriptEngine::RemoteScripting(t.isRemote)
);
break;
}
}
if (t.invert) {
value *= -1.f;
}
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
auto itRange = joystick->buttonMapping.equal_range(i);
for (auto it = itRange.first; it != itRange.second; ++it) {
bool active = global::joystickInputStates->button(
joystickInputState.name,
i,
it->second.action
);
if (std::abs(t.sensitivity) > std::numeric_limits<double>::epsilon()) {
value = static_cast<float>(value * t.sensitivity * _sensitivity);
}
else {
value = static_cast<float>(value * _sensitivity);
}
switch (t.type) {
case AxisType::None:
break;
case AxisType::OrbitX:
globalRotation.first = true;
globalRotation.second.x = value;
break;
case AxisType::OrbitY:
globalRotation.first = true;
globalRotation.second.y = value;
break;
case AxisType::Zoom:
case AxisType::ZoomIn:
zoom.first = true;
zoom.second += value;
break;
case AxisType::ZoomOut:
zoom.first = true;
zoom.second -= value;
break;
case AxisType::LocalRollX:
localRoll.first = true;
localRoll.second.x = value;
break;
case AxisType::LocalRollY:
localRoll.first = true;
localRoll.second.y = value;
break;
case AxisType::GlobalRollX:
globalRoll.first = true;
globalRoll.second.x = value;
break;
case AxisType::GlobalRollY:
globalRoll.first = true;
globalRoll.second.y = value;
break;
case AxisType::PanX:
localRotation.first = true;
localRotation.second.x = value;
break;
case AxisType::PanY:
localRotation.first = true;
localRotation.second.y = value;
break;
if (active) {
global::scriptEngine->queueScript(
it->second.command,
scripting::ScriptEngine::RemoteScripting(it->second.synchronization)
);
}
}
}
}
@@ -160,72 +214,122 @@ void JoystickCameraStates::updateStateFromInput(const InputState& inputState,
else {
_localRotationState.velocity.decelerate(deltaTime);
}
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
auto itRange = _buttonMapping.equal_range(i);
for (auto it = itRange.first; it != itRange.second; ++it) {
bool active = global::joystickInputStates->button(i, it->second.action);
if (active) {
global::scriptEngine->queueScript(
it->second.command,
scripting::ScriptEngine::RemoteScripting(it->second.synchronization)
);
}
}
}
}
void JoystickCameraStates::setAxisMapping(int axis, AxisType mapping,
void JoystickCameraStates::setAxisMapping(std::string joystickName,
int axis, AxisType mapping,
AxisInvert shouldInvert,
AxisNormalize shouldNormalize,
JoystickType joystickType,
bool isSticky,
double sensitivity)
{
ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes");
_axisMapping[axis].type = mapping;
_axisMapping[axis].invert = shouldInvert;
_axisMapping[axis].normalize = shouldNormalize;
_axisMapping[axis].isSticky = isSticky;
_axisMapping[axis].sensitivity = sensitivity;
if (isSticky) {
global::joystickInputStates->at(axis).isSticky = true;
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
_prevAxisValues[axis] = global::joystickInputStates->axis(axis);
joystickCameraState->axisMapping[axis].type = mapping;
joystickCameraState->axisMapping[axis].invert = shouldInvert;
joystickCameraState->axisMapping[axis].joystickType = joystickType;
joystickCameraState->axisMapping[axis].isSticky = isSticky;
joystickCameraState->axisMapping[axis].sensitivity = sensitivity;
joystickCameraState->prevAxisValues[axis] =
global::joystickInputStates->axis(joystickName, axis);
}
JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(int axis) const {
return _axisMapping[axis];
void JoystickCameraStates::setAxisMappingProperty(std::string joystickName,
int axis,
std::string propertyUri,
float min, float max,
AxisInvert shouldInvert,
bool isRemote)
{
ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes");
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
joystickCameraState->axisMapping[axis].type = AxisType::Property;
joystickCameraState->axisMapping[axis].invert = shouldInvert;
joystickCameraState->axisMapping[axis].propertyUri = propertyUri;
joystickCameraState->axisMapping[axis].minValue = min;
joystickCameraState->axisMapping[axis].maxValue = max;
joystickCameraState->axisMapping[axis].isRemote = isRemote;
joystickCameraState->prevAxisValues[axis] =
global::joystickInputStates->axis(joystickName, axis);
}
void JoystickCameraStates::setDeadzone(int axis, float deadzone) {
_axisMapping[axis].deadzone = deadzone;
JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(
const std::string& joystickName,
int axis) const
{
const JoystickCameraState* joystick = joystickCameraState(joystickName);
if (!joystick) {
JoystickCameraStates::AxisInformation dummy;
return dummy;
}
return joystick->axisMapping[axis];
}
float JoystickCameraStates::deadzone(int axis) const {
return _axisMapping[axis].deadzone;
void JoystickCameraStates::setDeadzone(const std::string& joystickName, int axis,
float deadzone)
{
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
joystickCameraState->axisMapping[axis].deadzone = deadzone;
}
void JoystickCameraStates::bindButtonCommand(int button, std::string command,
float JoystickCameraStates::deadzone(const std::string& joystickName, int axis) const {
const JoystickCameraState* joystick = joystickCameraState(joystickName);
if (!joystick) {
return 0.f;
}
return joystick->axisMapping[axis].deadzone;
}
void JoystickCameraStates::bindButtonCommand(const std::string& joystickName,
int button, std::string command,
JoystickAction action,
ButtonCommandRemote remote,
std::string documentation)
{
_buttonMapping.insert({
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
joystickCameraState->buttonMapping.insert({
button,
{ std::move(command), action, remote, std::move(documentation) }
});
}
void JoystickCameraStates::clearButtonCommand(int button) {
for (auto it = _buttonMapping.begin(); it != _buttonMapping.end();) {
void JoystickCameraStates::clearButtonCommand(const std::string& joystickName,
int button)
{
JoystickCameraState* joystick = joystickCameraState(joystickName);
if (!joystick) {
return;
}
for (auto it = joystick->buttonMapping.begin();
it != joystick->buttonMapping.end(); )
{
// If the current iterator is the button that we are looking for, delete it
// (std::multimap::erase will return the iterator to the next element for us)
if (it->first == button) {
it = _buttonMapping.erase(it);
it = joystick->buttonMapping.erase(it);
}
else {
++it;
@@ -233,14 +337,66 @@ void JoystickCameraStates::clearButtonCommand(int button) {
}
}
std::vector<std::string> JoystickCameraStates::buttonCommand(int button) const {
std::vector<std::string> JoystickCameraStates::buttonCommand(
const std::string& joystickName,
int button) const
{
std::vector<std::string> result;
auto itRange = _buttonMapping.equal_range(button);
const JoystickCameraState* joystick = joystickCameraState(joystickName);
if (!joystick) {
return result;
}
auto itRange = joystick->buttonMapping.equal_range(button);
for (auto it = itRange.first; it != itRange.second; ++it) {
result.push_back(it->second.command);
}
return result;
}
JoystickCameraStates::JoystickCameraState* JoystickCameraStates::joystickCameraState(
const std::string& joystickName)
{
for (JoystickCameraState& joystickCameraState : _joystickCameraStates) {
if (joystickCameraState.joystickName == joystickName) {
return &joystickCameraState;
}
}
return nullptr;
}
const JoystickCameraStates::JoystickCameraState*
JoystickCameraStates::joystickCameraState(const std::string& joystickName) const
{
for (const JoystickCameraState& joystickCameraState : _joystickCameraStates) {
if (joystickCameraState.joystickName == joystickName) {
return &joystickCameraState;
}
}
LWARNING(fmt::format("Cannot find JoystickCameraState with name '{}'", joystickName));
return nullptr;
}
JoystickCameraStates::JoystickCameraState*
JoystickCameraStates::findOrAddJoystickCameraState(const std::string& joystickName)
{
JoystickCameraState* joystick = joystickCameraState(joystickName);
if (!joystick) {
if (_joystickCameraStates.size() < JoystickInputStates::MaxNumJoysticks) {
_joystickCameraStates.push_back(JoystickCameraState());
joystick = &_joystickCameraStates.back();
joystick->joystickName = joystickName;
}
else {
LWARNING(fmt::format("Cannot add more joysticks, only {} joysticks are "
"supported", JoystickInputStates::MaxNumJoysticks));
return nullptr;
}
}
return joystick;
}
} // namespace openspace::interaction

View File

@@ -33,38 +33,68 @@
namespace openspace::interaction {
float JoystickInputStates::axis(int axis) const {
float JoystickInputStates::axis(const std::string& joystickName, int axis) const {
ghoul_precondition(axis >= 0, "axis must be 0 or positive");
float res = std::accumulate(
begin(),
end(),
0.f,
[axis](float value, const JoystickInputState& state) {
if (state.isConnected) {
value += state.axes[axis];
if (joystickName.empty()) {
float res = std::accumulate(
begin(),
end(),
0.f,
[axis](float value, const JoystickInputState& state) {
if (state.isConnected) {
value += state.axes[axis];
}
return value;
}
return value;
}
);
);
// If multiple joysticks are connected, we might get values outside the -1,1 range by
// summing them up
glm::clamp(res, -1.f, 1.f);
return res;
// If multiple joysticks are connected, we might get values outside the -1,1 range by
// summing them up
glm::clamp(res, -1.f, 1.f);
return res;
}
const JoystickInputState* state = nullptr;
for (auto it = begin(); it < end(); ++it) {
if (it->name == joystickName) {
state = &(*it);
}
}
if (!state) {
return 0.f;
}
return state->axes[axis];
}
bool JoystickInputStates::button(int button, JoystickAction action) const {
bool JoystickInputStates::button(const std::string& joystickName, int button, JoystickAction action) const {
ghoul_precondition(button >= 0, "button must be 0 or positive");
bool res = std::any_of(
begin(),
end(),
[button, action](const JoystickInputState& state) {
return state.isConnected ? (state.buttons[button] == action) : false;
if (joystickName.empty()) {
bool res = std::any_of(
begin(),
end(),
[button, action](const JoystickInputState& state) {
return state.isConnected ? (state.buttons[button] == action) : false;
}
);
return res;
}
const JoystickInputState* state = nullptr;
for (auto it = begin(); it < end(); ++it) {
if (it->name == joystickName) {
state = &(*it);
}
);
return res;
}
if (!state) {
return false;
}
return state->isConnected ? (state->buttons[button] == action) : false;
}
} // namespace openspace::interaction

View File

@@ -22,17 +22,15 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/keyboardinputstate.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/interaction/websocketinputstate.h>
#include <ghoul/fmt.h>
#include <algorithm>
namespace openspace::interaction {
void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
void KeyboardInputState::keyboardCallback(Key key, KeyModifier modifier,
KeyAction action)
{
if (action == KeyAction::Press) {
_keysDown.emplace_back(key, modifier);
}
@@ -51,47 +49,15 @@ void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction actio
}
}
void InputState::mouseButtonCallback(MouseButton button, MouseAction action) {
if (action == MouseAction::Press) {
_mouseButtonsDown.push_back(button);
}
else if (action == MouseAction::Release) {
_mouseButtonsDown.erase(
std::remove(_mouseButtonsDown.begin(), _mouseButtonsDown.end(), button),
_mouseButtonsDown.end()
);
}
}
void InputState::mousePositionCallback(double mouseX, double mouseY) {
_mousePosition = glm::dvec2(mouseX, mouseY);
}
void InputState::mouseScrollWheelCallback(double mouseScrollDelta) {
_mouseScrollDelta = mouseScrollDelta;
}
const std::vector<std::pair<Key, KeyModifier>>& InputState::pressedKeys() const {
const std::vector<std::pair<Key, KeyModifier>>& KeyboardInputState::pressedKeys() const {
return _keysDown;
}
const std::vector<MouseButton>& InputState::pressedMouseButtons() const {
return _mouseButtonsDown;
}
glm::dvec2 InputState::mousePosition() const {
return _mousePosition;
}
double InputState::mouseScrollDelta() const {
return _mouseScrollDelta;
}
bool InputState::isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const {
bool KeyboardInputState::isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const {
return std::find(_keysDown.begin(), _keysDown.end(), keyModPair) != _keysDown.end();
}
bool InputState::isKeyPressed(Key key) const {
bool KeyboardInputState::isKeyPressed(Key key) const {
auto it = std::find_if(
_keysDown.begin(),
_keysDown.end(),
@@ -102,37 +68,4 @@ bool InputState::isKeyPressed(Key key) const {
return it != _keysDown.end();
}
bool InputState::isMouseButtonPressed(MouseButton mouseButton) const {
auto it = std::find(_mouseButtonsDown.begin(), _mouseButtonsDown.end(), mouseButton);
return it != _mouseButtonsDown.end();
}
float InputState::joystickAxis(int i) const {
return global::joystickInputStates->axis(i);
}
bool InputState::joystickButton(int i) const {
return global::joystickInputStates->button(i, JoystickAction::Press);
}
float InputState::websocketAxis(int i) const {
return global::websocketInputStates->axis(i);
}
bool InputState::websocketButton(int i) const {
return global::websocketInputStates->button(i, WebsocketAction::Press);
}
void InputState::resetWebsockets() {
using K = size_t;
using V = WebsocketInputState*;
for (const std::pair<const K, V>& p : *global::websocketInputStates) {
p.second->isConnected = false;
}
}
bool InputState::hasWebsocketStates() const {
return !global::websocketInputStates->empty();
}
} // namespace openspace::interaction

View File

@@ -24,7 +24,8 @@
#include <openspace/interaction/mousecamerastates.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/mouseinputstate.h>
#include <openspace/interaction/keyboardinputstate.h>
namespace {
const double SENSITIVITY_ADJUSTMENT_INCREASE = 8.0;
@@ -37,7 +38,8 @@ MouseCameraStates::MouseCameraStates(double sensitivity, double velocityScaleFac
: CameraInteractionStates(sensitivity, velocityScaleFactor)
{}
void MouseCameraStates::updateStateFromInput(const InputState& inputState,
void MouseCameraStates::updateStateFromInput(const MouseInputState& mouseinputState,
const KeyboardInputState& keyboardinputState,
double deltaTime)
{
MouseButton primary =
@@ -45,17 +47,17 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState,
MouseButton secondary =
_isMouseButtonInverted ? MouseButton::Button1 : MouseButton::Button2;
glm::dvec2 mousePosition = inputState.mousePosition();
glm::dvec2 mousePosition = mouseinputState.mousePosition();
bool primaryPressed = inputState.isMouseButtonPressed(primary);
bool secondaryPressed = inputState.isMouseButtonPressed(secondary);
bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3);
bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) |
inputState.isKeyPressed(Key::RightControl);
bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift) |
inputState.isKeyPressed(Key::RightShift);
bool keyAltPressed = inputState.isKeyPressed(Key::LeftAlt) |
inputState.isKeyPressed(Key::RightAlt);
bool primaryPressed = mouseinputState.isMouseButtonPressed(primary);
bool secondaryPressed = mouseinputState.isMouseButtonPressed(secondary);
bool button3Pressed = mouseinputState.isMouseButtonPressed(MouseButton::Button3);
bool keyCtrlPressed = keyboardinputState.isKeyPressed(Key::LeftControl) |
keyboardinputState.isKeyPressed(Key::RightControl);
bool keyShiftPressed = keyboardinputState.isKeyPressed(Key::LeftShift) |
keyboardinputState.isKeyPressed(Key::RightShift);
bool keyAltPressed = keyboardinputState.isKeyPressed(Key::LeftAlt) |
keyboardinputState.isKeyPressed(Key::RightAlt);
// Update the mouse states
if (primaryPressed && !keyShiftPressed && !keyAltPressed) {
@@ -94,10 +96,10 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState,
mousePosition;
double sensitivity = _sensitivity;
if (inputState.isKeyPressed(Key::Z)) {
if (keyboardinputState.isKeyPressed(Key::Z)) {
sensitivity *= SENSITIVITY_ADJUSTMENT_INCREASE;
}
else if (inputState.isKeyPressed(Key::X)) {
else if (keyboardinputState.isKeyPressed(Key::X)) {
sensitivity *= SENSITIVITY_ADJUSTMENT_DECREASE;
}

View File

@@ -0,0 +1,68 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/mouseinputstate.h>
#include <algorithm>
namespace openspace::interaction {
void MouseInputState::mouseButtonCallback(MouseButton button, MouseAction action) {
if (action == MouseAction::Press) {
_mouseButtonsDown.push_back(button);
}
else if (action == MouseAction::Release) {
_mouseButtonsDown.erase(
std::remove(_mouseButtonsDown.begin(), _mouseButtonsDown.end(), button),
_mouseButtonsDown.end()
);
}
}
void MouseInputState::mousePositionCallback(double mouseX, double mouseY) {
_mousePosition = glm::dvec2(mouseX, mouseY);
}
void MouseInputState::mouseScrollWheelCallback(double mouseScrollDelta) {
_mouseScrollDelta = mouseScrollDelta;
}
const std::vector<MouseButton>& MouseInputState::pressedMouseButtons() const {
return _mouseButtonsDown;
}
glm::dvec2 MouseInputState::mousePosition() const {
return _mousePosition;
}
double MouseInputState::mouseScrollDelta() const {
return _mouseScrollDelta;
}
bool MouseInputState::isMouseButtonPressed(MouseButton mouseButton) const {
auto it = std::find(_mouseButtonsDown.begin(), _mouseButtonsDown.end(), mouseButton);
return it != _mouseButtonsDown.end();
}
} // namespace openspace::interaction

View File

@@ -24,13 +24,11 @@
#include <openspace/interaction/scriptcamerastates.h>
#include <openspace/interaction/inputstate.h>
namespace openspace::interaction {
ScriptCameraStates::ScriptCameraStates() : CameraInteractionStates(1.0, 1.0) {}
void ScriptCameraStates::updateStateFromInput(const InputState&, double deltaTime) {
void ScriptCameraStates::updateStateFromInput(double deltaTime) {
if (_localRotation != glm::dvec2(0.0)) {
_localRotationState.velocity.set(
_localRotation * _sensitivity,

View File

@@ -25,7 +25,6 @@
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/misc/exception.h>
#include <ghoul/misc/stringconversion.h>
@@ -39,7 +38,8 @@ WebsocketCameraStates::WebsocketCameraStates(double sensitivity,
: CameraInteractionStates(sensitivity, velocityScaleFactor)
{}
void WebsocketCameraStates::updateStateFromInput(const InputState& inputState,
void WebsocketCameraStates::updateStateFromInput(
const WebsocketInputStates& websocketInputStates,
double deltaTime)
{
std::pair<bool, glm::dvec2> globalRotation = { false, glm::dvec2(0.0) };
@@ -48,14 +48,14 @@ void WebsocketCameraStates::updateStateFromInput(const InputState& inputState,
std::pair<bool, glm::dvec2> globalRoll = { false, glm::dvec2(0.0) };
std::pair<bool, glm::dvec2> localRotation = { false, glm::dvec2(0.0) };
if (inputState.hasWebsocketStates()) {
if (!websocketInputStates.empty()) {
for (int i = 0; i < WebsocketInputState::MaxAxes; ++i) {
AxisInformation t = _axisMapping[i];
if (t.type == AxisType::None) {
continue;
}
float value = inputState.websocketAxis(i);
float value = websocketInputStates.axis(i);
bool hasValue = std::fabs(value) > t.deadzone;
if (!hasValue) {

View File

@@ -187,7 +187,11 @@ void NavigationHandler::updateCamera(double deltaTime) {
JoystickInputState()
);
}
_orbitalNavigator.updateStatesFromInput(_inputState, deltaTime);
_orbitalNavigator.updateStatesFromInput(
_mouseInputState,
_keyboardInputState,
deltaTime
);
_orbitalNavigator.updateCameraStateFromStates(deltaTime);
updateCameraTransitions();
}
@@ -351,25 +355,29 @@ Camera* NavigationHandler::camera() const {
return _camera;
}
const InputState& NavigationHandler::inputState() const {
return _inputState;
const MouseInputState& NavigationHandler::mouseInputState() const {
return _mouseInputState;
}
const KeyboardInputState& NavigationHandler::keyboardInputState() const {
return _keyboardInputState;
}
void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) {
if (!_disableMouseInputs) {
_inputState.mouseButtonCallback(button, action);
_mouseInputState.mouseButtonCallback(button, action);
}
}
void NavigationHandler::mousePositionCallback(double x, double y) {
if (!_disableMouseInputs) {
_inputState.mousePositionCallback(x, y);
_mouseInputState.mousePositionCallback(x, y);
}
}
void NavigationHandler::mouseScrollWheelCallback(double pos) {
if (!_disableMouseInputs) {
_inputState.mouseScrollWheelCallback(pos);
_mouseInputState.mouseScrollWheelCallback(pos);
}
}
@@ -377,7 +385,7 @@ void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActio
{
// There is no need to disable the keyboard callback based on a property as the vast
// majority of input is coming through Lua scripts anyway which are not blocked here
_inputState.keyboardCallback(key, modifier, action);
_keyboardInputState.keyboardCallback(key, modifier, action);
}
NavigationState NavigationHandler::navigationState() const {
@@ -489,23 +497,42 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) {
}
}
void NavigationHandler::setJoystickAxisMapping(int axis,
void NavigationHandler::setJoystickAxisMapping(std::string joystickName, int axis,
JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert,
JoystickCameraStates::AxisNormalize shouldNormalize,
JoystickCameraStates::JoystickType joystickType,
bool isSticky,
double sensitivity)
{
_orbitalNavigator.joystickStates().setAxisMapping(
std::move(joystickName),
axis,
mapping,
shouldInvert,
shouldNormalize,
joystickType,
isSticky,
sensitivity
);
}
void NavigationHandler::setJoystickAxisMappingProperty(std::string joystickName,
int axis,
std::string propertyUri,
float min, float max,
JoystickCameraStates::AxisInvert shouldInvert,
bool isRemote)
{
_orbitalNavigator.joystickStates().setAxisMappingProperty(
std::move(joystickName),
axis,
std::move(propertyUri),
min,
max,
shouldInvert,
isRemote
);
}
void NavigationHandler::setWebsocketAxisMapping(int axis,
WebsocketCameraStates::AxisType mapping,
WebsocketCameraStates::AxisInvert shouldInvert,
@@ -521,25 +548,31 @@ void NavigationHandler::setWebsocketAxisMapping(int axis,
JoystickCameraStates::AxisInformation
NavigationHandler::joystickAxisMapping(int axis) const
NavigationHandler::joystickAxisMapping(const std::string& joystickName, int axis) const
{
return _orbitalNavigator.joystickStates().axisMapping(axis);
return _orbitalNavigator.joystickStates().axisMapping(joystickName, axis);
}
void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) {
_orbitalNavigator.joystickStates().setDeadzone(axis, deadzone);
void NavigationHandler::setJoystickAxisDeadzone(const std::string& joystickName, int axis,
float deadzone)
{
_orbitalNavigator.joystickStates().setDeadzone(joystickName, axis, deadzone);
}
float NavigationHandler::joystickAxisDeadzone(int axis) const {
return _orbitalNavigator.joystickStates().deadzone(axis);
float NavigationHandler::joystickAxisDeadzone(const std::string& joystickName,
int axis) const
{
return _orbitalNavigator.joystickStates().deadzone(joystickName, axis);
}
void NavigationHandler::bindJoystickButtonCommand(int button, std::string command,
void NavigationHandler::bindJoystickButtonCommand(const std::string& joystickName,
int button, std::string command,
JoystickAction action,
JoystickCameraStates::ButtonCommandRemote remote,
std::string documentation)
{
_orbitalNavigator.joystickStates().bindButtonCommand(
joystickName,
button,
std::move(command),
action,
@@ -548,12 +581,16 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman
);
}
void NavigationHandler::clearJoystickButtonCommand(int button) {
_orbitalNavigator.joystickStates().clearButtonCommand(button);
void NavigationHandler::clearJoystickButtonCommand(const std::string& joystickName,
int button)
{
_orbitalNavigator.joystickStates().clearButtonCommand(joystickName, button);
}
std::vector<std::string> NavigationHandler::joystickButtonCommand(int button) const {
return _orbitalNavigator.joystickStates().buttonCommand(button);
std::vector<std::string> NavigationHandler::joystickButtonCommand(
const std::string& joystickName, int button) const
{
return _orbitalNavigator.joystickStates().buttonCommand(joystickName, button);
}
scripting::LuaLibrary NavigationHandler::luaLibrary() {
@@ -611,52 +648,79 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() {
{
"bindJoystickAxis",
&luascriptfunctions::bindJoystickAxis,
"int, axisType [, isInverted, isNormalized]",
"Binds the axis identified by the first argument to be used as the type "
"identified by the second argument. If 'isInverted' is 'true', the axis "
"value is inverted, if 'isNormalized' is true the axis value is "
"normalized from [-1, 1] to [0,1]."
"name, axis, axisType [, isInverted, joystickType, isSticky, sensitivity]",
"Finds the input joystick with the given 'name' and binds the axis "
"identified by the second argument to be used as the type identified by "
"the third argument. If 'isInverted' is 'true', the axis value is "
"inverted. 'joystickType' is if the joystick behaves more like a "
"joystick or a trigger, where the first is the default. If 'isSticky' is "
"'true', the value is calculated relative to the previous value. If "
"'sensitivity' is given then that value will affect the sensitivity of "
"the axis together with the global sensitivity."
},
{
"bindJoystickAxisProperty",
&luascriptfunctions::bindJoystickAxisProperty,
"name, axis, propertyUri [, min, max, isInverted, isSticky, sensitivity, "
"isRemote]",
"Finds the input joystick with the given 'name' and binds the axis "
"identified by the second argument to be bound to the property "
"identified by the third argument. 'min' and 'max' is the minimum and "
"the maximum allowed value for the given property and the axis value is "
"rescaled from [-1, 1] to [min, max], default is [0, 1]. If 'isInverted' "
"is 'true', the axis value is inverted. The last argument determines "
"whether the property change is going to be executed locally or "
"remotely, where the latter is the default."
},
{
"joystickAxis",
&luascriptfunctions::joystickAxis,
"int",
"Returns the joystick axis information for the passed axis. The "
"information that is returned is the current axis binding as a string, "
"whether the values are inverted as bool, and whether the value are "
"normalized as a bool"
"name, axis",
"Finds the input joystick with the given 'name' and returns the joystick "
"axis information for the passed axis. The information that is returned "
"is the current axis binding as a string, whether the values are "
"inverted as bool, the joystick type as a string, whether the axis is "
"sticky as bool, the sensitivity as number, the property uri bound to "
"the axis as string (empty is type is not Property), the min and max "
"values for the property as numbers and whether the property change will "
"be executed remotly as bool."
},
{
"setAxisDeadZone",
&luascriptfunctions::setJoystickAxisDeadzone,
"int, float",
"Sets the deadzone for a particular joystick axis which means that any "
"input less than this value is completely ignored."
"name, axis, float",
"Finds the input joystick with the given 'name' and sets the deadzone "
"for a particular joystick axis, which means that any input less than "
"this value is completely ignored."
},
{
"bindJoystickButton",
&luascriptfunctions::bindJoystickButton,
"int, string [, string, bool]",
"Binds a Lua script to be executed when the joystick button identified "
"by the first argument is triggered. The third argument determines when "
"the script should be executed, this defaults to 'pressed', which means "
"that the script is run when the user presses the button. The last "
"argument determines whether the command is going to be executable "
"locally or remotely. The latter being the default."
"name, button, string [, string, string, bool]",
"Finds the input joystick with the given 'name' and binds a Lua script "
"given by the third argument to be executed when the joystick button "
"identified by the second argument is triggered. The fifth argument "
"determines when the script should be executed, this defaults to "
"'Press', which means that the script is run when the user presses the "
"button. The fourth arguemnt is the documentation of the script in the "
"third argument. The sixth argument determines whether the command is "
"going to be executable locally or remotely, where the latter is the "
"default."
},
{
"clearJoystickButton",
&luascriptfunctions::clearJoystickButton,
"int",
"Removes all commands that are currently bound to the button identified "
"by the first argument"
"name, button",
"Finds the input joystick with the given 'name' and removes all commands "
"that are currently bound to the button identified by the second argument."
},
{
"joystickButton",
&luascriptfunctions::joystickButton,
"int",
"Returns the script that is currently bound to be executed when the "
"provided button is pressed"
"name, button",
"Finds the input joystick with the given 'name' and returns the script "
"that is currently bound to be executed when the provided button is "
"pressed."
},
{
"addGlobalRotation",

View File

@@ -151,68 +151,103 @@ int retargetAim(lua_State* L) {
}
int bindJoystickAxis(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, { 2, 6 }, "lua::bindJoystickAxis");
auto [axis, axisType, shouldInvert, shouldNormalize, isSticky, sensitivity] =
ghoul::lua::checkArgumentsAndThrow(L, { 3, 7 }, "lua::bindJoystickAxis");
auto [joystickName, axis, axisType, shouldInvert, joystickType, isSticky,
sensitivity] =
ghoul::lua::values<
int, std::string, std::optional<bool>, std::optional<bool>,
std::optional<bool>, std::optional<double>
std::string, int, std::string, std::optional<bool>,
std::optional<std::string>, std::optional<bool>, std::optional<double>
>(L);
shouldInvert = shouldInvert.value_or(false);
shouldNormalize = shouldNormalize.value_or(false);
isSticky = isSticky.value_or(false);
sensitivity = sensitivity.value_or(0.0);
joystickType = joystickType.value_or("JoystickLike");
global::navigationHandler->setJoystickAxisMapping(
std::move(joystickName),
axis,
ghoul::from_string<interaction::JoystickCameraStates::AxisType>(axisType),
interaction::JoystickCameraStates::AxisInvert(*shouldInvert),
interaction::JoystickCameraStates::AxisNormalize(*shouldNormalize),
ghoul::from_string<interaction::JoystickCameraStates::JoystickType>(*joystickType),
*isSticky,
*sensitivity
);
return 0;
}
int bindJoystickAxisProperty(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, { 3, 7 }, "lua::bindJoystickAxisProperty");
auto [joystickName, axis, propertyUri, min, max, shouldInvert, isRemote] =
ghoul::lua::values<
std::string, int, std::string, std::optional<float>, std::optional<float>,
std::optional<bool>, std::optional<bool>
>(L);
min = min.value_or(0.f);
max = max.value_or(1.f);
shouldInvert = shouldInvert.value_or(false);
isRemote = isRemote.value_or(true);
global::navigationHandler->setJoystickAxisMappingProperty(
std::move(joystickName),
axis,
std::move(propertyUri),
*min,
*max,
interaction::JoystickCameraStates::AxisInvert(*shouldInvert),
*isRemote
);
return 0;
}
int joystickAxis(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis");
const int axis = ghoul::lua::value<int>(L);
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickAxis");
auto [joystickName, axis] = ghoul::lua::values<std::string, int>(L);
using AI = interaction::JoystickCameraStates::AxisInformation;
AI info = global::navigationHandler->joystickAxisMapping(axis);
AI info = global::navigationHandler->joystickAxisMapping(joystickName, axis);
ghoul::lua::push(
L,
ghoul::to_string(info.type),
static_cast<bool>(info.invert),
static_cast<bool>(info.normalize),
ghoul::to_string(info.joystickType),
info.isSticky,
info.sensitivity
info.sensitivity,
info.propertyUri,
info.minValue,
info.maxValue,
info.isRemote
);
return 5;
return 9;
}
int setJoystickAxisDeadzone(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone");
auto [axis, deadzone] = ghoul::lua::values<int, float>(L);
ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::setJoystickAxisDeadzone");
auto [joystickName, axis, deadzone] = ghoul::lua::values<std::string, int, float>(L);
global::navigationHandler->setJoystickAxisDeadzone(axis, deadzone);
global::navigationHandler->setJoystickAxisDeadzone(joystickName, axis, deadzone);
return 0;
}
int joystickAxisDeadzone(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxisDeadzone");
const int axis = ghoul::lua::value<int>(L);
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickAxisDeadzone");
auto [joystickName, axis] = ghoul::lua::values<std::string, int>(L);
const float deadzone = global::navigationHandler->joystickAxisDeadzone(axis);
const float deadzone = global::navigationHandler->joystickAxisDeadzone(joystickName, axis);
ghoul::lua::push(L, deadzone);
return 1;
}
int bindJoystickButton(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, { 3, 5 }, "lua::bindJoystickButton");
auto [button, command, documentation, actionStr, isRemote] =
ghoul::lua::checkArgumentsAndThrow(L, { 4, 6 }, "lua::bindJoystickButton");
auto [joystickName, button, command, documentation, actionStr, isRemote] =
ghoul::lua::values<
int, std::string, std::string, std::optional<std::string>, std::optional<bool>
std::string,
int,
std::string,
std::string,
std::optional<std::string>,
std::optional<bool>
>(L);
actionStr = actionStr.value_or("Press");
isRemote = isRemote.value_or(true);
@@ -221,6 +256,7 @@ int bindJoystickButton(lua_State* L) {
ghoul::from_string<interaction::JoystickAction>(*actionStr);
global::navigationHandler->bindJoystickButtonCommand(
joystickName,
button,
command,
action,
@@ -231,18 +267,19 @@ int bindJoystickButton(lua_State* L) {
}
int clearJoystickButton(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearJoystickButton");
const int button = ghoul::lua::value<int>(L);
global::navigationHandler->clearJoystickButtonCommand(button);
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::clearJoystickButton");
auto [joystickName, button] = ghoul::lua::values<std::string, int>(L);
global::navigationHandler->clearJoystickButtonCommand(joystickName, button);
return 0;
}
int joystickButton(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickButton");
const int button = ghoul::lua::value<int>(L);
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::joystickButton");
auto [joystickName, button] = ghoul::lua::values<std::string, int>(L);
const std::vector<std::string>& cmds =
global::navigationHandler->joystickButtonCommand(button);
global::navigationHandler->joystickButtonCommand(joystickName, button);
std::string cmd = std::accumulate(
cmds.cbegin(),

View File

@@ -23,6 +23,8 @@
****************************************************************************************/
#include <openspace/camera/camerapose.h>
#include <openspace/interaction/mouseinputstate.h>
#include <openspace/interaction/keyboardinputstate.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/updatestructures.h>
@@ -543,13 +545,14 @@ void OrbitalNavigator::resetVelocities() {
}
}
void OrbitalNavigator::updateStatesFromInput(const InputState& inputState,
void OrbitalNavigator::updateStatesFromInput(const MouseInputState& mouseInputState,
const KeyboardInputState& keyboardInputState,
double deltaTime)
{
_mouseStates.updateStateFromInput(inputState, deltaTime);
_joystickStates.updateStateFromInput(inputState, deltaTime);
_websocketStates.updateStateFromInput(inputState, deltaTime);
_scriptStates.updateStateFromInput(inputState, deltaTime);
_mouseStates.updateStateFromInput(mouseInputState, keyboardInputState, deltaTime);
_joystickStates.updateStateFromInput(*global::joystickInputStates, deltaTime);
_websocketStates.updateStateFromInput(*global::websocketInputStates, deltaTime);
_scriptStates.updateStateFromInput(deltaTime);
bool interactionHappened = _mouseStates.hasNonZeroVelocities() ||
_joystickStates.hasNonZeroVelocities() ||