/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/hid/input_system.h" #include "xenia/base/profiling.h" #include "xenia/hid/hid_flags.h" #include "xenia/hid/input_driver.h" namespace xe { namespace hid { DEFINE_bool(vibration, true, "Toggle controller vibration.", "HID"); InputSystem::InputSystem(xe::ui::Window* window) : window_(window) {} InputSystem::~InputSystem() = default; X_STATUS InputSystem::Setup() { return X_STATUS_SUCCESS; } void InputSystem::AddDriver(std::unique_ptr driver) { drivers_.push_back(std::move(driver)); } void InputSystem::UpdateUsedSlot(uint8_t slot, bool connected) { if (slot == 0xFF) { slot = 0; } if (connected) { connected_slot |= (1 << slot); } else { connected_slot &= ~(1 << slot); } } X_RESULT InputSystem::GetCapabilities(uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES* out_caps) { SCOPE_profile_cpu_f("hid"); bool any_connected = false; for (auto& driver : drivers_) { X_RESULT result = driver->GetCapabilities(user_index, flags, out_caps); if (result != X_ERROR_DEVICE_NOT_CONNECTED) { any_connected = true; } if (result == X_ERROR_SUCCESS) { UpdateUsedSlot(user_index, any_connected); return result; } } UpdateUsedSlot(user_index, any_connected); return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; } X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE* out_state) { SCOPE_profile_cpu_f("hid"); bool any_connected = false; for (auto& driver : drivers_) { X_RESULT result = driver->GetState(user_index, out_state); if (result != X_ERROR_DEVICE_NOT_CONNECTED) { any_connected = true; } if (result == X_ERROR_SUCCESS) { UpdateUsedSlot(user_index, any_connected); return result; } } UpdateUsedSlot(user_index, any_connected); return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; } X_RESULT InputSystem::SetState(uint32_t user_index, X_INPUT_VIBRATION* vibration) { SCOPE_profile_cpu_f("hid"); X_INPUT_VIBRATION modified_vibration = ModifyVibrationLevel(vibration); bool any_connected = false; for (auto& driver : drivers_) { X_RESULT result = driver->SetState(user_index, &modified_vibration); if (result != X_ERROR_DEVICE_NOT_CONNECTED) { any_connected = true; } if (result == X_ERROR_SUCCESS) { UpdateUsedSlot(user_index, any_connected); return result; } } UpdateUsedSlot(user_index, any_connected); return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; } X_RESULT InputSystem::GetKeystroke(uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE* out_keystroke) { SCOPE_profile_cpu_f("hid"); bool any_connected = false; for (auto& driver : drivers_) { X_RESULT result = driver->GetKeystroke(user_index, flags, out_keystroke); if (result != X_ERROR_DEVICE_NOT_CONNECTED) { any_connected = true; } if (result == X_ERROR_SUCCESS || result == X_ERROR_EMPTY) { UpdateUsedSlot(user_index, any_connected); return result; } } UpdateUsedSlot(user_index, any_connected); return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED; } void InputSystem::ToggleVibration() { OVERRIDE_bool(vibration, !cvars::vibration); // 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++) { SetState(user_index, &vibration); } } X_INPUT_VIBRATION InputSystem::ModifyVibrationLevel( X_INPUT_VIBRATION* vibration) { X_INPUT_VIBRATION modified_vibration = *vibration; if (cvars::vibration) { return modified_vibration; } // TODO(Gliniak): Use modifier instead of boolean value. modified_vibration.left_motor_speed = 0; modified_vibration.right_motor_speed = 0; return modified_vibration; } std::unique_lock InputSystem::lock() { return std::unique_lock{lock_}; } } // namespace hid } // namespace xe