2017-01-20 20:52:32 +01:00
|
|
|
// Copyright 2017 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2021-06-23 15:59:56 +02:00
|
|
|
#include <functional>
|
2017-01-20 20:52:32 +01:00
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <utility>
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
#include "common/param_package.h"
|
2021-04-22 20:15:59 +02:00
|
|
|
#include "common/quaternion.h"
|
2017-08-06 21:54:19 +02:00
|
|
|
#include "common/vector_math.h"
|
2017-01-20 20:52:32 +01:00
|
|
|
|
|
|
|
namespace Input {
|
|
|
|
|
2020-01-15 11:25:15 +01:00
|
|
|
enum class AnalogDirection : u8 {
|
|
|
|
RIGHT,
|
|
|
|
LEFT,
|
|
|
|
UP,
|
|
|
|
DOWN,
|
|
|
|
};
|
2021-01-13 04:09:59 +01:00
|
|
|
struct AnalogProperties {
|
|
|
|
float deadzone;
|
|
|
|
float range;
|
|
|
|
float threshold;
|
|
|
|
};
|
2021-05-30 06:35:46 +02:00
|
|
|
template <typename StatusType>
|
|
|
|
struct InputCallback {
|
|
|
|
std::function<void(StatusType)> on_change;
|
|
|
|
};
|
2020-01-15 11:25:15 +01:00
|
|
|
|
2017-01-20 20:52:32 +01:00
|
|
|
/// An abstract class template for an input device (a button, an analog input, etc.).
|
|
|
|
template <typename StatusType>
|
|
|
|
class InputDevice {
|
|
|
|
public:
|
|
|
|
virtual ~InputDevice() = default;
|
|
|
|
virtual StatusType GetStatus() const {
|
|
|
|
return {};
|
2020-01-15 11:25:15 +01:00
|
|
|
}
|
2021-01-13 04:09:59 +01:00
|
|
|
virtual StatusType GetRawStatus() const {
|
|
|
|
return GetStatus();
|
|
|
|
}
|
|
|
|
virtual AnalogProperties GetAnalogProperties() const {
|
|
|
|
return {};
|
|
|
|
}
|
2020-11-15 12:22:01 +01:00
|
|
|
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
|
2020-01-15 11:25:15 +01:00
|
|
|
return {};
|
2017-01-20 20:52:32 +01:00
|
|
|
}
|
2020-11-24 03:11:21 +01:00
|
|
|
virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
|
|
|
|
[[maybe_unused]] f32 amp_high,
|
|
|
|
[[maybe_unused]] f32 freq_high) const {
|
2020-07-11 04:20:50 +02:00
|
|
|
return {};
|
|
|
|
}
|
2021-05-30 06:35:46 +02:00
|
|
|
void SetCallback(InputCallback<StatusType> callback_) {
|
|
|
|
callback = std::move(callback_);
|
|
|
|
}
|
|
|
|
void TriggerOnChange() {
|
|
|
|
if (callback.on_change) {
|
|
|
|
callback.on_change(GetStatus());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
InputCallback<StatusType> callback;
|
2017-01-20 20:52:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/// An abstract class template for a factory that can create input devices.
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
class Factory {
|
|
|
|
public:
|
|
|
|
virtual ~Factory() = default;
|
|
|
|
virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace Impl {
|
|
|
|
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
|
|
|
|
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
struct FactoryList {
|
|
|
|
static FactoryListType<InputDeviceType> list;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
|
|
|
|
|
|
|
|
} // namespace Impl
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers an input device factory.
|
|
|
|
* @tparam InputDeviceType the type of input devices the factory can create
|
|
|
|
* @param name the name of the factory. Will be used to match the "engine" parameter when creating
|
|
|
|
* a device
|
|
|
|
* @param factory the factory object to register
|
|
|
|
*/
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
|
|
|
|
auto pair = std::make_pair(name, std::move(factory));
|
|
|
|
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_ERROR(Input, "Factory '{}' already registered", name);
|
2017-01-20 20:52:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregisters an input device factory.
|
|
|
|
* @tparam InputDeviceType the type of input devices the factory can create
|
|
|
|
* @param name the name of the factory to unregister
|
|
|
|
*/
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
void UnregisterFactory(const std::string& name) {
|
|
|
|
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_ERROR(Input, "Factory '{}' not registered", name);
|
2017-01-20 20:52:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an input device from given paramters.
|
|
|
|
* @tparam InputDeviceType the type of input devices to create
|
|
|
|
* @param params a serialized ParamPackage string contains all parameters for creating the device
|
|
|
|
*/
|
|
|
|
template <typename InputDeviceType>
|
|
|
|
std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
|
|
|
|
const Common::ParamPackage package(params);
|
|
|
|
const std::string engine = package.Get("engine", "null");
|
|
|
|
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
|
|
|
|
const auto pair = factory_list.find(engine);
|
|
|
|
if (pair == factory_list.end()) {
|
|
|
|
if (engine != "null") {
|
2018-07-02 18:13:26 +02:00
|
|
|
LOG_ERROR(Input, "Unknown engine name: {}", engine);
|
2017-01-20 20:52:32 +01:00
|
|
|
}
|
|
|
|
return std::make_unique<InputDeviceType>();
|
|
|
|
}
|
|
|
|
return pair->second->Create(package);
|
|
|
|
}
|
|
|
|
|
2017-01-20 21:46:39 +01:00
|
|
|
/**
|
|
|
|
* A button device is an input device that returns bool as status.
|
|
|
|
* true for pressed; false for released.
|
|
|
|
*/
|
|
|
|
using ButtonDevice = InputDevice<bool>;
|
|
|
|
|
2017-01-20 22:58:03 +01:00
|
|
|
/**
|
|
|
|
* An analog device is an input device that returns a tuple of x and y coordinates as status. The
|
|
|
|
* coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up
|
|
|
|
* direction
|
|
|
|
*/
|
|
|
|
using AnalogDevice = InputDevice<std::tuple<float, float>>;
|
|
|
|
|
2020-10-20 19:55:25 +02:00
|
|
|
/**
|
|
|
|
* A vibration device is an input device that returns an unsigned byte as status.
|
|
|
|
* It represents whether the vibration device supports vibration or not.
|
|
|
|
* If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
|
|
|
|
*/
|
|
|
|
using VibrationDevice = InputDevice<u8>;
|
|
|
|
|
2017-08-06 21:54:19 +02:00
|
|
|
/**
|
2020-09-03 02:59:34 +02:00
|
|
|
* A motion status is an object that returns a tuple of accelerometer state vector,
|
2021-04-22 20:15:59 +02:00
|
|
|
* gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
|
|
|
|
* vector.
|
2020-09-05 04:48:03 +02:00
|
|
|
*
|
2021-04-22 20:15:59 +02:00
|
|
|
* For both 3D vectors:
|
2020-09-05 04:48:03 +02:00
|
|
|
* x+ is the same direction as RIGHT on D-pad.
|
|
|
|
* y+ is normal to the touch screen, pointing outward.
|
|
|
|
* z+ is the same direction as UP on D-pad.
|
|
|
|
*
|
|
|
|
* For accelerometer state vector
|
|
|
|
* Units: g (gravitational acceleration)
|
|
|
|
*
|
|
|
|
* For gyroscope state vector:
|
|
|
|
* Orientation is determined by right-hand rule.
|
|
|
|
* Units: deg/sec
|
|
|
|
*
|
|
|
|
* For rotation state vector
|
|
|
|
* Units: rotations
|
|
|
|
*
|
|
|
|
* For orientation state matrix
|
|
|
|
* x vector
|
|
|
|
* y vector
|
|
|
|
* z vector
|
2021-04-22 20:15:59 +02:00
|
|
|
*
|
|
|
|
* For quaternion state vector
|
|
|
|
* xyz vector
|
|
|
|
* w float
|
2020-09-05 04:48:03 +02:00
|
|
|
*/
|
2020-09-03 02:59:34 +02:00
|
|
|
using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
|
2021-04-22 20:15:59 +02:00
|
|
|
std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
|
2020-09-03 02:59:34 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A motion device is an input device that returns a motion status object
|
|
|
|
*/
|
|
|
|
using MotionDevice = InputDevice<MotionStatus>;
|
2020-09-05 04:48:03 +02:00
|
|
|
|
2017-08-08 20:34:17 +02:00
|
|
|
/**
|
2021-01-01 19:32:29 +01:00
|
|
|
* A touch status is an object that returns an array of 16 tuple elements of two floats and a bool.
|
|
|
|
* The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is
|
|
|
|
* pressed.
|
2017-08-08 20:34:17 +02:00
|
|
|
*/
|
2021-01-01 19:32:29 +01:00
|
|
|
using TouchStatus = std::array<std::tuple<float, float, bool>, 16>;
|
2020-11-18 05:55:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A touch device is an input device that returns a touch status object
|
|
|
|
*/
|
|
|
|
using TouchDevice = InputDevice<TouchStatus>;
|
2017-08-08 20:34:17 +02:00
|
|
|
|
2018-11-02 02:52:51 +01:00
|
|
|
/**
|
|
|
|
* A mouse device is an input device that returns a tuple of two floats and four ints.
|
|
|
|
* The first two floats are X and Y device coordinates of the mouse (from 0-1).
|
|
|
|
* The s32s are the mouse wheel.
|
|
|
|
*/
|
|
|
|
using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
|
|
|
|
|
2017-01-20 20:52:32 +01:00
|
|
|
} // namespace Input
|