core: hid: Enable pulling color data from controllers

This commit is contained in:
Narr the Reg 2022-12-20 13:23:31 -06:00
parent a4074001fe
commit ed5fa10e97
9 changed files with 246 additions and 2 deletions

View file

@ -93,6 +93,7 @@ void EmulatedController::ReloadFromSettings() {
motion_params[index] = Common::ParamPackage(player.motions[index]);
}
controller.color_values = {};
controller.colors_state.fullkey = {
.body = GetNpadColor(player.body_color_left),
.button = GetNpadColor(player.button_color_left),
@ -132,6 +133,11 @@ void EmulatedController::LoadDevices() {
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
color_params[LeftIndex] = left_joycon;
color_params[RightIndex] = right_joycon;
color_params[LeftIndex].Set("color", true);
color_params[RightIndex].Set("color", true);
battery_params[LeftIndex] = left_joycon;
battery_params[RightIndex] = right_joycon;
battery_params[LeftIndex].Set("battery", true);
@ -160,6 +166,7 @@ void EmulatedController::LoadDevices() {
Common::Input::CreateInputDevice);
std::ranges::transform(battery_params, battery_devices.begin(),
Common::Input::CreateInputDevice);
std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);
camera_devices = Common::Input::CreateInputDevice(camera_params);
ring_analog_device = Common::Input::CreateInputDevice(ring_params);
nfc_devices = Common::Input::CreateInputDevice(nfc_params);
@ -324,6 +331,19 @@ void EmulatedController::ReloadInput() {
battery_devices[index]->ForceUpdate();
}
for (std::size_t index = 0; index < color_devices.size(); ++index) {
if (!color_devices[index]) {
continue;
}
color_devices[index]->SetCallback({
.on_change =
[this, index](const Common::Input::CallbackStatus& callback) {
SetColors(callback, index);
},
});
color_devices[index]->ForceUpdate();
}
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
if (!motion_devices[index]) {
continue;
@ -429,6 +449,9 @@ void EmulatedController::UnloadInput() {
for (auto& battery : battery_devices) {
battery.reset();
}
for (auto& color : color_devices) {
color.reset();
}
for (auto& output : output_devices) {
output.reset();
}
@ -458,6 +481,11 @@ void EmulatedController::EnableConfiguration() {
void EmulatedController::DisableConfiguration() {
is_configuring = false;
// Get Joycon colors before turning on the controller
for (const auto& color_device : color_devices) {
color_device->ForceUpdate();
}
// Apply temporary npad type to the real controller
if (tmp_npad_type != npad_type) {
if (is_connected) {
@ -926,6 +954,58 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
TriggerOnChange(ControllerTriggerType::Motion, true);
}
void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
std::size_t index) {
if (index >= controller.color_values.size()) {
return;
}
std::unique_lock lock{mutex};
controller.color_values[index] = TransformToColor(callback);
if (is_configuring) {
lock.unlock();
TriggerOnChange(ControllerTriggerType::Color, false);
return;
}
if (controller.color_values[index].body == 0) {
return;
}
controller.colors_state.fullkey = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
if (npad_type == NpadStyleIndex::ProController) {
controller.colors_state.left = {
.body = GetNpadColor(controller.color_values[index].left_grip),
.button = GetNpadColor(controller.color_values[index].buttons),
};
controller.colors_state.right = {
.body = GetNpadColor(controller.color_values[index].right_grip),
.button = GetNpadColor(controller.color_values[index].buttons),
};
} else {
switch (index) {
case LeftIndex:
controller.colors_state.left = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
break;
case RightIndex:
controller.colors_state.right = {
.body = GetNpadColor(controller.color_values[index].body),
.button = GetNpadColor(controller.color_values[index].buttons),
};
break;
}
}
lock.unlock();
TriggerOnChange(ControllerTriggerType::Color, true);
}
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
std::size_t index) {
if (index >= controller.battery_values.size()) {

View file

@ -35,6 +35,8 @@ using ControllerMotionDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
using TriggerDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
using ColorDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using BatteryDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using CameraDevices = std::unique_ptr<Common::Input::InputDevice>;
@ -46,6 +48,7 @@ using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::Nu
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using CameraParams = Common::ParamPackage;
using RingAnalogParams = Common::ParamPackage;
@ -457,6 +460,13 @@ private:
*/
void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
* Updates the color status of the controller
* @param callback A CallbackStatus containing the color status
* @param index color ID of the to be updated
*/
void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
* Updates the battery status of the controller
* @param callback A CallbackStatus containing the battery status
@ -515,6 +525,7 @@ private:
ControllerMotionParams motion_params;
TriggerParams trigger_params;
BatteryParams battery_params;
ColorParams color_params;
CameraParams camera_params;
RingAnalogParams ring_params;
NfcParams nfc_params;
@ -525,6 +536,7 @@ private:
ControllerMotionDevices motion_devices;
TriggerDevices trigger_devices;
BatteryDevices battery_devices;
ColorDevices color_devices;
CameraDevices camera_devices;
RingAnalogDevice ring_analog_device;
NfcDevices nfc_devices;

View file

@ -304,6 +304,20 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
return nfc;
}
Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) {
Common::Input::BodyColorStatus color{};
switch (callback.type) {
case Common::Input::InputType::Color:
color = callback.color_status;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type);
break;
}
return color;
}
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties;
float& raw_value = analog.raw_value;

View file

@ -88,10 +88,18 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu
* Converts raw input data into a valid nfc status.
*
* @param callback Supported callbacks: Nfc.
* @return A valid CameraObject object.
* @return A valid data tag vector.
*/
Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid color status.
*
* @param callback Supported callbacks: Color.
* @return A valid Color object.
*/
Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback);
/**
* Converts raw analog data into a valid analog value
* @param analog An analog object containing raw data and properties

View file

@ -335,7 +335,16 @@ void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type,
}
void Joycons::OnColorUpdate(std::size_t port, Joycon::ControllerType type,
const Joycon::Color& value) {}
const Joycon::Color& value) {
const auto identifier = GetIdentifier(port, type);
Common::Input::BodyColorStatus color{
.body = value.body,
.buttons = value.buttons,
.left_grip = value.left_grip,
.right_grip = value.right_grip,
};
SetColor(identifier, color);
}
void Joycons::OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value) {
const auto identifier = GetIdentifier(port, type);

View file

@ -79,6 +79,17 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, Common::Input::Bat
TriggerOnBatteryChange(identifier, value);
}
void InputEngine::SetColor(const PadIdentifier& identifier, Common::Input::BodyColorStatus value) {
{
std::scoped_lock lock{mutex};
ControllerData& controller = controller_list.at(identifier);
if (!configuring) {
controller.color = value;
}
}
TriggerOnColorChange(identifier, value);
}
void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {
{
std::scoped_lock lock{mutex};
@ -176,6 +187,18 @@ Common::Input::BatteryLevel InputEngine::GetBattery(const PadIdentifier& identif
return controller.battery;
}
Common::Input::BodyColorStatus InputEngine::GetColor(const PadIdentifier& identifier) const {
std::scoped_lock lock{mutex};
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.RawString(),
identifier.pad, identifier.port);
return {};
}
const ControllerData& controller = controller_iter->second;
return controller.color;
}
BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
std::scoped_lock lock{mutex};
const auto controller_iter = controller_list.find(identifier);
@ -328,6 +351,20 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
}
}
void InputEngine::TriggerOnColorChange(const PadIdentifier& identifier,
[[maybe_unused]] Common::Input::BodyColorStatus value) {
std::scoped_lock lock{mutex_callback};
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Color, 0)) {
continue;
}
if (poller.callback.on_change) {
poller.callback.on_change();
}
}
}
void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
const BasicMotion& value) {
std::scoped_lock lock{mutex_callback};

View file

@ -40,6 +40,7 @@ enum class EngineInputType {
Battery,
Button,
Camera,
Color,
HatButton,
Motion,
Nfc,
@ -199,6 +200,7 @@ public:
bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const;
f32 GetAxis(const PadIdentifier& identifier, int axis) const;
Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const;
Common::Input::BodyColorStatus GetColor(const PadIdentifier& identifier) const;
BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const;
Common::Input::NfcStatus GetNfc(const PadIdentifier& identifier) const;
@ -212,6 +214,7 @@ protected:
void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
void SetColor(const PadIdentifier& identifier, Common::Input::BodyColorStatus value);
void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value);
void SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);
@ -227,6 +230,7 @@ private:
std::unordered_map<int, float> axes;
std::unordered_map<int, BasicMotion> motions;
Common::Input::BatteryLevel battery{};
Common::Input::BodyColorStatus color{};
Common::Input::CameraStatus camera{};
Common::Input::NfcStatus nfc{};
};
@ -235,6 +239,8 @@ private:
void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
void TriggerOnColorChange(const PadIdentifier& identifier,
Common::Input::BodyColorStatus value);
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
const BasicMotion& value);
void TriggerOnCameraChange(const PadIdentifier& identifier,

View file

@ -498,6 +498,58 @@ private:
InputEngine* input_engine;
};
class InputFromColor final : public Common::Input::InputDevice {
public:
explicit InputFromColor(PadIdentifier identifier_, InputEngine* input_engine_)
: identifier(identifier_), input_engine(input_engine_) {
UpdateCallback engine_callback{[this]() { OnChange(); }};
const InputIdentifier input_identifier{
.identifier = identifier,
.type = EngineInputType::Color,
.index = 0,
.callback = engine_callback,
};
last_color_value = {};
callback_key = input_engine->SetCallback(input_identifier);
}
~InputFromColor() override {
input_engine->DeleteCallback(callback_key);
}
Common::Input::BodyColorStatus GetStatus() const {
return input_engine->GetColor(identifier);
}
void ForceUpdate() override {
const Common::Input::CallbackStatus status{
.type = Common::Input::InputType::Color,
.color_status = GetStatus(),
};
last_color_value = status.color_status;
TriggerOnChange(status);
}
void OnChange() {
const Common::Input::CallbackStatus status{
.type = Common::Input::InputType::Color,
.color_status = GetStatus(),
};
if (status.color_status.body != last_color_value.body) {
last_color_value = status.color_status;
TriggerOnChange(status);
}
}
private:
const PadIdentifier identifier;
int callback_key;
Common::Input::BodyColorStatus last_color_value;
InputEngine* input_engine;
};
class InputFromMotion final : public Common::Input::InputDevice {
public:
explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, float gyro_threshold_,
@ -966,6 +1018,18 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice(
return std::make_unique<InputFromBattery>(identifier, input_engine.get());
}
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateColorDevice(
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<InputFromColor>(identifier, input_engine.get());
}
std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateMotionDevice(
Common::ParamPackage params) {
const PadIdentifier identifier = {
@ -1053,6 +1117,9 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::Create(
if (params.Has("battery")) {
return CreateBatteryDevice(params);
}
if (params.Has("color")) {
return CreateColorDevice(params);
}
if (params.Has("camera")) {
return CreateCameraDevice(params);
}

View file

@ -190,6 +190,17 @@ private:
std::unique_ptr<Common::Input::InputDevice> CreateBatteryDevice(
const Common::ParamPackage& params);
/**
* Creates a color device from the parameters given.
* @param params contains parameters for creating the device:
* - "guid": text string for identifying controllers
* - "port": port of the connected device
* - "pad": slot of the connected controller
* @returns a unique input device with the parameters specified
*/
std::unique_ptr<Common::Input::InputDevice> CreateColorDevice(
const Common::ParamPackage& params);
/**
* Creates a motion device from the parameters given.
* @param params contains parameters for creating the device: