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/Event.hpp>
#include <SFML/System/EnumArray.hpp>
#include <android/configuration.h>
#include <android/native_activity.h>
@ -75,7 +77,7 @@ struct ActivityStates
std::unordered_map<int, Vector2i> touchEvents;
Vector2i mousePosition;
bool isButtonPressed[Mouse::ButtonCount]{};
EnumArray<Mouse::Button, bool, Mouse::ButtonCount> isButtonPressed{};
bool mainOver{};

View File

@ -7,6 +7,7 @@ set(SRC
${INCROOT}/Angle.inl
${SRCROOT}/Clock.cpp
${INCROOT}/Clock.hpp
${SRCROOT}/EnumArray.hpp
${SRCROOT}/Err.cpp
${INCROOT}/Err.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();
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/System/EnumArray.hpp>
#include <SFML/System/Time.hpp>
#include <android/looper.h>
@ -47,7 +48,7 @@ namespace
ALooper* looper;
ASensorManager* sensorManager;
ASensorEventQueue* sensorEventQueue;
sf::Vector3f sensorData[sf::Sensor::Count];
sf::priv::EnumArray<sf::Sensor::Type, sf::Vector3f, sf::Sensor::Count> sensorData;
} // namespace
@ -104,8 +105,8 @@ bool SensorImpl::open(Sensor::Type sensor)
// Set the event rate (not to consume too much battery)
ASensorEventQueue_setEventRate(sensorEventQueue, m_sensor, static_cast<std::int32_t>(minimumDelay.asMicroseconds()));
// Save the index of the sensor
m_index = static_cast<unsigned int>(sensor);
// Save the type of the sensor
m_type = sensor;
return true;
}
@ -124,7 +125,7 @@ Vector3f SensorImpl::update() const
// Update our sensor data list
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)
{
// Find the Android sensor type
static int types[] = {ASENSOR_TYPE_ACCELEROMETER,
static EnumArray<Sensor::Type, int, Sensor::Count> types =
{ASENSOR_TYPE_ACCELEROMETER,
ASENSOR_TYPE_GYROSCOPE,
ASENSOR_TYPE_MAGNETIC_FIELD,
ASENSOR_TYPE_GRAVITY,
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
return ASensorManager_getDefaultSensor(sensorManager, type);
@ -215,7 +217,7 @@ int SensorImpl::processSensorEvents(int /* fd */, int /* events */, void* /* sen
if (!type)
continue;
sensorData[static_cast<int>(*type)] = data;
sensorData[*type] = data;
}
return 1;

View File

@ -122,7 +122,7 @@ private:
// Member data
////////////////////////////////////////////////////////////
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

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::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 y = static_cast<int>(AMotionEvent_getY(inputEvent, index));
@ -535,12 +536,12 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* inputEvent,
if (device == AINPUT_SOURCE_MOUSE)
{
event.type = Event::MouseButtonPressed;
event.mouseButton.button = static_cast<Mouse::Button>(id);
event.mouseButton.button = button;
event.mouseButton.x = x;
event.mouseButton.y = y;
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)
{
@ -557,12 +558,12 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* inputEvent,
if (device == AINPUT_SOURCE_MOUSE)
{
event.type = Event::MouseButtonReleased;
event.mouseButton.button = static_cast<Mouse::Button>(id);
event.mouseButton.button = button;
event.mouseButton.x = x;
event.mouseButton.y = y;
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)
{

View File

@ -28,6 +28,7 @@
#include <SFML/Window/Event.hpp>
#include <SFML/Window/InputImpl.hpp>
#include <SFML/System/EnumArray.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
@ -61,8 +62,8 @@ std::recursive_mutex inputMutex; // threadsafe? maybe...
sf::Vector2i mousePos; // current mouse position
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
std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether mouse buttons 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 keys are down
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"
@ -392,7 +393,7 @@ bool eventProcess(sf::Event& event)
event.mouseButton.x = mousePos.x;
event.mouseButton.y = mousePos.y;
mouseMap[static_cast<std::size_t>(*mb)] = inputEvent.value;
mouseMap[*mb] = inputEvent.value;
return true;
}
else
@ -632,7 +633,7 @@ bool isMouseButtonPressed(Mouse::Button button)
return false;
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)
{
state.axes[static_cast<int>(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::PovX] = static_cast<float>(hatValueMap[value].first);
state.axes[sf::Joystick::Axis::PovY] = static_cast<float>(hatValueMap[value].second);
}
} // namespace
@ -271,12 +271,12 @@ JoystickCaps JoystickImpl::getCapabilities() const
{
if (usage == HUG_HAT_SWITCH)
{
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = true;
caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true;
caps.axes[Joystick::Axis::PovX] = true;
caps.axes[Joystick::Axis::PovY] = true;
}
else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage))
{
caps.axes[static_cast<int>(*axis)] = true;
caps.axes[*axis] = true;
}
}
}
@ -333,7 +333,7 @@ JoystickState JoystickImpl::JoystickImpl::update()
int maximum = item.logical_maximum;
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)
{
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)
{
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/System/EnumArray.hpp>
namespace sf::priv
{
@ -41,7 +43,7 @@ namespace sf::priv
struct JoystickCaps
{
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
};
@ -52,7 +54,7 @@ struct JoystickCaps
struct JoystickState
{
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)
};

View File

@ -160,8 +160,8 @@ std::optional<sf::Joystick::Axis> usageToAxis(int usage)
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[static_cast<int>(sf::Joystick::Axis::PovY)] = static_cast<float>(hatValueMap[value].second);
state.axes[sf::Joystick::Axis::PovX] = static_cast<float>(hatValueMap[value].first);
state.axes[sf::Joystick::Axis::PovY] = static_cast<float>(hatValueMap[value].second);
}
} // namespace
@ -276,12 +276,12 @@ JoystickCaps JoystickImpl::getCapabilities() const
{
if (usage == HUG_HAT_SWITCH)
{
caps.axes[static_cast<int>(Joystick::Axis::PovX)] = true;
caps.axes[static_cast<int>(Joystick::Axis::PovY)] = true;
caps.axes[Joystick::Axis::PovX] = true;
caps.axes[Joystick::Axis::PovY] = true;
}
else if (const std::optional<Joystick::Axis> axis = usageToAxis(usage))
{
caps.axes[static_cast<int>(*axis)] = true;
caps.axes[*axis] = true;
}
}
}
@ -338,7 +338,7 @@ JoystickState JoystickImpl::JoystickImpl::update()
int maximum = item.logical_maximum;
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)
{
return m_sensors[static_cast<int>(sensor)].available;
return m_sensors[sensor].available;
}
////////////////////////////////////////////////////////////
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[static_cast<int>(sensor)].sensor.setEnabled(enabled);
m_sensors[sensor].enabled = enabled;
m_sensors[sensor].sensor.setEnabled(enabled);
}
else
{
@ -68,14 +68,14 @@ void SensorManager::setEnabled(Sensor::Type sensor, bool enabled)
////////////////////////////////////////////////////////////
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
{
return m_sensors[static_cast<int>(sensor)].value;
return m_sensors[sensor].value;
}
@ -100,19 +100,21 @@ SensorManager::SensorManager()
// Per sensor initialization
for (unsigned int i = 0; i < Sensor::Count; ++i)
{
const auto sensor = static_cast<Sensor::Type>(i);
// 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
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
{
m_sensors[i].available = false;
m_sensors[sensor].available = false;
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/SensorImpl.hpp>
#include <SFML/System/EnumArray.hpp>
namespace sf::priv
{
@ -133,7 +135,7 @@ private:
////////////////////////////////////////////////////////////
// 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

View File

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

View File

@ -331,14 +331,14 @@ JoystickCaps JoystickImpl::getCapabilities() const
if (caps.buttonCount > Joystick::ButtonCount)
caps.buttonCount = Joystick::ButtonCount;
caps.axes[static_cast<int>(Joystick::Axis::X)] = true;
caps.axes[static_cast<int>(Joystick::Axis::Y)] = true;
caps.axes[static_cast<int>(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[static_cast<int>(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[static_cast<int>(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::X] = true;
caps.axes[Joystick::Axis::Y] = true;
caps.axes[Joystick::Axis::Z] = (m_caps.wCaps & JOYCAPS_HASZ) != 0;
caps.axes[Joystick::Axis::R] = (m_caps.wCaps & JOYCAPS_HASR) != 0;
caps.axes[Joystick::Axis::U] = (m_caps.wCaps & JOYCAPS_HASU) != 0;
caps.axes[Joystick::Axis::V] = (m_caps.wCaps & JOYCAPS_HASV) != 0;
caps.axes[Joystick::Axis::PovX] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
caps.axes[Joystick::Axis::PovY] = (m_caps.wCaps & JOYCAPS_HASPOV) != 0;
return caps;
}
@ -379,22 +379,22 @@ JoystickState JoystickImpl::update()
state.connected = true;
// 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) *
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) *
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) *
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) *
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) *
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) *
200.f / static_cast<float>(m_caps.wVmax - m_caps.wVmin);
@ -402,13 +402,13 @@ JoystickState JoystickImpl::update()
if (pos.dwPOV != 0xFFFF)
{
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[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100;
state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100;
state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100;
}
else
{
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0;
state.axes[Joystick::Axis::PovX] = 0;
state.axes[Joystick::Axis::PovY] = 0;
}
// Buttons
@ -877,7 +877,10 @@ JoystickCaps JoystickImpl::getCapabilitiesDInput() const
// Check which axes have valid offsets
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;
}
@ -929,9 +932,10 @@ JoystickState JoystickImpl::updateDInputBuffered()
// Get the current state of each axis
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);
@ -939,18 +943,18 @@ JoystickState JoystickImpl::updateDInputBuffered()
{
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[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100.f;
m_state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100.f;
m_state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100.f;
}
else
{
m_state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0.f;
m_state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0.f;
m_state.axes[Joystick::Axis::PovX] = 0.f;
m_state.axes[Joystick::Axis::PovY] = 0.f;
}
}
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;
@ -1018,37 +1022,38 @@ JoystickState JoystickImpl::updateDInputPolled()
// Get the current state of each axis
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(
*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)
{
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[static_cast<int>(Joystick::Axis::PovY)] = std::cos(angle) * 100.f;
state.axes[Joystick::Axis::PovX] = std::sin(angle) * 100.f;
state.axes[Joystick::Axis::PovY] = std::cos(angle) * 100.f;
}
else
{
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0.f;
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0.f;
state.axes[Joystick::Axis::PovX] = 0.f;
state.axes[Joystick::Axis::PovY] = 0.f;
}
}
else
{
state.axes[i] = (static_cast<float>(*reinterpret_cast<const LONG*>(
reinterpret_cast<const char*>(&joystate) + m_axes[i])) +
state.axes[axis] = (static_cast<float>(*reinterpret_cast<const LONG*>(
reinterpret_cast<const char*>(&joystate) + m_axes[axis])) +
0.5f) *
100.f / 32767.5f;
}
}
else
{
state.axes[i] = 0.f;
state.axes[axis] = 0.f;
}
}
@ -1103,23 +1108,23 @@ BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECT
{
// Axes
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)
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)
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)
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)
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)
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)
{
if (joystick.m_axes[static_cast<int>(Joystick::Axis::U)] == -1)
joystick.m_axes[static_cast<int>(Joystick::Axis::U)] = DIJOFS_SLIDER(0);
if (joystick.m_axes[Joystick::Axis::U] == -1)
joystick.m_axes[Joystick::Axis::U] = DIJOFS_SLIDER(0);
else
joystick.m_axes[static_cast<int>(Joystick::Axis::V)] = DIJOFS_SLIDER(1);
joystick.m_axes[Joystick::Axis::V] = DIJOFS_SLIDER(1);
}
else
return DIENUM_CONTINUE;
@ -1145,10 +1150,10 @@ BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECT
// POVs
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[static_cast<int>(Joystick::Axis::PovY)] = DIJOFS_POV(0);
joystick.m_axes[Joystick::Axis::PovX] = DIJOFS_POV(0);
joystick.m_axes[Joystick::Axis::PovY] = DIJOFS_POV(0);
}
}

View File

@ -27,6 +27,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/EnumArray.hpp>
#include <SFML/System/Win32/WindowsHeader.hpp>
#include <dinput.h>
@ -216,7 +217,7 @@ private:
JOYCAPS m_caps{}; //!< Joystick capabilities
IDirectInputDevice8W* m_device{}; //!< DirectInput 8.x device
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
Joystick::Identification m_identification; //!< Joystick identification
JoystickState m_state; //!< Buffered joystick state

View File

@ -34,7 +34,6 @@
#include <SFML/System/Sleep.hpp>
#include <SFML/System/Time.hpp>
#include <algorithm>
#include <memory>
#include <cmath>
@ -122,7 +121,7 @@ WindowImpl::WindowImpl() : m_joystickStatesImpl(std::make_unique<JoystickStatesI
for (unsigned int i = 0; i < Joystick::Count; ++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
@ -240,7 +239,7 @@ void WindowImpl::processJoystickEvents()
// Clear previous axes positions
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)
@ -250,20 +249,21 @@ void WindowImpl::processJoystickEvents()
// Axes
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 currPos = m_joystickStatesImpl->states[i].axes[j];
const float prevPos = m_previousAxes[i][axis];
const float currPos = m_joystickStatesImpl->states[i].axes[axis];
if (std::abs(currPos - prevPos) >= m_joystickThreshold)
{
Event event;
event.type = Event::JoystickMoved;
event.joystickMove.joystickId = i;
event.joystickMove.axis = static_cast<Joystick::Axis>(j);
event.joystickMove.axis = axis;
event.joystickMove.position = currPos;
pushEvent(event);
m_previousAxes[i][j] = currPos;
m_previousAxes[i][axis] = currPos;
}
}
}
@ -302,18 +302,18 @@ void WindowImpl::processSensorEvents()
if (SensorManager::getInstance().isEnabled(sensor))
{
// Copy the previous value of the sensor and get the new one
const Vector3f previousValue = m_sensorValue[i];
m_sensorValue[i] = SensorManager::getInstance().getValue(sensor);
const Vector3f previousValue = m_sensorValue[sensor];
m_sensorValue[sensor] = SensorManager::getInstance().getValue(sensor);
// 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.type = Event::SensorChanged;
event.sensor.type = sensor;
event.sensor.x = m_sensorValue[i].x;
event.sensor.y = m_sensorValue[i].y;
event.sensor.z = m_sensorValue[i].z;
event.sensor.x = m_sensorValue[sensor].x;
event.sensor.y = m_sensorValue[sensor].y;
event.sensor.z = m_sensorValue[sensor].z;
pushEvent(event);
}
}

View File

@ -39,6 +39,9 @@
#include <SFML/Window/Vulkan.hpp>
#include <SFML/Window/WindowHandle.hpp>
#include <SFML/System/EnumArray.hpp>
#include <array>
#include <memory>
#include <optional>
#include <queue>
@ -331,9 +334,10 @@ private:
////////////////////////////////////////////////////////////
std::queue<Event> m_events; //!< Queue of available events
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_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_maximumSize; //!< Maximum window size
};

View File

@ -377,10 +377,10 @@ JoystickCaps JoystickImpl::getCapabilities() const
// Axis:
for (const auto& [axis, iohidElementRef] : m_axis)
caps.axes[static_cast<int>(axis)] = true;
caps.axes[axis] = true;
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;
}
@ -480,7 +480,7 @@ JoystickState JoystickImpl::update()
const double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
const auto scaledValue = static_cast<float>(
(((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:
@ -508,17 +508,17 @@ JoystickState JoystickImpl::update()
case 1:
case 2:
case 3:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = +100;
state.axes[Joystick::Axis::PovX] = +100;
break;
case 5:
case 6:
case 7:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = -100;
state.axes[Joystick::Axis::PovX] = -100;
break;
default:
state.axes[static_cast<int>(Joystick::Axis::PovX)] = 0;
state.axes[Joystick::Axis::PovX] = 0;
break;
}
@ -528,17 +528,17 @@ JoystickState JoystickImpl::update()
case 0:
case 1:
case 7:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = +100;
state.axes[Joystick::Axis::PovY] = +100;
break;
case 3:
case 4:
case 5:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = -100;
state.axes[Joystick::Axis::PovY] = -100;
break;
default:
state.axes[static_cast<int>(Joystick::Axis::PovY)] = 0;
state.axes[Joystick::Axis::PovY] = 0;
break;
}
}