summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/hid/input_converter.cpp2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp65
-rw-r--r--src/core/hle/kernel/k_page_table.h15
-rw-r--r--src/input_common/drivers/sdl_driver.cpp5
-rw-r--r--src/input_common/helpers/stick_from_buttons.cpp30
-rw-r--r--src/input_common/helpers/touch_from_buttons.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h4
-rw-r--r--src/yuzu/applets/qt_controller.cpp2
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp89
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h2
-rw-r--r--src/yuzu/configuration/configure_vibration.cpp74
-rw-r--r--src/yuzu/configuration/configure_vibration.h18
-rw-r--r--src/yuzu/configuration/configure_vibration.ui7
15 files changed, 232 insertions, 90 deletions
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 860aab400..cd41607a7 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -28,7 +28,7 @@ Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackSta
if (value > 0.8f) {
battery = Common::Input::BatteryLevel::Full;
}
- if (value >= 1.0f) {
+ if (value >= 0.95f) {
battery = Common::Input::BatteryLevel::Charging;
}
break;
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 393214082..912853e5c 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -61,7 +61,8 @@ constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr
} // namespace
-KPageTable::KPageTable(Core::System& system_) : system{system_} {}
+KPageTable::KPageTable(Core::System& system_)
+ : general_lock{system_.Kernel()}, map_physical_memory_lock{system_.Kernel()}, system{system_} {}
KPageTable::~KPageTable() = default;
@@ -284,7 +285,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Verify that the destination memory is unmapped.
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
@@ -302,7 +303,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
}
ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
const std::size_t num_pages{size / PageSize};
@@ -339,7 +340,7 @@ ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t
}
ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
if (!size) {
return ResultSuccess;
@@ -373,7 +374,7 @@ ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
KPageTable& src_page_table, VAddr src_addr) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
const std::size_t num_pages{size / PageSize};
@@ -401,10 +402,10 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
// Lock the physical memory lock.
- std::lock_guard phys_lk(map_physical_memory_lock);
+ KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
std::size_t mapped_size{};
const VAddr end_addr{addr + size};
@@ -480,7 +481,11 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
}
ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ // Lock the physical memory lock.
+ KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
+
+ // Lock the table.
+ KScopedLightLock lk(general_lock);
const VAddr end_addr{addr + size};
ResultCode result{ResultSuccess};
@@ -542,7 +547,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
}
ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
@@ -581,7 +586,7 @@ ResultCode KPageTable::MapMemory(VAddr dst_addr, VAddr src_addr, std::size_t siz
}
ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
@@ -624,6 +629,8 @@ ResultCode KPageTable::UnmapMemory(VAddr dst_addr, VAddr src_addr, std::size_t s
ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
KMemoryPermission perm) {
+ ASSERT(this->IsLockedByCurrentThread());
+
VAddr cur_addr{addr};
for (const auto& node : page_linked_list.Nodes()) {
@@ -652,7 +659,7 @@ ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Check the memory state.
R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
@@ -669,6 +676,8 @@ ResultCode KPageTable::MapPages(VAddr address, KPageLinkedList& page_linked_list
}
ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
+ ASSERT(this->IsLockedByCurrentThread());
+
VAddr cur_addr{addr};
for (const auto& node : page_linked_list.Nodes()) {
@@ -693,7 +702,7 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Check the memory state.
R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, state, KMemoryPermission::None,
@@ -714,7 +723,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
const size_t num_pages = size / PageSize;
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Verify we can change the memory permission.
KMemoryState old_state;
@@ -768,7 +777,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
}
KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
return block_manager->FindBlock(addr).GetMemoryInfo();
}
@@ -783,7 +792,7 @@ KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
}
ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryState state{};
KMemoryAttribute attribute{};
@@ -801,7 +810,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
}
ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryState state{};
@@ -820,7 +829,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
const size_t num_pages = size / PageSize;
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Verify we can change the memory permission.
KMemoryState old_state;
@@ -849,7 +858,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
KMemoryAttribute::SetMask);
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Verify we can change the memory attribute.
KMemoryState old_state;
@@ -880,7 +889,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask
ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
// Lock the table.
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
// Only process page tables are allowed to set heap size.
ASSERT(!this->IsKernel());
@@ -891,15 +900,15 @@ ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
}
ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
- // Lock the physical memory lock.
- std::lock_guard phys_lk(map_physical_memory_lock);
+ // Lock the physical memory mutex.
+ KScopedLightLock map_phys_mem_lk(map_physical_memory_lock);
// Try to perform a reduction in heap, instead of an extension.
VAddr cur_address{};
std::size_t allocation_size{};
{
// Lock the table.
- std::lock_guard lk(page_table_lock);
+ KScopedLightLock lk(general_lock);
// Validate that setting heap size is possible at all.
R_UNLESS(!is_kernel, ResultOutOfMemory);
@@ -964,7 +973,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
// Map the pages.
{
// Lock the table.
- std::lock_guard lk(page_table_lock);
+ KScopedLightLock lk(general_lock);
// Ensure that the heap hasn't changed since we began executing.
ASSERT(cur_address == current_heap_end);
@@ -1006,7 +1015,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
bool is_map_only, VAddr region_start,
std::size_t region_num_pages, KMemoryState state,
KMemoryPermission perm, PAddr map_addr) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
if (!CanContain(region_start, region_num_pages * PageSize, state)) {
return ResultInvalidCurrentMemory;
@@ -1037,7 +1046,7 @@ ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages,
}
ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryPermission perm{};
if (const ResultCode result{CheckMemoryState(
@@ -1060,7 +1069,7 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
}
ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryPermission perm{};
if (const ResultCode result{CheckMemoryState(
@@ -1083,7 +1092,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
}
ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
@@ -1110,7 +1119,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
}
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
- std::lock_guard lock{page_table_lock};
+ KScopedLightLock lk(general_lock);
KMemoryPermission new_perm = KMemoryPermission::UserReadWrite;
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index ecae939a0..c98887d34 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -5,12 +5,12 @@
#pragma once
#include <memory>
-#include <mutex>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
+#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/result.h"
@@ -147,11 +147,12 @@ private:
}
bool IsLockedByCurrentThread() const {
- return true;
+ return general_lock.IsLockedByCurrentThread();
}
- std::recursive_mutex page_table_lock;
- std::mutex map_physical_memory_lock;
+ mutable KLightLock general_lock;
+ mutable KLightLock map_physical_memory_lock;
+
std::unique_ptr<KMemoryBlockManager> block_manager;
public:
@@ -210,7 +211,7 @@ public:
return alias_code_region_end - alias_code_region_start;
}
size_t GetNormalMemorySize() {
- std::lock_guard lk(page_table_lock);
+ KScopedLightLock lk(general_lock);
return GetHeapSize() + mapped_physical_memory_size;
}
constexpr std::size_t GetAddressSpaceWidth() const {
@@ -252,7 +253,9 @@ public:
constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const {
return !IsOutsideASLRRegion(address, size);
}
- constexpr PAddr GetPhysicalAddr(VAddr addr) {
+
+ PAddr GetPhysicalAddr(VAddr addr) {
+ ASSERT(IsLockedByCurrentThread());
const auto backing_addr = page_table_impl.backing_addr[addr >> PageBits];
ASSERT(backing_addr);
return backing_addr + addr;
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 577bf5c31..b031a8523 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -181,11 +181,10 @@ public:
case SDL_JOYSTICK_POWER_EMPTY:
return BatteryLevel::Empty;
case SDL_JOYSTICK_POWER_LOW:
- return BatteryLevel::Critical;
- case SDL_JOYSTICK_POWER_MEDIUM:
return BatteryLevel::Low;
- case SDL_JOYSTICK_POWER_FULL:
+ case SDL_JOYSTICK_POWER_MEDIUM:
return BatteryLevel::Medium;
+ case SDL_JOYSTICK_POWER_FULL:
case SDL_JOYSTICK_POWER_MAX:
return BatteryLevel::Full;
case SDL_JOYSTICK_POWER_UNKNOWN:
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index e23394f5f..31e6f62ab 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -167,12 +167,34 @@ public:
}
void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) {
- modifier_status = button_callback.button_status.value;
+ const auto& new_status = button_callback.button_status;
+ const bool new_button_value = new_status.inverted ? !new_status.value : new_status.value;
+ modifier_status.toggle = new_status.toggle;
+
+ // Update button status with current
+ if (!modifier_status.toggle) {
+ modifier_status.locked = false;
+ if (modifier_status.value != new_button_value) {
+ modifier_status.value = new_button_value;
+ }
+ } else {
+ // Toggle button and lock status
+ if (new_button_value && !modifier_status.locked) {
+ modifier_status.locked = true;
+ modifier_status.value = !modifier_status.value;
+ }
+
+ // Unlock button ready for next press
+ if (!new_button_value && modifier_status.locked) {
+ modifier_status.locked = false;
+ }
+ }
+
UpdateStatus();
}
void UpdateStatus() {
- const float coef = modifier_status ? modifier_scale : 1.0f;
+ const float coef = modifier_status.value ? modifier_scale : 1.0f;
bool r = right_status;
bool l = left_status;
@@ -266,7 +288,7 @@ public:
if (down_status) {
--y;
}
- const float coef = modifier_status ? modifier_scale : 1.0f;
+ const float coef = modifier_status.value ? modifier_scale : 1.0f;
status.x.raw_value = static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF);
status.y.raw_value = static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF);
return status;
@@ -287,9 +309,9 @@ private:
bool down_status{};
bool left_status{};
bool right_status{};
- bool modifier_status{};
float last_x_axis_value{};
float last_y_axis_value{};
+ Common::Input::ButtonStatus modifier_status{};
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
std::chrono::time_point<std::chrono::steady_clock> last_update;
};
diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp
index ece1e3b32..f1b57d03a 100644
--- a/src/input_common/helpers/touch_from_buttons.cpp
+++ b/src/input_common/helpers/touch_from_buttons.cpp
@@ -4,7 +4,6 @@
#include <algorithm>
#include "common/settings.h"
-#include "core/frontend/framebuffer_layout.h"
#include "input_common/helpers/touch_from_buttons.h"
namespace InputCommon {
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 3bfdf41ba..7d9d4f7ba 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -140,12 +140,12 @@ bool VKScheduler::UpdateRescaling(bool is_rescaling) {
void VKScheduler::WorkerThread(std::stop_token stop_token) {
Common::SetCurrentThreadName("yuzu:VulkanWorker");
do {
- if (work_queue.empty()) {
- wait_cv.notify_all();
- }
std::unique_ptr<CommandChunk> work;
{
std::unique_lock lock{work_mutex};
+ if (work_queue.empty()) {
+ wait_cv.notify_all();
+ }
work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); });
if (stop_token.stop_requested()) {
continue;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 1b06c9296..e69aa136b 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -146,6 +146,7 @@ private:
using FuncType = TypedCommand<T>;
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
+ recorded_counts++;
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
if (command_offset > sizeof(data) - sizeof(FuncType)) {
return false;
@@ -167,7 +168,7 @@ private:
}
bool Empty() const {
- return command_offset == 0;
+ return recorded_counts == 0;
}
bool HasSubmit() const {
@@ -178,6 +179,7 @@ private:
Command* first = nullptr;
Command* last = nullptr;
+ size_t recorded_counts = 0;
size_t command_offset = 0;
bool submit = false;
alignas(std::max_align_t) std::array<u8, 0x8000> data{};
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 4239c17f5..4104928d1 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -257,7 +257,7 @@ void QtControllerSelectorDialog::LoadConfiguration() {
}
void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
- ConfigureVibration dialog(this);
+ ConfigureVibration dialog(this, system.HIDCore());
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint);
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index d53179dbb..7c5776189 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -164,7 +164,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
});
connect(ui->vibrationButton, &QPushButton::clicked,
- [this] { CallConfigureDialog<ConfigureVibration>(*this); });
+ [this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); });
connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] {
CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 6630321cb..fb168b2ca 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -70,7 +70,6 @@ void PlayerControlPreview::UpdateColors() {
colors.slider_arrow = QColor(14, 15, 18);
colors.font2 = QColor(255, 255, 255);
colors.indicator = QColor(170, 238, 255);
- colors.indicator2 = QColor(100, 255, 100);
colors.deadzone = QColor(204, 136, 136);
colors.slider_button = colors.button;
}
@@ -88,7 +87,6 @@ void PlayerControlPreview::UpdateColors() {
colors.slider_arrow = QColor(65, 68, 73);
colors.font2 = QColor(0, 0, 0);
colors.indicator = QColor(0, 0, 200);
- colors.indicator2 = QColor(0, 150, 0);
colors.deadzone = QColor(170, 0, 0);
colors.slider_button = QColor(153, 149, 149);
}
@@ -101,6 +99,8 @@ void PlayerControlPreview::UpdateColors() {
colors.font = QColor(255, 255, 255);
colors.led_on = QColor(255, 255, 0);
colors.led_off = QColor(170, 238, 255);
+ colors.indicator2 = QColor(59, 165, 93);
+ colors.charging = QColor(250, 168, 26);
colors.left = colors.primary;
colors.right = colors.primary;
@@ -357,7 +357,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
DrawCircle(p, center + QPoint(26, 71), 5);
// Draw battery
- DrawBattery(p, center + QPoint(-170, -140),
+ DrawBattery(p, center + QPoint(-160, -140),
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
}
@@ -484,7 +484,7 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5);
// Draw battery
- DrawBattery(p, center + QPoint(110, -140),
+ DrawBattery(p, center + QPoint(120, -140),
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
}
@@ -621,9 +621,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f);
// Draw battery
- DrawBattery(p, center + QPoint(-100, -160),
+ DrawBattery(p, center + QPoint(-200, -10),
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
- DrawBattery(p, center + QPoint(40, -160),
+ DrawBattery(p, center + QPoint(160, -10),
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
}
@@ -694,12 +694,12 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
// ZL and ZR buttons
p.setPen(colors.outline);
- DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
- DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
+ DrawTriggerButton(p, center + QPoint(-210, -120), Direction::Left, button_values[ZL]);
+ DrawTriggerButton(p, center + QPoint(210, -120), Direction::Right, button_values[ZR]);
p.setPen(colors.transparent);
p.setBrush(colors.font);
- DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
- DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
+ DrawSymbol(p, center + QPoint(-210, -120), Symbol::ZL, 1.5f);
+ DrawSymbol(p, center + QPoint(210, -120), Symbol::ZR, 1.5f);
// Minus and Plus button
p.setPen(colors.outline);
@@ -725,9 +725,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f);
// Draw battery
- DrawBattery(p, center + QPoint(-200, 110),
+ DrawBattery(p, center + QPoint(-188, 95),
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
- DrawBattery(p, center + QPoint(130, 110),
+ DrawBattery(p, center + QPoint(150, 95),
battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]);
}
@@ -781,12 +781,12 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
// ZL and ZR buttons
p.setPen(colors.outline);
- DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
- DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
+ DrawTriggerButton(p, center + QPoint(-210, -120), Direction::Left, button_values[ZL]);
+ DrawTriggerButton(p, center + QPoint(210, -120), Direction::Right, button_values[ZR]);
p.setPen(colors.transparent);
p.setBrush(colors.font);
- DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
- DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
+ DrawSymbol(p, center + QPoint(-210, -120), Symbol::ZL, 1.5f);
+ DrawSymbol(p, center + QPoint(210, -120), Symbol::ZR, 1.5f);
// Minus and Plus buttons
p.setPen(colors.outline);
@@ -818,7 +818,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f);
// Draw battery
- DrawBattery(p, center + QPoint(-30, -160),
+ DrawBattery(p, center + QPoint(-20, -160),
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
}
@@ -875,7 +875,7 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) {
DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8);
// Draw battery
- DrawBattery(p, center + QPoint(-30, -165),
+ DrawBattery(p, center + QPoint(-20, 110),
battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]);
}
@@ -1030,6 +1030,10 @@ constexpr std::array<float, 30 * 2> symbol_c = {
-2.37f, 5.64f, -0.65f, 6.44f, 1.25f, 6.47f, 3.06f, 5.89f, 4.63f, 4.92f, 4.63f, 6.83f,
};
+constexpr std::array<float, 6 * 2> symbol_charging = {
+ 6.5f, -1.0f, 1.0f, -1.0f, 1.0f, -3.0f, -6.5f, 1.0f, -1.0f, 1.0f, -1.0f, 3.0f,
+};
+
constexpr std::array<float, 12 * 2> house = {
-1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
@@ -2674,36 +2678,43 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center,
if (battery == Common::Input::BatteryLevel::None) {
return;
}
- p.setPen(colors.outline);
+ // Draw outline
+ p.setPen(QPen(colors.button, 5));
+ p.setBrush(colors.transparent);
+ p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
+
+ p.setPen(QPen(colors.button, 3));
+ p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
+
+ // Draw Battery shape
+ p.setPen(QPen(colors.indicator2, 3));
p.setBrush(colors.transparent);
- p.drawRect(center.x(), center.y(), 56, 20);
- p.drawRect(center.x() + 56, center.y() + 6, 3, 8);
- p.setBrush(colors.deadzone);
+ p.drawRoundedRect(center.x(), center.y(), 34, 16, 2, 2);
+
+ p.setPen(QPen(colors.indicator2, 1));
+ p.setBrush(colors.indicator2);
+ p.drawRect(center.x() + 35, center.y() + 4.5f, 4, 7);
switch (battery) {
case Common::Input::BatteryLevel::Charging:
- p.setBrush(colors.indicator2);
- p.drawText(center + QPoint(2, 14), tr("Charging"));
+ p.drawRect(center.x(), center.y(), 34, 16);
+ p.setPen(colors.slider);
+ p.setBrush(colors.charging);
+ DrawSymbol(p, center + QPointF(17.0f, 8.0f), Symbol::Charging, 2.1f);
break;
case Common::Input::BatteryLevel::Full:
- p.drawRect(center.x() + 42, center.y(), 14, 20);
- p.drawRect(center.x() + 28, center.y(), 14, 20);
- p.drawRect(center.x() + 14, center.y(), 14, 20);
- p.drawRect(center.x(), center.y(), 14, 20);
+ p.drawRect(center.x(), center.y(), 34, 16);
break;
case Common::Input::BatteryLevel::Medium:
- p.drawRect(center.x() + 28, center.y(), 14, 20);
- p.drawRect(center.x() + 14, center.y(), 14, 20);
- p.drawRect(center.x(), center.y(), 14, 20);
+ p.drawRect(center.x(), center.y(), 25, 16);
break;
case Common::Input::BatteryLevel::Low:
- p.drawRect(center.x() + 14, center.y(), 14, 20);
- p.drawRect(center.x(), center.y(), 14, 20);
+ p.drawRect(center.x(), center.y(), 17, 16);
break;
case Common::Input::BatteryLevel::Critical:
- p.drawRect(center.x(), center.y(), 14, 20);
+ p.drawRect(center.x(), center.y(), 6, 16);
break;
case Common::Input::BatteryLevel::Empty:
- p.drawRect(center.x(), center.y(), 5, 20);
+ p.drawRect(center.x(), center.y(), 3, 16);
break;
default:
break;
@@ -2724,6 +2735,7 @@ void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol
std::array<QPointF, symbol_sl.size() / 2> sl_icon;
std::array<QPointF, symbol_zr.size() / 2> zr_icon;
std::array<QPointF, symbol_sr.size() / 2> sr_icon;
+ std::array<QPointF, symbol_charging.size() / 2> charging_icon;
switch (symbol) {
case Symbol::House:
for (std::size_t point = 0; point < house.size() / 2; ++point) {
@@ -2809,6 +2821,13 @@ void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol
}
p.drawPolygon(sr_icon.data(), static_cast<int>(sr_icon.size()));
break;
+ case Symbol::Charging:
+ for (std::size_t point = 0; point < symbol_charging.size() / 2; ++point) {
+ charging_icon[point] = center + QPointF(symbol_charging[point * 2] * icon_size,
+ symbol_charging[point * 2 + 1] * icon_size);
+ }
+ p.drawPolygon(charging_icon.data(), static_cast<int>(charging_icon.size()));
+ break;
}
}
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 4cd5c3be0..3582ef77a 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -72,6 +72,7 @@ private:
ZL,
ZR,
SR,
+ Charging,
};
struct ColorMapping {
@@ -94,6 +95,7 @@ private:
QColor slider_button{};
QColor slider_arrow{};
QColor deadzone{};
+ QColor charging{};
};
void UpdateColors();
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index adce04b27..779b6401c 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -9,11 +9,14 @@
#include "common/param_package.h"
#include "common/settings.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
+#include "core/hid/hid_types.h"
#include "ui_configure_vibration.h"
#include "yuzu/configuration/configure_vibration.h"
-ConfigureVibration::ConfigureVibration(QWidget* parent)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigureVibration>()) {
+ConfigureVibration::ConfigureVibration(QWidget* parent, Core::HID::HIDCore& hid_core_)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigureVibration>()), hid_core{hid_core_} {
ui->setupUi(this);
vibration_groupboxes = {
@@ -31,6 +34,13 @@ ConfigureVibration::ConfigureVibration(QWidget* parent)
const auto& players = Settings::values.players.GetValue();
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+ auto controller = hid_core.GetEmulatedControllerByIndex(i);
+ Core::HID::ControllerUpdateCallback engine_callback{
+ .on_change = [this,
+ i](Core::HID::ControllerTriggerType type) { VibrateController(type, i); },
+ .is_npad_service = false,
+ };
+ controller_callback_key[i] = controller->SetCallback(engine_callback);
vibration_groupboxes[i]->setChecked(players[i].vibration_enabled);
vibration_spinboxes[i]->setValue(players[i].vibration_strength);
}
@@ -45,7 +55,14 @@ ConfigureVibration::ConfigureVibration(QWidget* parent)
RetranslateUI();
}
-ConfigureVibration::~ConfigureVibration() = default;
+ConfigureVibration::~ConfigureVibration() {
+ StopVibrations();
+
+ for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+ auto controller = hid_core.GetEmulatedControllerByIndex(i);
+ controller->DeleteCallback(controller_callback_key[i]);
+ }
+};
void ConfigureVibration::ApplyConfiguration() {
auto& players = Settings::values.players.GetValue();
@@ -70,3 +87,54 @@ void ConfigureVibration::changeEvent(QEvent* event) {
void ConfigureVibration::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type,
+ std::size_t player_index) {
+ if (type != Core::HID::ControllerTriggerType::Button) {
+ return;
+ }
+
+ auto& player = Settings::values.players.GetValue()[player_index];
+ auto controller = hid_core.GetEmulatedControllerByIndex(player_index);
+ const int vibration_strenght = vibration_spinboxes[player_index]->value();
+ const auto& buttons = controller->GetButtonsValues();
+
+ bool button_is_pressed = false;
+ for (std::size_t i = 0; i < buttons.size(); ++i) {
+ if (buttons[i].value) {
+ button_is_pressed = true;
+ break;
+ }
+ }
+
+ if (!button_is_pressed) {
+ StopVibrations();
+ return;
+ }
+
+ const int old_vibration_enabled = player.vibration_enabled;
+ const bool old_vibration_strenght = player.vibration_strength;
+ player.vibration_enabled = true;
+ player.vibration_strength = vibration_strenght;
+
+ const Core::HID::VibrationValue vibration{
+ .low_amplitude = 1.0f,
+ .low_frequency = 160.0f,
+ .high_amplitude = 1.0f,
+ .high_frequency = 320.0f,
+ };
+ controller->SetVibration(0, vibration);
+ controller->SetVibration(1, vibration);
+
+ // Restore previous values
+ player.vibration_enabled = old_vibration_enabled;
+ player.vibration_strength = old_vibration_strenght;
+}
+
+void ConfigureVibration::StopVibrations() {
+ for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
+ auto controller = hid_core.GetEmulatedControllerByIndex(i);
+ controller->SetVibration(0, Core::HID::DEFAULT_VIBRATION_VALUE);
+ controller->SetVibration(1, Core::HID::DEFAULT_VIBRATION_VALUE);
+ }
+}
diff --git a/src/yuzu/configuration/configure_vibration.h b/src/yuzu/configuration/configure_vibration.h
index 37bbc2653..50b8195fa 100644
--- a/src/yuzu/configuration/configure_vibration.h
+++ b/src/yuzu/configuration/configure_vibration.h
@@ -15,11 +15,16 @@ namespace Ui {
class ConfigureVibration;
}
+namespace Core::HID {
+enum class ControllerTriggerType;
+class HIDCore;
+} // namespace Core::HID
+
class ConfigureVibration : public QDialog {
Q_OBJECT
public:
- explicit ConfigureVibration(QWidget* parent);
+ explicit ConfigureVibration(QWidget* parent, Core::HID::HIDCore& hid_core_);
~ConfigureVibration() override;
void ApplyConfiguration();
@@ -27,14 +32,21 @@ public:
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
+ void VibrateController(Core::HID::ControllerTriggerType type, std::size_t player_index);
+ void StopVibrations();
std::unique_ptr<Ui::ConfigureVibration> ui;
static constexpr std::size_t NUM_PLAYERS = 8;
- // Groupboxes encapsulating the vibration strength spinbox.
+ /// Groupboxes encapsulating the vibration strength spinbox.
std::array<QGroupBox*, NUM_PLAYERS> vibration_groupboxes;
- // Spinboxes representing the vibration strength percentage.
+ /// Spinboxes representing the vibration strength percentage.
std::array<QSpinBox*, NUM_PLAYERS> vibration_spinboxes;
+
+ /// Callback index to stop the controllers events
+ std::array<int, NUM_PLAYERS> controller_callback_key;
+
+ Core::HID::HIDCore& hid_core;
};
diff --git a/src/yuzu/configuration/configure_vibration.ui b/src/yuzu/configuration/configure_vibration.ui
index efdf317a9..447a18eb1 100644
--- a/src/yuzu/configuration/configure_vibration.ui
+++ b/src/yuzu/configuration/configure_vibration.ui
@@ -17,6 +17,13 @@
<string notr="true"/>
</property>
<layout class="QVBoxLayout">
+ <item row="0" column="0" colspan="4">
+ <widget class="QLabel" name="label_1">
+ <property name="text">
+ <string>Press any controller button to vibrate the controller.</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QGroupBox" name="vibrationStrengthGroup">
<property name="title">