summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/stream.cpp9
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/string_util.cpp14
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp4
-rw-r--r--src/core/hle/service/hid/hid.cpp1
-rw-r--r--src/core/hle/service/olsc/olsc.cpp13
-rw-r--r--src/core/settings.h5
-rw-r--r--src/input_common/mouse/mouse_input.cpp32
-rw-r--r--src/input_common/mouse/mouse_input.h7
-rw-r--r--src/input_common/mouse/mouse_poller.cpp3
-rw-r--r--src/input_common/udp/client.cpp4
-rw-r--r--src/input_common/udp/client.h3
-rw-r--r--src/input_common/udp/udp.cpp4
-rw-r--r--src/video_core/CMakeLists.txt11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/texture_cache/util.cpp34
-rw-r--r--src/yuzu/bootmanager.cpp14
-rw-r--r--src/yuzu/configuration/config.cpp10
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui82
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp279
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h8
-rw-r--r--src/yuzu/main.cpp24
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp3
26 files changed, 353 insertions, 225 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 5b0b285cd..b0f6f0c34 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -111,7 +111,14 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
111 111
112 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 112 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
113 113
114 core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {}); 114 const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);
115
116 // If ns_late is higher than the update rate ignore the delay
117 if (ns_late > buffer_release_ns) {
118 ns_late = {};
119 }
120
121 core_timing.ScheduleEvent(buffer_release_ns - ns_late, release_event, {});
115} 122}
116 123
117void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) { 124void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index bfd11e76d..263c457cd 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -206,6 +206,8 @@ if (MSVC)
206else() 206else()
207 target_compile_options(common PRIVATE 207 target_compile_options(common PRIVATE
208 -Werror 208 -Werror
209
210 $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
209 ) 211 )
210endif() 212endif()
211 213
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 4cba2aaa4..7b614ad89 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -141,27 +141,13 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
141} 141}
142 142
143std::string UTF16ToUTF8(const std::u16string& input) { 143std::string UTF16ToUTF8(const std::u16string& input) {
144#ifdef _MSC_VER
145 // Workaround for missing char16_t/char32_t instantiations in MSVC2017
146 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
147 std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
148 return convert.to_bytes(tmp_buffer);
149#else
150 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; 144 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
151 return convert.to_bytes(input); 145 return convert.to_bytes(input);
152#endif
153} 146}
154 147
155std::u16string UTF8ToUTF16(const std::string& input) { 148std::u16string UTF8ToUTF16(const std::string& input) {
156#ifdef _MSC_VER
157 // Workaround for missing char16_t/char32_t instantiations in MSVC2017
158 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
159 auto tmp_buffer = convert.from_bytes(input);
160 return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
161#else
162 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; 149 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
163 return convert.from_bytes(input); 150 return convert.from_bytes(input);
164#endif
165} 151}
166 152
167#ifdef _WIN32 153#ifdef _WIN32
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 386d7bddf..987076956 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -653,6 +653,8 @@ else()
653 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> 653 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
654 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> 654 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
655 655
656 $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
657
656 -Wno-sign-conversion 658 -Wno-sign-conversion
657 ) 659 )
658endif() 660endif()
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 3022438b1..79b209c6b 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -121,6 +121,10 @@ void SoftwareKeyboard::ExecuteInteractive() {
121 std::memcpy(&request, data.data(), sizeof(Request)); 121 std::memcpy(&request, data.data(), sizeof(Request));
122 122
123 switch (request) { 123 switch (request) {
124 case Request::Finalize:
125 complete = true;
126 broker.SignalStateChanged();
127 break;
124 case Request::Calc: { 128 case Request::Calc: {
125 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1})); 129 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
126 broker.SignalStateChanged(); 130 broker.SignalStateChanged();
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 51a010a55..1e2677320 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -110,6 +110,7 @@ void IAppletResource::DeactivateController(HidController controller) {
110 110
111IAppletResource ::~IAppletResource() { 111IAppletResource ::~IAppletResource() {
112 system.CoreTiming().UnscheduleEvent(pad_update_event, 0); 112 system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
113 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
113} 114}
114 115
115void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 116void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 4440135ed..e2ac71fa1 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -17,7 +17,7 @@ public:
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, &OLSC::Initialize, "Initialize"}, 18 {0, &OLSC::Initialize, "Initialize"},
19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"}, 19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
20 {13, nullptr, "GetSaveDataBackupSetting"}, 20 {13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"}, 21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
22 {15, nullptr, "SetCustomData"}, 22 {15, nullptr, "SetCustomData"},
23 {16, nullptr, "DeleteSaveDataBackupSetting"}, 23 {16, nullptr, "DeleteSaveDataBackupSetting"},
@@ -52,6 +52,17 @@ private:
52 rb.Push(RESULT_SUCCESS); 52 rb.Push(RESULT_SUCCESS);
53 } 53 }
54 54
55 void GetSaveDataBackupSetting(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 // backup_setting is set to 0 since real value is unknown
59 constexpr u64 backup_setting = 0;
60
61 IPC::ResponseBuilder rb{ctx, 4};
62 rb.Push(RESULT_SUCCESS);
63 rb.Push(backup_setting);
64 }
65
55 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) { 66 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called"); 67 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57 68
diff --git a/src/core/settings.h b/src/core/settings.h
index a324530bd..d849dded3 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -181,12 +181,13 @@ struct Values {
181 std::string motion_device; 181 std::string motion_device;
182 std::string udp_input_servers; 182 std::string udp_input_servers;
183 183
184 bool emulate_analog_keyboard; 184 bool mouse_panning;
185 185 float mouse_panning_sensitivity;
186 bool mouse_enabled; 186 bool mouse_enabled;
187 std::string mouse_device; 187 std::string mouse_device;
188 MouseButtonsRaw mouse_buttons; 188 MouseButtonsRaw mouse_buttons;
189 189
190 bool emulate_analog_keyboard;
190 bool keyboard_enabled; 191 bool keyboard_enabled;
191 KeyboardKeysRaw keyboard_keys; 192 KeyboardKeysRaw keyboard_keys;
192 KeyboardModsRaw keyboard_mods; 193 KeyboardModsRaw keyboard_mods;
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index 10786a541..67a584d53 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2+ 2// Licensed under GPLv2+
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/settings.h"
5#include "input_common/mouse/mouse_input.h" 6#include "input_common/mouse/mouse_input.h"
6 7
7namespace MouseInput { 8namespace MouseInput {
@@ -36,6 +37,9 @@ void Mouse::UpdateThread() {
36 if (configuring) { 37 if (configuring) {
37 UpdateYuzuSettings(); 38 UpdateYuzuSettings();
38 } 39 }
40 if (mouse_panning_timout++ > 8) {
41 StopPanning();
42 }
39 std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); 43 std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
40 } 44 }
41} 45}
@@ -65,8 +69,34 @@ void Mouse::PressButton(int x, int y, int button_) {
65 mouse_info[button_index].data.pressed = true; 69 mouse_info[button_index].data.pressed = true;
66} 70}
67 71
68void Mouse::MouseMove(int x, int y) { 72void Mouse::StopPanning() {
73 for (MouseInfo& info : mouse_info) {
74 if (Settings::values.mouse_panning) {
75 info.data.axis = {};
76 info.tilt_speed = 0;
77 info.last_mouse_change = {};
78 }
79 }
80}
81
82void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
69 for (MouseInfo& info : mouse_info) { 83 for (MouseInfo& info : mouse_info) {
84 if (Settings::values.mouse_panning) {
85 const auto mouse_change = Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y);
86 mouse_panning_timout = 0;
87
88 if (mouse_change.y == 0 && mouse_change.x == 0) {
89 continue;
90 }
91
92 info.last_mouse_change = (info.last_mouse_change * 0.8f) + (mouse_change * 0.2f);
93 info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x),
94 static_cast<int>(16 * -info.last_mouse_change.y)};
95 info.tilt_direction = info.last_mouse_change;
96 info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
97 continue;
98 }
99
70 if (info.data.pressed) { 100 if (info.data.pressed) {
71 const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; 101 const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin;
72 const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; 102 const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position;
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 58803c1bf..46aa676c1 100644
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -57,8 +57,10 @@ public:
57 * Signals that mouse has moved. 57 * Signals that mouse has moved.
58 * @param x the x-coordinate of the cursor 58 * @param x the x-coordinate of the cursor
59 * @param y the y-coordinate of the cursor 59 * @param y the y-coordinate of the cursor
60 * @param center_x the x-coordinate of the middle of the screen
61 * @param center_y the y-coordinate of the middle of the screen
60 */ 62 */
61 void MouseMove(int x, int y); 63 void MouseMove(int x, int y, int center_x, int center_y);
62 64
63 /** 65 /**
64 * Signals that a motion sensor tilt has ended. 66 * Signals that a motion sensor tilt has ended.
@@ -74,11 +76,13 @@ public:
74private: 76private:
75 void UpdateThread(); 77 void UpdateThread();
76 void UpdateYuzuSettings(); 78 void UpdateYuzuSettings();
79 void StopPanning();
77 80
78 struct MouseInfo { 81 struct MouseInfo {
79 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; 82 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
80 Common::Vec2<int> mouse_origin; 83 Common::Vec2<int> mouse_origin;
81 Common::Vec2<int> last_mouse_position; 84 Common::Vec2<int> last_mouse_position;
85 Common::Vec2<float> last_mouse_change;
82 bool is_tilting = false; 86 bool is_tilting = false;
83 float sensitivity{0.120f}; 87 float sensitivity{0.120f};
84 88
@@ -94,5 +98,6 @@ private:
94 Common::SPSCQueue<MouseStatus> mouse_queue; 98 Common::SPSCQueue<MouseStatus> mouse_queue;
95 bool configuring{false}; 99 bool configuring{false};
96 bool update_thread_running{true}; 100 bool update_thread_running{true};
101 int mouse_panning_timout{};
97}; 102};
98} // namespace MouseInput 103} // namespace MouseInput
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 3d799b293..bb56787ee 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -6,6 +6,7 @@
6#include <utility> 6#include <utility>
7 7
8#include "common/threadsafe_queue.h" 8#include "common/threadsafe_queue.h"
9#include "core/settings.h"
9#include "input_common/mouse/mouse_input.h" 10#include "input_common/mouse/mouse_input.h"
10#include "input_common/mouse/mouse_poller.h" 11#include "input_common/mouse/mouse_poller.h"
11 12
@@ -71,7 +72,7 @@ public:
71 std::lock_guard lock{mutex}; 72 std::lock_guard lock{mutex};
72 const auto axis_value = 73 const auto axis_value =
73 static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis)); 74 static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
74 return axis_value / (100.0f * range); 75 return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
75 } 76 }
76 77
77 std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { 78 std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index e7e50d789..c4afa4174 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -144,6 +144,10 @@ Client::~Client() {
144 Reset(); 144 Reset();
145} 145}
146 146
147Client::ClientData::ClientData() = default;
148
149Client::ClientData::~ClientData() = default;
150
147std::vector<Common::ParamPackage> Client::GetInputDevices() const { 151std::vector<Common::ParamPackage> Client::GetInputDevices() const {
148 std::vector<Common::ParamPackage> devices; 152 std::vector<Common::ParamPackage> devices;
149 for (std::size_t client = 0; client < clients.size(); client++) { 153 for (std::size_t client = 0; client < clients.size(); client++) {
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 822f9c550..a523f6124 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -98,6 +98,9 @@ public:
98 98
99private: 99private:
100 struct ClientData { 100 struct ClientData {
101 ClientData();
102 ~ClientData();
103
101 std::string host{"127.0.0.1"}; 104 std::string host{"127.0.0.1"};
102 u16 port{26760}; 105 u16 port{26760};
103 std::size_t pad_index{}; 106 std::size_t pad_index{};
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index b630281a0..9829da6f0 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -84,8 +84,8 @@ public:
84 84
85private: 85private:
86 const std::string ip; 86 const std::string ip;
87 const u16 port; 87 [[maybe_unused]] const u16 port;
88 const u16 pad; 88 [[maybe_unused]] const u16 pad;
89 CemuhookUDP::Client* client; 89 CemuhookUDP::Client* client;
90 mutable std::mutex mutex; 90 mutable std::mutex mutex;
91}; 91};
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 2cf95937e..dd4c29ed3 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -271,14 +271,13 @@ create_target_directory_groups(video_core)
271target_link_libraries(video_core PUBLIC common core) 271target_link_libraries(video_core PUBLIC common core)
272target_link_libraries(video_core PRIVATE glad xbyak) 272target_link_libraries(video_core PRIVATE glad xbyak)
273 273
274if (MSVC) 274if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
275 target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR}) 275 add_dependencies(video_core ffmpeg-build)
276 target_link_libraries(video_core PUBLIC ${FFMPEG_LIBRARY_DIR}/swscale.lib ${FFMPEG_LIBRARY_DIR}/avcodec.lib ${FFMPEG_LIBRARY_DIR}/avutil.lib)
277else()
278 target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR})
279 target_link_libraries(video_core PRIVATE ${FFMPEG_LIBRARIES})
280endif() 276endif()
281 277
278target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR})
279target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES})
280
282add_dependencies(video_core host_shaders) 281add_dependencies(video_core host_shaders)
283target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 282target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
284target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) 283target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 8aa63d329..ea4ca9a82 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -67,9 +67,6 @@ constexpr size_t TOTAL_CONST_BUFFER_BYTES =
67constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16; 67constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
68constexpr size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16; 68constexpr size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16;
69 69
70constexpr size_t MAX_TEXTURES = 192;
71constexpr size_t MAX_IMAGES = 48;
72
73struct TextureHandle { 70struct TextureHandle {
74 constexpr TextureHandle(u32 data, bool via_header_index) { 71 constexpr TextureHandle(u32 data, bool via_header_index) {
75 const Tegra::Texture::TextureHandle handle{data}; 72 const Tegra::Texture::TextureHandle handle{data};
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index bb2cdef81..a0bc1f7b6 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -169,40 +169,6 @@ template <u32 GOB_EXTENT>
169 return Common::DivCeil(AdjustMipSize(size, level), block_size); 169 return Common::DivCeil(AdjustMipSize(size, level), block_size);
170} 170}
171 171
172[[nodiscard]] constexpr u32 LayerSize(const TICEntry& config, PixelFormat format) {
173 return config.Width() * config.Height() * BytesPerBlock(format);
174}
175
176[[nodiscard]] constexpr bool HasTwoDimsPerLayer(TextureType type) {
177 switch (type) {
178 case TextureType::Texture2D:
179 case TextureType::Texture2DArray:
180 case TextureType::Texture2DNoMipmap:
181 case TextureType::Texture3D:
182 case TextureType::TextureCubeArray:
183 case TextureType::TextureCubemap:
184 return true;
185 case TextureType::Texture1D:
186 case TextureType::Texture1DArray:
187 case TextureType::Texture1DBuffer:
188 return false;
189 }
190 return false;
191}
192
193[[nodiscard]] constexpr bool HasTwoDimsPerLayer(ImageType type) {
194 switch (type) {
195 case ImageType::e2D:
196 case ImageType::e3D:
197 case ImageType::Linear:
198 return true;
199 case ImageType::e1D:
200 case ImageType::Buffer:
201 return false;
202 }
203 UNREACHABLE_MSG("Invalid image type={}", static_cast<int>(type));
204}
205
206[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) { 172[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) {
207 switch (num_samples) { 173 switch (num_samples) {
208 case 1: 174 case 1:
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index ffdf34a4a..d9a3035cb 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -405,12 +405,17 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
405 if (event->source() == Qt::MouseEventSynthesizedBySystem) { 405 if (event->source() == Qt::MouseEventSynthesizedBySystem) {
406 return; 406 return;
407 } 407 }
408
409 auto pos = event->pos(); 408 auto pos = event->pos();
410 const auto [x, y] = ScaleTouch(pos); 409 const auto [x, y] = ScaleTouch(pos);
411 input_subsystem->GetMouse()->MouseMove(x, y); 410 const int center_x = width() / 2;
411 const int center_y = height() / 2;
412 input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y);
412 this->TouchMoved(x, y, 0); 413 this->TouchMoved(x, y, 0);
413 414
415 if (Settings::values.mouse_panning) {
416 QCursor::setPos(mapToGlobal({center_x, center_y}));
417 }
418
414 emit MouseActivity(); 419 emit MouseActivity();
415} 420}
416 421
@@ -714,6 +719,11 @@ void GRenderWindow::showEvent(QShowEvent* event) {
714 719
715bool GRenderWindow::eventFilter(QObject* object, QEvent* event) { 720bool GRenderWindow::eventFilter(QObject* object, QEvent* event) {
716 if (event->type() == QEvent::HoverMove) { 721 if (event->type() == QEvent::HoverMove) {
722 if (Settings::values.mouse_panning) {
723 auto* hover_event = static_cast<QMouseEvent*>(event);
724 mouseMoveEvent(hover_event);
725 return false;
726 }
717 emit MouseActivity(); 727 emit MouseActivity();
718 } 728 }
719 return false; 729 return false;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8d85a1986..8f7458119 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -220,7 +220,7 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default
220// This must be in alphabetical order according to action name as it must have the same order as 220// This must be in alphabetical order according to action name as it must have the same order as
221// UISetting::values.shortcuts, which is alphabetically ordered. 221// UISetting::values.shortcuts, which is alphabetically ordered.
222// clang-format off 222// clang-format off
223const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{ 223const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{
224 {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}}, 224 {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
225 {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}}, 225 {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}},
226 {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}}, 226 {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
@@ -235,6 +235,7 @@ const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
235 {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, 235 {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
236 {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, 236 {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
237 {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}}, 237 {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
238 {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::ApplicationShortcut}},
238 {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}}, 239 {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
239 {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, 240 {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}},
240}}; 241}};
@@ -507,6 +508,9 @@ void Config::ReadControlValues() {
507 508
508 Settings::values.emulate_analog_keyboard = 509 Settings::values.emulate_analog_keyboard =
509 ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool(); 510 ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
511 Settings::values.mouse_panning = ReadSetting(QStringLiteral("mouse_panning"), false).toBool();
512 Settings::values.mouse_panning_sensitivity =
513 ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
510 514
511 ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true); 515 ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true);
512 ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"), 516 ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
@@ -1184,7 +1188,9 @@ void Config::SaveControlValues() {
1184 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); 1188 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
1185 WriteSetting(QStringLiteral("emulate_analog_keyboard"), 1189 WriteSetting(QStringLiteral("emulate_analog_keyboard"),
1186 Settings::values.emulate_analog_keyboard, false); 1190 Settings::values.emulate_analog_keyboard, false);
1187 1191 WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false);
1192 WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
1193 Settings::values.mouse_panning_sensitivity, 1.0f);
1188 qt_config->endGroup(); 1194 qt_config->endGroup();
1189} 1195}
1190 1196
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 8a600e19d..949c4eb13 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -42,7 +42,7 @@ public:
42 default_mouse_buttons; 42 default_mouse_buttons;
43 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; 43 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
44 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; 44 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
45 static const std::array<UISettings::Shortcut, 16> default_hotkeys; 45 static const std::array<UISettings::Shortcut, 17> default_hotkeys;
46 46
47private: 47private:
48 void Initialize(const std::string& config_name); 48 void Initialize(const std::string& config_name);
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 4e557bc6f..a1a0eb676 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -122,6 +122,9 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
122 Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); 122 Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
123 Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); 123 Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
124 Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); 124 Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked();
125 Settings::values.mouse_panning = ui->mouse_panning->isChecked();
126 Settings::values.mouse_panning_sensitivity =
127 static_cast<float>(ui->mouse_panning_sensitivity->value());
125 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); 128 Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
126} 129}
127 130
@@ -149,6 +152,8 @@ void ConfigureInputAdvanced::LoadConfiguration() {
149 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled); 152 ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
150 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled); 153 ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
151 ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard); 154 ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard);
155 ui->mouse_panning->setChecked(Settings::values.mouse_panning);
156 ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity);
152 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); 157 ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
153 158
154 UpdateUIEnabled(); 159 UpdateUIEnabled();
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index f207e5d3b..173130d8d 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2546,27 +2546,65 @@
2546 </property> 2546 </property>
2547 </widget> 2547 </widget>
2548 </item> 2548 </item>
2549 <item row="1" column="0"> 2549 <item row="1" column="0">
2550 <widget class="QCheckBox" name="emulate_analog_keyboard"> 2550 <widget class="QCheckBox" name="emulate_analog_keyboard">
2551 <property name="minimumSize"> 2551 <property name="minimumSize">
2552 <size> 2552 <size>
2553 <width>0</width> 2553 <width>0</width>
2554 <height>23</height> 2554 <height>23</height>
2555 </size> 2555 </size>
2556 </property> 2556 </property>
2557 <property name="text"> 2557 <property name="text">
2558 <string>Emulate Analog with Keyboard Input</string> 2558 <string>Emulate Analog with Keyboard Input</string>
2559 </property> 2559 </property>
2560 </widget> 2560 </widget>
2561 </item> 2561 </item>
2562 <item row="5" column="2"> 2562 <item row="2" column="0">
2563 <widget class="QCheckBox" name="mouse_panning">
2564 <property name="minimumSize">
2565 <size>
2566 <width>0</width>
2567 <height>23</height>
2568 </size>
2569 </property>
2570 <property name="text">
2571 <string>Enable mouse panning</string>
2572 </property>
2573 </widget>
2574 </item>
2575 <item row="2" column="2">
2576 <widget class="QDoubleSpinBox" name="mouse_panning_sensitivity">
2577 <property name="toolTip">
2578 <string>Mouse sensitivity</string>
2579 </property>
2580 <property name="alignment">
2581 <set>Qt::AlignCenter</set>
2582 </property>
2583 <property name="decimals">
2584 <number>2</number>
2585 </property>
2586 <property name="minimum">
2587 <double>0.100000000000000</double>
2588 </property>
2589 <property name="maximum">
2590 <double>16.000000000000000</double>
2591 </property>
2592 <property name="singleStep">
2593 <double>0.010000000000000</double>
2594 </property>
2595 <property name="value">
2596 <double>1.000000000000000</double>
2597 </property>
2598 </widget>
2599 </item>
2600 <item row="6" column="2">
2563 <widget class="QPushButton" name="touchscreen_advanced"> 2601 <widget class="QPushButton" name="touchscreen_advanced">
2564 <property name="text"> 2602 <property name="text">
2565 <string>Advanced</string> 2603 <string>Advanced</string>
2566 </property> 2604 </property>
2567 </widget> 2605 </widget>
2568 </item> 2606 </item>
2569 <item row="2" column="1"> 2607 <item row="3" column="1">
2570 <spacer name="horizontalSpacer_8"> 2608 <spacer name="horizontalSpacer_8">
2571 <property name="orientation"> 2609 <property name="orientation">
2572 <enum>Qt::Horizontal</enum> 2610 <enum>Qt::Horizontal</enum>
@@ -2582,21 +2620,21 @@
2582 </property> 2620 </property>
2583 </spacer> 2621 </spacer>
2584 </item> 2622 </item>
2585 <item row="2" column="2"> 2623 <item row="3" column="2">
2586 <widget class="QPushButton" name="mouse_advanced"> 2624 <widget class="QPushButton" name="mouse_advanced">
2587 <property name="text"> 2625 <property name="text">
2588 <string>Advanced</string> 2626 <string>Advanced</string>
2589 </property> 2627 </property>
2590 </widget> 2628 </widget>
2591 </item> 2629 </item>
2592 <item row="5" column="0"> 2630 <item row="6" column="0">
2593 <widget class="QCheckBox" name="touchscreen_enabled"> 2631 <widget class="QCheckBox" name="touchscreen_enabled">
2594 <property name="text"> 2632 <property name="text">
2595 <string>Touchscreen</string> 2633 <string>Touchscreen</string>
2596 </property> 2634 </property>
2597 </widget> 2635 </widget>
2598 </item> 2636 </item>
2599 <item row="2" column="0"> 2637 <item row="3" column="0">
2600 <widget class="QCheckBox" name="mouse_enabled"> 2638 <widget class="QCheckBox" name="mouse_enabled">
2601 <property name="minimumSize"> 2639 <property name="minimumSize">
2602 <size> 2640 <size>
@@ -2609,28 +2647,28 @@
2609 </property> 2647 </property>
2610 </widget> 2648 </widget>
2611 </item> 2649 </item>
2612 <item row="7" column="0"> 2650 <item row="8" column="0">
2613 <widget class="QLabel" name="motion_touch"> 2651 <widget class="QLabel" name="motion_touch">
2614 <property name="text"> 2652 <property name="text">
2615 <string>Motion / Touch</string> 2653 <string>Motion / Touch</string>
2616 </property> 2654 </property>
2617 </widget> 2655 </widget>
2618 </item> 2656 </item>
2619 <item row="7" column="2"> 2657 <item row="8" column="2">
2620 <widget class="QPushButton" name="buttonMotionTouch"> 2658 <widget class="QPushButton" name="buttonMotionTouch">
2621 <property name="text"> 2659 <property name="text">
2622 <string>Configure</string> 2660 <string>Configure</string>
2623 </property> 2661 </property>
2624 </widget> 2662 </widget>
2625 </item> 2663 </item>
2626 <item row="6" column="0"> 2664 <item row="7" column="0">
2627 <widget class="QCheckBox" name="debug_enabled"> 2665 <widget class="QCheckBox" name="debug_enabled">
2628 <property name="text"> 2666 <property name="text">
2629 <string>Debug Controller</string> 2667 <string>Debug Controller</string>
2630 </property> 2668 </property>
2631 </widget> 2669 </widget>
2632 </item> 2670 </item>
2633 <item row="6" column="2"> 2671 <item row="7" column="2">
2634 <widget class="QPushButton" name="debug_configure"> 2672 <widget class="QPushButton" name="debug_configure">
2635 <property name="text"> 2673 <property name="text">
2636 <string>Configure</string> 2674 <string>Configure</string>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index e3e8bde48..0e8a964d2 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -37,7 +37,8 @@ void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam&
37 Input::CreateDevice<Input::AnalogDevice>); 37 Input::CreateDevice<Input::AnalogDevice>);
38 UpdateColors(); 38 UpdateColors();
39} 39}
40void PlayerControlPreview::SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_, 40void PlayerControlPreview::SetPlayerInputRaw(std::size_t index,
41 const Settings::ButtonsRaw& buttons_,
41 Settings::AnalogsRaw analogs_) { 42 Settings::AnalogsRaw analogs_) {
42 player_index = index; 43 player_index = index;
43 std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 44 std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
@@ -517,14 +518,15 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
517 { 518 {
518 // Draw joysticks 519 // Draw joysticks
519 using namespace Settings::NativeAnalog; 520 using namespace Settings::NativeAnalog;
520 DrawJoystick(p, center + QPointF(-65, -65) + (axis_values[LStick].value * 7), 1.62f, 521 const auto& l_stick = axis_values[LStick];
521 button_values[Settings::NativeButton::LStick]); 522 const auto l_button = button_values[Settings::NativeButton::LStick];
522 DrawJoystick(p, center + QPointF(65, 12) + (axis_values[RStick].value * 7), 1.62f, 523 const auto& r_stick = axis_values[RStick];
523 button_values[Settings::NativeButton::RStick]); 524 const auto r_button = button_values[Settings::NativeButton::RStick];
524 DrawRawJoystick(p, center + QPointF(-180, 90), axis_values[LStick].raw_value, 525
525 axis_values[LStick].properties); 526 DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button);
526 DrawRawJoystick(p, center + QPointF(180, 90), axis_values[RStick].raw_value, 527 DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button);
527 axis_values[RStick].properties); 528 DrawRawJoystick(p, center + QPointF(-180, 90), l_stick.raw_value, l_stick.properties);
529 DrawRawJoystick(p, center + QPointF(180, 90), r_stick.raw_value, r_stick.properties);
528 } 530 }
529 531
530 using namespace Settings::NativeButton; 532 using namespace Settings::NativeButton;
@@ -603,14 +605,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
603 { 605 {
604 // Draw joysticks 606 // Draw joysticks
605 using namespace Settings::NativeAnalog; 607 using namespace Settings::NativeAnalog;
606 DrawJoystick(p, center + QPointF(-171, -41) + (axis_values[LStick].value * 4), 1.0f, 608 const auto& l_stick = axis_values[LStick];
607 button_values[Settings::NativeButton::LStick]); 609 const auto l_button = button_values[Settings::NativeButton::LStick];
608 DrawJoystick(p, center + QPointF(171, 8) + (axis_values[RStick].value * 4), 1.0f, 610 const auto& r_stick = axis_values[RStick];
609 button_values[Settings::NativeButton::RStick]); 611 const auto r_button = button_values[Settings::NativeButton::RStick];
610 DrawRawJoystick(p, center + QPointF(-50, 0), axis_values[LStick].raw_value, 612
611 axis_values[LStick].properties); 613 DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button);
612 DrawRawJoystick(p, center + QPointF(50, 0), axis_values[RStick].raw_value, 614 DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button);
613 axis_values[RStick].properties); 615 DrawRawJoystick(p, center + QPointF(-50, 0), l_stick.raw_value, l_stick.properties);
616 DrawRawJoystick(p, center + QPointF(50, 0), r_stick.raw_value, r_stick.properties);
614 } 617 }
615 618
616 using namespace Settings::NativeButton; 619 using namespace Settings::NativeButton;
@@ -699,9 +702,9 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
699 { 702 {
700 // Draw joysticks 703 // Draw joysticks
701 using namespace Settings::NativeAnalog; 704 using namespace Settings::NativeAnalog;
702 DrawProJoystick(p, center + QPointF(-111, -55) + (axis_values[LStick].value * 11), 705 DrawProJoystick(p, center + QPointF(-111, -55), axis_values[LStick].value, 11,
703 button_values[Settings::NativeButton::LStick]); 706 button_values[Settings::NativeButton::LStick]);
704 DrawProJoystick(p, center + QPointF(51, 0) + (axis_values[RStick].value * 11), 707 DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11,
705 button_values[Settings::NativeButton::RStick]); 708 button_values[Settings::NativeButton::RStick]);
706 DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value, 709 DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value,
707 axis_values[LStick].properties); 710 axis_values[LStick].properties);
@@ -1002,12 +1005,6 @@ constexpr std::array<float, 3 * 2> up_arrow_symbol = {
1002 0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f, 1005 0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f,
1003}; 1006};
1004 1007
1005constexpr std::array<float, 13 * 2> up_arrow = {
1006 9.4f, -9.8f, 9.4f, -10.2f, 8.9f, -29.8f, 8.5f, -30.0f, 8.1f,
1007 -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f, -29.8f, -9.3f, -29.5f,
1008 -9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f,
1009};
1010
1011constexpr std::array<float, 64 * 2> trigger_button = { 1008constexpr std::array<float, 64 * 2> trigger_button = {
1012 5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f, 1009 5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f,
1013 9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f, 1010 9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f,
@@ -1457,15 +1454,18 @@ void PlayerControlPreview::DrawProBody(QPainter& p, const QPointF center) {
1457 constexpr int radius1 = 32; 1454 constexpr int radius1 = 32;
1458 1455
1459 for (std::size_t point = 0; point < pro_left_handle.size() / 2; ++point) { 1456 for (std::size_t point = 0; point < pro_left_handle.size() / 2; ++point) {
1460 qleft_handle[point] = 1457 const float left_x = pro_left_handle[point * 2 + 0];
1461 center + QPointF(pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]); 1458 const float left_y = pro_left_handle[point * 2 + 1];
1462 qright_handle[point] = 1459
1463 center + QPointF(-pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]); 1460 qleft_handle[point] = center + QPointF(left_x, left_y);
1461 qright_handle[point] = center + QPointF(-left_x, left_y);
1464 } 1462 }
1465 for (std::size_t point = 0; point < pro_body.size() / 2; ++point) { 1463 for (std::size_t point = 0; point < pro_body.size() / 2; ++point) {
1466 qbody[point] = center + QPointF(pro_body[point * 2], pro_body[point * 2 + 1]); 1464 const float body_x = pro_body[point * 2 + 0];
1467 qbody[pro_body.size() - 1 - point] = 1465 const float body_y = pro_body[point * 2 + 1];
1468 center + QPointF(-pro_body[point * 2], pro_body[point * 2 + 1]); 1466
1467 qbody[point] = center + QPointF(body_x, body_y);
1468 qbody[pro_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
1469 } 1469 }
1470 1470
1471 // Draw left handle body 1471 // Draw left handle body
@@ -1496,21 +1496,25 @@ void PlayerControlPreview::DrawGCBody(QPainter& p, const QPointF center) {
1496 constexpr float angle = 2 * 3.1415f / 8; 1496 constexpr float angle = 2 * 3.1415f / 8;
1497 1497
1498 for (std::size_t point = 0; point < gc_left_body.size() / 2; ++point) { 1498 for (std::size_t point = 0; point < gc_left_body.size() / 2; ++point) {
1499 qleft_handle[point] = 1499 const float body_x = gc_left_body[point * 2 + 0];
1500 center + QPointF(gc_left_body[point * 2], gc_left_body[point * 2 + 1]); 1500 const float body_y = gc_left_body[point * 2 + 1];
1501 qright_handle[point] = 1501
1502 center + QPointF(-gc_left_body[point * 2], gc_left_body[point * 2 + 1]); 1502 qleft_handle[point] = center + QPointF(body_x, body_y);
1503 qright_handle[point] = center + QPointF(-body_x, body_y);
1503 } 1504 }
1504 for (std::size_t point = 0; point < gc_body.size() / 2; ++point) { 1505 for (std::size_t point = 0; point < gc_body.size() / 2; ++point) {
1505 qbody[point] = center + QPointF(gc_body[point * 2], gc_body[point * 2 + 1]); 1506 const float body_x = gc_body[point * 2 + 0];
1506 qbody[gc_body.size() - 1 - point] = 1507 const float body_y = gc_body[point * 2 + 1];
1507 center + QPointF(-gc_body[point * 2], gc_body[point * 2 + 1]); 1508
1509 qbody[point] = center + QPointF(body_x, body_y);
1510 qbody[gc_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
1508 } 1511 }
1509 for (std::size_t point = 0; point < 8; ++point) { 1512 for (std::size_t point = 0; point < 8; ++point) {
1510 left_hex[point] = 1513 const float point_cos = std::cos(point * angle);
1511 center + QPointF(34 * std::cos(point * angle) - 111, 34 * std::sin(point * angle) - 44); 1514 const float point_sin = std::sin(point * angle);
1512 right_hex[point] = 1515
1513 center + QPointF(26 * std::cos(point * angle) + 61, 26 * std::sin(point * angle) + 37); 1516 left_hex[point] = center + QPointF(34 * point_cos - 111, 34 * point_sin - 44);
1517 right_hex[point] = center + QPointF(26 * point_cos + 61, 26 * point_sin + 37);
1514 } 1518 }
1515 1519
1516 // Draw body 1520 // Draw body
@@ -1631,32 +1635,36 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
1631 constexpr float offset = 209.3f; 1635 constexpr float offset = 209.3f;
1632 1636
1633 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) { 1637 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
1634 left_joycon[point] = center + QPointF(left_joycon_body[point * 2] * size + offset, 1638 const float body_x = left_joycon_body[point * 2 + 0];
1635 left_joycon_body[point * 2 + 1] * size - 1); 1639 const float body_y = left_joycon_body[point * 2 + 1];
1636 right_joycon[point] = center + QPointF(-left_joycon_body[point * 2] * size - offset, 1640
1637 left_joycon_body[point * 2 + 1] * size - 1); 1641 left_joycon[point] = center + QPointF(body_x * size + offset, body_y * size - 1);
1642 right_joycon[point] = center + QPointF(-body_x * size - offset, body_y * size - 1);
1638 } 1643 }
1639 for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) { 1644 for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) {
1640 qleft_joycon_slider[point] = 1645 const float slider_x = left_joycon_slider[point * 2 + 0];
1641 center + QPointF(left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]); 1646 const float slider_y = left_joycon_slider[point * 2 + 1];
1642 qright_joycon_slider[point] = 1647
1643 center + QPointF(-left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]); 1648 qleft_joycon_slider[point] = center + QPointF(slider_x, slider_y);
1649 qright_joycon_slider[point] = center + QPointF(-slider_x, slider_y);
1644 } 1650 }
1645 for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) { 1651 for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) {
1652 const float top_view_x = left_joycon_topview[point * 2 + 0];
1653 const float top_view_y = left_joycon_topview[point * 2 + 1];
1654
1646 qleft_joycon_topview[point] = 1655 qleft_joycon_topview[point] =
1647 center + QPointF(left_joycon_topview[point * 2] * size2 - 52, 1656 center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
1648 left_joycon_topview[point * 2 + 1] * size2 - 52);
1649 qright_joycon_topview[point] = 1657 qright_joycon_topview[point] =
1650 center + QPointF(-left_joycon_topview[point * 2] * size2 + 52, 1658 center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
1651 left_joycon_topview[point * 2 + 1] * size2 - 52);
1652 } 1659 }
1653 for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) { 1660 for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) {
1661 const float top_view_x = left_joycon_slider_topview[point * 2 + 0];
1662 const float top_view_y = left_joycon_slider_topview[point * 2 + 1];
1663
1654 qleft_joycon_slider_topview[point] = 1664 qleft_joycon_slider_topview[point] =
1655 center + QPointF(left_joycon_slider_topview[point * 2] * size2 - 52, 1665 center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
1656 left_joycon_slider_topview[point * 2 + 1] * size2 - 52);
1657 qright_joycon_slider_topview[point] = 1666 qright_joycon_slider_topview[point] =
1658 center + QPointF(-left_joycon_slider_topview[point * 2] * size2 + 52, 1667 center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
1659 left_joycon_slider_topview[point * 2 + 1] * size2 - 52);
1660 } 1668 }
1661 1669
1662 // right joycon body 1670 // right joycon body
@@ -1905,18 +1913,19 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bo
1905 std::array<QPointF, pro_body_top.size()> qbody_top; 1913 std::array<QPointF, pro_body_top.size()> qbody_top;
1906 1914
1907 for (std::size_t point = 0; point < pro_left_trigger.size() / 2; ++point) { 1915 for (std::size_t point = 0; point < pro_left_trigger.size() / 2; ++point) {
1908 qleft_trigger[point] = 1916 const float trigger_x = pro_left_trigger[point * 2 + 0];
1909 center + QPointF(pro_left_trigger[point * 2], 1917 const float trigger_y = pro_left_trigger[point * 2 + 1];
1910 pro_left_trigger[point * 2 + 1] + (left_pressed ? 2 : 0)); 1918
1911 qright_trigger[point] = 1919 qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 2 : 0));
1912 center + QPointF(-pro_left_trigger[point * 2], 1920 qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 2 : 0));
1913 pro_left_trigger[point * 2 + 1] + (right_pressed ? 2 : 0));
1914 } 1921 }
1915 1922
1916 for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) { 1923 for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) {
1917 qbody_top[pro_body_top.size() - 1 - point] = 1924 const float top_x = pro_body_top[point * 2 + 0];
1918 center + QPointF(-pro_body_top[point * 2], pro_body_top[point * 2 + 1]); 1925 const float top_y = pro_body_top[point * 2 + 1];
1919 qbody_top[point] = center + QPointF(pro_body_top[point * 2], pro_body_top[point * 2 + 1]); 1926
1927 qbody_top[pro_body_top.size() - 1 - point] = center + QPointF(-top_x, top_y);
1928 qbody_top[point] = center + QPointF(top_x, top_y);
1920 } 1929 }
1921 1930
1922 // Pro body detail 1931 // Pro body detail
@@ -1939,12 +1948,11 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, boo
1939 std::array<QPointF, left_gc_trigger.size() / 2> qright_trigger; 1948 std::array<QPointF, left_gc_trigger.size() / 2> qright_trigger;
1940 1949
1941 for (std::size_t point = 0; point < left_gc_trigger.size() / 2; ++point) { 1950 for (std::size_t point = 0; point < left_gc_trigger.size() / 2; ++point) {
1942 qleft_trigger[point] = 1951 const float trigger_x = left_gc_trigger[point * 2 + 0];
1943 center + QPointF(left_gc_trigger[point * 2], 1952 const float trigger_y = left_gc_trigger[point * 2 + 1];
1944 left_gc_trigger[point * 2 + 1] + (left_pressed ? 10 : 0)); 1953
1945 qright_trigger[point] = 1954 qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 10 : 0));
1946 center + QPointF(-left_gc_trigger[point * 2], 1955 qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 10 : 0));
1947 left_gc_trigger[point * 2 + 1] + (right_pressed ? 10 : 0));
1948 } 1956 }
1949 1957
1950 // Left trigger 1958 // Left trigger
@@ -1973,12 +1981,13 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente
1973 std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger; 1981 std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger;
1974 1982
1975 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { 1983 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
1984 const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
1985 const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
1986
1976 qleft_trigger[point] = 1987 qleft_trigger[point] =
1977 center + QPointF(left_joycon_trigger[point * 2], 1988 center + QPointF(left_trigger_x, left_trigger_y + (left_pressed ? 0.5f : 0));
1978 left_joycon_trigger[point * 2 + 1] + (left_pressed ? 0.5f : 0));
1979 qright_trigger[point] = 1989 qright_trigger[point] =
1980 center + QPointF(-left_joycon_trigger[point * 2], 1990 center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed ? 0.5f : 0));
1981 left_joycon_trigger[point * 2 + 1] + (right_pressed ? 0.5f : 0));
1982 } 1991 }
1983 1992
1984 // Left trigger 1993 // Left trigger
@@ -1998,12 +2007,14 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, b
1998 constexpr float size = 1.62f; 2007 constexpr float size = 1.62f;
1999 constexpr float offset = 210.6f; 2008 constexpr float offset = 210.6f;
2000 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { 2009 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
2001 qleft_trigger[point] = 2010 const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
2002 center + QPointF(left_joycon_trigger[point * 2] * size + offset, 2011 const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
2003 left_joycon_trigger[point * 2 + 1] * size + (left_pressed ? 0.5f : 0)); 2012
2004 qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset, 2013 qleft_trigger[point] = center + QPointF(left_trigger_x * size + offset,
2005 left_joycon_trigger[point * 2 + 1] * size + 2014 left_trigger_y * size + (left_pressed ? 0.5f : 0));
2006 (right_pressed ? 0.5f : 0)); 2015 qright_trigger[point] =
2016 center + QPointF(-left_trigger_x * size - offset,
2017 left_trigger_y * size + (right_pressed ? 0.5f : 0));
2007 } 2018 }
2008 2019
2009 // Left trigger 2020 // Left trigger
@@ -2023,13 +2034,16 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce
2023 constexpr float size = 0.9f; 2034 constexpr float size = 0.9f;
2024 2035
2025 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { 2036 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2026 qleft_trigger[point] = center + QPointF(left_joystick_L_topview[point * 2] * size - 50, 2037 const float top_view_x = left_joystick_L_topview[point * 2 + 0];
2027 left_joystick_L_topview[point * 2 + 1] * size - 52); 2038 const float top_view_y = left_joystick_L_topview[point * 2 + 1];
2039
2040 qleft_trigger[point] = center + QPointF(top_view_x * size - 50, top_view_y * size - 52);
2028 } 2041 }
2029 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { 2042 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2030 qright_trigger[point] = 2043 const float top_view_x = left_joystick_L_topview[point * 2 + 0];
2031 center + QPointF(-left_joystick_L_topview[point * 2] * size + 50, 2044 const float top_view_y = left_joystick_L_topview[point * 2 + 1];
2032 left_joystick_L_topview[point * 2 + 1] * size - 52); 2045
2046 qright_trigger[point] = center + QPointF(-top_view_x * size + 50, top_view_y * size - 52);
2033 } 2047 }
2034 2048
2035 p.setPen(colors.outline); 2049 p.setPen(colors.outline);
@@ -2273,15 +2287,39 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente
2273 p.drawLine(p2.at(32), p2.at(71)); 2287 p.drawLine(p2.at(32), p2.at(71));
2274} 2288}
2275 2289
2276void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, bool pressed) { 2290void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset,
2291 float offset_scalar, bool pressed) {
2292 const float radius1 = 24.0f;
2293 const float radius2 = 17.0f;
2294
2295 const QPointF offset_center = center + offset * offset_scalar;
2296
2297 const auto amplitude = static_cast<float>(
2298 1.0 - std::sqrt((offset.x() * offset.x()) + (offset.y() * offset.y())) * 0.1f);
2299
2300 const float rotation =
2301 ((offset.x() == 0) ? atan(1) * 2 : atan(offset.y() / offset.x())) * (180 / (atan(1) * 4));
2302
2303 p.save();
2304 p.translate(offset_center);
2305 p.rotate(rotation);
2306
2277 // Outer circle 2307 // Outer circle
2278 p.setPen(colors.outline); 2308 p.setPen(colors.outline);
2279 p.setBrush(pressed ? colors.highlight : colors.button); 2309 p.setBrush(pressed ? colors.highlight : colors.button);
2280 DrawCircle(p, center, 24.0f); 2310 p.drawEllipse(QPointF(0, 0), radius1 * amplitude, radius1);
2281 2311
2282 // Inner circle 2312 // Inner circle
2283 p.setBrush(pressed ? colors.highlight2 : colors.button2); 2313 p.setBrush(pressed ? colors.highlight2 : colors.button2);
2284 DrawCircle(p, center, 17.0f); 2314
2315 const float inner_offset =
2316 (radius1 - radius2) * 0.4f * ((offset.x() == 0 && offset.y() < 0) ? -1.0f : 1.0f);
2317 const float offset_factor = (1.0f - amplitude) / 0.1f;
2318
2319 p.drawEllipse(QPointF((offset.x() < 0) ? -inner_offset : inner_offset, 0) * offset_factor,
2320 radius2 * amplitude, radius2);
2321
2322 p.restore();
2285} 2323}
2286 2324
2287void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) { 2325void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) {
@@ -2299,7 +2337,7 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, boo
2299} 2337}
2300 2338
2301void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value, 2339void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value,
2302 const Input::AnalogProperties properties) { 2340 const Input::AnalogProperties& properties) {
2303 constexpr float size = 45.0f; 2341 constexpr float size = 45.0f;
2304 const float range = size * properties.range; 2342 const float range = size * properties.range;
2305 const float deadzone = size * properties.deadzone; 2343 const float deadzone = size * properties.deadzone;
@@ -2422,17 +2460,16 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen
2422 std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline; 2460 std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline;
2423 2461
2424 for (std::size_t point = 0; point < arrow_points - 1; ++point) { 2462 for (std::size_t point = 0; point < arrow_points - 1; ++point) {
2425 arrow_button_outline[point] = center + QPointF(up_arrow_button[point * 2] * size, 2463 const float up_arrow_x = up_arrow_button[point * 2 + 0];
2426 up_arrow_button[point * 2 + 1] * size); 2464 const float up_arrow_y = up_arrow_button[point * 2 + 1];
2465
2466 arrow_button_outline[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2427 arrow_button_outline[(arrow_points - 1) * 2 - point - 1] = 2467 arrow_button_outline[(arrow_points - 1) * 2 - point - 1] =
2428 center + 2468 center + QPointF(up_arrow_y * size, up_arrow_x * size);
2429 QPointF(up_arrow_button[point * 2 + 1] * size, up_arrow_button[point * 2] * size);
2430 arrow_button_outline[(arrow_points - 1) * 2 + point] = 2469 arrow_button_outline[(arrow_points - 1) * 2 + point] =
2431 center + 2470 center + QPointF(-up_arrow_x * size, -up_arrow_y * size);
2432 QPointF(-up_arrow_button[point * 2] * size, -up_arrow_button[point * 2 + 1] * size);
2433 arrow_button_outline[(arrow_points - 1) * 4 - point - 1] = 2471 arrow_button_outline[(arrow_points - 1) * 4 - point - 1] =
2434 center + 2472 center + QPointF(-up_arrow_y * size, -up_arrow_x * size);
2435 QPointF(-up_arrow_button[point * 2 + 1] * size, -up_arrow_button[point * 2] * size);
2436 } 2473 }
2437 // Draw arrow button outline 2474 // Draw arrow button outline
2438 p.setPen(colors.outline); 2475 p.setPen(colors.outline);
@@ -2446,22 +2483,21 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
2446 QPoint offset; 2483 QPoint offset;
2447 2484
2448 for (std::size_t point = 0; point < up_arrow_button.size() / 2; ++point) { 2485 for (std::size_t point = 0; point < up_arrow_button.size() / 2; ++point) {
2486 const float up_arrow_x = up_arrow_button[point * 2 + 0];
2487 const float up_arrow_y = up_arrow_button[point * 2 + 1];
2488
2449 switch (direction) { 2489 switch (direction) {
2450 case Direction::Up: 2490 case Direction::Up:
2451 arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size, 2491 arrow_button[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2452 up_arrow_button[point * 2 + 1] * size);
2453 break; 2492 break;
2454 case Direction::Left: 2493 case Direction::Left:
2455 arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, 2494 arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
2456 up_arrow_button[point * 2] * size);
2457 break; 2495 break;
2458 case Direction::Right: 2496 case Direction::Right:
2459 arrow_button[point] = center + QPointF(-up_arrow_button[point * 2 + 1] * size, 2497 arrow_button[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
2460 up_arrow_button[point * 2] * size);
2461 break; 2498 break;
2462 case Direction::Down: 2499 case Direction::Down:
2463 arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size, 2500 arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
2464 -up_arrow_button[point * 2 + 1] * size);
2465 break; 2501 break;
2466 case Direction::None: 2502 case Direction::None:
2467 break; 2503 break;
@@ -2500,17 +2536,17 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
2500void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, 2536void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
2501 const Direction direction, bool pressed) { 2537 const Direction direction, bool pressed) {
2502 std::array<QPointF, trigger_button.size() / 2> qtrigger_button; 2538 std::array<QPointF, trigger_button.size() / 2> qtrigger_button;
2503 QPoint offset;
2504 2539
2505 for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { 2540 for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) {
2541 const float trigger_button_x = trigger_button[point * 2 + 0];
2542 const float trigger_button_y = trigger_button[point * 2 + 1];
2543
2506 switch (direction) { 2544 switch (direction) {
2507 case Direction::Left: 2545 case Direction::Left:
2508 qtrigger_button[point] = 2546 qtrigger_button[point] = center + QPointF(-trigger_button_x, trigger_button_y);
2509 center + QPointF(-trigger_button[point * 2], trigger_button[point * 2 + 1]);
2510 break; 2547 break;
2511 case Direction::Right: 2548 case Direction::Right:
2512 qtrigger_button[point] = 2549 qtrigger_button[point] = center + QPointF(trigger_button_x, trigger_button_y);
2513 center + QPointF(trigger_button[point * 2], trigger_button[point * 2 + 1]);
2514 break; 2550 break;
2515 case Direction::Up: 2551 case Direction::Up:
2516 case Direction::Down: 2552 case Direction::Down:
@@ -2633,22 +2669,21 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
2633 std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol; 2669 std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol;
2634 2670
2635 for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) { 2671 for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) {
2672 const float up_arrow_x = up_arrow_symbol[point * 2 + 0];
2673 const float up_arrow_y = up_arrow_symbol[point * 2 + 1];
2674
2636 switch (direction) { 2675 switch (direction) {
2637 case Direction::Up: 2676 case Direction::Up:
2638 arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size, 2677 arrow_symbol[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2639 up_arrow_symbol[point * 2 + 1] * size);
2640 break; 2678 break;
2641 case Direction::Left: 2679 case Direction::Left:
2642 arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2 + 1] * size, 2680 arrow_symbol[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
2643 up_arrow_symbol[point * 2] * size);
2644 break; 2681 break;
2645 case Direction::Right: 2682 case Direction::Right:
2646 arrow_symbol[point] = center + QPointF(-up_arrow_symbol[point * 2 + 1] * size, 2683 arrow_symbol[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
2647 up_arrow_symbol[point * 2] * size);
2648 break; 2684 break;
2649 case Direction::Down: 2685 case Direction::Down:
2650 arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size, 2686 arrow_symbol[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
2651 -up_arrow_symbol[point * 2 + 1] * size);
2652 break; 2687 break;
2653 case Direction::None: 2688 case Direction::None:
2654 break; 2689 break;
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 39565f795..91c3343f1 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -25,7 +25,7 @@ public:
25 25
26 void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, 26 void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
27 const AnalogParam& analogs_param); 27 const AnalogParam& analogs_param);
28 void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_, 28 void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_,
29 Settings::AnalogsRaw analogs_); 29 Settings::AnalogsRaw analogs_);
30 void SetConnectedStatus(bool checked); 30 void SetConnectedStatus(bool checked);
31 void SetControllerType(Settings::ControllerType type); 31 void SetControllerType(Settings::ControllerType type);
@@ -138,9 +138,9 @@ private:
138 // Draw joystick functions 138 // Draw joystick functions
139 void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); 139 void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
140 void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); 140 void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
141 void DrawRawJoystick(QPainter& p, QPointF center, const QPointF value, 141 void DrawRawJoystick(QPainter& p, QPointF center, QPointF value,
142 const Input::AnalogProperties properties); 142 const Input::AnalogProperties& properties);
143 void DrawProJoystick(QPainter& p, QPointF center, bool pressed); 143 void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed);
144 void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); 144 void DrawGCJoystick(QPainter& p, QPointF center, bool pressed);
145 145
146 // Draw button functions 146 // Draw button functions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index ef92c25bc..52218eb70 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -850,6 +850,16 @@ void GMainWindow::InitializeHotkeys() {
850 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this), 850 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
851 &QShortcut::activated, this, 851 &QShortcut::activated, this,
852 [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); 852 [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
853
854 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
855 &QShortcut::activated, this, [&] {
856 Settings::values.mouse_panning = !Settings::values.mouse_panning;
857 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
858 mouse_hide_timer.start();
859 render_window->installEventFilter(render_window);
860 render_window->setAttribute(Qt::WA_Hover, true);
861 }
862 });
853} 863}
854 864
855void GMainWindow::SetDefaultUIGeometry() { 865void GMainWindow::SetDefaultUIGeometry() {
@@ -1197,7 +1207,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
1197 multicore_status_button->setDisabled(true); 1207 multicore_status_button->setDisabled(true);
1198 renderer_status_button->setDisabled(true); 1208 renderer_status_button->setDisabled(true);
1199 1209
1200 if (UISettings::values.hide_mouse) { 1210 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
1201 mouse_hide_timer.start(); 1211 mouse_hide_timer.start();
1202 render_window->installEventFilter(render_window); 1212 render_window->installEventFilter(render_window);
1203 render_window->setAttribute(Qt::WA_Hover, true); 1213 render_window->setAttribute(Qt::WA_Hover, true);
@@ -2359,7 +2369,7 @@ void GMainWindow::OnConfigure() {
2359 2369
2360 config->Save(); 2370 config->Save();
2361 2371
2362 if (UISettings::values.hide_mouse && emulation_running) { 2372 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
2363 render_window->installEventFilter(render_window); 2373 render_window->installEventFilter(render_window);
2364 render_window->setAttribute(Qt::WA_Hover, true); 2374 render_window->setAttribute(Qt::WA_Hover, true);
2365 mouse_hide_timer.start(); 2375 mouse_hide_timer.start();
@@ -2600,7 +2610,8 @@ void GMainWindow::UpdateUISettings() {
2600} 2610}
2601 2611
2602void GMainWindow::HideMouseCursor() { 2612void GMainWindow::HideMouseCursor() {
2603 if (emu_thread == nullptr || UISettings::values.hide_mouse == false) { 2613 if (emu_thread == nullptr ||
2614 (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) {
2604 mouse_hide_timer.stop(); 2615 mouse_hide_timer.stop();
2605 ShowMouseCursor(); 2616 ShowMouseCursor();
2606 return; 2617 return;
@@ -2610,13 +2621,16 @@ void GMainWindow::HideMouseCursor() {
2610 2621
2611void GMainWindow::ShowMouseCursor() { 2622void GMainWindow::ShowMouseCursor() {
2612 render_window->unsetCursor(); 2623 render_window->unsetCursor();
2613 if (emu_thread != nullptr && UISettings::values.hide_mouse) { 2624 if (emu_thread != nullptr &&
2625 (UISettings::values.hide_mouse || Settings::values.mouse_panning)) {
2614 mouse_hide_timer.start(); 2626 mouse_hide_timer.start();
2615 } 2627 }
2616} 2628}
2617 2629
2618void GMainWindow::OnMouseActivity() { 2630void GMainWindow::OnMouseActivity() {
2619 ShowMouseCursor(); 2631 if (!Settings::values.mouse_panning) {
2632 ShowMouseCursor();
2633 }
2620} 2634}
2621 2635
2622void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) { 2636void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 7843d5167..39841aa28 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -30,7 +30,8 @@ EmuWindow_SDL2::~EmuWindow_SDL2() {
30 30
31void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { 31void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
32 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); 32 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0);
33 input_subsystem->GetMouse()->MouseMove(x, y); 33
34 input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
34} 35}
35 36
36void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 37void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {