Add EnumArray to implement enum-indexed arrays

This commit is contained in:
kimci86 2023-12-17 02:31:25 +01:00 committed by GitHub
parent 92826e1c1f
commit a474654ea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 272 additions and 174 deletions

View File

@ -30,6 +30,8 @@
#include <SFML/Window/EglContext.hpp> #include <SFML/Window/EglContext.hpp>
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/System/EnumArray.hpp>
#include <android/configuration.h> #include <android/configuration.h>
#include <android/native_activity.h> #include <android/native_activity.h>
@ -73,9 +75,9 @@ struct ActivityStates
void (*forwardEvent)(const Event& event){}; void (*forwardEvent)(const Event& event){};
int (*processEvent)(int fd, int events, void* data){}; int (*processEvent)(int fd, int events, void* data){};
std::unordered_map<int, Vector2i> touchEvents; std::unordered_map<int, Vector2i> touchEvents;
Vector2i mousePosition; Vector2i mousePosition;
bool isButtonPressed[Mouse::ButtonCount]{}; EnumArray<Mouse::Button, bool, Mouse::ButtonCount> isButtonPressed{};
bool mainOver{}; bool mainOver{};

View File

@ -7,6 +7,7 @@ set(SRC
${INCROOT}/Angle.inl ${INCROOT}/Angle.inl
${SRCROOT}/Clock.cpp ${SRCROOT}/Clock.cpp
${INCROOT}/Clock.hpp ${INCROOT}/Clock.hpp
${SRCROOT}/EnumArray.hpp
${SRCROOT}/Err.cpp ${SRCROOT}/Err.cpp
${INCROOT}/Err.hpp ${INCROOT}/Err.hpp
${INCROOT}/Export.hpp ${INCROOT}/Export.hpp

View File

@ -0,0 +1,75 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <array>
#include <type_traits>
#include <cassert>
#include <cstddef>
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief Fixed-size array container indexed by an enumeration
///
////////////////////////////////////////////////////////////
template <typename Enum, typename Value, std::size_t Count>
struct EnumArray : public std::array<Value, Count>
{
static_assert(std::is_enum_v<Enum>, "Enum type parameter must be an enumeration");
////////////////////////////////////////////////////////////
/// \brief Returns a reference to the element associated to specified \a key
///
/// No bounds checking is performed in release builds.
///
////////////////////////////////////////////////////////////
constexpr Value& operator[](Enum key)
{
const auto index = static_cast<std::size_t>(key);
assert(index < Count && "Index is out of bounds");
return std::array<Value, Count>::operator[](index);
}
////////////////////////////////////////////////////////////
/// \brief Returns a reference to the element associated to specified \a key
///
/// No bounds checking is performed in release builds.
///
////////////////////////////////////////////////////////////
constexpr const Value& operator[](Enum key) const
{
const auto index = static_cast<std::size_t>(key);
assert(index < Count && "Index is out of bounds");
return std::array<Value, Count>::operator[](index);
}
};
} // namespace sf::priv

View File

@ -171,7 +171,7 @@ bool isMouseButtonPressed(Mouse::Button button)
ActivityStates& states = getActivity(); ActivityStates& states = getActivity();
const std::lock_guard lock(states.mutex); const std::lock_guard lock(states.mutex);
return states.isButtonPressed[static_cast<int>(button)]; return states.isButtonPressed[button];
} }

View File

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/SensorImpl.hpp> #include <SFML/Window/SensorImpl.hpp>
#include <SFML/System/EnumArray.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <android/looper.h> #include <android/looper.h>
@ -44,10 +45,10 @@
namespace namespace
{ {
ALooper* looper; ALooper* looper;
ASensorManager* sensorManager; ASensorManager* sensorManager;
ASensorEventQueue* sensorEventQueue; ASensorEventQueue* sensorEventQueue;
sf::Vector3f sensorData[sf::Sensor::Count]; sf::priv::EnumArray<sf::Sensor::Type, sf::Vector3f, sf::Sensor::Count> sensorData;
} // namespace } // namespace
@ -104,8 +105,8 @@ bool SensorImpl::open(Sensor::Type sensor)
// Set the event rate (not to consume too much battery) // Set the event rate (not to consume too much battery)
ASensorEventQueue_setEventRate(sensorEventQueue, m_sensor, static_cast<std::int32_t>(minimumDelay.asMicroseconds())); ASensorEventQueue_setEventRate(sensorEventQueue, m_sensor, static_cast<std::int32_t>(minimumDelay.asMicroseconds()));
// Save the index of the sensor // Save the type of the sensor
m_index = static_cast<unsigned int>(sensor); m_type = sensor;
return true; return true;
} }
@ -124,7 +125,7 @@ Vector3f SensorImpl::update() const
// Update our sensor data list // Update our sensor data list
ALooper_pollAll(0, nullptr, nullptr, nullptr); ALooper_pollAll(0, nullptr, nullptr, nullptr);
return sensorData[m_index]; return sensorData[m_type];
} }
@ -142,14 +143,15 @@ void SensorImpl::setEnabled(bool enabled)
const ASensor* SensorImpl::getDefaultSensor(Sensor::Type sensor) const ASensor* SensorImpl::getDefaultSensor(Sensor::Type sensor)
{ {
// Find the Android sensor type // Find the Android sensor type
static int types[] = {ASENSOR_TYPE_ACCELEROMETER, static EnumArray<Sensor::Type, int, Sensor::Count> types =
ASENSOR_TYPE_GYROSCOPE, {ASENSOR_TYPE_ACCELEROMETER,
ASENSOR_TYPE_MAGNETIC_FIELD, ASENSOR_TYPE_GYROSCOPE,
ASENSOR_TYPE_GRAVITY, ASENSOR_TYPE_MAGNETIC_FIELD,
ASENSOR_TYPE_LINEAR_ACCELERATION, ASENSOR_TYPE_GRAVITY,
ASENSOR_TYPE_ORIENTATION}; ASENSOR_TYPE_LINEAR_ACCELERATION,
ASENSOR_TYPE_ORIENTATION};
int type = types[static_cast<int>(sensor)]; int type = types[sensor];
// Retrieve the default sensor matching this type // Retrieve the default sensor matching this type
return ASensorManager_getDefaultSensor(sensorManager, type); return ASensorManager_getDefaultSensor(sensorManager, type);
@ -215,7 +217,7 @@ int SensorImpl::processSensorEvents(int /* fd */, int /* events */, void* /* sen
if (!type) if (!type)
continue; continue;
sensorData[static_cast<int>(*type)] = data; sensorData[*type] = data;
} }
return 1; return 1;

View File

@ -122,7 +122,7 @@ private:
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const ASensor* m_sensor; ///< Android sensor structure const ASensor* m_sensor; ///< Android sensor structure
unsigned int m_index; ///< Index of the sensor Sensor::Type m_type; ///< Type of the sensor
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -524,6 +524,7 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* inputEvent,
std::size_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; std::size_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
std::int32_t id = AMotionEvent_getPointerId(inputEvent, index); std::int32_t id = AMotionEvent_getPointerId(inputEvent, index);
const auto button = static_cast<Mouse::Button>(id);
int x = static_cast<int>(AMotionEvent_getX(inputEvent, index)); int x = static_cast<int>(AMotionEvent_getX(inputEvent, index));
int y = static_cast<int>(AMotionEvent_getY(inputEvent, index)); int y = static_cast<int>(AMotionEvent_getY(inputEvent, index));
@ -535,12 +536,12 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* inputEvent,
if (device == AINPUT_SOURCE_MOUSE) if (device == AINPUT_SOURCE_MOUSE)
{ {
event.type = Event::MouseButtonPressed; event.type = Event::MouseButtonPressed;
event.mouseButton.button = static_cast<Mouse::Button>(id); event.mouseButton.button = button;
event.mouseButton.x = x; event.mouseButton.x = x;
event.mouseButton.y = y; event.mouseButton.y = y;
if (id >= 0 && id < static_cast<int>(Mouse::ButtonCount)) if (id >= 0 && id < static_cast<int>(Mouse::ButtonCount))
states.isButtonPressed[id] = true; states.isButtonPressed[button] = true;
} }
else if (static_cast<unsigned int>(device) & AINPUT_SOURCE_TOUCHSCREEN) else if (static_cast<unsigned int>(device) & AINPUT_SOURCE_TOUCHSCREEN)
{ {
@ -557,12 +558,12 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* inputEvent,
if (device == AINPUT_SOURCE_MOUSE) if (device == AINPUT_SOURCE_MOUSE)
{ {
event.type = Event::MouseButtonReleased; event.type = Event::MouseButtonReleased;
event.mouseButton.button = static_cast<Mouse::Button>(id); event.mouseButton.button = button;
event.mouseButton.x = x; event.mouseButton.x = x;
event.mouseButton.y = y; event.mouseButton.y = y;
if (id >= 0 && id < static_cast<int>(Mouse::ButtonCount)) if (id >= 0 && id < static_cast<int>(Mouse::ButtonCount))
states.isButtonPressed[id] = false; states.isButtonPressed[button] = false;
} }
else if (static_cast<std::uint32_t>(device) & AINPUT_SOURCE_TOUCHSCREEN) else if (static_cast<std::uint32_t>(device) & AINPUT_SOURCE_TOUCHSCREEN)
{ {

View File

@ -28,6 +28,7 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/InputImpl.hpp> #include <SFML/Window/InputImpl.hpp>
#include <SFML/System/EnumArray.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <algorithm> #include <algorithm>
@ -60,9 +61,9 @@ struct TouchSlot
std::recursive_mutex inputMutex; // threadsafe? maybe... std::recursive_mutex inputMutex; // threadsafe? maybe...
sf::Vector2i mousePos; // current mouse position sf::Vector2i mousePos; // current mouse position
std::vector<int> fileDescriptors; // list of open file descriptors for /dev/input std::vector<int> fileDescriptors; // list of open file descriptors for /dev/input
std::vector<bool> mouseMap(sf::Mouse::ButtonCount, false); // track whether keys are down sf::priv::EnumArray<sf::Mouse::Button, bool, sf::Mouse::ButtonCount> mouseMap{}; // track whether mouse buttons are down
std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether mouse buttons are down std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether keys are down
int touchFd = -1; // file descriptor we have seen MT events on; assumes only 1 int touchFd = -1; // file descriptor we have seen MT events on; assumes only 1
std::vector<TouchSlot> touchSlots; // track the state of each touch "slot" std::vector<TouchSlot> touchSlots; // track the state of each touch "slot"
@ -392,7 +393,7 @@ bool eventProcess(sf::Event& event)
event.mouseButton.x = mousePos.x; event.mouseButton.x = mousePos.x;
event.mouseButton.y = mousePos.y; event.mouseButton.y = mousePos.y;
mouseMap[static_cast<std::size_t>(*mb)] = inputEvent.value; mouseMap[*mb] = inputEvent.value;
return true; return true;
} }
else else
@ -632,7 +633,7 @@ bool isMouseButtonPressed(Mouse::Button button)
return false; return false;
update(); update();
return mouseMap[static_cast<std::size_t>(button)]; return mouseMap[button];
} }

View File

@ -159,8 +159,8 @@ std::optional<sf::Joystick::Axis> usageToAxis(int usage)
void hatValueToSfml(int value, sf::priv::JoystickState& state) void hatValueToSfml(int value, sf::priv::JoystickState& state)
{ {
state.axes[static_cast<int>(sf::Joystick::Axis::PovX)] = static_cast<float>(hatValueMap[value].first); state.axes[sf::Joystick::Axis::PovX] = static_cast<float>(hatValueMap[value].first);
state.axes[static_cast<int>(sf::Joystick::Axis::PovY)] = static_cast<float>(hatValueMap[value].second); state.axes[sf::Joystick::Axis::PovY] = static_cast<float>(hatValueMap[value].second);
} }
} // namespace } // namespace
@ -271,12 +271,12 @@ JoystickCaps JoystickImpl::getCapabilities() const
{ {
if (usage == HUG_HAT_SWITCH) if (usage == HUG_HAT_SWITCH)
{ {
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = true; caps.axes[Joystick::Axis::PovX] = true;
caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true; caps.axes[Joystick::Axis::PovY] = true;
} }
else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage)) else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage))
{ {
caps.axes[static_cast<int>(*axis)] = true; caps.axes[*axis] = true;
} }
} }
} }
@ -332,8 +332,8 @@ JoystickState JoystickImpl::JoystickImpl::update()
int minimum = item.logical_minimum; int minimum = item.logical_minimum;
int maximum = item.logical_maximum; int maximum = item.logical_maximum;
value = (value - minimum) * 200 / (maximum - minimum) - 100; value = (value - minimum) * 200 / (maximum - minimum) - 100;
m_state.axes[static_cast<int>(*axis)] = static_cast<float>(value); m_state.axes[*axis] = static_cast<float>(value);
} }
} }
} }

View File

@ -50,7 +50,7 @@ unsigned int Joystick::getButtonCount(unsigned int joystick)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Joystick::hasAxis(unsigned int joystick, Axis axis) bool Joystick::hasAxis(unsigned int joystick, Axis axis)
{ {
return priv::JoystickManager::getInstance().getCapabilities(joystick).axes[static_cast<int>(axis)]; return priv::JoystickManager::getInstance().getCapabilities(joystick).axes[axis];
} }
@ -65,7 +65,7 @@ bool Joystick::isButtonPressed(unsigned int joystick, unsigned int button)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
float Joystick::getAxisPosition(unsigned int joystick, Axis axis) float Joystick::getAxisPosition(unsigned int joystick, Axis axis)
{ {
return priv::JoystickManager::getInstance().getState(joystick).axes[static_cast<int>(axis)]; return priv::JoystickManager::getInstance().getState(joystick).axes[axis];
} }

View File

@ -31,6 +31,8 @@
#include <SFML/Window/Joystick.hpp> #include <SFML/Window/Joystick.hpp>
#include <SFML/System/EnumArray.hpp>
namespace sf::priv namespace sf::priv
{ {
@ -40,8 +42,8 @@ namespace sf::priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
struct JoystickCaps struct JoystickCaps
{ {
unsigned int buttonCount{}; //!< Number of buttons supported by the joystick unsigned int buttonCount{}; //!< Number of buttons supported by the joystick
bool axes[Joystick::AxisCount]{}; //!< Support for each axis EnumArray<Joystick::Axis, bool, Joystick::AxisCount> axes{}; //!< Support for each axis
}; };
@ -51,9 +53,9 @@ struct JoystickCaps
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
struct JoystickState struct JoystickState
{ {
bool connected{}; //!< Is the joystick currently connected? bool connected{}; //!< Is the joystick currently connected?
float axes[Joystick::AxisCount]{}; //!< Position of each axis, in range [-100, 100] EnumArray<Joystick::Axis, float, Joystick::AxisCount> axes{}; //!< Position of each axis, in range [-100, 100]
bool buttons[Joystick::ButtonCount]{}; //!< Status of each button (true = pressed) bool buttons[Joystick::ButtonCount]{}; //!< Status of each button (true = pressed)
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -160,8 +160,8 @@ std::optional<sf::Joystick::Axis> usageToAxis(int usage)
void hatValueToSfml(int value, sf::priv::JoystickState& state) void hatValueToSfml(int value, sf::priv::JoystickState& state)
{ {
state.axes[static_cast<int>(sf::Joystick::Axis::PovX)] = static_cast<float>(hatValueMap[value].first); state.axes[sf::Joystick::Axis::PovX] = static_cast<float>(hatValueMap[value].first);
state.axes[static_cast<int>(sf::Joystick::Axis::PovY)] = static_cast<float>(hatValueMap[value].second); state.axes[sf::Joystick::Axis::PovY] = static_cast<float>(hatValueMap[value].second);
} }
} // namespace } // namespace
@ -276,12 +276,12 @@ JoystickCaps JoystickImpl::getCapabilities() const
{ {
if (usage == HUG_HAT_SWITCH) if (usage == HUG_HAT_SWITCH)
{ {
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = true; caps.axes[Joystick::Axis::PovX] = true;
caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true; caps.axes[Joystick::Axis::PovY] = true;
} }
else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage)) else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage))
{ {
caps.axes[static_cast<int>(*axis)] = true; caps.axes[*axis] = true;
} }
} }
} }
@ -337,8 +337,8 @@ JoystickState JoystickImpl::JoystickImpl::update()
int minimum = item.logical_minimum; int minimum = item.logical_minimum;
int maximum = item.logical_maximum; int maximum = item.logical_maximum;
value = (value - minimum) * 200 / (maximum - minimum) - 100; value = (value - minimum) * 200 / (maximum - minimum) - 100;
m_state.axes[static_cast<int>(*axis)] = value; m_state.axes[*axis] = value;
} }
} }
} }

View File

@ -45,17 +45,17 @@ SensorManager& SensorManager::getInstance()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SensorManager::isAvailable(Sensor::Type sensor) bool SensorManager::isAvailable(Sensor::Type sensor)
{ {
return m_sensors[static_cast<int>(sensor)].available; return m_sensors[sensor].available;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SensorManager::setEnabled(Sensor::Type sensor, bool enabled) void SensorManager::setEnabled(Sensor::Type sensor, bool enabled)
{ {
if (m_sensors[static_cast<int>(sensor)].available) if (m_sensors[sensor].available)
{ {
m_sensors[static_cast<int>(sensor)].enabled = enabled; m_sensors[sensor].enabled = enabled;
m_sensors[static_cast<int>(sensor)].sensor.setEnabled(enabled); m_sensors[sensor].sensor.setEnabled(enabled);
} }
else else
{ {
@ -68,14 +68,14 @@ void SensorManager::setEnabled(Sensor::Type sensor, bool enabled)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SensorManager::isEnabled(Sensor::Type sensor) const bool SensorManager::isEnabled(Sensor::Type sensor) const
{ {
return m_sensors[static_cast<int>(sensor)].enabled; return m_sensors[sensor].enabled;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector3f SensorManager::getValue(Sensor::Type sensor) const Vector3f SensorManager::getValue(Sensor::Type sensor) const
{ {
return m_sensors[static_cast<int>(sensor)].value; return m_sensors[sensor].value;
} }
@ -100,19 +100,21 @@ SensorManager::SensorManager()
// Per sensor initialization // Per sensor initialization
for (unsigned int i = 0; i < Sensor::Count; ++i) for (unsigned int i = 0; i < Sensor::Count; ++i)
{ {
const auto sensor = static_cast<Sensor::Type>(i);
// Check which sensors are available // Check which sensors are available
m_sensors[i].available = SensorImpl::isAvailable(static_cast<Sensor::Type>(i)); m_sensors[sensor].available = SensorImpl::isAvailable(sensor);
// Open the available sensors // Open the available sensors
if (m_sensors[i].available) if (m_sensors[sensor].available)
{ {
if (m_sensors[i].sensor.open(static_cast<Sensor::Type>(i))) if (m_sensors[sensor].sensor.open(sensor))
{ {
m_sensors[i].sensor.setEnabled(false); m_sensors[sensor].sensor.setEnabled(false);
} }
else else
{ {
m_sensors[i].available = false; m_sensors[sensor].available = false;
err() << "Warning: sensor " << i << " failed to open, will not be available" << std::endl; err() << "Warning: sensor " << i << " failed to open, will not be available" << std::endl;
} }
} }

View File

@ -30,6 +30,8 @@
#include <SFML/Window/Sensor.hpp> #include <SFML/Window/Sensor.hpp>
#include <SFML/Window/SensorImpl.hpp> #include <SFML/Window/SensorImpl.hpp>
#include <SFML/System/EnumArray.hpp>
namespace sf::priv namespace sf::priv
{ {
@ -133,7 +135,7 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Item m_sensors[Sensor::Count]; //!< Sensors information and state EnumArray<Sensor::Type, Item, Sensor::Count> m_sensors; //!< Sensors information and state
}; };
} // namespace sf::priv } // namespace sf::priv

View File

@ -603,17 +603,17 @@ JoystickCaps JoystickImpl::getCapabilities() const
switch (m_mapping[i]) switch (m_mapping[i])
{ {
// clang-format off // clang-format off
case ABS_X: caps.axes[static_cast<int>(Joystick::Axis::X)] = true; break; case ABS_X: caps.axes[Joystick::Axis::X] = true; break;
case ABS_Y: caps.axes[static_cast<int>(Joystick::Axis::Y)] = true; break; case ABS_Y: caps.axes[Joystick::Axis::Y] = true; break;
case ABS_Z: case ABS_Z:
case ABS_THROTTLE: caps.axes[static_cast<int>(Joystick::Axis::Z)] = true; break; case ABS_THROTTLE: caps.axes[Joystick::Axis::Z] = true; break;
case ABS_RZ: case ABS_RZ:
case ABS_RUDDER: caps.axes[static_cast<int>(Joystick::Axis::R)] = true; break; case ABS_RUDDER: caps.axes[Joystick::Axis::R] = true; break;
case ABS_RX: caps.axes[static_cast<int>(Joystick::Axis::U)] = true; break; case ABS_RX: caps.axes[Joystick::Axis::U] = true; break;
case ABS_RY: caps.axes[static_cast<int>(Joystick::Axis::V)] = true; break; case ABS_RY: caps.axes[Joystick::Axis::V] = true; break;
case ABS_HAT0X: caps.axes[static_cast<int>(Joystick::Axis::PovX)] = true; break; case ABS_HAT0X: caps.axes[Joystick::Axis::PovX] = true; break;
case ABS_HAT0Y: caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true; break; case ABS_HAT0Y: caps.axes[Joystick::Axis::PovY] = true; break;
default: break; default: break;
// clang-format on // clang-format on
} }
} }
@ -655,30 +655,30 @@ JoystickState JoystickImpl::JoystickImpl::update()
switch (m_mapping[joyState.number]) switch (m_mapping[joyState.number])
{ {
case ABS_X: case ABS_X:
m_state.axes[static_cast<int>(Joystick::Axis::X)] = value; m_state.axes[Joystick::Axis::X] = value;
break; break;
case ABS_Y: case ABS_Y:
m_state.axes[static_cast<int>(Joystick::Axis::Y)] = value; m_state.axes[Joystick::Axis::Y] = value;
break; break;
case ABS_Z: case ABS_Z:
case ABS_THROTTLE: case ABS_THROTTLE:
m_state.axes[static_cast<int>(Joystick::Axis::Z)] = value; m_state.axes[Joystick::Axis::Z] = value;
break; break;
case ABS_RZ: case ABS_RZ:
case ABS_RUDDER: case ABS_RUDDER:
m_state.axes[static_cast<int>(Joystick::Axis::R)] = value; m_state.axes[Joystick::Axis::R] = value;
break; break;
case ABS_RX: case ABS_RX:
m_state.axes[static_cast<int>(Joystick::Axis::U)] = value; m_state.axes[Joystick::Axis::U] = value;
break; break;
case ABS_RY: case ABS_RY:
m_state.axes[static_cast<int>(Joystick::Axis::V)] = value; m_state.axes[Joystick::Axis::V] = value;
break; break;
case ABS_HAT0X: case ABS_HAT0X:
m_state.axes[static_cast<int>(Joystick::Axis::PovX)] = value; m_state.axes[Joystick::Axis::PovX] = value;
break; break;
case ABS_HAT0Y: case ABS_HAT0Y:
m_state.axes[static_cast<int>(Joystick::Axis::PovY)] = value; m_state.axes[Joystick::Axis::PovY] = value;
break; break;
default: default:
break; break;

View File

@ -331,14 +331,14 @@ JoystickCaps JoystickImpl::getCapabilities() const
if (caps.buttonCount > Joystick::ButtonCount) if (caps.buttonCount > Joystick::ButtonCount)
caps.buttonCount = Joystick::ButtonCount; caps.buttonCount = Joystick::ButtonCount;
caps.axes[static_cast<int>(Joystick::Axis::X)] = true; caps.axes[Joystick::Axis::X] = true;
caps.axes[static_cast<int>(Joystick::Axis::Y)] = true; caps.axes[Joystick::Axis::Y] = true;
caps.axes[static_cast<int>(Joystick::Axis::Z)] = (m_caps.wCaps & JOYCAPS_HASZ) != 0; caps.axes[Joystick::Axis::Z] = (m_caps.wCaps & JOYCAPS_HASZ) != 0;
caps.axes[static_cast<int>(Joystick::Axis::R)] = (m_caps.wCaps & JOYCAPS_HASR) != 0; caps.axes[Joystick::Axis::R] = (m_caps.wCaps & JOYCAPS_HASR) != 0;
caps.axes[static_cast<int>(Joystick::Axis::U)] = (m_caps.wCaps & JOYCAPS_HASU) != 0; caps.axes[Joystick::Axis::U] = (m_caps.wCaps & JOYCAPS_HASU) != 0;
caps.axes[static_cast<int>(Joystick::Axis::V)] = (m_caps.wCaps & JOYCAPS_HASV) != 0; caps.axes[Joystick::Axis::V] = (m_caps.wCaps & JOYCAPS_HASV) != 0;
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0; caps.axes[Joystick::Axis::PovX] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
caps.axes[static_cast<int>(Joystick::Axis::PovY)] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0; caps.axes[Joystick::Axis::PovY] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
return caps; return caps;
} }
@ -379,36 +379,36 @@ JoystickState JoystickImpl::update()
state.connected = true; state.connected = true;
// Axes // Axes
state.axes[static_cast<int>(Joystick::Axis::X)] = (static_cast<float>(pos.dwXpos) - state.axes[Joystick::Axis::X] = (static_cast<float>(pos.dwXpos) -
static_cast<float>(m_caps.wXmax + m_caps.wXmin) / 2.f) * static_cast<float>(m_caps.wXmax + m_caps.wXmin) / 2.f) *
200.f / static_cast<float>(m_caps.wXmax - m_caps.wXmin); 200.f / static_cast<float>(m_caps.wXmax - m_caps.wXmin);
state.axes[static_cast<int>(Joystick::Axis::Y)] = (static_cast<float>(pos.dwYpos) - state.axes[Joystick::Axis::Y] = (static_cast<float>(pos.dwYpos) -
static_cast<float>(m_caps.wYmax + m_caps.wYmin) / 2.f) * static_cast<float>(m_caps.wYmax + m_caps.wYmin) / 2.f) *
200.f / static_cast<float>(m_caps.wYmax - m_caps.wYmin); 200.f / static_cast<float>(m_caps.wYmax - m_caps.wYmin);
state.axes[static_cast<int>(Joystick::Axis::Z)] = (static_cast<float>(pos.dwZpos) - state.axes[Joystick::Axis::Z] = (static_cast<float>(pos.dwZpos) -
static_cast<float>(m_caps.wZmax + m_caps.wZmin) / 2.f) * static_cast<float>(m_caps.wZmax + m_caps.wZmin) / 2.f) *
200.f / static_cast<float>(m_caps.wZmax - m_caps.wZmin); 200.f / static_cast<float>(m_caps.wZmax - m_caps.wZmin);
state.axes[static_cast<int>(Joystick::Axis::R)] = (static_cast<float>(pos.dwRpos) - state.axes[Joystick::Axis::R] = (static_cast<float>(pos.dwRpos) -
static_cast<float>(m_caps.wRmax + m_caps.wRmin) / 2.f) * static_cast<float>(m_caps.wRmax + m_caps.wRmin) / 2.f) *
200.f / static_cast<float>(m_caps.wRmax - m_caps.wRmin); 200.f / static_cast<float>(m_caps.wRmax - m_caps.wRmin);
state.axes[static_cast<int>(Joystick::Axis::U)] = (static_cast<float>(pos.dwUpos) - state.axes[Joystick::Axis::U] = (static_cast<float>(pos.dwUpos) -
static_cast<float>(m_caps.wUmax + m_caps.wUmin) / 2.f) * static_cast<float>(m_caps.wUmax + m_caps.wUmin) / 2.f) *
200.f / static_cast<float>(m_caps.wUmax - m_caps.wUmin); 200.f / static_cast<float>(m_caps.wUmax - m_caps.wUmin);
state.axes[static_cast<int>(Joystick::Axis::V)] = (static_cast<float>(pos.dwVpos) - state.axes[Joystick::Axis::V] = (static_cast<float>(pos.dwVpos) -
static_cast<float>(m_caps.wVmax + m_caps.wVmin) / 2.f) * static_cast<float>(m_caps.wVmax + m_caps.wVmin) / 2.f) *
200.f / static_cast<float>(m_caps.wVmax - m_caps.wVmin); 200.f / static_cast<float>(m_caps.wVmax - m_caps.wVmin);
// Special case for POV, it is given as an angle // Special case for POV, it is given as an angle
if (pos.dwPOV != 0xFFFF) if (pos.dwPOV != 0xFFFF)
{ {
const float angle = static_cast<float>(pos.dwPOV) / 18000.f * 3.141592654f; const float angle = static_cast<float>(pos.dwPOV) / 18000.f * 3.141592654f;
state.axes[static_cast<int>(Joystick::Axis::PovX)] = std::sin(angle) * 100; state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100; state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100;
} }
else else
{ {
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0; state.axes[Joystick::Axis::PovX] = 0;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0; state.axes[Joystick::Axis::PovY] = 0;
} }
// Buttons // Buttons
@ -877,7 +877,10 @@ JoystickCaps JoystickImpl::getCapabilitiesDInput() const
// Check which axes have valid offsets // Check which axes have valid offsets
for (unsigned int i = 0; i < Joystick::AxisCount; ++i) for (unsigned int i = 0; i < Joystick::AxisCount; ++i)
caps.axes[i] = (m_axes[i] != -1); {
const auto axis = static_cast<Joystick::Axis>(i);
caps.axes[axis] = (m_axes[axis] != -1);
}
return caps; return caps;
} }
@ -929,9 +932,10 @@ JoystickState JoystickImpl::updateDInputBuffered()
// Get the current state of each axis // Get the current state of each axis
for (unsigned int j = 0; j < Joystick::AxisCount; ++j) for (unsigned int j = 0; j < Joystick::AxisCount; ++j)
{ {
if (m_axes[j] == static_cast<int>(events[i].dwOfs)) const auto axis = static_cast<Joystick::Axis>(j);
if (m_axes[axis] == static_cast<int>(events[i].dwOfs))
{ {
if ((j == static_cast<int>(Joystick::Axis::PovX)) || (j == static_cast<int>(Joystick::Axis::PovY))) if ((axis == Joystick::Axis::PovX) || (axis == Joystick::Axis::PovY))
{ {
const unsigned short value = LOWORD(events[i].dwData); const unsigned short value = LOWORD(events[i].dwData);
@ -939,18 +943,18 @@ JoystickState JoystickImpl::updateDInputBuffered()
{ {
const float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f; const float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
m_state.axes[static_cast<int>(Joystick::Axis::PovX)] = std::sin(angle) * 100.f; m_state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100.f;
m_state.axes[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100.f; m_state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100.f;
} }
else else
{ {
m_state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0.f; m_state.axes[Joystick::Axis::PovX] = 0.f;
m_state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0.f; m_state.axes[Joystick::Axis::PovY] = 0.f;
} }
} }
else else
{ {
m_state.axes[j] = (static_cast<float>(static_cast<short>(events[i].dwData)) + 0.5f) * 100.f / 32767.5f; m_state.axes[axis] = (static_cast<float>(static_cast<short>(events[i].dwData)) + 0.5f) * 100.f / 32767.5f;
} }
eventHandled = true; eventHandled = true;
@ -1018,37 +1022,38 @@ JoystickState JoystickImpl::updateDInputPolled()
// Get the current state of each axis // Get the current state of each axis
for (unsigned int i = 0; i < Joystick::AxisCount; ++i) for (unsigned int i = 0; i < Joystick::AxisCount; ++i)
{ {
if (m_axes[i] != -1) const auto axis = static_cast<Joystick::Axis>(i);
if (m_axes[axis] != -1)
{ {
if ((i == static_cast<int>(Joystick::Axis::PovX)) || (i == static_cast<int>(Joystick::Axis::PovY))) if ((axis == Joystick::Axis::PovX) || (axis == Joystick::Axis::PovY))
{ {
const unsigned short value = LOWORD( const unsigned short value = LOWORD(
*reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[i])); *reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[axis]));
if (value != 0xFFFF) if (value != 0xFFFF)
{ {
const float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f; const float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
state.axes[static_cast<int>(Joystick::Axis::PovX)] = std::sin(angle) * 100.f; state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100.f;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100.f; state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100.f;
} }
else else
{ {
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0.f; state.axes[Joystick::Axis::PovX] = 0.f;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0.f; state.axes[Joystick::Axis::PovY] = 0.f;
} }
} }
else else
{ {
state.axes[i] = (static_cast<float>(*reinterpret_cast<const LONG*>( state.axes[axis] = (static_cast<float>(*reinterpret_cast<const LONG*>(
reinterpret_cast<const char*>(&joystate) + m_axes[i])) + reinterpret_cast<const char*>(&joystate) + m_axes[axis])) +
0.5f) * 0.5f) *
100.f / 32767.5f; 100.f / 32767.5f;
} }
} }
else else
{ {
state.axes[i] = 0.f; state.axes[axis] = 0.f;
} }
} }
@ -1103,23 +1108,23 @@ BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECT
{ {
// Axes // Axes
if (deviceObjectInstance->guidType == guids::GUID_XAxis) if (deviceObjectInstance->guidType == guids::GUID_XAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::X)] = DIJOFS_X; joystick.m_axes[Joystick::Axis::X] = DIJOFS_X;
else if (deviceObjectInstance->guidType == guids::GUID_YAxis) else if (deviceObjectInstance->guidType == guids::GUID_YAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::Y)] = DIJOFS_Y; joystick.m_axes[Joystick::Axis::Y] = DIJOFS_Y;
else if (deviceObjectInstance->guidType == guids::GUID_ZAxis) else if (deviceObjectInstance->guidType == guids::GUID_ZAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::Z)] = DIJOFS_Z; joystick.m_axes[Joystick::Axis::Z] = DIJOFS_Z;
else if (deviceObjectInstance->guidType == guids::GUID_RzAxis) else if (deviceObjectInstance->guidType == guids::GUID_RzAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::R)] = DIJOFS_RZ; joystick.m_axes[Joystick::Axis::R] = DIJOFS_RZ;
else if (deviceObjectInstance->guidType == guids::GUID_RxAxis) else if (deviceObjectInstance->guidType == guids::GUID_RxAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::U)] = DIJOFS_RX; joystick.m_axes[Joystick::Axis::U] = DIJOFS_RX;
else if (deviceObjectInstance->guidType == guids::GUID_RyAxis) else if (deviceObjectInstance->guidType == guids::GUID_RyAxis)
joystick.m_axes[static_cast<int>(Joystick::Axis::V)] = DIJOFS_RY; joystick.m_axes[Joystick::Axis::V] = DIJOFS_RY;
else if (deviceObjectInstance->guidType == guids::GUID_Slider) else if (deviceObjectInstance->guidType == guids::GUID_Slider)
{ {
if (joystick.m_axes[static_cast<int>(Joystick::Axis::U)] == -1) if (joystick.m_axes[Joystick::Axis::U] == -1)
joystick.m_axes[static_cast<int>(Joystick::Axis::U)] = DIJOFS_SLIDER(0); joystick.m_axes[Joystick::Axis::U] = DIJOFS_SLIDER(0);
else else
joystick.m_axes[static_cast<int>(Joystick::Axis::V)] = DIJOFS_SLIDER(1); joystick.m_axes[Joystick::Axis::V] = DIJOFS_SLIDER(1);
} }
else else
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
@ -1145,10 +1150,10 @@ BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECT
// POVs // POVs
if (deviceObjectInstance->guidType == guids::GUID_POV) if (deviceObjectInstance->guidType == guids::GUID_POV)
{ {
if (joystick.m_axes[static_cast<int>(Joystick::Axis::PovX)] == -1) if (joystick.m_axes[Joystick::Axis::PovX] == -1)
{ {
joystick.m_axes[static_cast<int>(Joystick::Axis::PovX)] = DIJOFS_POV(0); joystick.m_axes[Joystick::Axis::PovX] = DIJOFS_POV(0);
joystick.m_axes[static_cast<int>(Joystick::Axis::PovY)] = DIJOFS_POV(0); joystick.m_axes[Joystick::Axis::PovY] = DIJOFS_POV(0);
} }
} }

View File

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/System/EnumArray.hpp>
#include <SFML/System/Win32/WindowsHeader.hpp> #include <SFML/System/Win32/WindowsHeader.hpp>
#include <dinput.h> #include <dinput.h>
@ -212,11 +213,11 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int m_index{}; //!< Index of the joystick unsigned int m_index{}; //!< Index of the joystick
JOYCAPS m_caps{}; //!< Joystick capabilities JOYCAPS m_caps{}; //!< Joystick capabilities
IDirectInputDevice8W* m_device{}; //!< DirectInput 8.x device IDirectInputDevice8W* m_device{}; //!< DirectInput 8.x device
DIDEVCAPS m_deviceCaps{}; //!< DirectInput device capabilities DIDEVCAPS m_deviceCaps{}; //!< DirectInput device capabilities
int m_axes[Joystick::AxisCount]{}; //!< Offsets to the bytes containing the axes states, -1 if not available EnumArray<Joystick::Axis, int, Joystick::AxisCount> m_axes{}; //!< Offsets to the bytes containing the axes states, -1 if not available
int m_buttons[Joystick::ButtonCount]{}; //!< Offsets to the bytes containing the button states, -1 if not available int m_buttons[Joystick::ButtonCount]{}; //!< Offsets to the bytes containing the button states, -1 if not available
Joystick::Identification m_identification; //!< Joystick identification Joystick::Identification m_identification; //!< Joystick identification
JoystickState m_state; //!< Buffered joystick state JoystickState m_state; //!< Buffered joystick state

View File

@ -34,7 +34,6 @@
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <algorithm>
#include <memory> #include <memory>
#include <cmath> #include <cmath>
@ -122,7 +121,7 @@ WindowImpl::WindowImpl() : m_joystickStatesImpl(std::make_unique<JoystickStatesI
for (unsigned int i = 0; i < Joystick::Count; ++i) for (unsigned int i = 0; i < Joystick::Count; ++i)
{ {
m_joystickStatesImpl->states[i] = JoystickManager::getInstance().getState(i); m_joystickStatesImpl->states[i] = JoystickManager::getInstance().getState(i);
std::fill_n(m_previousAxes[i], static_cast<std::size_t>(Joystick::AxisCount), 0.f); m_previousAxes[i].fill(0.f);
} }
// Get the initial sensor states // Get the initial sensor states
@ -240,7 +239,7 @@ void WindowImpl::processJoystickEvents()
// Clear previous axes positions // Clear previous axes positions
if (connected) if (connected)
std::fill_n(m_previousAxes[i], static_cast<std::size_t>(Joystick::AxisCount), 0.f); m_previousAxes[i].fill(0.f);
} }
if (connected) if (connected)
@ -250,20 +249,21 @@ void WindowImpl::processJoystickEvents()
// Axes // Axes
for (unsigned int j = 0; j < Joystick::AxisCount; ++j) for (unsigned int j = 0; j < Joystick::AxisCount; ++j)
{ {
if (caps.axes[j]) const auto axis = static_cast<Joystick::Axis>(j);
if (caps.axes[axis])
{ {
const float prevPos = m_previousAxes[i][j]; const float prevPos = m_previousAxes[i][axis];
const float currPos = m_joystickStatesImpl->states[i].axes[j]; const float currPos = m_joystickStatesImpl->states[i].axes[axis];
if (std::abs(currPos - prevPos) >= m_joystickThreshold) if (std::abs(currPos - prevPos) >= m_joystickThreshold)
{ {
Event event; Event event;
event.type = Event::JoystickMoved; event.type = Event::JoystickMoved;
event.joystickMove.joystickId = i; event.joystickMove.joystickId = i;
event.joystickMove.axis = static_cast<Joystick::Axis>(j); event.joystickMove.axis = axis;
event.joystickMove.position = currPos; event.joystickMove.position = currPos;
pushEvent(event); pushEvent(event);
m_previousAxes[i][j] = currPos; m_previousAxes[i][axis] = currPos;
} }
} }
} }
@ -302,18 +302,18 @@ void WindowImpl::processSensorEvents()
if (SensorManager::getInstance().isEnabled(sensor)) if (SensorManager::getInstance().isEnabled(sensor))
{ {
// Copy the previous value of the sensor and get the new one // Copy the previous value of the sensor and get the new one
const Vector3f previousValue = m_sensorValue[i]; const Vector3f previousValue = m_sensorValue[sensor];
m_sensorValue[i] = SensorManager::getInstance().getValue(sensor); m_sensorValue[sensor] = SensorManager::getInstance().getValue(sensor);
// If the value has changed, trigger an event // If the value has changed, trigger an event
if (m_sensorValue[i] != previousValue) // TODO use a threshold? if (m_sensorValue[sensor] != previousValue) // TODO use a threshold?
{ {
Event event; Event event;
event.type = Event::SensorChanged; event.type = Event::SensorChanged;
event.sensor.type = sensor; event.sensor.type = sensor;
event.sensor.x = m_sensorValue[i].x; event.sensor.x = m_sensorValue[sensor].x;
event.sensor.y = m_sensorValue[i].y; event.sensor.y = m_sensorValue[sensor].y;
event.sensor.z = m_sensorValue[i].z; event.sensor.z = m_sensorValue[sensor].z;
pushEvent(event); pushEvent(event);
} }
} }

View File

@ -39,6 +39,9 @@
#include <SFML/Window/Vulkan.hpp> #include <SFML/Window/Vulkan.hpp>
#include <SFML/Window/WindowHandle.hpp> #include <SFML/Window/WindowHandle.hpp>
#include <SFML/System/EnumArray.hpp>
#include <array>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <queue> #include <queue>
@ -329,11 +332,12 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::queue<Event> m_events; //!< Queue of available events std::queue<Event> m_events; //!< Queue of available events
std::unique_ptr<JoystickStatesImpl> m_joystickStatesImpl; //!< Previous state of the joysticks (PImpl) std::unique_ptr<JoystickStatesImpl> m_joystickStatesImpl; //!< Previous state of the joysticks (PImpl)
Vector3f m_sensorValue[Sensor::Count]; //!< Previous value of the sensors EnumArray<Sensor::Type, Vector3f, Sensor::Count> m_sensorValue; //!< Previous value of the sensors
float m_joystickThreshold{0.1f}; //!< Joystick threshold (minimum motion for "move" event to be generated) float m_joystickThreshold{0.1f}; //!< Joystick threshold (minimum motion for "move" event to be generated)
float m_previousAxes[Joystick::Count][Joystick::AxisCount]{}; //!< Position of each axis last time a move event triggered, in range [-100, 100] std::array<EnumArray<Joystick::Axis, float, Joystick::AxisCount>, Joystick::Count>
m_previousAxes{}; //!< Position of each axis last time a move event triggered, in range [-100, 100]
std::optional<Vector2u> m_minimumSize; //!< Minimum window size std::optional<Vector2u> m_minimumSize; //!< Minimum window size
std::optional<Vector2u> m_maximumSize; //!< Maximum window size std::optional<Vector2u> m_maximumSize; //!< Maximum window size
}; };

View File

@ -377,10 +377,10 @@ JoystickCaps JoystickImpl::getCapabilities() const
// Axis: // Axis:
for (const auto& [axis, iohidElementRef] : m_axis) for (const auto& [axis, iohidElementRef] : m_axis)
caps.axes[static_cast<int>(axis)] = true; caps.axes[axis] = true;
if (m_hat != nullptr) if (m_hat != nullptr)
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true; caps.axes[Joystick::Axis::PovX] = caps.axes[Joystick::Axis::PovY] = true;
return caps; return caps;
} }
@ -480,7 +480,7 @@ JoystickState JoystickImpl::update()
const double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical); const double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
const auto scaledValue = static_cast<float>( const auto scaledValue = static_cast<float>(
(((physicalValue - physicalMin) * (scaledMax - scaledMin)) / (physicalMax - physicalMin)) + scaledMin); (((physicalValue - physicalMin) * (scaledMax - scaledMin)) / (physicalMax - physicalMin)) + scaledMin);
state.axes[static_cast<int>(axis)] = scaledValue; state.axes[axis] = scaledValue;
} }
// Update POV/Hat state. Assuming model described in `open`, values are: // Update POV/Hat state. Assuming model described in `open`, values are:
@ -508,17 +508,17 @@ JoystickState JoystickImpl::update()
case 1: case 1:
case 2: case 2:
case 3: case 3:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = +100; state.axes[Joystick::Axis::PovX] = +100;
break; break;
case 5: case 5:
case 6: case 6:
case 7: case 7:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = -100; state.axes[Joystick::Axis::PovX] = -100;
break; break;
default: default:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0; state.axes[Joystick::Axis::PovX] = 0;
break; break;
} }
@ -528,17 +528,17 @@ JoystickState JoystickImpl::update()
case 0: case 0:
case 1: case 1:
case 7: case 7:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = +100; state.axes[Joystick::Axis::PovY] = +100;
break; break;
case 3: case 3:
case 4: case 4:
case 5: case 5:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = -100; state.axes[Joystick::Axis::PovY] = -100;
break; break;
default: default:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0; state.axes[Joystick::Axis::PovY] = 0;
break; break;
} }
} }