Introduce optional timestamp into internal Controller axis values

This can be used to determine if consecutive identifical values should
be output.
This commit is contained in:
David Rowe 2018-12-20 14:34:12 +13:00
parent 4aa26715c0
commit 84c6bb4797
10 changed files with 106 additions and 51 deletions

View file

@ -0,0 +1,18 @@
//
// AxisValue.cpp
//
// Created by David Rowe on 14 Dec 2018.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AxisValue.h"
namespace controller {
AxisValue::AxisValue(const float value, const quint64 timestamp) :
value(value), timestamp(timestamp) { }
}

View file

@ -0,0 +1,31 @@
//
// AxisValue.h
//
// Created by David Rowe on 13 Dec 2018.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_controllers_AxisValue_h
#define hifi_controllers_AxisValue_h
#include <QtCore/qglobal.h>
namespace controller {
struct AxisValue {
public:
float value { 0.0f };
// The value can be timestamped to determine if consecutive identical values should be output (e.g., mouse movement).
quint64 timestamp { 0 };
AxisValue() {}
AxisValue(const float value, const quint64 timestamp);
};
}
#endif // hifi_controllers_AxisValue_h

View file

@ -26,12 +26,12 @@ namespace controller {
return 0.0f;
}
float InputDevice::getAxis(int channel) const {
AxisValue InputDevice::getAxis(int channel) const {
auto axis = _axisStateMap.find(channel);
if (axis != _axisStateMap.end()) {
return (*axis).second;
} else {
return 0.0f;
return AxisValue();
}
}
@ -71,7 +71,7 @@ namespace controller {
float InputDevice::getValue(ChannelType channelType, uint16_t channel) const {
switch (channelType) {
case ChannelType::AXIS:
return getAxis(channel);
return getAxis(channel).value;
case ChannelType::BUTTON:
return getButton(channel);

View file

@ -16,6 +16,7 @@
#include <QtCore/QString>
#include "AxisValue.h"
#include "Pose.h"
#include "Input.h"
#include "StandardControls.h"
@ -103,12 +104,12 @@ public:
using Pointer = std::shared_ptr<InputDevice>;
typedef std::unordered_set<int> ButtonPressedMap;
typedef std::map<int, float> AxisStateMap;
typedef std::map<int, AxisValue> AxisStateMap;
typedef std::map<int, Pose> PoseStateMap;
// Get current state for each channel
float getButton(int channel) const;
float getAxis(int channel) const;
AxisValue getAxis(int channel) const;
Pose getPose(int channel) const;
float getValue(const Input& input) const;

View file

@ -27,15 +27,15 @@ void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputC
_inputDevice->update(deltaTime, inputCalibrationData);
eraseMouseClicked();
_inputDevice->_axisStateMap[MOUSE_AXIS_X] = _lastCursor.x();
_inputDevice->_axisStateMap[MOUSE_AXIS_Y] = _lastCursor.y();
_inputDevice->_axisStateMap[MOUSE_AXIS_X].value = _lastCursor.x();
_inputDevice->_axisStateMap[MOUSE_AXIS_Y].value = _lastCursor.y();
QPoint currentMove = _lastCursor - _previousCursor;
_inputDevice->_axisStateMap[MOUSE_AXIS_X_POS] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_X_NEG] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_X_POS].value = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_X_NEG].value = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
// Y mouse is inverted positive is pointing up the screen
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_POS] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_NEG] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_POS].value = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
_inputDevice->_axisStateMap[MOUSE_AXIS_Y_NEG].value = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
_previousCursor = _lastCursor;
});
@ -124,10 +124,11 @@ void KeyboardMouseDevice::mouseMoveEvent(QMouseEvent* event) {
void KeyboardMouseDevice::wheelEvent(QWheelEvent* event) {
auto currentMove = event->angleDelta() / 120.0f;
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()] = (currentMove.x() > 0 ? currentMove.x() : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()] = (currentMove.x() < 0 ? -currentMove.x() : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()] = (currentMove.y() > 0 ? currentMove.y() : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()] = (currentMove.y() < 0 ? -currentMove.y() : 0.0f);
// ####### TODO: Use AxisValue timestamps?
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_POS).getChannel()].value = (currentMove.x() > 0 ? currentMove.x() : 0, 0);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_X_NEG).getChannel()].value = (currentMove.x() < 0 ? -currentMove.x() : 0, 0);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_POS).getChannel()].value = (currentMove.y() > 0 ? currentMove.y() : 0);
_inputDevice->_axisStateMap[_inputDevice->makeInput(MOUSE_AXIS_WHEEL_Y_NEG).getChannel()].value = (currentMove.y() < 0 ? -currentMove.y() : 0);
}
glm::vec2 evalAverageTouchPoints(const QList<QTouchEvent::TouchPoint>& points) {
@ -167,11 +168,12 @@ void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) {
} else {
auto currentMove = currentPos - _lastTouch;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()] = (currentMove.x > 0 ? currentMove.x : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()] = (currentMove.x < 0 ? -currentMove.x : 0.0f);
// ####### TODO: Use AxisValue timestamp fields?
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()].value = (currentMove.x > 0 ? currentMove.x : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()].value = (currentMove.x < 0 ? -currentMove.x : 0.0f);
// Y mouse is inverted positive is pointing up the screen
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()] = (currentMove.y < 0 ? -currentMove.y : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = (currentMove.y > 0 ? currentMove.y : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()].value = (currentMove.y < 0 ? -currentMove.y : 0.0f);
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_NEG).getChannel()].value = (currentMove.y > 0 ? currentMove.y : 0.0f);
}
_lastTouch = currentPos;

View file

@ -38,28 +38,29 @@ void TouchscreenDevice::pluginUpdate(float deltaTime, const controller::InputCal
_inputDevice->update(deltaTime, inputCalibrationData);
});
// ####### TODO: Use AxisValue timestamp fields?
float distanceScaleX, distanceScaleY;
if (_touchPointCount == 1) {
if (_firstTouchVec.x < _currentTouchVec.x) {
distanceScaleX = (_currentTouchVec.x - _firstTouchVec.x) / _screenDPIScale.x;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()] = distanceScaleX;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_POS).getChannel()].value = distanceScaleX;
} else if (_firstTouchVec.x > _currentTouchVec.x) {
distanceScaleX = (_firstTouchVec.x - _currentTouchVec.x) / _screenDPIScale.x;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()] = distanceScaleX;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_X_NEG).getChannel()].value = distanceScaleX;
}
// Y axis is inverted, positive is pointing up the screen
if (_firstTouchVec.y > _currentTouchVec.y) {
distanceScaleY = (_firstTouchVec.y - _currentTouchVec.y) / _screenDPIScale.y;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()] = distanceScaleY;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_POS).getChannel()].value = distanceScaleY;
} else if (_firstTouchVec.y < _currentTouchVec.y) {
distanceScaleY = (_currentTouchVec.y - _firstTouchVec.y) / _screenDPIScale.y;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_NEG).getChannel()] = distanceScaleY;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_AXIS_Y_NEG).getChannel()].value = distanceScaleY;
}
} else if (_touchPointCount == 2) {
if (_pinchScale > _lastPinchScale && _pinchScale != 0) {
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_GESTURE_PINCH_POS).getChannel()] = 1.0f;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_GESTURE_PINCH_POS).getChannel()].value = 1.0f;
} else if (_pinchScale != 0) {
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_GESTURE_PINCH_NEG).getChannel()] = 1.0f;
_inputDevice->_axisStateMap[_inputDevice->makeInput(TOUCH_GESTURE_PINCH_NEG).getChannel()].value = 1.0;
}
_lastPinchScale = _pinchScale;
}

View file

@ -135,8 +135,8 @@ glm::vec2 TouchscreenVirtualPadDevice::clippedPointInCircle(float radius, glm::v
void TouchscreenVirtualPadDevice::processInputDeviceForMove(VirtualPad::Manager& virtualPadManager) {
vec2 clippedPoint = clippedPointInCircle(_fixedRadiusForCalc, _moveRefTouchPoint, _moveCurrentTouchPoint);
_inputDevice->_axisStateMap[controller::LX] = (clippedPoint.x - _moveRefTouchPoint.x) / _fixedRadiusForCalc;
_inputDevice->_axisStateMap[controller::LY] = (clippedPoint.y - _moveRefTouchPoint.y) / _fixedRadiusForCalc;
_inputDevice->_axisStateMap[controller::LX].value = (clippedPoint.x - _moveRefTouchPoint.x) / _fixedRadiusForCalc;
_inputDevice->_axisStateMap[controller::LY].value = (clippedPoint.y - _moveRefTouchPoint.y) / _fixedRadiusForCalc;
virtualPadManager.getLeftVirtualPad()->setFirstTouch(_moveRefTouchPoint);
virtualPadManager.getLeftVirtualPad()->setCurrentTouch(clippedPoint);
@ -148,8 +148,10 @@ void TouchscreenVirtualPadDevice::processInputDeviceForView() {
// We use average across how many times we've got touchUpdate events.
// Using the average instead of the full deltaX and deltaY, makes deltaTime in MyAvatar dont't accelerate rotation when there is a low touchUpdate rate (heavier domains).
// (Because it multiplies this input value by deltaTime (with a coefficient)).
_inputDevice->_axisStateMap[controller::RX] = _viewTouchUpdateCount == 0 ? 0 : (_viewCurrentTouchPoint.x - _viewRefTouchPoint.x) / _viewTouchUpdateCount;
_inputDevice->_axisStateMap[controller::RY] = _viewTouchUpdateCount == 0 ? 0 : (_viewCurrentTouchPoint.y - _viewRefTouchPoint.y) / _viewTouchUpdateCount;
_inputDevice->_axisStateMap[controller::RX].value =
_viewTouchUpdateCount == 0 ? 0 : (_viewCurrentTouchPoint.x - _viewRefTouchPoint.x) / _viewTouchUpdateCount;
_inputDevice->_axisStateMap[controller::RY].value =
_viewTouchUpdateCount == 0 ? 0 : (_viewCurrentTouchPoint.y - _viewRefTouchPoint.y) / _viewTouchUpdateCount;
// after use, save last touch point as ref
_viewRefTouchPoint = _viewCurrentTouchPoint;
@ -442,8 +444,8 @@ void TouchscreenVirtualPadDevice::moveTouchUpdate(glm::vec2 touchPoint) {
void TouchscreenVirtualPadDevice::moveTouchEnd() {
if (_moveHasValidTouch) { // do stuff once
_moveHasValidTouch = false;
_inputDevice->_axisStateMap[controller::LX] = 0;
_inputDevice->_axisStateMap[controller::LY] = 0;
_inputDevice->_axisStateMap[controller::LX].value = 0;
_inputDevice->_axisStateMap[controller::LY].value = 0;
}
}
@ -465,8 +467,8 @@ void TouchscreenVirtualPadDevice::viewTouchUpdate(glm::vec2 touchPoint) {
void TouchscreenVirtualPadDevice::viewTouchEnd() {
if (_viewHasValidTouch) { // do stuff once
_viewHasValidTouch = false;
_inputDevice->_axisStateMap[controller::RX] = 0;
_inputDevice->_axisStateMap[controller::RY] = 0;
_inputDevice->_axisStateMap[controller::RX].value = 0;
_inputDevice->_axisStateMap[controller::RY].value = 0;
}
}

View file

@ -46,8 +46,8 @@ void Joystick::closeJoystick() {
void Joystick::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
for (auto axisState : _axisStateMap) {
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
_axisStateMap[axisState.first] = 0.0f;
if (fabsf(axisState.second.value) < CONTROLLER_THRESHOLD) {
_axisStateMap[axisState.first].value = 0.0f;
}
}
}
@ -59,7 +59,7 @@ void Joystick::focusOutEvent() {
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()].value = (float)event.value / MAX_AXIS;
}
void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {

View file

@ -258,15 +258,15 @@ void OculusControllerManager::TouchDevice::update(float deltaTime,
using namespace controller;
// Axes
const auto& inputState = _parent._touchInputState;
_axisStateMap[LX] = inputState.Thumbstick[ovrHand_Left].x;
_axisStateMap[LY] = inputState.Thumbstick[ovrHand_Left].y;
_axisStateMap[LT] = inputState.IndexTrigger[ovrHand_Left];
_axisStateMap[LEFT_GRIP] = inputState.HandTrigger[ovrHand_Left];
_axisStateMap[LX].value = inputState.Thumbstick[ovrHand_Left].x;
_axisStateMap[LY].value = inputState.Thumbstick[ovrHand_Left].y;
_axisStateMap[LT].value = inputState.IndexTrigger[ovrHand_Left];
_axisStateMap[LEFT_GRIP].value = inputState.HandTrigger[ovrHand_Left];
_axisStateMap[RX] = inputState.Thumbstick[ovrHand_Right].x;
_axisStateMap[RY] = inputState.Thumbstick[ovrHand_Right].y;
_axisStateMap[RT] = inputState.IndexTrigger[ovrHand_Right];
_axisStateMap[RIGHT_GRIP] = inputState.HandTrigger[ovrHand_Right];
_axisStateMap[RX].value = inputState.Thumbstick[ovrHand_Right].x;
_axisStateMap[RY].value = inputState.Thumbstick[ovrHand_Right].y;
_axisStateMap[RT].value = inputState.IndexTrigger[ovrHand_Right];
_axisStateMap[RIGHT_GRIP].value = inputState.HandTrigger[ovrHand_Right];
// Buttons
for (const auto& pair : BUTTON_MAP) {

View file

@ -928,8 +928,8 @@ void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxi
const float CENTER_DEADBAND = 0.6f;
const float DIAGONAL_DIVIDE_IN_RADIANS = PI / 4.0f;
if (_buttonPressedMap.find(sButton) != _buttonPressedMap.end()) {
float absX = abs(_axisStateMap[xAxis]);
float absY = abs(_axisStateMap[yAxis]);
float absX = abs(_axisStateMap[xAxis].value);
float absY = abs(_axisStateMap[yAxis].value);
glm::vec2 cartesianQuadrantI(absX, absY);
float angle = glm::atan(cartesianQuadrantI.y / cartesianQuadrantI.x);
float radius = glm::length(cartesianQuadrantI);
@ -956,10 +956,10 @@ void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32
} else {
stick = _filteredRightStick.process(deltaTime, stick);
}
_axisStateMap[isLeftHand ? LX : RX] = stick.x;
_axisStateMap[isLeftHand ? LY : RY] = stick.y;
_axisStateMap[isLeftHand ? LX : RX].value = stick.x;
_axisStateMap[isLeftHand ? LY : RY].value = stick.y;
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
_axisStateMap[isLeftHand ? LT : RT] = x;
_axisStateMap[isLeftHand ? LT : RT].value = x;
// The click feeling on the Vive controller trigger represents a value of *precisely* 1.0,
// so we can expose that as an additional button
if (x >= 1.0f) {
@ -1000,7 +1000,7 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint
if (button == vr::k_EButton_ApplicationMenu) {
_buttonPressedMap.insert(isLeftHand ? LEFT_APP_MENU : RIGHT_APP_MENU);
} else if (button == vr::k_EButton_Grip) {
_axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP] = 1.0f;
_axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP].value = 1.0f;
} else if (button == vr::k_EButton_SteamVR_Trigger) {
_buttonPressedMap.insert(isLeftHand ? LT : RT);
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
@ -1008,7 +1008,7 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint
}
} else {
if (button == vr::k_EButton_Grip) {
_axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP] = 0.0f;
_axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP].value = 0.0f;
}
}