summaryrefslogtreecommitdiffstats
path: root/src/input_common/drivers
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/input_common/drivers/android.cpp324
-rw-r--r--src/input_common/drivers/android.h123
2 files changed, 416 insertions, 31 deletions
diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp
index b6a03fdc0..e859cc538 100644
--- a/src/input_common/drivers/android.cpp
+++ b/src/input_common/drivers/android.cpp
@@ -1,30 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
+#include <set>
+#include <common/settings_input.h>
+#include <jni.h>
+#include "common/android/android_common.h"
+#include "common/android/id_cache.h"
#include "input_common/drivers/android.h"
namespace InputCommon {
Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
-void Android::RegisterController(std::size_t controller_number) {
- PreSetController(GetIdentifier(controller_number));
+void Android::RegisterController(jobject j_input_device) {
+ auto env = Common::Android::GetEnvForThread();
+ const std::string guid = Common::Android::GetJString(
+ env, static_cast<jstring>(
+ env->CallObjectMethod(j_input_device, Common::Android::GetYuzuDeviceGetGUID())));
+ const s32 port = env->CallIntMethod(j_input_device, Common::Android::GetYuzuDeviceGetPort());
+ const auto identifier = GetIdentifier(guid, static_cast<size_t>(port));
+ PreSetController(identifier);
+
+ if (input_devices.find(identifier) != input_devices.end()) {
+ env->DeleteGlobalRef(input_devices[identifier]);
+ }
+ auto new_device = env->NewGlobalRef(j_input_device);
+ input_devices[identifier] = new_device;
}
-void Android::SetButtonState(std::size_t controller_number, int button_id, bool value) {
- const auto identifier = GetIdentifier(controller_number);
+void Android::SetButtonState(std::string guid, size_t port, int button_id, bool value) {
+ const auto identifier = GetIdentifier(guid, port);
SetButton(identifier, button_id, value);
}
-void Android::SetAxisState(std::size_t controller_number, int axis_id, float value) {
- const auto identifier = GetIdentifier(controller_number);
+void Android::SetAxisPosition(std::string guid, size_t port, int axis_id, float value) {
+ const auto identifier = GetIdentifier(guid, port);
SetAxis(identifier, axis_id, value);
}
-void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x,
+void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp, float gyro_x,
float gyro_y, float gyro_z, float accel_x, float accel_y,
float accel_z) {
- const auto identifier = GetIdentifier(controller_number);
+ const auto identifier = GetIdentifier(guid, port);
const BasicMotion motion_data{
.gyro_x = gyro_x,
.gyro_y = gyro_y,
@@ -37,10 +54,295 @@ void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp,
SetMotion(identifier, 0, motion_data);
}
-PadIdentifier Android::GetIdentifier(std::size_t controller_number) const {
+Common::Input::DriverResult Android::SetVibration(
+ [[maybe_unused]] const PadIdentifier& identifier,
+ [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
+ auto device = input_devices.find(identifier);
+ if (device != input_devices.end()) {
+ Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) {
+ float average_intensity =
+ static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0);
+ env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
+ average_intensity);
+ });
+ return Common::Input::DriverResult::Success;
+ }
+ return Common::Input::DriverResult::NotSupported;
+}
+
+bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
+ auto device = input_devices.find(identifier);
+ if (device != input_devices.end()) {
+ return Common::Android::RunJNIOnFiber<bool>([&](JNIEnv* env) {
+ return static_cast<bool>(env->CallBooleanMethod(
+ device->second, Common::Android::GetYuzuDeviceGetSupportsVibration()));
+ });
+ }
+ return false;
+}
+
+std::vector<Common::ParamPackage> Android::GetInputDevices() const {
+ std::vector<Common::ParamPackage> devices;
+ auto env = Common::Android::GetEnvForThread();
+ for (const auto& [key, value] : input_devices) {
+ auto name_object = static_cast<jstring>(
+ env->CallObjectMethod(value, Common::Android::GetYuzuDeviceGetName()));
+ const std::string name =
+ fmt::format("{} {}", Common::Android::GetJString(env, name_object), key.port);
+ devices.emplace_back(Common::ParamPackage{
+ {"engine", GetEngineName()},
+ {"display", std::move(name)},
+ {"guid", key.guid.RawString()},
+ {"port", std::to_string(key.port)},
+ });
+ }
+ return devices;
+}
+
+std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const {
+ auto j_axes = static_cast<jobjectArray>(
+ env->CallObjectMethod(j_device, Common::Android::GetYuzuDeviceGetAxes()));
+ std::set<s32> axes;
+ for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
+ jobject axis = env->GetObjectArrayElement(j_axes, i);
+ axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField()));
+ }
+ return axes;
+}
+
+Common::ParamPackage Android::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
+ int axis_y) const {
+ Common::ParamPackage params;
+ params.Set("engine", GetEngineName());
+ params.Set("port", static_cast<int>(identifier.port));
+ params.Set("guid", identifier.guid.RawString());
+ params.Set("axis_x", axis_x);
+ params.Set("axis_y", axis_y);
+ params.Set("offset_x", 0);
+ params.Set("offset_y", 0);
+ params.Set("invert_x", "+");
+
+ // Invert Y-Axis by default
+ params.Set("invert_y", "-");
+ return params;
+}
+
+Common::ParamPackage Android::BuildAnalogParamPackageForButton(PadIdentifier identifier, s32 axis,
+ bool invert) const {
+ Common::ParamPackage params{};
+ params.Set("engine", GetEngineName());
+ params.Set("port", static_cast<int>(identifier.port));
+ params.Set("guid", identifier.guid.RawString());
+ params.Set("axis", axis);
+ params.Set("threshold", "0.5");
+ params.Set("invert", invert ? "-" : "+");
+ return params;
+}
+
+Common::ParamPackage Android::BuildButtonParamPackageForButton(PadIdentifier identifier,
+ s32 button) const {
+ Common::ParamPackage params{};
+ params.Set("engine", GetEngineName());
+ params.Set("port", static_cast<int>(identifier.port));
+ params.Set("guid", identifier.guid.RawString());
+ params.Set("button", button);
+ return params;
+}
+
+bool Android::MatchVID(Common::UUID device, const std::vector<std::string>& vids) const {
+ for (size_t i = 0; i < vids.size(); ++i) {
+ auto fucker = device.RawString();
+ if (fucker.find(vids[i]) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+AnalogMapping Android::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
+ if (!params.Has("guid") || !params.Has("port")) {
+ return {};
+ }
+
+ auto identifier =
+ GetIdentifier(params.Get("guid", ""), static_cast<size_t>(params.Get("port", 0)));
+ auto& j_device = input_devices[identifier];
+ if (j_device == nullptr) {
+ return {};
+ }
+
+ auto env = Common::Android::GetEnvForThread();
+ std::set<s32> axes = GetDeviceAxes(env, j_device);
+ if (axes.size() == 0) {
+ return {};
+ }
+
+ AnalogMapping mapping = {};
+ if (axes.find(AXIS_X) != axes.end() && axes.find(AXIS_Y) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeAnalog::LStick,
+ BuildParamPackageForAnalog(identifier, AXIS_X, AXIS_Y));
+ }
+
+ if (axes.find(AXIS_RX) != axes.end() && axes.find(AXIS_RY) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeAnalog::RStick,
+ BuildParamPackageForAnalog(identifier, AXIS_RX, AXIS_RY));
+ } else if (axes.find(AXIS_Z) != axes.end() && axes.find(AXIS_RZ) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeAnalog::RStick,
+ BuildParamPackageForAnalog(identifier, AXIS_Z, AXIS_RZ));
+ }
+ return mapping;
+}
+
+ButtonMapping Android::GetButtonMappingForDevice(const Common::ParamPackage& params) {
+ if (!params.Has("guid") || !params.Has("port")) {
+ return {};
+ }
+
+ auto identifier =
+ GetIdentifier(params.Get("guid", ""), static_cast<size_t>(params.Get("port", 0)));
+ auto& j_device = input_devices[identifier];
+ if (j_device == nullptr) {
+ return {};
+ }
+
+ auto env = Common::Android::GetEnvForThread();
+ jintArray j_keys = env->NewIntArray(static_cast<int>(keycode_ids.size()));
+ env->SetIntArrayRegion(j_keys, 0, static_cast<int>(keycode_ids.size()), keycode_ids.data());
+ auto j_has_keys_object = static_cast<jbooleanArray>(
+ env->CallObjectMethod(j_device, Common::Android::GetYuzuDeviceHasKeys(), j_keys));
+ jboolean isCopy = false;
+ jboolean* j_has_keys = env->GetBooleanArrayElements(j_has_keys_object, &isCopy);
+
+ std::set<s32> available_keys;
+ for (size_t i = 0; i < keycode_ids.size(); ++i) {
+ if (j_has_keys[i]) {
+ available_keys.insert(keycode_ids[i]);
+ }
+ }
+
+ // Some devices use axes instead of buttons for certain controls so we need all the axes here
+ std::set<s32> axes = GetDeviceAxes(env, j_device);
+
+ ButtonMapping mapping = {};
+ if (axes.find(AXIS_HAT_X) != axes.end() && axes.find(AXIS_HAT_Y) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::DUp,
+ BuildAnalogParamPackageForButton(identifier, AXIS_HAT_Y, true));
+ mapping.insert_or_assign(Settings::NativeButton::DDown,
+ BuildAnalogParamPackageForButton(identifier, AXIS_HAT_Y, false));
+ mapping.insert_or_assign(Settings::NativeButton::DLeft,
+ BuildAnalogParamPackageForButton(identifier, AXIS_HAT_X, true));
+ mapping.insert_or_assign(Settings::NativeButton::DRight,
+ BuildAnalogParamPackageForButton(identifier, AXIS_HAT_X, false));
+ } else if (available_keys.find(KEYCODE_DPAD_UP) != available_keys.end() &&
+ available_keys.find(KEYCODE_DPAD_DOWN) != available_keys.end() &&
+ available_keys.find(KEYCODE_DPAD_LEFT) != available_keys.end() &&
+ available_keys.find(KEYCODE_DPAD_RIGHT) != available_keys.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::DUp,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_UP));
+ mapping.insert_or_assign(Settings::NativeButton::DDown,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_DOWN));
+ mapping.insert_or_assign(Settings::NativeButton::DLeft,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_LEFT));
+ mapping.insert_or_assign(Settings::NativeButton::DRight,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_RIGHT));
+ }
+
+ if (axes.find(AXIS_LTRIGGER) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::ZL, BuildAnalogParamPackageForButton(
+ identifier, AXIS_LTRIGGER, false));
+ } else if (available_keys.find(KEYCODE_BUTTON_L2) != available_keys.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::ZL,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_L2));
+ }
+
+ if (axes.find(AXIS_RTRIGGER) != axes.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::ZR, BuildAnalogParamPackageForButton(
+ identifier, AXIS_RTRIGGER, false));
+ } else if (available_keys.find(KEYCODE_BUTTON_R2) != available_keys.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::ZR,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_R2));
+ }
+
+ if (available_keys.find(KEYCODE_BUTTON_A) != available_keys.end()) {
+ if (MatchVID(identifier.guid, flipped_ab_vids)) {
+ mapping.insert_or_assign(Settings::NativeButton::B, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_A));
+ } else {
+ mapping.insert_or_assign(Settings::NativeButton::A, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_A));
+ }
+ }
+ if (available_keys.find(KEYCODE_BUTTON_B) != available_keys.end()) {
+ if (MatchVID(identifier.guid, flipped_ab_vids)) {
+ mapping.insert_or_assign(Settings::NativeButton::A, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_B));
+ } else {
+ mapping.insert_or_assign(Settings::NativeButton::B, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_B));
+ }
+ }
+ if (available_keys.find(KEYCODE_BUTTON_X) != available_keys.end()) {
+ if (MatchVID(identifier.guid, flipped_xy_vids)) {
+ mapping.insert_or_assign(Settings::NativeButton::Y, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_X));
+ } else {
+ mapping.insert_or_assign(Settings::NativeButton::X, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_X));
+ }
+ }
+ if (available_keys.find(KEYCODE_BUTTON_Y) != available_keys.end()) {
+ if (MatchVID(identifier.guid, flipped_xy_vids)) {
+ mapping.insert_or_assign(Settings::NativeButton::X, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_Y));
+ } else {
+ mapping.insert_or_assign(Settings::NativeButton::Y, BuildButtonParamPackageForButton(
+ identifier, KEYCODE_BUTTON_Y));
+ }
+ }
+
+ if (available_keys.find(KEYCODE_BUTTON_L1) != available_keys.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::L,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_L1));
+ }
+ if (available_keys.find(KEYCODE_BUTTON_R1) != available_keys.end()) {
+ mapping.insert_or_assign(Settings::NativeButton::R,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_R1));
+ }
+
+ if (available_keys.find(KEYCODE_BUTTON_THUMBL) != available_keys.end()) {
+ mapping.insert_or_assign(
+ Settings::NativeButton::LStick,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_THUMBL));
+ }
+ if (available_keys.find(KEYCODE_BUTTON_THUMBR) != available_keys.end()) {
+ mapping.insert_or_assign(
+ Settings::NativeButton::RStick,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_THUMBR));
+ }
+
+ if (available_keys.find(KEYCODE_BUTTON_START) != available_keys.end()) {
+ mapping.insert_or_assign(
+ Settings::NativeButton::Plus,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_START));
+ }
+ if (available_keys.find(KEYCODE_BUTTON_SELECT) != available_keys.end()) {
+ mapping.insert_or_assign(
+ Settings::NativeButton::Minus,
+ BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_SELECT));
+ }
+
+ return mapping;
+}
+
+Common::Input::ButtonNames Android::GetUIName(
+ [[maybe_unused]] const Common::ParamPackage& params) const {
+ return Common::Input::ButtonNames::Value;
+}
+
+PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const {
return {
- .guid = Common::UUID{},
- .port = controller_number,
+ .guid = Common::UUID{guid},
+ .port = port,
.pad = 0,
};
}
diff --git a/src/input_common/drivers/android.h b/src/input_common/drivers/android.h
index 3f01817f6..ac60e3598 100644
--- a/src/input_common/drivers/android.h
+++ b/src/input_common/drivers/android.h
@@ -3,6 +3,8 @@
#pragma once
+#include <set>
+#include <jni.h>
#include "input_common/input_engine.h"
namespace InputCommon {
@@ -15,40 +17,121 @@ public:
explicit Android(std::string input_engine_);
/**
- * Registers controller number to accept new inputs
- * @param controller_number the controller number that will take this action
+ * Registers controller number to accept new inputs.
+ * @param j_input_device YuzuInputDevice object from the Android frontend to register.
*/
- void RegisterController(std::size_t controller_number);
+ void RegisterController(jobject j_input_device);
/**
- * Sets the status of all buttons bound with the key to pressed
- * @param controller_number the controller number that will take this action
- * @param button_id the id of the button
- * @param value indicates if the button is pressed or not
+ * Sets the status of a button on a specific controller.
+ * @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
+ * @param port Port determined by controller connection order.
+ * @param button_id The Android Keycode corresponding to this event.
+ * @param value Whether the button is pressed or not.
*/
- void SetButtonState(std::size_t controller_number, int button_id, bool value);
+ void SetButtonState(std::string guid, size_t port, int button_id, bool value);
/**
- * Sets the status of a analog input to a specific player index
- * @param controller_number the controller number that will take this action
- * @param axis_id the id of the axis to move
- * @param value the analog position of the axis
+ * Sets the status of an axis on a specific controller.
+ * @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
+ * @param port Port determined by controller connection order.
+ * @param axis_id The Android axis ID corresponding to this event.
+ * @param value Value along the given axis.
*/
- void SetAxisState(std::size_t controller_number, int axis_id, float value);
+ void SetAxisPosition(std::string guid, size_t port, int axis_id, float value);
/**
- * Sets the status of the motion sensor to a specific player index
- * @param controller_number the controller number that will take this action
- * @param delta_timestamp time passed since last reading
- * @param gyro_x,gyro_y,gyro_z the gyro sensor readings
- * @param accel_x,accel_y,accel_z the accelerometer reading
+ * Sets the status of the motion sensor on a specific controller
+ * @param guid 32 character hexadecimal string consisting of the controller's PID+VID.
+ * @param port Port determined by controller connection order.
+ * @param delta_timestamp Time passed since the last read.
+ * @param gyro_x,gyro_y,gyro_z Gyro sensor readings.
+ * @param accel_x,accel_y,accel_z Accelerometer sensor readings.
*/
- void SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x,
+ void SetMotionState(std::string guid, size_t port, u64 delta_timestamp, float gyro_x,
float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z);
+ Common::Input::DriverResult SetVibration(
+ const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
+
+ bool IsVibrationEnabled(const PadIdentifier& identifier) override;
+
+ std::vector<Common::ParamPackage> GetInputDevices() const override;
+
+ /**
+ * Gets the axes reported by the YuzuInputDevice.
+ * @param env JNI environment pointer.
+ * @param j_device YuzuInputDevice from the Android frontend.
+ * @return Set of the axes reported by the underlying Android InputDevice
+ */
+ std::set<s32> GetDeviceAxes(JNIEnv* env, jobject& j_device) const;
+
+ Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
+ int axis_y) const;
+
+ Common::ParamPackage BuildAnalogParamPackageForButton(PadIdentifier identifier, s32 axis,
+ bool invert) const;
+
+ Common::ParamPackage BuildButtonParamPackageForButton(PadIdentifier identifier,
+ s32 button) const;
+
+ bool MatchVID(Common::UUID device, const std::vector<std::string>& vids) const;
+
+ AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
+
+ ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
+
+ Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
+
private:
+ std::unordered_map<PadIdentifier, jobject> input_devices;
+
/// Returns the correct identifier corresponding to the player index
- PadIdentifier GetIdentifier(std::size_t controller_number) const;
+ PadIdentifier GetIdentifier(const std::string& guid, size_t port) const;
+
+ static constexpr s32 AXIS_X = 0;
+ static constexpr s32 AXIS_Y = 1;
+ static constexpr s32 AXIS_Z = 11;
+ static constexpr s32 AXIS_RX = 12;
+ static constexpr s32 AXIS_RY = 13;
+ static constexpr s32 AXIS_RZ = 14;
+ static constexpr s32 AXIS_HAT_X = 15;
+ static constexpr s32 AXIS_HAT_Y = 16;
+ static constexpr s32 AXIS_LTRIGGER = 17;
+ static constexpr s32 AXIS_RTRIGGER = 18;
+
+ static constexpr s32 KEYCODE_DPAD_UP = 19;
+ static constexpr s32 KEYCODE_DPAD_DOWN = 20;
+ static constexpr s32 KEYCODE_DPAD_LEFT = 21;
+ static constexpr s32 KEYCODE_DPAD_RIGHT = 22;
+ static constexpr s32 KEYCODE_BUTTON_A = 96;
+ static constexpr s32 KEYCODE_BUTTON_B = 97;
+ static constexpr s32 KEYCODE_BUTTON_X = 99;
+ static constexpr s32 KEYCODE_BUTTON_Y = 100;
+ static constexpr s32 KEYCODE_BUTTON_L1 = 102;
+ static constexpr s32 KEYCODE_BUTTON_R1 = 103;
+ static constexpr s32 KEYCODE_BUTTON_L2 = 104;
+ static constexpr s32 KEYCODE_BUTTON_R2 = 105;
+ static constexpr s32 KEYCODE_BUTTON_THUMBL = 106;
+ static constexpr s32 KEYCODE_BUTTON_THUMBR = 107;
+ static constexpr s32 KEYCODE_BUTTON_START = 108;
+ static constexpr s32 KEYCODE_BUTTON_SELECT = 109;
+ const std::vector<s32> keycode_ids{
+ KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_RIGHT,
+ KEYCODE_BUTTON_A, KEYCODE_BUTTON_B, KEYCODE_BUTTON_X, KEYCODE_BUTTON_Y,
+ KEYCODE_BUTTON_L1, KEYCODE_BUTTON_R1, KEYCODE_BUTTON_L2, KEYCODE_BUTTON_R2,
+ KEYCODE_BUTTON_THUMBL, KEYCODE_BUTTON_THUMBR, KEYCODE_BUTTON_START, KEYCODE_BUTTON_SELECT,
+ };
+
+ const std::string sony_vid{"054c"};
+ const std::string nintendo_vid{"057e"};
+ const std::string razer_vid{"1532"};
+ const std::string redmagic_vid{"3537"};
+ const std::string backbone_labs_vid{"358a"};
+ const std::vector<std::string> flipped_ab_vids{sony_vid, nintendo_vid, razer_vid, redmagic_vid,
+ backbone_labs_vid};
+ const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid,
+ backbone_labs_vid};
};
} // namespace InputCommon