Merge pull request #7575 from lioncash/input

input_engine: Minor object churn cleanup
This commit is contained in:
bunnei 2021-12-13 16:50:54 -08:00 committed by GitHub
commit ad45963b45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 109 additions and 114 deletions

View file

@ -266,11 +266,9 @@ class OutputDevice {
public:
virtual ~OutputDevice() = default;
virtual void SetLED([[maybe_unused]] LedStatus led_status) {
return;
}
virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) {
virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
return VibrationError::NotSupported;
}

View file

@ -69,7 +69,7 @@ private:
libusb_device_handle* handle{};
};
GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) {
GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
if (usb_adapter_handle) {
return;
}
@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
return true;
}
Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier,
const Common::Input::VibrationStatus vibration) {
Common::Input::VibrationError GCAdapter::SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
const auto processed_amplitude =
static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);

View file

@ -22,13 +22,13 @@ namespace InputCommon {
class LibUSBContext;
class LibUSBDeviceHandle;
class GCAdapter : public InputCommon::InputEngine {
class GCAdapter : public InputEngine {
public:
explicit GCAdapter(const std::string& input_engine_);
~GCAdapter();
explicit GCAdapter(std::string input_engine_);
~GCAdapter() override;
Common::Input::VibrationError SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override;
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
/// Used for automapping features
std::vector<Common::ParamPackage> GetInputDevices() const override;

View file

@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = {
.pad = 1,
};
Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) {
Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
// Keyboard is broken into 3 diferent sets:
// key: Unfiltered intended for controllers.
// keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation.

View file

@ -12,9 +12,9 @@ namespace InputCommon {
* A button device factory representing a keyboard. It receives keyboard events and forward them
* to all button devices it created.
*/
class Keyboard final : public InputCommon::InputEngine {
class Keyboard final : public InputEngine {
public:
explicit Keyboard(const std::string& input_engine_);
explicit Keyboard(std::string input_engine_);
/**
* Sets the status of all buttons bound with the key to pressed

View file

@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = {
.pad = 0,
};
Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) {
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
PreSetController(identifier);
PreSetAxis(identifier, mouse_axis_x);
PreSetAxis(identifier, mouse_axis_y);

View file

@ -27,9 +27,9 @@ enum class MouseButton {
* A button device factory representing a keyboard. It receives keyboard events and forward them
* to all button devices it created.
*/
class Mouse final : public InputCommon::InputEngine {
class Mouse final : public InputEngine {
public:
explicit Mouse(const std::string& input_engine_);
explicit Mouse(std::string input_engine_);
/**
* Signals that mouse has moved.

View file

@ -88,7 +88,7 @@ public:
return true;
}
BasicMotion GetMotion() {
const BasicMotion& GetMotion() const {
return motion;
}
@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
if (joystick->UpdateMotion(event.csensor)) {
const PadIdentifier identifier = joystick->GetPadIdentifier();
SetMotion(identifier, 0, joystick->GetMotion());
};
}
}
break;
}
@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() {
joystick_map.clear();
}
SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) {
SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
if (!Settings::values.enable_raw_input) {
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
@ -491,8 +491,9 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
}
return devices;
}
Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier,
const Common::Input::VibrationStatus vibration) {
Common::Input::VibrationError SDLDriver::SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
const auto joystick =
GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port));
const auto process_amplitude_exp = [](f32 amplitude, f32 factor) {
@ -526,6 +527,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi
return Common::Input::VibrationError::None;
}
Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,
s32 axis, float value) const {
Common::ParamPackage params{};

View file

@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController;
using SDL_Joystick = struct _SDL_Joystick;
using SDL_JoystickID = s32;
namespace InputCommon {
class SDLJoystick;
using ButtonBindings =
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
using ZButtonBindings =
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
namespace InputCommon {
class SDLJoystick;
class SDLDriver : public InputCommon::InputEngine {
class SDLDriver : public InputEngine {
public:
/// Initializes and registers SDL device factories
SDLDriver(const std::string& input_engine_);
explicit SDLDriver(std::string input_engine_);
/// Unregisters SDL device factories and shut them down.
~SDLDriver() override;
@ -59,7 +59,7 @@ public:
u8 GetHatButtonId(const std::string& direction_name) const override;
Common::Input::VibrationError SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override;
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
private:
void InitJoystick(int joystick_index);

View file

@ -46,7 +46,7 @@ constexpr std::array<std::pair<std::string_view, TasButton>, 20> text_to_tas_but
{"KEY_ZR", TasButton::TRIGGER_ZR},
};
Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) {
Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) {
PadIdentifier identifier{
.guid = Common::UUID{},

View file

@ -81,10 +81,10 @@ enum class TasState {
Stopped,
};
class Tas final : public InputCommon::InputEngine {
class Tas final : public InputEngine {
public:
explicit Tas(const std::string& input_engine_);
~Tas();
explicit Tas(std::string input_engine_);
~Tas() override;
/**
* Changes the input status that will be stored in each frame

View file

@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = {
.pad = 0,
};
TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) {
TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
PreSetController(identifier);
}

View file

@ -12,9 +12,9 @@ namespace InputCommon {
* A button device factory representing a keyboard. It receives keyboard events and forward them
* to all button devices it created.
*/
class TouchScreen final : public InputCommon::InputEngine {
class TouchScreen final : public InputEngine {
public:
explicit TouchScreen(const std::string& input_engine_);
explicit TouchScreen(std::string input_engine_);
/**
* Signals that mouse has moved.

View file

@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) {
socket->Loop();
}
UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) {
UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
LOG_INFO(Input, "Udp Initialization started");
ReloadSockets();
}

View file

@ -49,10 +49,10 @@ struct DeviceStatus {
* A button device factory representing a keyboard. It receives keyboard events and forward them
* to all button devices it created.
*/
class UDPClient final : public InputCommon::InputEngine {
class UDPClient final : public InputEngine {
public:
explicit UDPClient(const std::string& input_engine_);
~UDPClient();
explicit UDPClient(std::string input_engine_);
~UDPClient() override;
void ReloadSockets();

View file

@ -10,41 +10,31 @@ namespace InputCommon {
void InputEngine::PreSetController(const PadIdentifier& identifier) {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
controller_list.insert_or_assign(identifier, ControllerData{});
}
controller_list.try_emplace(identifier);
}
void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {
std::lock_guard lock{mutex};
ControllerData& controller = controller_list.at(identifier);
if (!controller.buttons.contains(button)) {
controller.buttons.insert_or_assign(button, false);
}
controller.buttons.try_emplace(button, false);
}
void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {
std::lock_guard lock{mutex};
ControllerData& controller = controller_list.at(identifier);
if (!controller.hat_buttons.contains(button)) {
controller.hat_buttons.insert_or_assign(button, u8{0});
}
controller.hat_buttons.try_emplace(button, u8{0});
}
void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {
std::lock_guard lock{mutex};
ControllerData& controller = controller_list.at(identifier);
if (!controller.axes.contains(axis)) {
controller.axes.insert_or_assign(axis, 0.0f);
}
controller.axes.try_emplace(axis, 0.0f);
}
void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {
std::lock_guard lock{mutex};
ControllerData& controller = controller_list.at(identifier);
if (!controller.motions.contains(motion)) {
controller.motions.insert_or_assign(motion, BasicMotion{});
}
controller.motions.try_emplace(motion);
}
void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {
@ -91,7 +81,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value
TriggerOnBatteryChange(identifier, value);
}
void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) {
void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {
{
std::lock_guard lock{mutex};
ControllerData& controller = controller_list.at(identifier);
@ -104,85 +94,93 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMo
bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
identifier.pad, identifier.port);
return false;
}
ControllerData controller = controller_list.at(identifier);
if (!controller.buttons.contains(button)) {
const ControllerData& controller = controller_iter->second;
const auto button_iter = controller.buttons.find(button);
if (button_iter == controller.buttons.cend()) {
LOG_ERROR(Input, "Invalid button {}", button);
return false;
}
return controller.buttons.at(button);
return button_iter->second;
}
bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
identifier.pad, identifier.port);
return false;
}
ControllerData controller = controller_list.at(identifier);
if (!controller.hat_buttons.contains(button)) {
const ControllerData& controller = controller_iter->second;
const auto hat_iter = controller.hat_buttons.find(button);
if (hat_iter == controller.hat_buttons.cend()) {
LOG_ERROR(Input, "Invalid hat button {}", button);
return false;
}
return (controller.hat_buttons.at(button) & direction) != 0;
return (hat_iter->second & direction) != 0;
}
f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
identifier.pad, identifier.port);
return 0.0f;
}
ControllerData controller = controller_list.at(identifier);
if (!controller.axes.contains(axis)) {
const ControllerData& controller = controller_iter->second;
const auto axis_iter = controller.axes.find(axis);
if (axis_iter == controller.axes.cend()) {
LOG_ERROR(Input, "Invalid axis {}", axis);
return 0.0f;
}
return controller.axes.at(axis);
return axis_iter->second;
}
BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
identifier.pad, identifier.port);
return BatteryLevel::Charging;
}
ControllerData controller = controller_list.at(identifier);
const ControllerData& controller = controller_iter->second;
return controller.battery;
}
BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
std::lock_guard lock{mutex};
if (!controller_list.contains(identifier)) {
const auto controller_iter = controller_list.find(identifier);
if (controller_iter == controller_list.cend()) {
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
identifier.pad, identifier.port);
return {};
}
ControllerData controller = controller_list.at(identifier);
const ControllerData& controller = controller_iter->second;
return controller.motions.at(motion);
}
void InputEngine::ResetButtonState() {
for (std::pair<PadIdentifier, ControllerData> controller : controller_list) {
for (std::pair<int, bool> button : controller.second.buttons) {
for (const auto& controller : controller_list) {
for (const auto& button : controller.second.buttons) {
SetButton(controller.first, button.first, false);
}
for (std::pair<int, bool> button : controller.second.hat_buttons) {
for (const auto& button : controller.second.hat_buttons) {
SetHatButton(controller.first, button.first, false);
}
}
}
void InputEngine::ResetAnalogState() {
for (std::pair<PadIdentifier, ControllerData> controller : controller_list) {
for (std::pair<int, float> axis : controller.second.axes) {
for (const auto& controller : controller_list) {
for (const auto& axis : controller.second.axes) {
SetAxis(controller.first, axis.first, 0.0);
}
}
@ -190,7 +188,7 @@ void InputEngine::ResetAnalogState() {
void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {
std::lock_guard lock{mutex_callback};
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {
continue;
@ -218,7 +216,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but
void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {
std::lock_guard lock{mutex_callback};
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {
continue;
@ -247,7 +245,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int
void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {
std::lock_guard lock{mutex_callback};
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {
continue;
@ -274,7 +272,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,
void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
[[maybe_unused]] BatteryLevel value) {
std::lock_guard lock{mutex_callback};
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {
continue;
@ -286,9 +284,9 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
}
void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
BasicMotion value) {
const BasicMotion& value) {
std::lock_guard lock{mutex_callback};
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
for (const auto& poller_pair : callback_list) {
const InputIdentifier& poller = poller_pair.second;
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {
continue;
@ -342,7 +340,7 @@ const std::string& InputEngine::GetEngineName() const {
int InputEngine::SetCallback(InputIdentifier input_identifier) {
std::lock_guard lock{mutex_callback};
callback_list.insert_or_assign(last_callback_key, input_identifier);
callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));
return last_callback_key++;
}

View file

@ -23,15 +23,15 @@ struct PadIdentifier {
friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;
};
// Basic motion data containing data from the sensors and a timestamp in microsecons
// Basic motion data containing data from the sensors and a timestamp in microseconds
struct BasicMotion {
float gyro_x;
float gyro_y;
float gyro_z;
float accel_x;
float accel_y;
float accel_z;
u64 delta_timestamp;
float gyro_x{};
float gyro_y{};
float gyro_z{};
float accel_x{};
float accel_y{};
float accel_z{};
u64 delta_timestamp{};
};
// Stages of a battery charge
@ -102,9 +102,7 @@ struct InputIdentifier {
class InputEngine {
public:
explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {
callback_list.clear();
}
explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {}
virtual ~InputEngine() = default;
@ -116,14 +114,12 @@ public:
// Sets a led pattern for a controller
virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier,
[[maybe_unused]] const Common::Input::LedStatus led_status) {
return;
}
[[maybe_unused]] const Common::Input::LedStatus& led_status) {}
// Sets rumble to a controller
virtual Common::Input::VibrationError SetRumble(
[[maybe_unused]] const PadIdentifier& identifier,
[[maybe_unused]] const Common::Input::VibrationStatus vibration) {
[[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
return Common::Input::VibrationError::NotSupported;
}
@ -140,36 +136,36 @@ public:
/// Used for automapping features
virtual std::vector<Common::ParamPackage> GetInputDevices() const {
return {};
};
}
/// Retrieves the button mappings for the given device
virtual InputCommon::ButtonMapping GetButtonMappingForDevice(
virtual ButtonMapping GetButtonMappingForDevice(
[[maybe_unused]] const Common::ParamPackage& params) {
return {};
};
}
/// Retrieves the analog mappings for the given device
virtual InputCommon::AnalogMapping GetAnalogMappingForDevice(
virtual AnalogMapping GetAnalogMappingForDevice(
[[maybe_unused]] const Common::ParamPackage& params) {
return {};
};
}
/// Retrieves the motion mappings for the given device
virtual InputCommon::MotionMapping GetMotionMappingForDevice(
virtual MotionMapping GetMotionMappingForDevice(
[[maybe_unused]] const Common::ParamPackage& params) {
return {};
};
}
/// Retrieves the name of the given input.
virtual Common::Input::ButtonNames GetUIName(
[[maybe_unused]] const Common::ParamPackage& params) const {
return Common::Input::ButtonNames::Engine;
};
}
/// Retrieves the index number of the given hat button direction
virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const {
return 0;
};
}
void PreSetController(const PadIdentifier& identifier);
void PreSetButton(const PadIdentifier& identifier, int button);
@ -194,7 +190,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, BatteryLevel value);
void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value);
void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
return "Unknown";
@ -206,14 +202,15 @@ private:
std::unordered_map<int, u8> hat_buttons;
std::unordered_map<int, float> axes;
std::unordered_map<int, BasicMotion> motions;
BatteryLevel battery;
BatteryLevel battery{};
};
void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value);
void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value);
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value);
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
const BasicMotion& value);
bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
const PadIdentifier& identifier, EngineInputType type,

View file

@ -668,12 +668,12 @@ public:
explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)
: identifier(identifier_), input_engine(input_engine_) {}
virtual void SetLED(Common::Input::LedStatus led_status) {
virtual void SetLED(const Common::Input::LedStatus& led_status) {
input_engine->SetLeds(identifier, led_status);
}
virtual Common::Input::VibrationError SetVibration(
Common::Input::VibrationStatus vibration_status) {
const Common::Input::VibrationStatus& vibration_status) {
return input_engine->SetRumble(identifier, vibration_status);
}