Skip to content

Commit

Permalink
Merge branch 'xenia-canary:canary_experimental' into Custom
Browse files Browse the repository at this point in the history
  • Loading branch information
backgamon authored Jun 1, 2024
2 parents f0705f7 + ce990e2 commit d607c1f
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 22 deletions.
115 changes: 101 additions & 14 deletions src/xenia/hid/input_system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
******************************************************************************
*/

#include "xenia/base/logging.h"

#include "xenia/hid/input_system.h"

#include "xenia/base/profiling.h"
Expand All @@ -18,6 +20,13 @@ namespace hid {

DEFINE_bool(vibration, true, "Toggle controller vibration.", "HID");

DEFINE_double(left_stick_deadzone_percentage, 0.0,
"Defines deadzone level for left stick. Allowed range [0.0-1.0].",
"HID");
DEFINE_double(
right_stick_deadzone_percentage, 0.0,
"Defines deadzone level for right stick. Allowed range [0.0-1.0].", "HID");

InputSystem::InputSystem(xe::ui::Window* window) : window_(window) {}

InputSystem::~InputSystem() = default;
Expand All @@ -28,15 +37,30 @@ void InputSystem::AddDriver(std::unique_ptr<InputDriver> driver) {
drivers_.push_back(std::move(driver));
}

void InputSystem::UpdateUsedSlot(uint8_t slot, bool connected) {
void InputSystem::UpdateUsedSlot(InputDriver* driver, uint8_t slot,
bool connected) {
if (slot == 0xFF) {
slot = 0;
}

if (connected) {
connected_slot |= (1 << slot);
} else {
connected_slot &= ~(1 << slot);
if (connected_slots.test(slot) == connected) {
// No state change, so nothing to do.
return;
}

XELOGI(controller_slot_state_change_message[connected].c_str(), slot);
connected_slots.flip(slot);

if (driver) {
X_INPUT_CAPABILITIES capabilities = {};
const X_RESULT result = driver->GetCapabilities(slot, 0, &capabilities);
if (result != X_STATUS_SUCCESS) {
return;
}

controllers_max_joystick_value[slot] = {
{capabilities.gamepad.thumb_lx, capabilities.gamepad.thumb_ly},
{capabilities.gamepad.thumb_rx, capabilities.gamepad.thumb_ry}};
}
}

Expand All @@ -51,11 +75,11 @@ X_RESULT InputSystem::GetCapabilities(uint32_t user_index, uint32_t flags,
any_connected = true;
}
if (result == X_ERROR_SUCCESS) {
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(driver.get(), user_index, any_connected);
return result;
}
}
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(nullptr, user_index, any_connected);
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
}

Expand All @@ -69,11 +93,12 @@ X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE* out_state) {
any_connected = true;
}
if (result == X_ERROR_SUCCESS) {
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(driver.get(), user_index, any_connected);
AdjustDeadzoneLevels(user_index, &out_state->gamepad);
return result;
}
}
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(nullptr, user_index, any_connected);
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
}

Expand All @@ -88,11 +113,11 @@ X_RESULT InputSystem::SetState(uint32_t user_index,
any_connected = true;
}
if (result == X_ERROR_SUCCESS) {
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(driver.get(), user_index, any_connected);
return result;
}
}
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(nullptr, user_index, any_connected);
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
}

Expand All @@ -107,11 +132,11 @@ X_RESULT InputSystem::GetKeystroke(uint32_t user_index, uint32_t flags,
any_connected = true;
}
if (result == X_ERROR_SUCCESS || result == X_ERROR_EMPTY) {
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(driver.get(), user_index, any_connected);
return result;
}
}
UpdateUsedSlot(user_index, any_connected);
UpdateUsedSlot(nullptr, user_index, any_connected);
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
}

Expand All @@ -120,11 +145,73 @@ void InputSystem::ToggleVibration() {
// Send instant update to vibration state to prevent awaiting for next tick.
X_INPUT_VIBRATION vibration = X_INPUT_VIBRATION();

for (uint8_t user_index = 0; user_index < 4; user_index++) {
for (uint8_t user_index = 0; user_index < max_allowed_controllers;
user_index++) {
SetState(user_index, &vibration);
}
}

void InputSystem::AdjustDeadzoneLevels(const uint8_t slot,
X_INPUT_GAMEPAD* gamepad) {
if (slot > max_allowed_controllers) {
return;
}

// Left stick
if (cvars::left_stick_deadzone_percentage > 0.0 &&
cvars::left_stick_deadzone_percentage < 1.0) {
const double deadzone_lx_percentage =
controllers_max_joystick_value[slot].first.first *
cvars::left_stick_deadzone_percentage;
const double deadzone_ly_percentage =
controllers_max_joystick_value[slot].first.second *
cvars::left_stick_deadzone_percentage;

const double theta = std::atan2(static_cast<double>(gamepad->thumb_ly),
static_cast<double>(gamepad->thumb_lx));

const double deadzone_y_value = std::sin(theta) * deadzone_ly_percentage;
const double deadzone_x_value = std::cos(theta) * deadzone_lx_percentage;

if (gamepad->thumb_ly > -deadzone_y_value &&
gamepad->thumb_ly < deadzone_y_value) {
gamepad->thumb_ly = 0;
}

if (gamepad->thumb_lx > -deadzone_x_value &&
gamepad->thumb_lx < deadzone_x_value) {
gamepad->thumb_lx = 0;
}
}

// Right stick
if (cvars::right_stick_deadzone_percentage > 0.0 &&
cvars::right_stick_deadzone_percentage < 1.0) {
const double deadzone_rx_percentage =
controllers_max_joystick_value[slot].second.first *
cvars::right_stick_deadzone_percentage;
const double deadzone_ry_percentage =
controllers_max_joystick_value[slot].second.second *
cvars::right_stick_deadzone_percentage;

const double theta = std::atan2(static_cast<double>(gamepad->thumb_ry),
static_cast<double>(gamepad->thumb_rx));

const double deadzone_y_value = std::sin(theta) * deadzone_ry_percentage;
const double deadzone_x_value = std::cos(theta) * deadzone_rx_percentage;

if (gamepad->thumb_ry > -deadzone_y_value &&
gamepad->thumb_ry < deadzone_y_value) {
gamepad->thumb_ry = 0;
}

if (gamepad->thumb_rx > -deadzone_x_value &&
gamepad->thumb_rx < deadzone_x_value) {
gamepad->thumb_rx = 0;
}
}
}

X_INPUT_VIBRATION InputSystem::ModifyVibrationLevel(
X_INPUT_VIBRATION* vibration) {
X_INPUT_VIBRATION modified_vibration = *vibration;
Expand Down
25 changes: 21 additions & 4 deletions src/xenia/hid/input_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#ifndef XENIA_HID_INPUT_SYSTEM_H_
#define XENIA_HID_INPUT_SYSTEM_H_

#include <bitset>
#include <memory>
#include <vector>
#include "xenia/base/mutex.h"
Expand All @@ -26,6 +27,8 @@ class Window;
namespace xe {
namespace hid {

static constexpr uint8_t max_allowed_controllers = 4;

class InputSystem {
public:
explicit InputSystem(xe::ui::Window* window);
Expand All @@ -45,18 +48,32 @@ class InputSystem {
X_INPUT_KEYSTROKE* out_keystroke);

void ToggleVibration();
void UpdateUsedSlot(uint8_t slot, bool connected);
uint8_t GetConnectedSlots() const { return connected_slot; }

const std::bitset<max_allowed_controllers> GetConnectedSlots() const {
return connected_slots;
}

std::unique_lock<xe_unlikely_mutex> lock();

private:
typedef std::pair<uint16_t, uint16_t> joystick_value;

const std::string controller_slot_state_change_message[2] = {
"Controller disconnected from slot {}.",
"New controller connected to slot {}."};

void UpdateUsedSlot(InputDriver* driver, uint8_t slot, bool connected);
void AdjustDeadzoneLevels(const uint8_t slot, X_INPUT_GAMEPAD* gamepad);
X_INPUT_VIBRATION ModifyVibrationLevel(X_INPUT_VIBRATION* vibration);

xe::ui::Window* window_ = nullptr;

std::vector<std::unique_ptr<InputDriver>> drivers_;

X_INPUT_VIBRATION ModifyVibrationLevel(X_INPUT_VIBRATION* vibration);
uint8_t connected_slot = 0b0001;
std::bitset<max_allowed_controllers> connected_slots = {};
std::array<std::pair<joystick_value, joystick_value>, max_allowed_controllers>
controllers_max_joystick_value = {};

xe_unlikely_mutex lock_;
};

Expand Down
6 changes: 3 additions & 3 deletions src/xenia/kernel/kernel_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ bool KernelState::Restore(ByteStream* stream) {
return true;
}

uint8_t KernelState::GetConnectedUsers() const {
std::bitset<4> KernelState::GetConnectedUsers() const {
auto input_sys = emulator_->input_system();

auto lock = input_sys->lock();
Expand Down Expand Up @@ -1109,10 +1109,10 @@ void KernelState::EmulateCPInterruptDPC(uint32_t interrupt_callback,
}

void KernelState::UpdateUsedUserProfiles() {
const uint8_t used_slots_bitmask = GetConnectedUsers();
const std::bitset<4> used_slots = GetConnectedUsers();

for (uint32_t i = 1; i < cvars::max_signed_profiles; i++) {
bool is_used = used_slots_bitmask & (1 << i);
bool is_used = used_slots.test(i);

if (IsUserSignedIn(i) && !is_used) {
user_profiles_.erase(i);
Expand Down
3 changes: 2 additions & 1 deletion src/xenia/kernel/kernel_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define XENIA_KERNEL_KERNEL_STATE_H_

#include <atomic>
#include <bitset>
#include <condition_variable>
#include <functional>
#include <list>
Expand Down Expand Up @@ -193,7 +194,7 @@ class KernelState {
return content_manager_.get();
}

uint8_t GetConnectedUsers() const;
std::bitset<4> GetConnectedUsers() const;
void UpdateUsedUserProfiles();

bool IsUserSignedIn(uint32_t index) const {
Expand Down

0 comments on commit d607c1f

Please sign in to comment.