| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- // Copyright 2021 yuzu Emulator Project
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included
- #include <algorithm>
- #include <fmt/format.h>
- #include "core/hid/emulated_devices.h"
- #include "core/hid/input_converter.h"
- namespace Core::HID {
- EmulatedDevices::EmulatedDevices() = default;
- EmulatedDevices::~EmulatedDevices() = default;
- void EmulatedDevices::ReloadFromSettings() {
- ReloadInput();
- }
- void EmulatedDevices::ReloadInput() {
- // If you load any device here add the equivalent to the UnloadInput() function
- std::size_t key_index = 0;
- for (auto& mouse_device : mouse_button_devices) {
- Common::ParamPackage mouse_params;
- mouse_params.Set("engine", "mouse");
- mouse_params.Set("button", static_cast<int>(key_index));
- mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
- key_index++;
- }
- mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
- "engine:mouse,axis_x:0,axis_y:1");
- // First two axis are reserved for mouse position
- key_index = 2;
- for (auto& mouse_device : mouse_analog_devices) {
- Common::ParamPackage mouse_params;
- mouse_params.Set("engine", "mouse");
- mouse_params.Set("axis", static_cast<int>(key_index));
- mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
- key_index++;
- }
- key_index = 0;
- for (auto& keyboard_device : keyboard_devices) {
- // Keyboard keys are only mapped on port 1, pad 0
- Common::ParamPackage keyboard_params;
- keyboard_params.Set("engine", "keyboard");
- keyboard_params.Set("button", static_cast<int>(key_index));
- keyboard_params.Set("port", 1);
- keyboard_params.Set("pad", 0);
- keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
- key_index++;
- }
- key_index = 0;
- for (auto& keyboard_device : keyboard_modifier_devices) {
- // Keyboard moddifiers are only mapped on port 1, pad 1
- Common::ParamPackage keyboard_params;
- keyboard_params.Set("engine", "keyboard");
- keyboard_params.Set("button", static_cast<int>(key_index));
- keyboard_params.Set("port", 1);
- keyboard_params.Set("pad", 1);
- keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
- key_index++;
- }
- for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
- if (!mouse_button_devices[index]) {
- continue;
- }
- Common::Input::InputCallback button_callback{
- [this, index](Common::Input::CallbackStatus callback) {
- SetMouseButton(callback, index);
- }};
- mouse_button_devices[index]->SetCallback(button_callback);
- }
- for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
- if (!mouse_analog_devices[index]) {
- continue;
- }
- Common::Input::InputCallback button_callback{
- [this, index](Common::Input::CallbackStatus callback) {
- SetMouseAnalog(callback, index);
- }};
- mouse_analog_devices[index]->SetCallback(button_callback);
- }
- if (mouse_stick_device) {
- Common::Input::InputCallback button_callback{
- [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }};
- mouse_stick_device->SetCallback(button_callback);
- }
- for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
- if (!keyboard_devices[index]) {
- continue;
- }
- Common::Input::InputCallback button_callback{
- [this, index](Common::Input::CallbackStatus callback) {
- SetKeyboardButton(callback, index);
- }};
- keyboard_devices[index]->SetCallback(button_callback);
- }
- for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
- if (!keyboard_modifier_devices[index]) {
- continue;
- }
- Common::Input::InputCallback button_callback{
- [this, index](Common::Input::CallbackStatus callback) {
- SetKeyboardModifier(callback, index);
- }};
- keyboard_modifier_devices[index]->SetCallback(button_callback);
- }
- }
- void EmulatedDevices::UnloadInput() {
- for (auto& button : mouse_button_devices) {
- button.reset();
- }
- for (auto& analog : mouse_analog_devices) {
- analog.reset();
- }
- mouse_stick_device.reset();
- for (auto& button : keyboard_devices) {
- button.reset();
- }
- for (auto& button : keyboard_modifier_devices) {
- button.reset();
- }
- }
- void EmulatedDevices::EnableConfiguration() {
- is_configuring = true;
- SaveCurrentConfig();
- }
- void EmulatedDevices::DisableConfiguration() {
- is_configuring = false;
- }
- bool EmulatedDevices::IsConfiguring() const {
- return is_configuring;
- }
- void EmulatedDevices::SaveCurrentConfig() {
- if (!is_configuring) {
- return;
- }
- }
- void EmulatedDevices::RestoreConfig() {
- if (!is_configuring) {
- return;
- }
- ReloadFromSettings();
- }
- void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) {
- if (index >= device_status.keyboard_values.size()) {
- return;
- }
- std::lock_guard lock{mutex};
- bool value_changed = false;
- const auto new_status = TransformToButton(callback);
- auto& current_status = device_status.keyboard_values[index];
- current_status.toggle = new_status.toggle;
- // Update button status with current status
- if (!current_status.toggle) {
- current_status.locked = false;
- if (current_status.value != new_status.value) {
- current_status.value = new_status.value;
- value_changed = true;
- }
- } else {
- // Toggle button and lock status
- if (new_status.value && !current_status.locked) {
- current_status.locked = true;
- current_status.value = !current_status.value;
- value_changed = true;
- }
- // Unlock button, ready for next press
- if (!new_status.value && current_status.locked) {
- current_status.locked = false;
- }
- }
- if (!value_changed) {
- return;
- }
- if (is_configuring) {
- TriggerOnChange(DeviceTriggerType::Keyboard);
- return;
- }
- // Index should be converted from NativeKeyboard to KeyboardKeyIndex
- UpdateKey(index, current_status.value);
- TriggerOnChange(DeviceTriggerType::Keyboard);
- }
- void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
- constexpr std::size_t KEYS_PER_BYTE = 8;
- auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
- const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
- if (status) {
- entry = entry | mask;
- } else {
- entry = static_cast<u8>(entry & ~mask);
- }
- }
- void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback,
- std::size_t index) {
- if (index >= device_status.keyboard_moddifier_values.size()) {
- return;
- }
- std::lock_guard lock{mutex};
- bool value_changed = false;
- const auto new_status = TransformToButton(callback);
- auto& current_status = device_status.keyboard_moddifier_values[index];
- current_status.toggle = new_status.toggle;
- // Update button status with current
- if (!current_status.toggle) {
- current_status.locked = false;
- if (current_status.value != new_status.value) {
- current_status.value = new_status.value;
- value_changed = true;
- }
- } else {
- // Toggle button and lock status
- if (new_status.value && !current_status.locked) {
- current_status.locked = true;
- current_status.value = !current_status.value;
- value_changed = true;
- }
- // Unlock button ready for next press
- if (!new_status.value && current_status.locked) {
- current_status.locked = false;
- }
- }
- if (!value_changed) {
- return;
- }
- if (is_configuring) {
- TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
- return;
- }
- switch (index) {
- case Settings::NativeKeyboard::LeftControl:
- case Settings::NativeKeyboard::RightControl:
- device_status.keyboard_moddifier_state.control.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::LeftShift:
- case Settings::NativeKeyboard::RightShift:
- device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::LeftAlt:
- device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::RightAlt:
- device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::CapsLock:
- device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::ScrollLock:
- device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
- break;
- case Settings::NativeKeyboard::NumLock:
- device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
- break;
- }
- TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
- }
- void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) {
- if (index >= device_status.mouse_button_values.size()) {
- return;
- }
- std::lock_guard lock{mutex};
- bool value_changed = false;
- const auto new_status = TransformToButton(callback);
- auto& current_status = device_status.mouse_button_values[index];
- current_status.toggle = new_status.toggle;
- // Update button status with current
- if (!current_status.toggle) {
- current_status.locked = false;
- if (current_status.value != new_status.value) {
- current_status.value = new_status.value;
- value_changed = true;
- }
- } else {
- // Toggle button and lock status
- if (new_status.value && !current_status.locked) {
- current_status.locked = true;
- current_status.value = !current_status.value;
- value_changed = true;
- }
- // Unlock button ready for next press
- if (!new_status.value && current_status.locked) {
- current_status.locked = false;
- }
- }
- if (!value_changed) {
- return;
- }
- if (is_configuring) {
- TriggerOnChange(DeviceTriggerType::Mouse);
- return;
- }
- switch (index) {
- case Settings::NativeMouseButton::Left:
- device_status.mouse_button_state.left.Assign(current_status.value);
- break;
- case Settings::NativeMouseButton::Right:
- device_status.mouse_button_state.right.Assign(current_status.value);
- break;
- case Settings::NativeMouseButton::Middle:
- device_status.mouse_button_state.middle.Assign(current_status.value);
- break;
- case Settings::NativeMouseButton::Forward:
- device_status.mouse_button_state.forward.Assign(current_status.value);
- break;
- case Settings::NativeMouseButton::Back:
- device_status.mouse_button_state.back.Assign(current_status.value);
- break;
- }
- TriggerOnChange(DeviceTriggerType::Mouse);
- }
- void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) {
- if (index >= device_status.mouse_analog_values.size()) {
- return;
- }
- std::lock_guard lock{mutex};
- const auto analog_value = TransformToAnalog(callback);
- device_status.mouse_analog_values[index] = analog_value;
- if (is_configuring) {
- device_status.mouse_position_state = {};
- TriggerOnChange(DeviceTriggerType::Mouse);
- return;
- }
- switch (index) {
- case Settings::NativeMouseWheel::X:
- device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
- break;
- case Settings::NativeMouseWheel::Y:
- device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
- break;
- }
- TriggerOnChange(DeviceTriggerType::Mouse);
- }
- void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) {
- std::lock_guard lock{mutex};
- const auto touch_value = TransformToTouch(callback);
- device_status.mouse_stick_value = touch_value;
- if (is_configuring) {
- device_status.mouse_position_state = {};
- TriggerOnChange(DeviceTriggerType::Mouse);
- return;
- }
- device_status.mouse_position_state.x = touch_value.x.value;
- device_status.mouse_position_state.y = touch_value.y.value;
- TriggerOnChange(DeviceTriggerType::Mouse);
- }
- KeyboardValues EmulatedDevices::GetKeyboardValues() const {
- return device_status.keyboard_values;
- }
- KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
- return device_status.keyboard_moddifier_values;
- }
- MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
- return device_status.mouse_button_values;
- }
- KeyboardKey EmulatedDevices::GetKeyboard() const {
- return device_status.keyboard_state;
- }
- KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
- return device_status.keyboard_moddifier_state;
- }
- MouseButton EmulatedDevices::GetMouseButtons() const {
- return device_status.mouse_button_state;
- }
- MousePosition EmulatedDevices::GetMousePosition() const {
- return device_status.mouse_position_state;
- }
- AnalogStickState EmulatedDevices::GetMouseWheel() const {
- return device_status.mouse_wheel_state;
- }
- void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
- for (const auto& poller_pair : callback_list) {
- const InterfaceUpdateCallback& poller = poller_pair.second;
- if (poller.on_change) {
- poller.on_change(type);
- }
- }
- }
- int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
- std::lock_guard lock{mutex};
- callback_list.insert_or_assign(last_callback_key, update_callback);
- return last_callback_key++;
- }
- void EmulatedDevices::DeleteCallback(int key) {
- std::lock_guard lock{mutex};
- const auto& iterator = callback_list.find(key);
- if (iterator == callback_list.end()) {
- LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
- return;
- }
- callback_list.erase(iterator);
- }
- } // namespace Core::HID
|