early-access version 3702

This commit is contained in:
pineappleEA
2023-06-22 07:53:33 +02:00
parent d8ad4a1c8c
commit 7d5a10eb6b
45 changed files with 1799 additions and 331 deletions

View File

@@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
OnMotionUpdate(port, type, id, value);
}},
.on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }},
.on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) {
OnAmiiboUpdate(port, type, amiibo_data);
.on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) {
OnAmiiboUpdate(port, type, tag_info);
}},
.on_camera_data = {[this, port](const std::vector<u8>& camera_data,
Joycon::IrsResolution format) {
@@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c
return Common::Input::NfcState::Success;
};
Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) {
auto handle = GetHandle(identifier);
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
return TranslateDriverResult(handle->StartNfcPolling());
};
Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) {
auto handle = GetHandle(identifier);
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
return TranslateDriverResult(handle->StopNfcPolling());
};
Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier,
std::vector<u8>& out_data) {
auto handle = GetHandle(identifier);
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
return TranslateDriverResult(handle->ReadAmiiboData(out_data));
}
Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier,
const std::vector<u8>& data) {
auto handle = GetHandle(identifier);
if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) {
return Common::Input::NfcState::WriteFailed;
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
return Common::Input::NfcState::Success;
return TranslateDriverResult(handle->WriteNfcData(data));
};
Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
const Common::Input::MifareRequest& request,
Common::Input::MifareRequest& data) {
auto handle = GetHandle(identifier);
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command);
std::vector<Joycon::MifareReadChunk> read_request{};
for (const auto& request_data : request.data) {
if (request_data.command == 0) {
continue;
}
Joycon::MifareReadChunk chunk = {
.command = command,
.sector_key = {},
.sector = request_data.sector,
};
memcpy(chunk.sector_key.data(), request_data.key.data(),
sizeof(Joycon::MifareReadChunk::sector_key));
read_request.emplace_back(chunk);
}
std::vector<Joycon::MifareReadData> read_data(read_request.size());
const auto result = handle->ReadMifareData(read_request, read_data);
if (result == Joycon::DriverResult::Success) {
for (std::size_t i = 0; i < read_request.size(); i++) {
data.data[i] = {
.command = static_cast<u8>(command),
.sector = read_data[i].sector,
.key = {},
.data = read_data[i].data,
};
}
}
return TranslateDriverResult(result);
};
Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier,
const Common::Input::MifareRequest& request) {
auto handle = GetHandle(identifier);
if (handle == nullptr) {
return Common::Input::NfcState::Unknown;
}
const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command);
std::vector<Joycon::MifareWriteChunk> write_request{};
for (const auto& request_data : request.data) {
if (request_data.command == 0) {
continue;
}
Joycon::MifareWriteChunk chunk = {
.command = command,
.sector_key = {},
.sector = request_data.sector,
.data = {},
};
memcpy(chunk.sector_key.data(), request_data.key.data(),
sizeof(Joycon::MifareReadChunk::sector_key));
memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data));
write_request.emplace_back(chunk);
}
return TranslateDriverResult(handle->WriteMifareData(write_request));
};
Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier,
@@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) {
}
void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type,
const std::vector<u8>& amiibo_data) {
const Joycon::TagInfo& tag_info) {
const auto identifier = GetIdentifier(port, type);
const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved
: Common::Input::NfcState::NewAmiibo;
SetNfc(identifier, {nfc_state, amiibo_data});
const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved
: Common::Input::NfcState::NewAmiibo;
const Common::Input::NfcStatus nfc_status{
.state = nfc_state,
.uuid_length = tag_info.uuid_length,
.protocol = tag_info.protocol,
.tag_type = tag_info.tag_type,
.uuid = tag_info.uuid,
};
SetNfc(identifier, nfc_status);
}
void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
@@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
return "Unknown Switch Controller";
}
}
Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const {
switch (result) {
case Joycon::DriverResult::Success:
return Common::Input::NfcState::Success;
case Joycon::DriverResult::Disabled:
return Common::Input::NfcState::WrongDeviceState;
case Joycon::DriverResult::NotSupported:
return Common::Input::NfcState::NotSupported;
default:
return Common::Input::NfcState::Unknown;
}
}
} // namespace InputCommon

View File

@@ -15,6 +15,7 @@ using SerialNumber = std::array<u8, 15>;
struct Battery;
struct Color;
struct MotionData;
struct TagInfo;
enum class ControllerType : u8;
enum class DriverResult;
enum class IrsResolution;
@@ -39,9 +40,18 @@ public:
Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier,
Common::Input::CameraFormat camera_format) override;
Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override;
Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override;
Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override;
Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier,
std::vector<u8>& out_data) override;
Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier,
const std::vector<u8>& data) override;
Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier,
const Common::Input::MifareRequest& request,
Common::Input::MifareRequest& out_data) override;
Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier,
const Common::Input::MifareRequest& request) override;
Common::Input::DriverResult SetPollingMode(
const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override;
@@ -82,7 +92,7 @@ private:
const Joycon::MotionData& value);
void OnRingConUpdate(f32 ring_data);
void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type,
const std::vector<u8>& amiibo_data);
const Joycon::TagInfo& amiibo_data);
void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
Joycon::IrsResolution format);
@@ -102,6 +112,8 @@ private:
/// Returns the name of the device in text format
std::string JoyconName(Joycon::ControllerType type) const;
Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const;
std::jthread scan_thread;
// Joycon types are split by type to ease supporting dualjoycon configurations

View File

@@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
UpdateStickInput();
UpdateMotionInput();
if (mouse_panning_timeout++ > 20) {
StopPanning();
}
std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
}
}
@@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() {
return;
}
const float sensitivity =
Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity;
const float length = last_mouse_change.Length();
// Slow movement by 4%
last_mouse_change *= 0.96f;
SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity);
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity);
// Prevent input from exceeding the max range (1.0f) too much,
// but allow some room to make it easier to sustain
if (length > 1.2f) {
last_mouse_change /= length;
last_mouse_change *= 1.2f;
}
auto mouse_change = last_mouse_change;
// Bind the mouse change to [0 <= deadzone_counterweight <= 1,1]
if (length < 1.0f) {
const float deadzone_h_counterweight =
Settings::values.mouse_panning_deadzone_x_counterweight.GetValue();
const float deadzone_v_counterweight =
Settings::values.mouse_panning_deadzone_y_counterweight.GetValue();
mouse_change /= length;
mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f;
mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f;
}
SetAxis(identifier, mouse_axis_x, mouse_change.x);
SetAxis(identifier, mouse_axis_y, -mouse_change.y);
// Decay input over time
const float clamped_length = std::min(1.0f, length);
const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue();
const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f;
const float min_decay = Settings::values.mouse_panning_min_decay.GetValue();
const float clamped_decay = std::min(1 - min_decay / 100.0f, decay);
last_mouse_change *= clamped_decay;
}
void Mouse::UpdateMotionInput() {
const float sensitivity =
Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity;
// This may need its own sensitivity instead of using the average
const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() +
Settings::values.mouse_panning_y_sensitivity.GetValue()) /
2.0f * default_motion_sensitivity;
const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x +
last_motion_change.y * last_motion_change.y);
@@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() {
void Mouse::Move(int x, int y, int center_x, int center_y) {
if (Settings::values.mouse_panning) {
mouse_panning_timeout = 0;
auto mouse_change =
const auto mouse_change =
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
const float x_sensitivity =
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
const float y_sensitivity =
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
last_motion_change += {-mouse_change.y, -mouse_change.x, 0};
const auto move_distance = mouse_change.Length();
if (move_distance == 0) {
return;
}
// Make slow movements at least 3 units on length
if (move_distance < 3.0f) {
// Normalize value
mouse_change /= move_distance;
mouse_change *= 3.0f;
}
// Average mouse movements
last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f);
const auto last_move_distance = last_mouse_change.Length();
// Make fast movements clamp to 8 units on length
if (last_move_distance > 8.0f) {
// Normalize value
last_mouse_change /= last_move_distance;
last_mouse_change *= 8.0f;
}
// Ignore average if it's less than 1 unit and use current movement value
if (last_move_distance < 1.0f) {
last_mouse_change = mouse_change / mouse_change.Length();
}
last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f;
last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f;
return;
}
if (button_pressed) {
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity);
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity);
const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue();
const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue();
SetAxis(identifier, mouse_axis_x,
static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f);
SetAxis(identifier, mouse_axis_y,
static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f);
last_motion_change = {
static_cast<float>(-mouse_move.y) / 50.0f,
@@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() {
button_pressed = false;
}
void Mouse::StopPanning() {
last_mouse_change = {};
}
std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
devices.emplace_back(Common::ParamPackage{

View File

@@ -98,7 +98,6 @@ private:
void UpdateThread(std::stop_token stop_token);
void UpdateStickInput();
void UpdateMotionInput();
void StopPanning();
Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
@@ -108,7 +107,6 @@ private:
Common::Vec3<float> last_motion_change;
Common::Vec2<int> wheel_position;
bool button_pressed;
int mouse_panning_timeout{};
std::jthread update_thread;
};

View File

@@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode(
switch (polling_mode) {
case Common::Input::PollingMode::NFC:
if (state == State::Initialized) {
state = State::WaitingForAmiibo;
}
state = State::Initialized;
return Common::Input::DriverResult::Success;
default:
if (state == State::AmiiboIsOpen) {
if (state == State::TagNearby) {
CloseAmiibo();
}
state = State::Disabled;
return Common::Input::DriverResult::NotSupported;
}
}
@@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc(
[[maybe_unused]] const PadIdentifier& identifier_) const {
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) {
if (state != State::Initialized) {
return Common::Input::NfcState::WrongDeviceState;
}
state = State::WaitingForAmiibo;
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) {
if (state == State::Disabled) {
return Common::Input::NfcState::WrongDeviceState;
}
if (state == State::TagNearby) {
CloseAmiibo();
}
state = State::Initialized;
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_,
std::vector<u8>& out_data) {
if (state != State::TagNearby) {
return Common::Input::NfcState::WrongDeviceState;
}
if (status.tag_type != 1U << 1) {
return Common::Input::NfcState::InvalidTagType;
}
out_data.resize(nfc_data.size());
memcpy(out_data.data(), nfc_data.data(), nfc_data.size());
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::WriteNfcData(
[[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) {
@@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData(
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_,
const Common::Input::MifareRequest& request,
Common::Input::MifareRequest& out_data) {
if (state != State::TagNearby) {
return Common::Input::NfcState::WrongDeviceState;
}
if (status.tag_type != 1U << 6) {
return Common::Input::NfcState::InvalidTagType;
}
for (std::size_t i = 0; i < request.data.size(); i++) {
if (request.data[i].command == 0) {
continue;
}
out_data.data[i].command = request.data[i].command;
out_data.data[i].sector = request.data[i].sector;
const std::size_t sector_index =
request.data[i].sector * sizeof(Common::Input::MifareData::data);
if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) {
return Common::Input::NfcState::WriteFailed;
}
// Ignore the sector key as we don't support it
memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index,
sizeof(Common::Input::MifareData::data));
}
return Common::Input::NfcState::Success;
}
Common::Input::NfcState VirtualAmiibo::WriteMifareData(
const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) {
if (state != State::TagNearby) {
return Common::Input::NfcState::WrongDeviceState;
}
if (status.tag_type != 1U << 6) {
return Common::Input::NfcState::InvalidTagType;
}
for (std::size_t i = 0; i < request.data.size(); i++) {
if (request.data[i].command == 0) {
continue;
}
const std::size_t sector_index =
request.data[i].sector * sizeof(Common::Input::MifareData::data);
if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) {
return Common::Input::NfcState::WriteFailed;
}
// Ignore the sector key as we don't support it
memcpy(nfc_data.data() + sector_index, request.data[i].data.data(),
sizeof(Common::Input::MifareData::data));
}
return Common::Input::NfcState::Success;
}
VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {
return state;
}
@@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {
case AmiiboSizeWithoutPassword:
case AmiiboSizeWithSignature:
nfc_data.resize(AmiiboSize);
status.tag_type = 1U << 1;
status.uuid_length = 7;
break;
case MifareSize:
nfc_data.resize(MifareSize);
status.tag_type = 1U << 6;
status.uuid_length = 4;
break;
default:
return Info::NotAnAmiibo;
}
state = State::AmiiboIsOpen;
status.uuid = {};
status.protocol = 1;
state = State::TagNearby;
status.state = Common::Input::NfcState::NewAmiibo,
memcpy(nfc_data.data(), data.data(), data.size_bytes());
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});
memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length);
SetNfc(identifier, status);
return Info::Success;
}
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
if (state == State::AmiiboIsOpen) {
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});
if (state == State::TagNearby) {
SetNfc(identifier, status);
return Info::Success;
}
@@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
}
VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo
: State::Initialized;
SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}});
if (state != State::TagNearby) {
return Info::Success;
}
state = State::WaitingForAmiibo;
status.state = Common::Input::NfcState::AmiiboRemoved;
SetNfc(identifier, status);
status.tag_type = 0;
return Info::Success;
}

View File

@@ -20,9 +20,10 @@ namespace InputCommon {
class VirtualAmiibo final : public InputEngine {
public:
enum class State {
Disabled,
Initialized,
WaitingForAmiibo,
AmiiboIsOpen,
TagNearby,
};
enum class Info {
@@ -41,9 +42,17 @@ public:
const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;
Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override;
Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override;
Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_,
std::vector<u8>& out_data) override;
Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
const std::vector<u8>& data) override;
Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_,
const Common::Input::MifareRequest& data,
Common::Input::MifareRequest& out_data) override;
Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_,
const Common::Input::MifareRequest& data) override;
State GetCurrentState() const;
@@ -61,8 +70,9 @@ private:
static constexpr std::size_t MifareSize = 0x400;
std::string file_path{};
State state{State::Initialized};
State state{State::Disabled};
std::vector<u8> nfc_data;
Common::Input::NfcStatus status;
Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive};
};
} // namespace InputCommon