Преглед изворни кода

input_common: Create input poller and mapping

german77 пре 4 година
родитељ
комит
854c933716

+ 6 - 0
src/input_common/CMakeLists.txt

@@ -3,6 +3,12 @@ add_library(input_common STATIC
     analog_from_button.h
     keyboard.cpp
     keyboard.h
+    input_engine.cpp
+    input_engine.h
+    input_mapping.cpp
+    input_mapping.h
+    input_poller.cpp
+    input_poller.h
     main.cpp
     main.h
     motion_from_button.cpp

+ 171 - 0
src/input_common/input_mapping.cpp

@@ -0,0 +1,171 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/common_types.h"
+#include "input_common/input_engine.h"
+#include "input_common/input_mapping.h"
+
+namespace InputCommon {
+
+MappingFactory::MappingFactory() {}
+
+void MappingFactory::BeginMapping(Polling::InputType type) {
+    is_enabled = true;
+    input_type = type;
+    input_queue.Clear();
+    first_axis = -1;
+    second_axis = -1;
+}
+
+[[nodiscard]] const Common::ParamPackage MappingFactory::GetNextInput() {
+    Common::ParamPackage input;
+    input_queue.Pop(input);
+    return input;
+}
+
+void MappingFactory::RegisterInput(const MappingData& data) {
+    if (!is_enabled) {
+        return;
+    }
+    switch (input_type) {
+    case Polling::InputType::Button:
+        RegisterButton(data);
+        return;
+    case Polling::InputType::Stick:
+        RegisterStick(data);
+        return;
+    case Polling::InputType::Motion:
+        RegisterMotion(data);
+        return;
+    default:
+        return;
+    }
+}
+
+void MappingFactory::StopMapping() {
+    is_enabled = false;
+    input_type = Polling::InputType::None;
+    input_queue.Clear();
+}
+
+void MappingFactory::RegisterButton(const MappingData& data) {
+    Common::ParamPackage new_input;
+    new_input.Set("engine", data.engine);
+    if (data.pad.guid != Common::UUID{}) {
+        new_input.Set("guid", data.pad.guid.Format());
+    }
+    new_input.Set("port", static_cast<int>(data.pad.port));
+    new_input.Set("pad", static_cast<int>(data.pad.pad));
+    switch (data.type) {
+    case EngineInputType::Button:
+        // Workaround for old compatibility
+        if (data.engine == "keyboard") {
+            new_input.Set("code", data.index);
+            break;
+        }
+        new_input.Set("button", data.index);
+        break;
+    case EngineInputType::HatButton:
+        new_input.Set("hat", data.index);
+        new_input.Set("direction", data.hat_name);
+        break;
+    case EngineInputType::Analog:
+        new_input.Set("axis", data.index);
+        new_input.Set("threshold", 0.5f);
+        break;
+    default:
+        return;
+    }
+    input_queue.Push(new_input);
+}
+
+void MappingFactory::RegisterStick(const MappingData& data) {
+    Common::ParamPackage new_input;
+    new_input.Set("engine", data.engine);
+    if (data.pad.guid != Common::UUID{}) {
+        new_input.Set("guid", data.pad.guid.Format());
+    }
+    new_input.Set("port", static_cast<int>(data.pad.port));
+    new_input.Set("pad", static_cast<int>(data.pad.pad));
+
+    // If engine is mouse map the mouse position as a joystick
+    if (data.engine == "mouse") {
+        new_input.Set("axis_x", 0);
+        new_input.Set("axis_y", 1);
+        new_input.Set("threshold", 0.5f);
+        new_input.Set("range", 1.0f);
+        new_input.Set("deadzone", 0.0f);
+        input_queue.Push(new_input);
+        return;
+    }
+
+    switch (data.type) {
+    case EngineInputType::Button:
+    case EngineInputType::HatButton:
+        RegisterButton(data);
+        return;
+    case EngineInputType::Analog:
+        if (first_axis == data.index) {
+            return;
+        }
+        if (first_axis == -1) {
+            first_axis = data.index;
+            return;
+        }
+        new_input.Set("axis_x", first_axis);
+        new_input.Set("axis_y", data.index);
+        new_input.Set("threshold", 0.5f);
+        new_input.Set("range", 0.95f);
+        new_input.Set("deadzone", 0.15f);
+        break;
+    default:
+        return;
+    }
+    input_queue.Push(new_input);
+}
+
+void MappingFactory::RegisterMotion(const MappingData& data) {
+    Common::ParamPackage new_input;
+    new_input.Set("engine", data.engine);
+    if (data.pad.guid != Common::UUID{}) {
+        new_input.Set("guid", data.pad.guid.Format());
+    }
+    new_input.Set("port", static_cast<int>(data.pad.port));
+    new_input.Set("pad", static_cast<int>(data.pad.pad));
+    switch (data.type) {
+    case EngineInputType::Button:
+    case EngineInputType::HatButton:
+        RegisterButton(data);
+        return;
+    case EngineInputType::Analog:
+        if (first_axis == data.index) {
+            return;
+        }
+        if (second_axis == data.index) {
+            return;
+        }
+        if (first_axis == -1) {
+            first_axis = data.index;
+            return;
+        }
+        if (second_axis == -1) {
+            second_axis = data.index;
+            return;
+        }
+        new_input.Set("axis_x", first_axis);
+        new_input.Set("axis_y", second_axis);
+        new_input.Set("axis_z", data.index);
+        new_input.Set("range", 1.0f);
+        new_input.Set("deadzone", 0.20f);
+        break;
+    case EngineInputType::Motion:
+        new_input.Set("motion", data.index);
+        break;
+    default:
+        return;
+    }
+    input_queue.Push(new_input);
+}
+
+} // namespace InputCommon

+ 76 - 0
src/input_common/input_mapping.h

@@ -0,0 +1,76 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+#include "common/threadsafe_queue.h"
+
+namespace InputCommon {
+class InputEngine;
+struct MappingData;
+
+class MappingFactory {
+public:
+    MappingFactory();
+
+    /**
+     * Resets all varables to beggin the mapping process
+     * @param "type": type of input desired to be returned
+     */
+    void BeginMapping(Polling::InputType type);
+
+    /// Returns an input event with mapping information from the input_queue
+    [[nodiscard]] const Common::ParamPackage GetNextInput();
+
+    /**
+     * Registers mapping input data from the driver
+     * @param "data": An struct containing all the information needed to create a proper
+     * ParamPackage
+     */
+    void RegisterInput(const MappingData& data);
+
+    /// Stop polling from all backends
+    void StopMapping();
+
+private:
+    /**
+     * If provided data satisfies the requeriments it will push an element to the input_queue
+     * Supported input:
+     *     - Button: Creates a basic button ParamPackage
+     *     - HatButton: Creates a basic hat button ParamPackage
+     *     - Analog: Creates a basic analog ParamPackage
+     * @param "data": An struct containing all the information needed to create a proper
+     * ParamPackage
+     */
+    void RegisterButton(const MappingData& data);
+
+    /**
+     * If provided data satisfies the requeriments it will push an element to the input_queue
+     * Supported input:
+     *     - Button, HatButton: Pass the data to RegisterButton
+     *     - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage
+     * @param "data": An struct containing all the information needed to create a proper
+     * ParamPackage
+     */
+    void RegisterStick(const MappingData& data);
+
+    /**
+     * If provided data satisfies the requeriments it will push an element to the input_queue
+     * Supported input:
+     *     - Button, HatButton: Pass the data to RegisterButton
+     *     - Analog: Stores the first two axis and on the third axis creates a basic Motion
+     * ParamPackage
+     *     - Motion: Creates a basic Motion ParamPackage
+     * @param "data": An struct containing all the information needed to create a proper
+     * ParamPackage
+     */
+    void RegisterMotion(const MappingData& data);
+
+    Common::SPSCQueue<Common::ParamPackage> input_queue;
+    Polling::InputType input_type{Polling::InputType::None};
+    bool is_enabled{};
+    int first_axis = -1;
+    int second_axis = -1;
+};
+
+} // namespace InputCommon

+ 860 - 0
src/input_common/input_poller.cpp

@@ -0,0 +1,860 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/common_types.h"
+#include "common/input.h"
+
+#include "input_common/input_engine.h"
+#include "input_common/input_poller.h"
+
+namespace InputCommon {
+
+class DummyInput final : public Input::InputDevice {
+public:
+    explicit DummyInput() {}
+    ~DummyInput() {}
+};
+
+class InputFromButton final : public Input::InputDevice {
+public:
+    explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_,
+                             InputEngine* input_engine_)
+        : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
+          input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Button,
+            .index = button,
+            .callback = engine_callback,
+        };
+        last_button_value = false;
+        callback_key = input_engine->SetCallback(input_identifier);
+    }
+
+    ~InputFromButton() {
+        input_engine->DeleteCallback(callback_key);
+    }
+
+    Input::ButtonStatus GetStatus() const {
+        return {
+            .value = input_engine->GetButton(identifier, button),
+            .inverted = inverted,
+            .toggle = toggle,
+        };
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Button,
+            .button_status = GetStatus(),
+        };
+
+        if (status.button_status.value != last_button_value) {
+            last_button_value = status.button_status.value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 button;
+    const bool toggle;
+    const bool inverted;
+    int callback_key;
+    bool last_button_value;
+    InputEngine* input_engine;
+};
+
+class InputFromHatButton final : public Input::InputDevice {
+public:
+    explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_,
+                                bool inverted_, InputEngine* input_engine_)
+        : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_),
+          inverted(inverted_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::HatButton,
+            .index = button,
+            .callback = engine_callback,
+        };
+        last_button_value = false;
+        callback_key = input_engine->SetCallback(input_identifier);
+    }
+
+    ~InputFromHatButton() {
+        input_engine->DeleteCallback(callback_key);
+    }
+
+    Input::ButtonStatus GetStatus() const {
+        return {
+            .value = input_engine->GetHatButton(identifier, button, direction),
+            .inverted = inverted,
+            .toggle = toggle,
+        };
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Button,
+            .button_status = GetStatus(),
+        };
+
+        if (status.button_status.value != last_button_value) {
+            last_button_value = status.button_status.value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 button;
+    const u8 direction;
+    const bool toggle;
+    const bool inverted;
+    int callback_key;
+    bool last_button_value;
+    InputEngine* input_engine;
+};
+
+class InputFromStick final : public Input::InputDevice {
+public:
+    explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_,
+                            Input::AnalogProperties properties_x_,
+                            Input::AnalogProperties properties_y_, InputEngine* input_engine_)
+        : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
+          properties_y(properties_y_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier x_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_x,
+            .callback = engine_callback,
+        };
+        const InputIdentifier y_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_y,
+            .callback = engine_callback,
+        };
+        last_axis_x_value = 0.0f;
+        last_axis_y_value = 0.0f;
+        callback_key_x = input_engine->SetCallback(x_input_identifier);
+        callback_key_y = input_engine->SetCallback(y_input_identifier);
+    }
+
+    ~InputFromStick() {
+        input_engine->DeleteCallback(callback_key_x);
+        input_engine->DeleteCallback(callback_key_y);
+    }
+
+    Input::StickStatus GetStatus() const {
+        Input::StickStatus status;
+        status.x = {
+            .raw_value = input_engine->GetAxis(identifier, axis_x),
+            .properties = properties_x,
+        };
+        status.y = {
+            .raw_value = input_engine->GetAxis(identifier, axis_y),
+            .properties = properties_y,
+        };
+        return status;
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Stick,
+            .stick_status = GetStatus(),
+        };
+
+        if (status.stick_status.x.raw_value != last_axis_x_value ||
+            status.stick_status.y.raw_value != last_axis_y_value) {
+            last_axis_x_value = status.stick_status.x.raw_value;
+            last_axis_y_value = status.stick_status.y.raw_value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 axis_x;
+    const u32 axis_y;
+    const Input::AnalogProperties properties_x;
+    const Input::AnalogProperties properties_y;
+    int callback_key_x;
+    int callback_key_y;
+    float last_axis_x_value;
+    float last_axis_y_value;
+    InputEngine* input_engine;
+};
+
+class InputFromTouch final : public Input::InputDevice {
+public:
+    explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_,
+                            bool inverted_, u32 axis_x_, u32 axis_y_,
+                            Input::AnalogProperties properties_x_,
+                            Input::AnalogProperties properties_y_, InputEngine* input_engine_)
+        : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_),
+          inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
+          properties_y(properties_y_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier button_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Button,
+            .index = button,
+            .callback = engine_callback,
+        };
+        const InputIdentifier x_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_x,
+            .callback = engine_callback,
+        };
+        const InputIdentifier y_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_y,
+            .callback = engine_callback,
+        };
+        last_axis_x_value = 0.0f;
+        last_axis_y_value = 0.0f;
+        last_button_value = false;
+        callback_key_button = input_engine->SetCallback(button_input_identifier);
+        callback_key_x = input_engine->SetCallback(x_input_identifier);
+        callback_key_y = input_engine->SetCallback(y_input_identifier);
+    }
+
+    ~InputFromTouch() {
+        input_engine->DeleteCallback(callback_key_button);
+        input_engine->DeleteCallback(callback_key_x);
+        input_engine->DeleteCallback(callback_key_y);
+    }
+
+    Input::TouchStatus GetStatus() const {
+        Input::TouchStatus status;
+        status.id = touch_id;
+        status.pressed = {
+            .value = input_engine->GetButton(identifier, button),
+            .inverted = inverted,
+            .toggle = toggle,
+        };
+        status.x = {
+            .raw_value = input_engine->GetAxis(identifier, axis_x),
+            .properties = properties_x,
+        };
+        status.y = {
+            .raw_value = input_engine->GetAxis(identifier, axis_y),
+            .properties = properties_y,
+        };
+        return status;
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Touch,
+            .touch_status = GetStatus(),
+        };
+
+        if (status.touch_status.x.raw_value != last_axis_x_value ||
+            status.touch_status.y.raw_value != last_axis_y_value ||
+            status.touch_status.pressed.value != last_button_value) {
+            last_axis_x_value = status.touch_status.x.raw_value;
+            last_axis_y_value = status.touch_status.y.raw_value;
+            last_button_value = status.touch_status.pressed.value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 touch_id;
+    const u32 button;
+    const bool toggle;
+    const bool inverted;
+    const u32 axis_x;
+    const u32 axis_y;
+    const Input::AnalogProperties properties_x;
+    const Input::AnalogProperties properties_y;
+    int callback_key_button;
+    int callback_key_x;
+    int callback_key_y;
+    bool last_button_value;
+    float last_axis_x_value;
+    float last_axis_y_value;
+    InputEngine* input_engine;
+};
+
+class InputFromTrigger final : public Input::InputDevice {
+public:
+    explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_,
+                              u32 axis_, Input::AnalogProperties properties_,
+                              InputEngine* input_engine_)
+        : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
+          axis(axis_), properties(properties_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier button_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Button,
+            .index = button,
+            .callback = engine_callback,
+        };
+        const InputIdentifier axis_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis,
+            .callback = engine_callback,
+        };
+        last_axis_value = 0.0f;
+        last_button_value = false;
+        callback_key_button = input_engine->SetCallback(button_input_identifier);
+        axis_callback_key = input_engine->SetCallback(axis_input_identifier);
+    }
+
+    ~InputFromTrigger() {
+        input_engine->DeleteCallback(callback_key_button);
+        input_engine->DeleteCallback(axis_callback_key);
+    }
+
+    Input::TriggerStatus GetStatus() const {
+        const Input::AnalogStatus analog_status{
+            .raw_value = input_engine->GetAxis(identifier, axis),
+            .properties = properties,
+        };
+        return {
+            .analog = analog_status,
+            .pressed = input_engine->GetButton(identifier, button),
+        };
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Trigger,
+            .trigger_status = GetStatus(),
+        };
+
+        if (status.trigger_status.analog.raw_value != last_axis_value ||
+            status.trigger_status.pressed != last_button_value) {
+            last_axis_value = status.trigger_status.analog.raw_value;
+            last_button_value = status.trigger_status.pressed;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 button;
+    const bool toggle;
+    const bool inverted;
+    const u32 axis;
+    const Input::AnalogProperties properties;
+    int callback_key_button;
+    int axis_callback_key;
+    bool last_button_value;
+    float last_axis_value;
+    InputEngine* input_engine;
+};
+
+class InputFromAnalog final : public Input::InputDevice {
+public:
+    explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_,
+                             Input::AnalogProperties properties_, InputEngine* input_engine_)
+        : identifier(identifier_), axis(axis_), properties(properties_),
+          input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis,
+            .callback = engine_callback,
+        };
+        last_axis_value = 0.0f;
+        callback_key = input_engine->SetCallback(input_identifier);
+    }
+
+    ~InputFromAnalog() {
+        input_engine->DeleteCallback(callback_key);
+    }
+
+    Input::AnalogStatus GetStatus() const {
+        return {
+            .raw_value = input_engine->GetAxis(identifier, axis),
+            .properties = properties,
+        };
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Analog,
+            .analog_status = GetStatus(),
+        };
+
+        if (status.analog_status.raw_value != last_axis_value) {
+            last_axis_value = status.analog_status.raw_value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 axis;
+    const Input::AnalogProperties properties;
+    int callback_key;
+    float last_axis_value;
+    InputEngine* input_engine;
+};
+
+class InputFromBattery final : public Input::InputDevice {
+public:
+    explicit InputFromBattery(PadIdentifier identifier_, InputEngine* input_engine_)
+        : identifier(identifier_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Battery,
+            .index = 0,
+            .callback = engine_callback,
+        };
+        last_battery_value = Input::BatteryStatus::Charging;
+        callback_key = input_engine->SetCallback(input_identifier);
+    }
+
+    ~InputFromBattery() {
+        input_engine->DeleteCallback(callback_key);
+    }
+
+    Input::BatteryStatus GetStatus() const {
+        return static_cast<Input::BatteryLevel>(input_engine->GetBattery(identifier));
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Battery,
+            .battery_status = GetStatus(),
+        };
+
+        if (status.battery_status != last_battery_value) {
+            last_battery_value = status.battery_status;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    int callback_key;
+    Input::BatteryStatus last_battery_value;
+    InputEngine* input_engine;
+};
+
+class InputFromMotion final : public Input::InputDevice {
+public:
+    explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_,
+                             InputEngine* input_engine_)
+        : identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Motion,
+            .index = motion_sensor,
+            .callback = engine_callback,
+        };
+        callback_key = input_engine->SetCallback(input_identifier);
+    }
+
+    ~InputFromMotion() {
+        input_engine->DeleteCallback(callback_key);
+    }
+
+    Input::MotionStatus GetStatus() const {
+        const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor);
+        Input::MotionStatus status{};
+        const Input::AnalogProperties properties = {
+            .deadzone = 0.001f,
+            .range = 1.0f,
+            .offset = 0.0f,
+        };
+        status.accel.x = {.raw_value = basic_motion.accel_x, .properties = properties};
+        status.accel.y = {.raw_value = basic_motion.accel_y, .properties = properties};
+        status.accel.z = {.raw_value = basic_motion.accel_z, .properties = properties};
+        status.gyro.x = {.raw_value = basic_motion.gyro_x, .properties = properties};
+        status.gyro.y = {.raw_value = basic_motion.gyro_y, .properties = properties};
+        status.gyro.z = {.raw_value = basic_motion.gyro_z, .properties = properties};
+        status.delta_timestamp = basic_motion.delta_timestamp;
+        return status;
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Motion,
+            .motion_status = GetStatus(),
+        };
+
+        TriggerOnChange(status);
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 motion_sensor;
+    int callback_key;
+    InputEngine* input_engine;
+};
+
+class InputFromAxisMotion final : public Input::InputDevice {
+public:
+    explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_,
+                                 Input::AnalogProperties properties_x_,
+                                 Input::AnalogProperties properties_y_,
+                                 Input::AnalogProperties properties_z_, InputEngine* input_engine_)
+        : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), axis_z(axis_z_),
+          properties_x(properties_x_), properties_y(properties_y_), properties_z(properties_z_),
+          input_engine(input_engine_) {
+        UpdateCallback engine_callback{[this]() { OnChange(); }};
+        const InputIdentifier x_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_x,
+            .callback = engine_callback,
+        };
+        const InputIdentifier y_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_y,
+            .callback = engine_callback,
+        };
+        const InputIdentifier z_input_identifier{
+            .identifier = identifier,
+            .type = EngineInputType::Analog,
+            .index = axis_z,
+            .callback = engine_callback,
+        };
+        last_axis_x_value = 0.0f;
+        last_axis_y_value = 0.0f;
+        last_axis_z_value = 0.0f;
+        callback_key_x = input_engine->SetCallback(x_input_identifier);
+        callback_key_y = input_engine->SetCallback(y_input_identifier);
+        callback_key_z = input_engine->SetCallback(z_input_identifier);
+    }
+
+    ~InputFromAxisMotion() {
+        input_engine->DeleteCallback(callback_key_x);
+        input_engine->DeleteCallback(callback_key_y);
+        input_engine->DeleteCallback(callback_key_z);
+    }
+
+    Input::MotionStatus GetStatus() const {
+        Input::MotionStatus status{};
+        status.gyro.x = {
+            .raw_value = input_engine->GetAxis(identifier, axis_x),
+            .properties = properties_x,
+        };
+        status.gyro.y = {
+            .raw_value = input_engine->GetAxis(identifier, axis_y),
+            .properties = properties_y,
+        };
+        status.gyro.z = {
+            .raw_value = input_engine->GetAxis(identifier, axis_z),
+            .properties = properties_z,
+        };
+        return status;
+    }
+
+    void OnChange() {
+        const Input::CallbackStatus status{
+            .type = Input::InputType::Motion,
+            .motion_status = GetStatus(),
+        };
+
+        if (status.motion_status.gyro.x.raw_value != last_axis_x_value ||
+            status.motion_status.gyro.y.raw_value != last_axis_y_value ||
+            status.motion_status.gyro.z.raw_value != last_axis_z_value) {
+            last_axis_x_value = status.motion_status.gyro.x.raw_value;
+            last_axis_y_value = status.motion_status.gyro.y.raw_value;
+            last_axis_z_value = status.motion_status.gyro.z.raw_value;
+            TriggerOnChange(status);
+        }
+    }
+
+private:
+    const PadIdentifier identifier;
+    const u32 axis_x;
+    const u32 axis_y;
+    const u32 axis_z;
+    const Input::AnalogProperties properties_x;
+    const Input::AnalogProperties properties_y;
+    const Input::AnalogProperties properties_z;
+    int callback_key_x;
+    int callback_key_y;
+    int callback_key_z;
+    float last_axis_x_value;
+    float last_axis_y_value;
+    float last_axis_z_value;
+    InputEngine* input_engine;
+};
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateButtonDevice(
+    const Common::ParamPackage& params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto button_id = static_cast<u32>(params.Get("button", 0));
+    const auto keyboard_key = static_cast<u32>(params.Get("code", 0));
+    const auto toggle = params.Get("toggle", false);
+    const auto inverted = params.Get("inverted", false);
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetButton(identifier, button_id);
+    input_engine->PreSetButton(identifier, keyboard_key);
+    if (keyboard_key != 0) {
+        return std::make_unique<InputFromButton>(identifier, keyboard_key, toggle, inverted,
+                                                 input_engine.get());
+    }
+    return std::make_unique<InputFromButton>(identifier, button_id, toggle, inverted,
+                                             input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateHatButtonDevice(
+    const Common::ParamPackage& params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto button_id = static_cast<u32>(params.Get("hat", 0));
+    const auto direction = input_engine->GetHatButtonId(params.Get("direction", ""));
+    const auto toggle = params.Get("toggle", false);
+    const auto inverted = params.Get("inverted", false);
+
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetHatButton(identifier, button_id);
+    return std::make_unique<InputFromHatButton>(identifier, button_id, direction, toggle, inverted,
+                                                input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateStickDevice(
+    const Common::ParamPackage& params) {
+    const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f);
+    const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
+    const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
+    const Input::AnalogProperties properties_x = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_x", "+") == "-",
+    };
+
+    const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
+    const Input::AnalogProperties properties_y = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_y", "+") != "+",
+    };
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetAxis(identifier, axis_x);
+    input_engine->PreSetAxis(identifier, axis_y);
+    return std::make_unique<InputFromStick>(identifier, axis_x, axis_y, properties_x, properties_y,
+                                            input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateAnalogDevice(
+    const Common::ParamPackage& params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto axis = static_cast<u32>(params.Get("axis", 0));
+    const Input::AnalogProperties properties = {
+        .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f),
+        .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f),
+        .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
+        .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert", "+") == "-",
+    };
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetAxis(identifier, axis);
+    return std::make_unique<InputFromAnalog>(identifier, axis, properties, input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateTriggerDevice(
+    const Common::ParamPackage& params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto button = static_cast<u32>(params.Get("button", 0));
+    const auto toggle = params.Get("toggle", false);
+    const auto inverted = params.Get("inverted", false);
+
+    const auto axis = static_cast<u32>(params.Get("axis", 0));
+    const Input::AnalogProperties properties = {
+        .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f),
+        .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f),
+        .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
+        .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert", false) != 0,
+    };
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetAxis(identifier, axis);
+    input_engine->PreSetButton(identifier, button);
+    return std::make_unique<InputFromTrigger>(identifier, button, toggle, inverted, axis,
+                                              properties, input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateTouchDevice(
+    const Common::ParamPackage& params) {
+    const auto touch_id = params.Get("touch_id", 0);
+    const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
+    const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
+    const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    const auto button = static_cast<u32>(params.Get("button", 0));
+    const auto toggle = params.Get("toggle", false);
+    const auto inverted = params.Get("inverted", false);
+
+    const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
+    const Input::AnalogProperties properties_x = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_x", "+") == "-",
+    };
+
+    const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
+    const Input::AnalogProperties properties_y = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_y", false) != 0,
+    };
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetAxis(identifier, axis_x);
+    input_engine->PreSetAxis(identifier, axis_y);
+    input_engine->PreSetButton(identifier, button);
+    return std::make_unique<InputFromTouch>(identifier, touch_id, button, toggle, inverted, axis_x,
+                                            axis_y, properties_x, properties_y, input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateBatteryDevice(
+    const Common::ParamPackage& params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    input_engine->PreSetController(identifier);
+    return std::make_unique<InputFromBattery>(identifier, input_engine.get());
+}
+
+std::unique_ptr<Input::InputDevice> InputFactory::CreateMotionDevice(Common::ParamPackage params) {
+    const PadIdentifier identifier = {
+        .guid = Common::UUID{params.Get("guid", "")},
+        .port = static_cast<std::size_t>(params.Get("port", 0)),
+        .pad = static_cast<std::size_t>(params.Get("pad", 0)),
+    };
+
+    if (params.Has("motion")) {
+        const auto motion_sensor = params.Get("motion", 0);
+        input_engine->PreSetController(identifier);
+        input_engine->PreSetMotion(identifier, motion_sensor);
+        return std::make_unique<InputFromMotion>(identifier, motion_sensor, input_engine.get());
+    }
+
+    const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f);
+    const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
+    const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
+
+    const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
+    const Input::AnalogProperties properties_x = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_x", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_x", "+") == "-",
+    };
+
+    const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
+    const Input::AnalogProperties properties_y = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_y", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_y", "+") != "+",
+    };
+
+    const auto axis_z = static_cast<u32>(params.Get("axis_z", 1));
+    const Input::AnalogProperties properties_z = {
+        .deadzone = deadzone,
+        .range = range,
+        .threshold = threshold,
+        .offset = std::clamp(params.Get("offset_z", 0.0f), -1.0f, 1.0f),
+        .inverted = params.Get("invert_z", "+") != "+",
+    };
+    input_engine->PreSetController(identifier);
+    input_engine->PreSetAxis(identifier, axis_x);
+    input_engine->PreSetAxis(identifier, axis_y);
+    input_engine->PreSetAxis(identifier, axis_z);
+    return std::make_unique<InputFromAxisMotion>(identifier, axis_x, axis_y, axis_z, properties_x,
+                                                 properties_y, properties_z, input_engine.get());
+}
+
+InputFactory::InputFactory(std::shared_ptr<InputEngine> input_engine_)
+    : input_engine(std::move(input_engine_)) {}
+
+std::unique_ptr<Input::InputDevice> InputFactory::Create(const Common::ParamPackage& params) {
+    if (params.Has("button") && params.Has("axis")) {
+        return CreateTriggerDevice(params);
+    }
+    if (params.Has("button") && params.Has("axis_x") && params.Has("axis_y")) {
+        return CreateTouchDevice(params);
+    }
+    if (params.Has("button") || params.Has("code")) {
+        return CreateButtonDevice(params);
+    }
+    if (params.Has("hat")) {
+        return CreateHatButtonDevice(params);
+    }
+    if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
+        return CreateMotionDevice(params);
+    }
+    if (params.Has("motion")) {
+        return CreateMotionDevice(params);
+    }
+    if (params.Has("axis_x") && params.Has("axis_y")) {
+        return CreateStickDevice(params);
+    }
+    if (params.Has("axis")) {
+        return CreateAnalogDevice(params);
+    }
+    if (params.Has("battery")) {
+        return CreateBatteryDevice(params);
+    }
+    LOG_ERROR(Input, "Invalid parameters given");
+    return std::make_unique<DummyInput>();
+}
+
+} // namespace InputCommon

+ 189 - 0
src/input_common/input_poller.h

@@ -0,0 +1,189 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+namespace Input {
+class InputDevice;
+
+template <typename InputDevice>
+class Factory;
+}; // namespace Input
+
+namespace InputCommon {
+class InputEngine;
+/**
+ * An Input factory. It receives input events and forward them to all input devices it created.
+ */
+class InputFactory final : public Input::Factory<Input::InputDevice> {
+public:
+    explicit InputFactory(std::shared_ptr<InputEngine> input_engine_);
+
+    /**
+     * Creates a input device from the parameters given. Identifies the type of input to be returned
+     * if it contains the following parameters:
+     * - button: Contains "button" or "code"
+     * - hat_button: Contains "hat"
+     * - analog: Contains "axis"
+     * - trigger: Contains "button" and  "axis"
+     * - stick: Contains "axis_x" and "axis_y"
+     * - motion: Contains "axis_x", "axis_y" and "axis_z"
+     * - motion: Contains "motion"
+     * - touch: Contains "button", "axis_x" and "axis_y"
+     * - battery: Contains "battery"
+     * @param params contains parameters for creating the device:
+     * @param    - "code": the code of the keyboard key to bind with the input
+     * @param    - "button": same as "code" but for controller buttons
+     * @param    - "hat": similar as "button" but it's a group of hat buttons from SDL
+     * @param    - "axis": the axis number of the axis to bind with the input
+     * @param    - "motion": the motion number of the motion to bind with the input
+     * @param    - "axis_x": same as axis but specifing horizontal direction
+     * @param    - "axis_y": same as axis but specifing vertical direction
+     * @param    - "axis_z": same as axis but specifing forward direction
+     * @param   - "battery": Only used as a placeholder to set the input type
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> Create(const Common::ParamPackage& params) override;
+
+private:
+    /**
+     * Creates a button device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "code": the code of the keyboard key to bind with the input
+     * @param    - "button": same as "code" but for controller buttons
+     * @param    - "toggle": press once to enable, press again to disable
+     * @param    - "inverted": inverts the output of the button
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateButtonDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a hat button device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "button": the controller hat id to bind with the input
+     * @param    - "direction": the direction id to be detected
+     * @param    - "toggle": press once to enable, press again to disable
+     * @param    - "inverted": inverts the output of the button
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateHatButtonDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a stick device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "axis_x": the controller horizontal axis id to bind with the input
+     * @param    - "axis_y": the controller vertical axis id to bind with the input
+     * @param    - "deadzone": the mimimum required value to be detected
+     * @param    - "range": the maximum value required to reach 100%
+     * @param    - "threshold": the mimimum required value to considered pressed
+     * @param    - "offset_x": the amount of offset in the x axis
+     * @param    - "offset_y": the amount of offset in the y axis
+     * @param    - "invert_x": inverts the sign of the horizontal axis
+     * @param    - "invert_y": inverts the sign of the vertical axis
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateStickDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates an analog device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "axis": the controller axis id to bind with the input
+     * @param    - "deadzone": the mimimum required value to be detected
+     * @param    - "range": the maximum value required to reach 100%
+     * @param    - "threshold": the mimimum required value to considered pressed
+     * @param    - "offset": the amount of offset in the axis
+     * @param    - "invert": inverts the sign of the axis
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateAnalogDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a trigger device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "button": the controller hat id to bind with the input
+     * @param    - "direction": the direction id to be detected
+     * @param    - "toggle": press once to enable, press again to disable
+     * @param    - "inverted": inverts the output of the button
+     * @param    - "axis": the controller axis id to bind with the input
+     * @param    - "deadzone": the mimimum required value to be detected
+     * @param    - "range": the maximum value required to reach 100%
+     * @param    - "threshold": the mimimum required value to considered pressed
+     * @param    - "offset": the amount of offset in the axis
+     * @param    - "invert": inverts the sign of the axis
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateTriggerDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a touch device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "button": the controller hat id to bind with the input
+     * @param    - "direction": the direction id to be detected
+     * @param    - "toggle": press once to enable, press again to disable
+     * @param    - "inverted": inverts the output of the button
+     * @param    - "axis_x": the controller horizontal axis id to bind with the input
+     * @param    - "axis_y": the controller vertical axis id to bind with the input
+     * @param    - "deadzone": the mimimum required value to be detected
+     * @param    - "range": the maximum value required to reach 100%
+     * @param    - "threshold": the mimimum required value to considered pressed
+     * @param    - "offset_x": the amount of offset in the x axis
+     * @param    - "offset_y": the amount of offset in the y axis
+     * @param    - "invert_x": inverts the sign of the horizontal axis
+     * @param    - "invert_y": inverts the sign of the vertical axis
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateTouchDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a battery device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateBatteryDevice(const Common::ParamPackage& params);
+
+    /**
+     * Creates a motion device from the parameters given.
+     * @param params contains parameters for creating the device:
+     * @param    - "axis_x": the controller horizontal axis id to bind with the input
+     * @param    - "axis_y": the controller vertical axis id to bind with the input
+     * @param    - "axis_z": the controller fordward axis id to bind with the input
+     * @param    - "deadzone": the mimimum required value to be detected
+     * @param    - "range": the maximum value required to reach 100%
+     * @param    - "offset_x": the amount of offset in the x axis
+     * @param    - "offset_y": the amount of offset in the y axis
+     * @param    - "offset_z": the amount of offset in the z axis
+     * @param    - "invert_x": inverts the sign of the horizontal axis
+     * @param    - "invert_y": inverts the sign of the vertical axis
+     * @param    - "invert_z": inverts the sign of the fordward axis
+     * @param    - "guid": text string for identifing controllers
+     * @param    - "port": port of the connected device
+     * @param    - "pad": slot of the connected controller
+     * @return an unique input device with the parameters specified
+     */
+    std::unique_ptr<Input::InputDevice> CreateMotionDevice(Common::ParamPackage params);
+
+    std::shared_ptr<InputEngine> input_engine;
+};
+} // namespace InputCommon

+ 3 - 0
src/input_common/main.h

@@ -38,6 +38,9 @@ namespace Polling {
 
 enum class DeviceType { Button, AnalogPreferred, Motion };
 
+/// Type of input desired for mapping purposes
+enum class InputType { None, Button, Stick, Motion, Touch };
+
 /**
  * A class that can be used to get inputs from an input device like controllers without having to
  * poll the device's status yourself