summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/common/common_funcs.h6
-rw-r--r--src/common/fiber.cpp23
-rw-r--r--src/common/fiber.h2
-rw-r--r--src/common/misc.cpp44
-rw-r--r--src/core/core.cpp13
-rw-r--r--src/core/cpu_manager.cpp8
-rw-r--r--src/core/crypto/aes_util.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp17
-rw-r--r--src/core/hle/kernel/k_thread.cpp50
-rw-r--r--src/core/hle/kernel/k_thread.h24
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/process.cpp5
-rw-r--r--src/core/hle/kernel/svc.cpp5
-rw-r--r--src/core/network/network.cpp173
-rw-r--r--src/core/network/network.h6
-rw-r--r--src/input_common/mouse/mouse_input.cpp11
-rw-r--r--src/input_common/mouse/mouse_input.h12
-rw-r--r--src/input_common/udp/client.cpp26
-rw-r--r--src/input_common/udp/client.h6
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/fibers.cpp28
-rw-r--r--src/tests/core/network/network.cpp28
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.cpp2
-rw-r--r--src/yuzu/bootmanager.cpp25
-rw-r--r--src/yuzu/bootmanager.h7
-rw-r--r--src/yuzu/configuration/config.cpp9
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp4
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp8
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h2
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp24
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h7
34 files changed, 366 insertions, 246 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1cfd3bbc9..8bd7e5f72 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,6 +27,7 @@ if (MSVC)
27 # /Zo - Enhanced debug info for optimized builds 27 # /Zo - Enhanced debug info for optimized builds
28 # /permissive- - Enables stricter C++ standards conformance checks 28 # /permissive- - Enables stricter C++ standards conformance checks
29 # /EHsc - C++-only exception handling semantics 29 # /EHsc - C++-only exception handling semantics
30 # /utf-8 - Set source and execution character sets to UTF-8
30 # /volatile:iso - Use strict standards-compliant volatile semantics. 31 # /volatile:iso - Use strict standards-compliant volatile semantics.
31 # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates 32 # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
32 # /Zc:inline - Let codegen omit inline functions in object files 33 # /Zc:inline - Let codegen omit inline functions in object files
@@ -38,6 +39,7 @@ if (MSVC)
38 /permissive- 39 /permissive-
39 /EHsc 40 /EHsc
40 /std:c++latest 41 /std:c++latest
42 /utf-8
41 /volatile:iso 43 /volatile:iso
42 /Zc:externConstexpr 44 /Zc:externConstexpr
43 /Zc:inline 45 /Zc:inline
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 71b64e32a..4ace2cd33 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -52,9 +52,13 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
52// Generic function to get last error message. 52// Generic function to get last error message.
53// Call directly after the command or use the error num. 53// Call directly after the command or use the error num.
54// This function might change the error code. 54// This function might change the error code.
55// Defined in Misc.cpp. 55// Defined in misc.cpp.
56[[nodiscard]] std::string GetLastErrorMsg(); 56[[nodiscard]] std::string GetLastErrorMsg();
57 57
58// Like GetLastErrorMsg(), but passing an explicit error code.
59// Defined in misc.cpp.
60[[nodiscard]] std::string NativeErrorToString(int e);
61
58#define DECLARE_ENUM_FLAG_OPERATORS(type) \ 62#define DECLARE_ENUM_FLAG_OPERATORS(type) \
59 [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \ 63 [[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
60 using T = std::underlying_type_t<type>; \ 64 using T = std::underlying_type_t<type>; \
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index 3c1eefcb7..39532ff58 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -116,16 +116,19 @@ void Fiber::Rewind() {
116 boost::context::detail::jump_fcontext(impl->rewind_context, this); 116 boost::context::detail::jump_fcontext(impl->rewind_context, this);
117} 117}
118 118
119void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { 119void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
120 ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); 120 to.impl->guard.lock();
121 ASSERT_MSG(to != nullptr, "Next fiber is null!"); 121 to.impl->previous_fiber = weak_from.lock();
122 to->impl->guard.lock(); 122
123 to->impl->previous_fiber = from; 123 auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to);
124 auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); 124
125 ASSERT(from->impl->previous_fiber != nullptr); 125 // "from" might no longer be valid if the thread was killed
126 from->impl->previous_fiber->impl->context = transfer.fctx; 126 if (auto from = weak_from.lock()) {
127 from->impl->previous_fiber->impl->guard.unlock(); 127 ASSERT(from->impl->previous_fiber != nullptr);
128 from->impl->previous_fiber.reset(); 128 from->impl->previous_fiber->impl->context = transfer.fctx;
129 from->impl->previous_fiber->impl->guard.unlock();
130 from->impl->previous_fiber.reset();
131 }
129} 132}
130 133
131std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 134std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
diff --git a/src/common/fiber.h b/src/common/fiber.h
index f7f587f8c..f2a8ff29a 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -41,7 +41,7 @@ public:
41 41
42 /// Yields control from Fiber 'from' to Fiber 'to' 42 /// Yields control from Fiber 'from' to Fiber 'to'
43 /// Fiber 'from' must be the currently running fiber. 43 /// Fiber 'from' must be the currently running fiber.
44 static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); 44 static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
45 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); 45 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
46 46
47 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); 47 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 1d5393597..495385b9e 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -12,27 +12,41 @@
12 12
13#include "common/common_funcs.h" 13#include "common/common_funcs.h"
14 14
15// Generic function to get last error message. 15std::string NativeErrorToString(int e) {
16// Call directly after the command or use the error num.
17// This function might change the error code.
18std::string GetLastErrorMsg() {
19 static constexpr std::size_t buff_size = 255;
20 char err_str[buff_size];
21
22#ifdef _WIN32 16#ifdef _WIN32
23 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 17 LPSTR err_str;
24 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); 18
25 return std::string(err_str, buff_size); 19 DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
26#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) 20 FORMAT_MESSAGE_IGNORE_INSERTS,
21 nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
22 reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
23 if (!res) {
24 return "(FormatMessageA failed to format error)";
25 }
26 std::string ret(err_str);
27 LocalFree(err_str);
28 return ret;
29#else
30 char err_str[255];
31#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
27 // Thread safe (GNU-specific) 32 // Thread safe (GNU-specific)
28 const char* str = strerror_r(errno, err_str, buff_size); 33 const char* str = strerror_r(e, err_str, sizeof(err_str));
29 return std::string(str); 34 return std::string(str);
30#else 35#else
31 // Thread safe (XSI-compliant) 36 // Thread safe (XSI-compliant)
32 const int success = strerror_r(errno, err_str, buff_size); 37 int second_err = strerror_r(e, err_str, sizeof(err_str));
33 if (success != 0) { 38 if (second_err != 0) {
34 return {}; 39 return "(strerror_r failed to format error)";
35 } 40 }
36 return std::string(err_str); 41 return std::string(err_str);
42#endif // GLIBC etc.
43#endif // _WIN32
44}
45
46std::string GetLastErrorMsg() {
47#ifdef _WIN32
48 return NativeErrorToString(GetLastError());
49#else
50 return NativeErrorToString(errno);
37#endif 51#endif
38} 52}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index de6305e2a..305f56ff1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -299,28 +299,17 @@ struct System::Impl {
299 gpu_core->WaitIdle(); 299 gpu_core->WaitIdle();
300 } 300 }
301 301
302 // Shutdown emulation session
303 services.reset(); 302 services.reset();
304 service_manager.reset(); 303 service_manager.reset();
305 cheat_engine.reset(); 304 cheat_engine.reset();
306 telemetry_session.reset(); 305 telemetry_session.reset();
307
308 // Close all CPU/threading state
309 cpu_manager.Shutdown(); 306 cpu_manager.Shutdown();
310
311 // Release the Time Manager's resources
312 time_manager.Shutdown(); 307 time_manager.Shutdown();
313
314 // Shutdown kernel and core timing
315 core_timing.Shutdown(); 308 core_timing.Shutdown();
316 kernel.Shutdown();
317
318 // Close app loader
319 app_loader.reset(); 309 app_loader.reset();
320 gpu_core.reset(); 310 gpu_core.reset();
321 perf_stats.reset(); 311 perf_stats.reset();
322 312 kernel.Shutdown();
323 // Clear all applets
324 applet_manager.ClearAll(); 313 applet_manager.ClearAll();
325 314
326 LOG_DEBUG(Core, "Shutdown OK"); 315 LOG_DEBUG(Core, "Shutdown OK");
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 8f04fb8f5..bdb374792 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -148,7 +148,7 @@ void CpuManager::MultiCoreRunSuspendThread() {
148 auto core = kernel.GetCurrentHostThreadID(); 148 auto core = kernel.GetCurrentHostThreadID();
149 auto& scheduler = *kernel.CurrentScheduler(); 149 auto& scheduler = *kernel.CurrentScheduler();
150 Kernel::KThread* current_thread = scheduler.GetCurrentThread(); 150 Kernel::KThread* current_thread = scheduler.GetCurrentThread();
151 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); 151 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
152 ASSERT(scheduler.ContextSwitchPending()); 152 ASSERT(scheduler.ContextSwitchPending());
153 ASSERT(core == kernel.GetCurrentHostThreadID()); 153 ASSERT(core == kernel.GetCurrentHostThreadID());
154 scheduler.RescheduleCurrentCore(); 154 scheduler.RescheduleCurrentCore();
@@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
245 auto core = kernel.GetCurrentHostThreadID(); 245 auto core = kernel.GetCurrentHostThreadID();
246 auto& scheduler = *kernel.CurrentScheduler(); 246 auto& scheduler = *kernel.CurrentScheduler();
247 Kernel::KThread* current_thread = scheduler.GetCurrentThread(); 247 Kernel::KThread* current_thread = scheduler.GetCurrentThread();
248 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); 248 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
249 ASSERT(scheduler.ContextSwitchPending()); 249 ASSERT(scheduler.ContextSwitchPending());
250 ASSERT(core == kernel.GetCurrentHostThreadID()); 250 ASSERT(core == kernel.GetCurrentHostThreadID());
251 scheduler.RescheduleCurrentCore(); 251 scheduler.RescheduleCurrentCore();
@@ -271,7 +271,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
271 scheduler.Unload(scheduler.GetCurrentThread()); 271 scheduler.Unload(scheduler.GetCurrentThread());
272 272
273 auto& next_scheduler = kernel.Scheduler(current_core); 273 auto& next_scheduler = kernel.Scheduler(current_core);
274 Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); 274 Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext());
275 } 275 }
276 276
277 // May have changed scheduler 277 // May have changed scheduler
@@ -363,7 +363,7 @@ void CpuManager::RunThread(std::size_t core) {
363 363
364 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); 364 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
365 data.is_running = true; 365 data.is_running = true;
366 Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); 366 Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
367 data.is_running = false; 367 data.is_running = false;
368 data.is_paused = true; 368 data.is_paused = true;
369 data.exit_barrier->Wait(); 369 data.exit_barrier->Wait();
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
index 6a9734812..cb7506241 100644
--- a/src/core/crypto/aes_util.cpp
+++ b/src/core/crypto/aes_util.cpp
@@ -105,8 +105,6 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
105 } 105 }
106 } 106 }
107 } 107 }
108
109 mbedtls_cipher_finish(context, nullptr, nullptr);
110} 108}
111 109
112template <typename Key, std::size_t KeySize> 110template <typename Key, std::size_t KeySize>
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index bb5f43b53..e7de48476 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -734,7 +734,7 @@ void KScheduler::ScheduleImpl() {
734 } 734 }
735 guard.unlock(); 735 guard.unlock();
736 736
737 Common::Fiber::YieldTo(*old_context, switch_fiber); 737 Common::Fiber::YieldTo(*old_context, *switch_fiber);
738 /// When a thread wakes up, the scheduler may have changed to other in another core. 738 /// When a thread wakes up, the scheduler may have changed to other in another core.
739 auto& next_scheduler = *system.Kernel().CurrentScheduler(); 739 auto& next_scheduler = *system.Kernel().CurrentScheduler();
740 next_scheduler.SwitchContextStep2(); 740 next_scheduler.SwitchContextStep2();
@@ -769,13 +769,8 @@ void KScheduler::SwitchToCurrent() {
769 break; 769 break;
770 } 770 }
771 } 771 }
772 std::shared_ptr<Common::Fiber>* next_context; 772 auto thread = next_thread ? next_thread : idle_thread;
773 if (next_thread != nullptr) { 773 Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext());
774 next_context = &next_thread->GetHostContext();
775 } else {
776 next_context = &idle_thread->GetHostContext();
777 }
778 Common::Fiber::YieldTo(switch_fiber, *next_context);
779 } while (!is_switch_pending()); 774 } while (!is_switch_pending());
780 } 775 }
781} 776}
@@ -800,9 +795,9 @@ void KScheduler::Initialize() {
800 std::string name = "Idle Thread Id:" + std::to_string(core_id); 795 std::string name = "Idle Thread Id:" + std::to_string(core_id);
801 std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); 796 std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
802 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); 797 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
803 auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, 798 auto thread_res = KThread::CreateThread(
804 KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0, 799 system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0,
805 nullptr, std::move(init_func), init_func_parameter); 800 static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter);
806 idle_thread = thread_res.Unwrap().get(); 801 idle_thread = thread_res.Unwrap().get();
807} 802}
808 803
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 1661afbd9..e0f53287c 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -995,22 +995,11 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
995 return host_context; 995 return host_context;
996} 996}
997 997
998ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags, 998ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system,
999 std::string name, VAddr entry_point, 999 ThreadType type_flags, std::string name,
1000 u32 priority, u64 arg, s32 processor_id, 1000 VAddr entry_point, u32 priority, u64 arg,
1001 VAddr stack_top, Process* owner_process) { 1001 s32 processor_id, VAddr stack_top,
1002 std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); 1002 Process* owner_process) {
1003 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
1004 return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
1005 owner_process, std::move(init_func), init_func_parameter);
1006}
1007
1008ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
1009 std::string name, VAddr entry_point,
1010 u32 priority, u64 arg, s32 processor_id,
1011 VAddr stack_top, Process* owner_process,
1012 std::function<void(void*)>&& thread_start_func,
1013 void* thread_start_parameter) {
1014 auto& kernel = system.Kernel(); 1003 auto& kernel = system.Kernel();
1015 1004
1016 std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel); 1005 std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
@@ -1027,12 +1016,35 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
1027 auto& scheduler = kernel.GlobalSchedulerContext(); 1016 auto& scheduler = kernel.GlobalSchedulerContext();
1028 scheduler.AddThread(thread); 1017 scheduler.AddThread(thread);
1029 1018
1030 thread->host_context =
1031 std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
1032
1033 return MakeResult<std::shared_ptr<KThread>>(std::move(thread)); 1019 return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
1034} 1020}
1035 1021
1022ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(
1023 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
1024 u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
1025 std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) {
1026 auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg,
1027 processor_id, stack_top, owner_process);
1028
1029 if (thread_result.Succeeded()) {
1030 (*thread_result)->host_context =
1031 std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
1032 }
1033
1034 return thread_result;
1035}
1036
1037ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread(
1038 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
1039 u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) {
1040 std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
1041
1042 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
1043
1044 return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id,
1045 stack_top, owner_process, std::move(init_func), init_func_parameter);
1046}
1047
1036KThread* GetCurrentThreadPointer(KernelCore& kernel) { 1048KThread* GetCurrentThreadPointer(KernelCore& kernel) {
1037 return kernel.GetCurrentEmuThread(); 1049 return kernel.GetCurrentEmuThread();
1038} 1050}
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index c8ac656a4..1c19b23dc 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -116,7 +116,7 @@ public:
116 using WaiterList = boost::intrusive::list<KThread>; 116 using WaiterList = boost::intrusive::list<KThread>;
117 117
118 /** 118 /**
119 * Creates and returns a new thread. The new thread is immediately scheduled 119 * Creates and returns a new thread.
120 * @param system The instance of the whole system 120 * @param system The instance of the whole system
121 * @param name The friendly name desired for the thread 121 * @param name The friendly name desired for the thread
122 * @param entry_point The address at which the thread should start execution 122 * @param entry_point The address at which the thread should start execution
@@ -127,12 +127,12 @@ public:
127 * @param owner_process The parent process for the thread, if null, it's a kernel thread 127 * @param owner_process The parent process for the thread, if null, it's a kernel thread
128 * @return A shared pointer to the newly created thread 128 * @return A shared pointer to the newly created thread
129 */ 129 */
130 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( 130 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
131 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, 131 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
132 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process); 132 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
133 133
134 /** 134 /**
135 * Creates and returns a new thread. The new thread is immediately scheduled 135 * Creates and returns a new thread, with a specified entry point.
136 * @param system The instance of the whole system 136 * @param system The instance of the whole system
137 * @param name The friendly name desired for the thread 137 * @param name The friendly name desired for the thread
138 * @param entry_point The address at which the thread should start execution 138 * @param entry_point The address at which the thread should start execution
@@ -145,11 +145,27 @@ public:
145 * @param thread_start_parameter The parameter which will passed to host context on init 145 * @param thread_start_parameter The parameter which will passed to host context on init
146 * @return A shared pointer to the newly created thread 146 * @return A shared pointer to the newly created thread
147 */ 147 */
148 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create( 148 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
149 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, 149 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
150 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, 150 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
151 std::function<void(void*)>&& thread_start_func, void* thread_start_parameter); 151 std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
152 152
153 /**
154 * Creates and returns a new thread for the emulated "user" process.
155 * @param system The instance of the whole system
156 * @param name The friendly name desired for the thread
157 * @param entry_point The address at which the thread should start execution
158 * @param priority The thread's priority
159 * @param arg User data to pass to the thread
160 * @param processor_id The ID(s) of the processors on which the thread is desired to be run
161 * @param stack_top The address of the thread's stack top
162 * @param owner_process The parent process for the thread, if null, it's a kernel thread
163 * @return A shared pointer to the newly created thread
164 */
165 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread(
166 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
167 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
168
153 [[nodiscard]] std::string GetName() const override { 169 [[nodiscard]] std::string GetName() const override {
154 return name; 170 return name;
155 } 171 }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 331cf3a60..780008b08 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -181,9 +181,9 @@ struct KernelCore::Impl {
181 std::string name = "Suspend Thread Id:" + std::to_string(i); 181 std::string name = "Suspend Thread Id:" + std::to_string(i);
182 std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); 182 std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
183 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); 183 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
184 auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0, 184 auto thread_res = KThread::CreateThread(
185 0, 0, static_cast<u32>(i), 0, nullptr, 185 system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
186 std::move(init_func), init_func_parameter); 186 nullptr, std::move(init_func), init_func_parameter);
187 187
188 suspend_threads[i] = std::move(thread_res).Unwrap(); 188 suspend_threads[i] = std::move(thread_res).Unwrap();
189 } 189 }
@@ -221,10 +221,9 @@ struct KernelCore::Impl {
221 // Gets the dummy KThread for the caller, allocating a new one if this is the first time 221 // Gets the dummy KThread for the caller, allocating a new one if this is the first time
222 KThread* GetHostDummyThread() { 222 KThread* GetHostDummyThread() {
223 const thread_local auto thread = 223 const thread_local auto thread =
224 KThread::Create( 224 KThread::CreateThread(
225 system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, 225 system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0,
226 KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr, 226 KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr)
227 []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr)
228 .Unwrap(); 227 .Unwrap();
229 return thread.get(); 228 return thread.get();
230 } 229 }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 73b85d6f9..9d5956ead 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -40,8 +40,9 @@ namespace {
40void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { 40void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
41 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); 41 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); 42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
43 auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, 43 auto thread_res =
44 owner_process.GetIdealCoreId(), stack_top, &owner_process); 44 KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0,
45 owner_process.GetIdealCoreId(), stack_top, &owner_process);
45 46
46 std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); 47 std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
47 48
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index cc8fa6576..326d3b9ec 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1532,8 +1532,9 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1532 std::shared_ptr<KThread> thread; 1532 std::shared_ptr<KThread> thread;
1533 { 1533 {
1534 KScopedLightLock lk{process.GetStateLock()}; 1534 KScopedLightLock lk{process.GetStateLock()};
1535 CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority, 1535 CASCADE_RESULT(thread,
1536 arg, core_id, stack_bottom, &process)); 1536 KThread::CreateUserThread(system, ThreadType::User, "", entry_point,
1537 priority, arg, core_id, stack_bottom, &process));
1537 } 1538 }
1538 1539
1539 const auto new_thread_handle = process.GetHandleTable().Create(thread); 1540 const auto new_thread_handle = process.GetHandleTable().Create(thread);
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 681e93468..526bfa110 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -7,6 +7,7 @@
7#include <limits> 7#include <limits>
8#include <utility> 8#include <utility>
9#include <vector> 9#include <vector>
10#include "common/common_funcs.h"
10 11
11#ifdef _WIN32 12#ifdef _WIN32
12#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname 13#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
@@ -90,15 +91,36 @@ LINGER MakeLinger(bool enable, u32 linger_value) {
90 return value; 91 return value;
91} 92}
92 93
93int LastError() {
94 return WSAGetLastError();
95}
96
97bool EnableNonBlock(SOCKET fd, bool enable) { 94bool EnableNonBlock(SOCKET fd, bool enable) {
98 u_long value = enable ? 1 : 0; 95 u_long value = enable ? 1 : 0;
99 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; 96 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
100} 97}
101 98
99Errno TranslateNativeError(int e) {
100 switch (e) {
101 case WSAEBADF:
102 return Errno::BADF;
103 case WSAEINVAL:
104 return Errno::INVAL;
105 case WSAEMFILE:
106 return Errno::MFILE;
107 case WSAENOTCONN:
108 return Errno::NOTCONN;
109 case WSAEWOULDBLOCK:
110 return Errno::AGAIN;
111 case WSAECONNREFUSED:
112 return Errno::CONNREFUSED;
113 case WSAEHOSTUNREACH:
114 return Errno::HOSTUNREACH;
115 case WSAENETDOWN:
116 return Errno::NETDOWN;
117 case WSAENETUNREACH:
118 return Errno::NETUNREACH;
119 default:
120 return Errno::OTHER;
121 }
122}
123
102#elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX 124#elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX
103 125
104using SOCKET = int; 126using SOCKET = int;
@@ -108,9 +130,6 @@ using ULONG = u64;
108constexpr SOCKET INVALID_SOCKET = -1; 130constexpr SOCKET INVALID_SOCKET = -1;
109constexpr SOCKET SOCKET_ERROR = -1; 131constexpr SOCKET SOCKET_ERROR = -1;
110 132
111constexpr int WSAEWOULDBLOCK = EAGAIN;
112constexpr int WSAENOTCONN = ENOTCONN;
113
114constexpr int SD_RECEIVE = SHUT_RD; 133constexpr int SD_RECEIVE = SHUT_RD;
115constexpr int SD_SEND = SHUT_WR; 134constexpr int SD_SEND = SHUT_WR;
116constexpr int SD_BOTH = SHUT_RDWR; 135constexpr int SD_BOTH = SHUT_RDWR;
@@ -162,10 +181,6 @@ linger MakeLinger(bool enable, u32 linger_value) {
162 return value; 181 return value;
163} 182}
164 183
165int LastError() {
166 return errno;
167}
168
169bool EnableNonBlock(int fd, bool enable) { 184bool EnableNonBlock(int fd, bool enable) {
170 int flags = fcntl(fd, F_GETFD); 185 int flags = fcntl(fd, F_GETFD);
171 if (flags == -1) { 186 if (flags == -1) {
@@ -179,8 +194,43 @@ bool EnableNonBlock(int fd, bool enable) {
179 return fcntl(fd, F_SETFD, flags) == 0; 194 return fcntl(fd, F_SETFD, flags) == 0;
180} 195}
181 196
197Errno TranslateNativeError(int e) {
198 switch (e) {
199 case EBADF:
200 return Errno::BADF;
201 case EINVAL:
202 return Errno::INVAL;
203 case EMFILE:
204 return Errno::MFILE;
205 case ENOTCONN:
206 return Errno::NOTCONN;
207 case EAGAIN:
208 return Errno::AGAIN;
209 case ECONNREFUSED:
210 return Errno::CONNREFUSED;
211 case EHOSTUNREACH:
212 return Errno::HOSTUNREACH;
213 case ENETDOWN:
214 return Errno::NETDOWN;
215 case ENETUNREACH:
216 return Errno::NETUNREACH;
217 default:
218 return Errno::OTHER;
219 }
220}
221
182#endif 222#endif
183 223
224Errno GetAndLogLastError() {
225#ifdef _WIN32
226 int e = WSAGetLastError();
227#else
228 int e = errno;
229#endif
230 LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
231 return TranslateNativeError(e);
232}
233
184int TranslateDomain(Domain domain) { 234int TranslateDomain(Domain domain) {
185 switch (domain) { 235 switch (domain) {
186 case Domain::INET: 236 case Domain::INET:
@@ -290,9 +340,7 @@ Errno SetSockOpt(SOCKET fd, int option, T value) {
290 if (result != SOCKET_ERROR) { 340 if (result != SOCKET_ERROR) {
291 return Errno::SUCCESS; 341 return Errno::SUCCESS;
292 } 342 }
293 const int ec = LastError(); 343 return GetAndLogLastError();
294 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
295 return Errno::SUCCESS;
296} 344}
297 345
298} // Anonymous namespace 346} // Anonymous namespace
@@ -308,14 +356,12 @@ NetworkInstance::~NetworkInstance() {
308std::pair<IPv4Address, Errno> GetHostIPv4Address() { 356std::pair<IPv4Address, Errno> GetHostIPv4Address() {
309 std::array<char, 256> name{}; 357 std::array<char, 256> name{};
310 if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { 358 if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
311 UNIMPLEMENTED_MSG("Unhandled gethostname error"); 359 return {IPv4Address{}, GetAndLogLastError()};
312 return {IPv4Address{}, Errno::SUCCESS};
313 } 360 }
314 361
315 hostent* const ent = gethostbyname(name.data()); 362 hostent* const ent = gethostbyname(name.data());
316 if (!ent) { 363 if (!ent) {
317 UNIMPLEMENTED_MSG("Unhandled gethostbyname error"); 364 return {IPv4Address{}, GetAndLogLastError()};
318 return {IPv4Address{}, Errno::SUCCESS};
319 } 365 }
320 if (ent->h_addr_list == nullptr) { 366 if (ent->h_addr_list == nullptr) {
321 UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); 367 UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
@@ -359,9 +405,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
359 405
360 ASSERT(result == SOCKET_ERROR); 406 ASSERT(result == SOCKET_ERROR);
361 407
362 const int ec = LastError(); 408 return {-1, GetAndLogLastError()};
363 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
364 return {-1, Errno::SUCCESS};
365} 409}
366 410
367Socket::~Socket() { 411Socket::~Socket() {
@@ -380,9 +424,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
380 return Errno::SUCCESS; 424 return Errno::SUCCESS;
381 } 425 }
382 426
383 const int ec = LastError(); 427 return GetAndLogLastError();
384 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
385 return Errno::SUCCESS;
386} 428}
387 429
388std::pair<Socket::AcceptResult, Errno> Socket::Accept() { 430std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
@@ -391,9 +433,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
391 const SOCKET new_socket = accept(fd, &addr, &addrlen); 433 const SOCKET new_socket = accept(fd, &addr, &addrlen);
392 434
393 if (new_socket == INVALID_SOCKET) { 435 if (new_socket == INVALID_SOCKET) {
394 const int ec = LastError(); 436 return {AcceptResult{}, GetAndLogLastError()};
395 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
396 return {AcceptResult{}, Errno::SUCCESS};
397 } 437 }
398 438
399 AcceptResult result; 439 AcceptResult result;
@@ -412,23 +452,14 @@ Errno Socket::Connect(SockAddrIn addr_in) {
412 return Errno::SUCCESS; 452 return Errno::SUCCESS;
413 } 453 }
414 454
415 switch (const int ec = LastError()) { 455 return GetAndLogLastError();
416 case WSAEWOULDBLOCK:
417 LOG_DEBUG(Service, "EAGAIN generated");
418 return Errno::AGAIN;
419 default:
420 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
421 return Errno::SUCCESS;
422 }
423} 456}
424 457
425std::pair<SockAddrIn, Errno> Socket::GetPeerName() { 458std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
426 sockaddr addr; 459 sockaddr addr;
427 socklen_t addrlen = sizeof(addr); 460 socklen_t addrlen = sizeof(addr);
428 if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { 461 if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) {
429 const int ec = LastError(); 462 return {SockAddrIn{}, GetAndLogLastError()};
430 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
431 return {SockAddrIn{}, Errno::SUCCESS};
432 } 463 }
433 464
434 ASSERT(addrlen == sizeof(sockaddr_in)); 465 ASSERT(addrlen == sizeof(sockaddr_in));
@@ -439,9 +470,7 @@ std::pair<SockAddrIn, Errno> Socket::GetSockName() {
439 sockaddr addr; 470 sockaddr addr;
440 socklen_t addrlen = sizeof(addr); 471 socklen_t addrlen = sizeof(addr);
441 if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { 472 if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) {
442 const int ec = LastError(); 473 return {SockAddrIn{}, GetAndLogLastError()};
443 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
444 return {SockAddrIn{}, Errno::SUCCESS};
445 } 474 }
446 475
447 ASSERT(addrlen == sizeof(sockaddr_in)); 476 ASSERT(addrlen == sizeof(sockaddr_in));
@@ -454,9 +483,7 @@ Errno Socket::Bind(SockAddrIn addr) {
454 return Errno::SUCCESS; 483 return Errno::SUCCESS;
455 } 484 }
456 485
457 const int ec = LastError(); 486 return GetAndLogLastError();
458 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
459 return Errno::SUCCESS;
460} 487}
461 488
462Errno Socket::Listen(s32 backlog) { 489Errno Socket::Listen(s32 backlog) {
@@ -464,9 +491,7 @@ Errno Socket::Listen(s32 backlog) {
464 return Errno::SUCCESS; 491 return Errno::SUCCESS;
465 } 492 }
466 493
467 const int ec = LastError(); 494 return GetAndLogLastError();
468 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
469 return Errno::SUCCESS;
470} 495}
471 496
472Errno Socket::Shutdown(ShutdownHow how) { 497Errno Socket::Shutdown(ShutdownHow how) {
@@ -489,14 +514,7 @@ Errno Socket::Shutdown(ShutdownHow how) {
489 return Errno::SUCCESS; 514 return Errno::SUCCESS;
490 } 515 }
491 516
492 switch (const int ec = LastError()) { 517 return GetAndLogLastError();
493 case WSAENOTCONN:
494 LOG_ERROR(Service, "ENOTCONN generated");
495 return Errno::NOTCONN;
496 default:
497 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
498 return Errno::SUCCESS;
499 }
500} 518}
501 519
502std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { 520std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
@@ -509,17 +527,7 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
509 return {static_cast<s32>(result), Errno::SUCCESS}; 527 return {static_cast<s32>(result), Errno::SUCCESS};
510 } 528 }
511 529
512 switch (const int ec = LastError()) { 530 return {-1, GetAndLogLastError()};
513 case WSAEWOULDBLOCK:
514 LOG_DEBUG(Service, "EAGAIN generated");
515 return {-1, Errno::AGAIN};
516 case WSAENOTCONN:
517 LOG_ERROR(Service, "ENOTCONN generated");
518 return {-1, Errno::NOTCONN};
519 default:
520 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
521 return {0, Errno::SUCCESS};
522 }
523} 531}
524 532
525std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { 533std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
@@ -541,17 +549,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
541 return {static_cast<s32>(result), Errno::SUCCESS}; 549 return {static_cast<s32>(result), Errno::SUCCESS};
542 } 550 }
543 551
544 switch (const int ec = LastError()) { 552 return {-1, GetAndLogLastError()};
545 case WSAEWOULDBLOCK:
546 LOG_DEBUG(Service, "EAGAIN generated");
547 return {-1, Errno::AGAIN};
548 case WSAENOTCONN:
549 LOG_ERROR(Service, "ENOTCONN generated");
550 return {-1, Errno::NOTCONN};
551 default:
552 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
553 return {-1, Errno::SUCCESS};
554 }
555} 553}
556 554
557std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { 555std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
@@ -564,18 +562,7 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
564 return {static_cast<s32>(result), Errno::SUCCESS}; 562 return {static_cast<s32>(result), Errno::SUCCESS};
565 } 563 }
566 564
567 const int ec = LastError(); 565 return {-1, GetAndLogLastError()};
568 switch (ec) {
569 case WSAEWOULDBLOCK:
570 LOG_DEBUG(Service, "EAGAIN generated");
571 return {-1, Errno::AGAIN};
572 case WSAENOTCONN:
573 LOG_ERROR(Service, "ENOTCONN generated");
574 return {-1, Errno::NOTCONN};
575 default:
576 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
577 return {-1, Errno::SUCCESS};
578 }
579} 566}
580 567
581std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, 568std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
@@ -597,9 +584,7 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
597 return {static_cast<s32>(result), Errno::SUCCESS}; 584 return {static_cast<s32>(result), Errno::SUCCESS};
598 } 585 }
599 586
600 const int ec = LastError(); 587 return {-1, GetAndLogLastError()};
601 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
602 return {-1, Errno::SUCCESS};
603} 588}
604 589
605Errno Socket::Close() { 590Errno Socket::Close() {
@@ -642,9 +627,7 @@ Errno Socket::SetNonBlock(bool enable) {
642 if (EnableNonBlock(fd, enable)) { 627 if (EnableNonBlock(fd, enable)) {
643 return Errno::SUCCESS; 628 return Errno::SUCCESS;
644 } 629 }
645 const int ec = LastError(); 630 return GetAndLogLastError();
646 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
647 return Errno::SUCCESS;
648} 631}
649 632
650bool Socket::IsOpened() const { 633bool Socket::IsOpened() const {
diff --git a/src/core/network/network.h b/src/core/network/network.h
index 76b2821f2..bd30f1899 100644
--- a/src/core/network/network.h
+++ b/src/core/network/network.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <utility> 8#include <utility>
9 9
10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
12namespace Network { 13namespace Network {
@@ -21,6 +22,11 @@ enum class Errno {
21 MFILE, 22 MFILE,
22 NOTCONN, 23 NOTCONN,
23 AGAIN, 24 AGAIN,
25 CONNREFUSED,
26 HOSTUNREACH,
27 NETDOWN,
28 NETUNREACH,
29 OTHER,
24}; 30};
25 31
26/// Address families 32/// Address families
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index b864d26f2..d81e790ee 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -59,7 +59,7 @@ void Mouse::UpdateYuzuSettings() {
59 }); 59 });
60} 60}
61 61
62void Mouse::PressButton(int x, int y, int button_) { 62void Mouse::PressButton(int x, int y, MouseButton button_) {
63 const auto button_index = static_cast<std::size_t>(button_); 63 const auto button_index = static_cast<std::size_t>(button_);
64 if (button_index >= mouse_info.size()) { 64 if (button_index >= mouse_info.size()) {
65 return; 65 return;
@@ -67,7 +67,7 @@ void Mouse::PressButton(int x, int y, int button_) {
67 67
68 const auto button = 1U << button_index; 68 const auto button = 1U << button_index;
69 buttons |= static_cast<u16>(button); 69 buttons |= static_cast<u16>(button);
70 last_button = static_cast<MouseButton>(button_index); 70 last_button = button_;
71 71
72 mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); 72 mouse_info[button_index].mouse_origin = Common::MakeVec(x, y);
73 mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); 73 mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y);
@@ -129,7 +129,7 @@ void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
129 } 129 }
130} 130}
131 131
132void Mouse::ReleaseButton(int button_) { 132void Mouse::ReleaseButton(MouseButton button_) {
133 const auto button_index = static_cast<std::size_t>(button_); 133 const auto button_index = static_cast<std::size_t>(button_);
134 if (button_index >= mouse_info.size()) { 134 if (button_index >= mouse_info.size()) {
135 return; 135 return;
@@ -152,6 +152,11 @@ void Mouse::BeginConfiguration() {
152 152
153void Mouse::EndConfiguration() { 153void Mouse::EndConfiguration() {
154 buttons = 0; 154 buttons = 0;
155 for (MouseInfo& info : mouse_info) {
156 info.tilt_speed = 0;
157 info.data.pressed = false;
158 info.data.axis = {0, 0};
159 }
155 last_button = MouseButton::Undefined; 160 last_button = MouseButton::Undefined;
156 mouse_queue.Clear(); 161 mouse_queue.Clear();
157 configuring = false; 162 configuring = false;
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 46aa676c1..3622fe080 100644
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -18,10 +18,12 @@ namespace MouseInput {
18 18
19enum class MouseButton { 19enum class MouseButton {
20 Left, 20 Left,
21 Wheel,
22 Right, 21 Right,
23 Forward, 22 Wheel,
24 Backward, 23 Backward,
24 Forward,
25 Task,
26 Extra,
25 Undefined, 27 Undefined,
26}; 28};
27 29
@@ -51,7 +53,7 @@ public:
51 * @param y the y-coordinate of the cursor 53 * @param y the y-coordinate of the cursor
52 * @param button_ the button pressed 54 * @param button_ the button pressed
53 */ 55 */
54 void PressButton(int x, int y, int button_); 56 void PressButton(int x, int y, MouseButton button_);
55 57
56 /** 58 /**
57 * Signals that mouse has moved. 59 * Signals that mouse has moved.
@@ -65,7 +67,7 @@ public:
65 /** 67 /**
66 * Signals that a motion sensor tilt has ended. 68 * Signals that a motion sensor tilt has ended.
67 */ 69 */
68 void ReleaseButton(int button_); 70 void ReleaseButton(MouseButton button_);
69 71
70 [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); 72 [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
71 [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; 73 [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
@@ -94,7 +96,7 @@ private:
94 u16 buttons{}; 96 u16 buttons{};
95 std::thread update_thread; 97 std::thread update_thread;
96 MouseButton last_button{MouseButton::Undefined}; 98 MouseButton last_button{MouseButton::Undefined};
97 std::array<MouseInfo, 5> mouse_info; 99 std::array<MouseInfo, 7> mouse_info;
98 Common::SPSCQueue<MouseStatus> mouse_queue; 100 Common::SPSCQueue<MouseStatus> mouse_queue;
99 bool configuring{false}; 101 bool configuring{false};
100 bool update_thread_running{true}; 102 bool update_thread_running{true};
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index c4afa4174..df73f9ff7 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -5,6 +5,7 @@
5#include <chrono> 5#include <chrono>
6#include <cstring> 6#include <cstring>
7#include <functional> 7#include <functional>
8#include <random>
8#include <thread> 9#include <thread>
9#include <boost/asio.hpp> 10#include <boost/asio.hpp>
10#include "common/logging/log.h" 11#include "common/logging/log.h"
@@ -26,10 +27,10 @@ class Socket {
26public: 27public:
27 using clock = std::chrono::system_clock; 28 using clock = std::chrono::system_clock;
28 29
29 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_, 30 explicit Socket(const std::string& host, u16 port, std::size_t pad_index_,
30 SocketCallback callback_) 31 SocketCallback callback_)
31 : callback(std::move(callback_)), timer(io_service), 32 : callback(std::move(callback_)), timer(io_service),
32 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_), 33 socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()),
33 pad_index(pad_index_) { 34 pad_index(pad_index_) {
34 boost::system::error_code ec{}; 35 boost::system::error_code ec{};
35 auto ipv4 = boost::asio::ip::make_address_v4(host, ec); 36 auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
@@ -63,6 +64,11 @@ public:
63 } 64 }
64 65
65private: 66private:
67 u32 GenerateRandomClientId() const {
68 std::random_device device;
69 return device();
70 }
71
66 void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { 72 void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) {
67 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { 73 if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) {
68 switch (*type) { 74 switch (*type) {
@@ -115,7 +121,7 @@ private:
115 boost::asio::basic_waitable_timer<clock> timer; 121 boost::asio::basic_waitable_timer<clock> timer;
116 udp::socket socket; 122 udp::socket socket;
117 123
118 u32 client_id{}; 124 const u32 client_id;
119 std::size_t pad_index{}; 125 std::size_t pad_index{};
120 126
121 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); 127 static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
@@ -203,7 +209,7 @@ void Client::ReloadSockets() {
203 LOG_ERROR(Input, "Duplicated UDP servers found"); 209 LOG_ERROR(Input, "Duplicated UDP servers found");
204 continue; 210 continue;
205 } 211 }
206 StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); 212 StartCommunication(client++, udp_input_address, udp_input_port, pad);
207 } 213 }
208 } 214 }
209} 215}
@@ -277,7 +283,7 @@ void Client::OnPadData(Response::PadData data, std::size_t client) {
277} 283}
278 284
279void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, 285void Client::StartCommunication(std::size_t client, const std::string& host, u16 port,
280 std::size_t pad_index, u32 client_id) { 286 std::size_t pad_index) {
281 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 287 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
282 [this](Response::PortInfo info) { OnPortInfo(info); }, 288 [this](Response::PortInfo info) { OnPortInfo(info); },
283 [this, client](Response::PadData data) { OnPadData(data, client); }}; 289 [this, client](Response::PadData data) { OnPadData(data, client); }};
@@ -287,7 +293,7 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16
287 clients[client].port = port; 293 clients[client].port = port;
288 clients[client].pad_index = pad_index; 294 clients[client].pad_index = pad_index;
289 clients[client].active = 0; 295 clients[client].active = 0;
290 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); 296 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback);
291 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 297 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
292 // Set motion parameters 298 // Set motion parameters
293 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode 299 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
@@ -416,7 +422,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
416 return pad_queue; 422 return pad_queue;
417} 423}
418 424
419void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 425void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
420 const std::function<void()>& success_callback, 426 const std::function<void()>& success_callback,
421 const std::function<void()>& failure_callback) { 427 const std::function<void()>& failure_callback) {
422 std::thread([=] { 428 std::thread([=] {
@@ -426,7 +432,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
426 .port_info = [](Response::PortInfo) {}, 432 .port_info = [](Response::PortInfo) {},
427 .pad_data = [&](Response::PadData) { success_event.Set(); }, 433 .pad_data = [&](Response::PadData) { success_event.Set(); },
428 }; 434 };
429 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 435 Socket socket{host, port, pad_index, std::move(callback)};
430 std::thread worker_thread{SocketLoop, &socket}; 436 std::thread worker_thread{SocketLoop, &socket};
431 const bool result = success_event.WaitFor(std::chrono::seconds(5)); 437 const bool result = success_event.WaitFor(std::chrono::seconds(5));
432 socket.Stop(); 438 socket.Stop();
@@ -440,7 +446,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
440} 446}
441 447
442CalibrationConfigurationJob::CalibrationConfigurationJob( 448CalibrationConfigurationJob::CalibrationConfigurationJob(
443 const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 449 const std::string& host, u16 port, std::size_t pad_index,
444 std::function<void(Status)> status_callback, 450 std::function<void(Status)> status_callback,
445 std::function<void(u16, u16, u16, u16)> data_callback) { 451 std::function<void(u16, u16, u16, u16)> data_callback) {
446 452
@@ -485,7 +491,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
485 complete_event.Set(); 491 complete_event.Set();
486 } 492 }
487 }}; 493 }};
488 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 494 Socket socket{host, port, pad_index, std::move(callback)};
489 std::thread worker_thread{SocketLoop, &socket}; 495 std::thread worker_thread{SocketLoop, &socket};
490 complete_event.Wait(); 496 complete_event.Wait();
491 socket.Stop(); 497 socket.Stop();
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index a523f6124..e9e438e88 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -126,7 +126,7 @@ private:
126 void OnPortInfo(Response::PortInfo); 126 void OnPortInfo(Response::PortInfo);
127 void OnPadData(Response::PadData, std::size_t client); 127 void OnPadData(Response::PadData, std::size_t client);
128 void StartCommunication(std::size_t client, const std::string& host, u16 port, 128 void StartCommunication(std::size_t client, const std::string& host, u16 port,
129 std::size_t pad_index, u32 client_id); 129 std::size_t pad_index);
130 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 130 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
131 const Common::Vec3<float>& gyro); 131 const Common::Vec3<float>& gyro);
132 132
@@ -165,7 +165,7 @@ public:
165 * @param data_callback Called when calibration data is ready 165 * @param data_callback Called when calibration data is ready
166 */ 166 */
167 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, 167 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index,
168 u32 client_id, std::function<void(Status)> status_callback, 168 std::function<void(Status)> status_callback,
169 std::function<void(u16, u16, u16, u16)> data_callback); 169 std::function<void(u16, u16, u16, u16)> data_callback);
170 ~CalibrationConfigurationJob(); 170 ~CalibrationConfigurationJob();
171 void Stop(); 171 void Stop();
@@ -174,7 +174,7 @@ private:
174 Common::Event complete_event; 174 Common::Event complete_event;
175}; 175};
176 176
177void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 177void TestCommunication(const std::string& host, u16 port, std::size_t pad_index,
178 const std::function<void()>& success_callback, 178 const std::function<void()>& success_callback,
179 const std::function<void()>& failure_callback); 179 const std::function<void()>& failure_callback);
180 180
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 4ea0076e9..d875c4fee 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -5,6 +5,7 @@ add_executable(tests
5 common/param_package.cpp 5 common/param_package.cpp
6 common/ring_buffer.cpp 6 common/ring_buffer.cpp
7 core/core_timing.cpp 7 core/core_timing.cpp
8 core/network/network.cpp
8 tests.cpp 9 tests.cpp
9 video_core/buffer_base.cpp 10 video_core/buffer_base.cpp
10) 11)
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp
index d94492fc6..751cbe196 100644
--- a/src/tests/common/fibers.cpp
+++ b/src/tests/common/fibers.cpp
@@ -67,7 +67,7 @@ void TestControl1::DoWork() {
67 value++; 67 value++;
68 } 68 }
69 results[id] = value; 69 results[id] = value;
70 Fiber::YieldTo(work_fibers[id], thread_fibers[id]); 70 Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
71} 71}
72 72
73void TestControl1::ExecuteThread(u32 id) { 73void TestControl1::ExecuteThread(u32 id) {
@@ -76,7 +76,7 @@ void TestControl1::ExecuteThread(u32 id) {
76 thread_fibers[id] = thread_fiber; 76 thread_fibers[id] = thread_fiber;
77 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); 77 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
78 items[id] = rand() % 256; 78 items[id] = rand() % 256;
79 Fiber::YieldTo(thread_fibers[id], work_fibers[id]); 79 Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
80 thread_fibers[id]->Exit(); 80 thread_fibers[id]->Exit();
81} 81}
82 82
@@ -117,11 +117,11 @@ public:
117 for (u32 i = 0; i < 12000; i++) { 117 for (u32 i = 0; i < 12000; i++) {
118 value1 += i; 118 value1 += i;
119 } 119 }
120 Fiber::YieldTo(fiber1, fiber3); 120 Fiber::YieldTo(fiber1, *fiber3);
121 const u32 id = thread_ids.Get(); 121 const u32 id = thread_ids.Get();
122 assert1 = id == 1; 122 assert1 = id == 1;
123 value2 += 5000; 123 value2 += 5000;
124 Fiber::YieldTo(fiber1, thread_fibers[id]); 124 Fiber::YieldTo(fiber1, *thread_fibers[id]);
125 } 125 }
126 126
127 void DoWork2() { 127 void DoWork2() {
@@ -129,7 +129,7 @@ public:
129 ; 129 ;
130 value2 = 2000; 130 value2 = 2000;
131 trap = false; 131 trap = false;
132 Fiber::YieldTo(fiber2, fiber1); 132 Fiber::YieldTo(fiber2, *fiber1);
133 assert3 = false; 133 assert3 = false;
134 } 134 }
135 135
@@ -137,19 +137,19 @@ public:
137 const u32 id = thread_ids.Get(); 137 const u32 id = thread_ids.Get();
138 assert2 = id == 0; 138 assert2 = id == 0;
139 value1 += 1000; 139 value1 += 1000;
140 Fiber::YieldTo(fiber3, thread_fibers[id]); 140 Fiber::YieldTo(fiber3, *thread_fibers[id]);
141 } 141 }
142 142
143 void ExecuteThread(u32 id); 143 void ExecuteThread(u32 id);
144 144
145 void CallFiber1() { 145 void CallFiber1() {
146 const u32 id = thread_ids.Get(); 146 const u32 id = thread_ids.Get();
147 Fiber::YieldTo(thread_fibers[id], fiber1); 147 Fiber::YieldTo(thread_fibers[id], *fiber1);
148 } 148 }
149 149
150 void CallFiber2() { 150 void CallFiber2() {
151 const u32 id = thread_ids.Get(); 151 const u32 id = thread_ids.Get();
152 Fiber::YieldTo(thread_fibers[id], fiber2); 152 Fiber::YieldTo(thread_fibers[id], *fiber2);
153 } 153 }
154 154
155 void Exit(); 155 void Exit();
@@ -241,23 +241,23 @@ public:
241 241
242 void DoWork1() { 242 void DoWork1() {
243 value1 += 1; 243 value1 += 1;
244 Fiber::YieldTo(fiber1, fiber2); 244 Fiber::YieldTo(fiber1, *fiber2);
245 const u32 id = thread_ids.Get(); 245 const u32 id = thread_ids.Get();
246 value3 += 1; 246 value3 += 1;
247 Fiber::YieldTo(fiber1, thread_fibers[id]); 247 Fiber::YieldTo(fiber1, *thread_fibers[id]);
248 } 248 }
249 249
250 void DoWork2() { 250 void DoWork2() {
251 value2 += 1; 251 value2 += 1;
252 const u32 id = thread_ids.Get(); 252 const u32 id = thread_ids.Get();
253 Fiber::YieldTo(fiber2, thread_fibers[id]); 253 Fiber::YieldTo(fiber2, *thread_fibers[id]);
254 } 254 }
255 255
256 void ExecuteThread(u32 id); 256 void ExecuteThread(u32 id);
257 257
258 void CallFiber1() { 258 void CallFiber1() {
259 const u32 id = thread_ids.Get(); 259 const u32 id = thread_ids.Get();
260 Fiber::YieldTo(thread_fibers[id], fiber1); 260 Fiber::YieldTo(thread_fibers[id], *fiber1);
261 } 261 }
262 262
263 void Exit(); 263 void Exit();
@@ -332,7 +332,7 @@ public:
332 332
333 void Execute() { 333 void Execute() {
334 thread_fiber = Fiber::ThreadToFiber(); 334 thread_fiber = Fiber::ThreadToFiber();
335 Fiber::YieldTo(thread_fiber, fiber1); 335 Fiber::YieldTo(thread_fiber, *fiber1);
336 thread_fiber->Exit(); 336 thread_fiber->Exit();
337 } 337 }
338 338
@@ -340,7 +340,7 @@ public:
340 fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); 340 fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this);
341 if (rewinded) { 341 if (rewinded) {
342 goal_reached = true; 342 goal_reached = true;
343 Fiber::YieldTo(fiber1, thread_fiber); 343 Fiber::YieldTo(fiber1, *thread_fiber);
344 } 344 }
345 rewinded = true; 345 rewinded = true;
346 fiber1->Rewind(); 346 fiber1->Rewind();
diff --git a/src/tests/core/network/network.cpp b/src/tests/core/network/network.cpp
new file mode 100644
index 000000000..b21ad8911
--- /dev/null
+++ b/src/tests/core/network/network.cpp
@@ -0,0 +1,28 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <catch2/catch.hpp>
6
7#include "core/network/network.h"
8#include "core/network/sockets.h"
9
10TEST_CASE("Network::Errors", "[core]") {
11 Network::NetworkInstance network_instance; // initialize network
12
13 Network::Socket socks[2];
14 for (Network::Socket& sock : socks) {
15 REQUIRE(sock.Initialize(Network::Domain::INET, Network::Type::STREAM,
16 Network::Protocol::TCP) == Network::Errno::SUCCESS);
17 }
18
19 Network::SockAddrIn addr{
20 Network::Domain::INET,
21 {127, 0, 0, 1},
22 1, // hopefully nobody running this test has something listening on port 1
23 };
24 REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED);
25
26 std::vector<u8> message{1, 2, 3, 4};
27 REQUIRE(socks[1].Recv(0, message).second == Network::Errno::NOTCONN);
28}
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp
index a99df9323..d8e92ac0e 100644
--- a/src/video_core/renderer_vulkan/vk_command_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp
@@ -10,7 +10,7 @@
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; 13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4;
14 14
15struct CommandPool::Pool { 15struct CommandPool::Pool {
16 vk::CommandPool handle; 16 vk::CommandPool handle;
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 1c61d419d..ae49cbb45 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -383,6 +383,25 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
383 input_subsystem->GetKeyboard()->ReleaseKey(event->key()); 383 input_subsystem->GetKeyboard()->ReleaseKey(event->key());
384} 384}
385 385
386MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
387 switch (button) {
388 case Qt::LeftButton:
389 return MouseInput::MouseButton::Left;
390 case Qt::RightButton:
391 return MouseInput::MouseButton::Right;
392 case Qt::MiddleButton:
393 return MouseInput::MouseButton::Wheel;
394 case Qt::BackButton:
395 return MouseInput::MouseButton::Backward;
396 case Qt::ForwardButton:
397 return MouseInput::MouseButton::Forward;
398 case Qt::TaskButton:
399 return MouseInput::MouseButton::Task;
400 default:
401 return MouseInput::MouseButton::Extra;
402 }
403}
404
386void GRenderWindow::mousePressEvent(QMouseEvent* event) { 405void GRenderWindow::mousePressEvent(QMouseEvent* event) {
387 // Touch input is handled in TouchBeginEvent 406 // Touch input is handled in TouchBeginEvent
388 if (event->source() == Qt::MouseEventSynthesizedBySystem) { 407 if (event->source() == Qt::MouseEventSynthesizedBySystem) {
@@ -391,7 +410,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
391 410
392 auto pos = event->pos(); 411 auto pos = event->pos();
393 const auto [x, y] = ScaleTouch(pos); 412 const auto [x, y] = ScaleTouch(pos);
394 input_subsystem->GetMouse()->PressButton(x, y, event->button()); 413 const auto button = QtButtonToMouseButton(event->button());
414 input_subsystem->GetMouse()->PressButton(x, y, button);
395 415
396 if (event->button() == Qt::LeftButton) { 416 if (event->button() == Qt::LeftButton) {
397 this->TouchPressed(x, y, 0); 417 this->TouchPressed(x, y, 0);
@@ -425,7 +445,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
425 return; 445 return;
426 } 446 }
427 447
428 input_subsystem->GetMouse()->ReleaseButton(event->button()); 448 const auto button = QtButtonToMouseButton(event->button());
449 input_subsystem->GetMouse()->ReleaseButton(button);
429 450
430 if (event->button() == Qt::LeftButton) { 451 if (event->button() == Qt::LeftButton) {
431 this->TouchReleased(0); 452 this->TouchReleased(0);
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index b5ec7de07..acfe2bc8c 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -28,6 +28,10 @@ namespace InputCommon {
28class InputSubsystem; 28class InputSubsystem;
29} 29}
30 30
31namespace MouseInput {
32enum class MouseButton;
33}
34
31namespace VideoCore { 35namespace VideoCore {
32enum class LoadCallbackStage; 36enum class LoadCallbackStage;
33} 37}
@@ -149,6 +153,9 @@ public:
149 void keyPressEvent(QKeyEvent* event) override; 153 void keyPressEvent(QKeyEvent* event) override;
150 void keyReleaseEvent(QKeyEvent* event) override; 154 void keyReleaseEvent(QKeyEvent* event) override;
151 155
156 /// Converts a Qt mouse button into MouseInput mouse button
157 static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button);
158
152 void mousePressEvent(QMouseEvent* event) override; 159 void mousePressEvent(QMouseEvent* event) override;
153 void mouseMoveEvent(QMouseEvent* event) override; 160 void mouseMoveEvent(QMouseEvent* event) override;
154 void mouseReleaseEvent(QMouseEvent* event) override; 161 void mouseReleaseEvent(QMouseEvent* event) override;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 3d6f64300..1bac57bb2 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -235,7 +235,7 @@ const std::array<UISettings::Shortcut, 17> 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 Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), Qt::ApplicationShortcut}},
239 {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}},
240 {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}},
241}}; 241}};
@@ -508,7 +508,7 @@ void Config::ReadControlValues() {
508 508
509 Settings::values.emulate_analog_keyboard = 509 Settings::values.emulate_analog_keyboard =
510 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(); 511 Settings::values.mouse_panning = false;
512 Settings::values.mouse_panning_sensitivity = 512 Settings::values.mouse_panning_sensitivity =
513 ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat(); 513 ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
514 514
@@ -648,7 +648,7 @@ void Config::ReadDebuggingValues() {
648void Config::ReadServiceValues() { 648void Config::ReadServiceValues() {
649 qt_config->beginGroup(QStringLiteral("Services")); 649 qt_config->beginGroup(QStringLiteral("Services"));
650 Settings::values.bcat_backend = 650 Settings::values.bcat_backend =
651 ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("null")) 651 ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("none"))
652 .toString() 652 .toString()
653 .toStdString(); 653 .toStdString();
654 Settings::values.bcat_boxcat_local = 654 Settings::values.bcat_boxcat_local =
@@ -1182,7 +1182,6 @@ void Config::SaveControlValues() {
1182 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); 1182 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
1183 WriteSetting(QStringLiteral("emulate_analog_keyboard"), 1183 WriteSetting(QStringLiteral("emulate_analog_keyboard"),
1184 Settings::values.emulate_analog_keyboard, false); 1184 Settings::values.emulate_analog_keyboard, false);
1185 WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false);
1186 WriteSetting(QStringLiteral("mouse_panning_sensitivity"), 1185 WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
1187 Settings::values.mouse_panning_sensitivity, 1.0f); 1186 Settings::values.mouse_panning_sensitivity, 1.0f);
1188 qt_config->endGroup(); 1187 qt_config->endGroup();
@@ -1239,7 +1238,7 @@ void Config::SaveDebuggingValues() {
1239void Config::SaveServiceValues() { 1238void Config::SaveServiceValues() {
1240 qt_config->beginGroup(QStringLiteral("Services")); 1239 qt_config->beginGroup(QStringLiteral("Services"));
1241 WriteSetting(QStringLiteral("bcat_backend"), 1240 WriteSetting(QStringLiteral("bcat_backend"),
1242 QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("null")); 1241 QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("none"));
1243 WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false); 1242 WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false);
1244 qt_config->endGroup(); 1243 qt_config->endGroup();
1245} 1244}
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 21d0d3449..bc572d319 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -21,6 +21,7 @@
21#include "input_common/mouse/mouse_poller.h" 21#include "input_common/mouse/mouse_poller.h"
22#include "input_common/udp/udp.h" 22#include "input_common/udp/udp.h"
23#include "ui_configure_input_player.h" 23#include "ui_configure_input_player.h"
24#include "yuzu/bootmanager.h"
24#include "yuzu/configuration/config.h" 25#include "yuzu/configuration/config.h"
25#include "yuzu/configuration/configure_input_player.h" 26#include "yuzu/configuration/configure_input_player.h"
26#include "yuzu/configuration/configure_input_player_widget.h" 27#include "yuzu/configuration/configure_input_player_widget.h"
@@ -1345,7 +1346,8 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
1345 return; 1346 return;
1346 } 1347 }
1347 1348
1348 input_subsystem->GetMouse()->PressButton(0, 0, event->button()); 1349 const auto button = GRenderWindow::QtButtonToMouseButton(event->button());
1350 input_subsystem->GetMouse()->PressButton(0, 0, button);
1349} 1351}
1350 1352
1351void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { 1353void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 1f2b792e4..52fdf7265 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -24,7 +24,7 @@
24 24
25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, 25CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
26 const std::string& host, u16 port, 26 const std::string& host, u16 port,
27 u8 pad_index, u16 client_id) 27 u8 pad_index)
28 : QDialog(parent) { 28 : QDialog(parent) {
29 layout = new QVBoxLayout; 29 layout = new QVBoxLayout;
30 status_label = new QLabel(tr("Communicating with the server...")); 30 status_label = new QLabel(tr("Communicating with the server..."));
@@ -41,7 +41,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
41 41
42 using namespace InputCommon::CemuhookUDP; 42 using namespace InputCommon::CemuhookUDP;
43 job = std::make_unique<CalibrationConfigurationJob>( 43 job = std::make_unique<CalibrationConfigurationJob>(
44 host, port, pad_index, client_id, 44 host, port, pad_index,
45 [this](CalibrationConfigurationJob::Status status) { 45 [this](CalibrationConfigurationJob::Status status) {
46 QString text; 46 QString text;
47 switch (status) { 47 switch (status) {
@@ -218,7 +218,6 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
218 udp_test_in_progress = true; 218 udp_test_in_progress = true;
219 InputCommon::CemuhookUDP::TestCommunication( 219 InputCommon::CemuhookUDP::TestCommunication(
220 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, 220 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0,
221 24872,
222 [this] { 221 [this] {
223 LOG_INFO(Frontend, "UDP input test success"); 222 LOG_INFO(Frontend, "UDP input test success");
224 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 223 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -233,8 +232,7 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
233 ui->touch_calibration_config->setEnabled(false); 232 ui->touch_calibration_config->setEnabled(false);
234 ui->touch_calibration_config->setText(tr("Configuring")); 233 ui->touch_calibration_config->setText(tr("Configuring"));
235 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), 234 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
236 static_cast<u16>(ui->udp_port->text().toUInt()), 0, 235 static_cast<u16>(ui->udp_port->text().toUInt()), 0);
237 24872);
238 dialog.exec(); 236 dialog.exec();
239 if (dialog.completed) { 237 if (dialog.completed) {
240 min_x = dialog.min_x; 238 min_x = dialog.min_x;
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
index 15d61e8ba..d76bc8154 100644
--- a/src/yuzu/configuration/configure_motion_touch.h
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -30,7 +30,7 @@ class CalibrationConfigurationDialog : public QDialog {
30 Q_OBJECT 30 Q_OBJECT
31public: 31public:
32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port, 32 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
33 u8 pad_index, u16 client_id); 33 u8 pad_index);
34 ~CalibrationConfigurationDialog() override; 34 ~CalibrationConfigurationDialog() override;
35 35
36private: 36private:
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0ba7c07cc..56d892a31 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -854,8 +854,7 @@ void GMainWindow::InitializeHotkeys() {
854 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), 854 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
855 &QShortcut::activated, this, [&] { 855 &QShortcut::activated, this, [&] {
856 Settings::values.mouse_panning = !Settings::values.mouse_panning; 856 Settings::values.mouse_panning = !Settings::values.mouse_panning;
857 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { 857 if (Settings::values.mouse_panning) {
858 mouse_hide_timer.start();
859 render_window->installEventFilter(render_window); 858 render_window->installEventFilter(render_window);
860 render_window->setAttribute(Qt::WA_Hover, true); 859 render_window->setAttribute(Qt::WA_Hover, true);
861 } 860 }
@@ -1208,11 +1207,14 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
1208 renderer_status_button->setDisabled(true); 1207 renderer_status_button->setDisabled(true);
1209 1208
1210 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) { 1209 if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
1211 mouse_hide_timer.start();
1212 render_window->installEventFilter(render_window); 1210 render_window->installEventFilter(render_window);
1213 render_window->setAttribute(Qt::WA_Hover, true); 1211 render_window->setAttribute(Qt::WA_Hover, true);
1214 } 1212 }
1215 1213
1214 if (UISettings::values.hide_mouse) {
1215 mouse_hide_timer.start();
1216 }
1217
1216 std::string title_name; 1218 std::string title_name;
1217 std::string title_version; 1219 std::string title_version;
1218 const auto res = system.GetGameName(title_name); 1220 const auto res = system.GetGameName(title_name);
@@ -2372,12 +2374,15 @@ void GMainWindow::OnConfigure() {
2372 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { 2374 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
2373 render_window->installEventFilter(render_window); 2375 render_window->installEventFilter(render_window);
2374 render_window->setAttribute(Qt::WA_Hover, true); 2376 render_window->setAttribute(Qt::WA_Hover, true);
2375 mouse_hide_timer.start();
2376 } else { 2377 } else {
2377 render_window->removeEventFilter(render_window); 2378 render_window->removeEventFilter(render_window);
2378 render_window->setAttribute(Qt::WA_Hover, false); 2379 render_window->setAttribute(Qt::WA_Hover, false);
2379 } 2380 }
2380 2381
2382 if (UISettings::values.hide_mouse) {
2383 mouse_hide_timer.start();
2384 }
2385
2381 UpdateStatusButtons(); 2386 UpdateStatusButtons();
2382} 2387}
2383 2388
@@ -2615,8 +2620,7 @@ void GMainWindow::UpdateUISettings() {
2615} 2620}
2616 2621
2617void GMainWindow::HideMouseCursor() { 2622void GMainWindow::HideMouseCursor() {
2618 if (emu_thread == nullptr || 2623 if (emu_thread == nullptr && UISettings::values.hide_mouse) {
2619 (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) {
2620 mouse_hide_timer.stop(); 2624 mouse_hide_timer.stop();
2621 ShowMouseCursor(); 2625 ShowMouseCursor();
2622 return; 2626 return;
@@ -2626,8 +2630,7 @@ void GMainWindow::HideMouseCursor() {
2626 2630
2627void GMainWindow::ShowMouseCursor() { 2631void GMainWindow::ShowMouseCursor() {
2628 render_window->unsetCursor(); 2632 render_window->unsetCursor();
2629 if (emu_thread != nullptr && 2633 if (emu_thread != nullptr && UISettings::values.hide_mouse) {
2630 (UISettings::values.hide_mouse || Settings::values.mouse_panning)) {
2631 mouse_hide_timer.start(); 2634 mouse_hide_timer.start();
2632 } 2635 }
2633} 2636}
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 6d8bc5509..43877fc98 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -457,7 +457,7 @@ void Config::ReadValues() {
457 Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); 457 Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
458 458
459 // Services 459 // Services
460 Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "null"); 460 Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "none");
461 Settings::values.bcat_boxcat_local = 461 Settings::values.bcat_boxcat_local =
462 sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false); 462 sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
463} 463}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 7e391ab89..ce8b7c218 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -35,18 +35,36 @@ void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
35 input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); 35 input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
36} 36}
37 37
38MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
39 switch (button) {
40 case SDL_BUTTON_LEFT:
41 return MouseInput::MouseButton::Left;
42 case SDL_BUTTON_RIGHT:
43 return MouseInput::MouseButton::Right;
44 case SDL_BUTTON_MIDDLE:
45 return MouseInput::MouseButton::Wheel;
46 case SDL_BUTTON_X1:
47 return MouseInput::MouseButton::Backward;
48 case SDL_BUTTON_X2:
49 return MouseInput::MouseButton::Forward;
50 default:
51 return MouseInput::MouseButton::Undefined;
52 }
53}
54
38void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 55void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
56 const auto mouse_button = SDLButtonToMouseButton(button);
39 if (button == SDL_BUTTON_LEFT) { 57 if (button == SDL_BUTTON_LEFT) {
40 if (state == SDL_PRESSED) { 58 if (state == SDL_PRESSED) {
41 TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); 59 TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0);
42 } else { 60 } else {
43 TouchReleased(0); 61 TouchReleased(0);
44 } 62 }
45 } else if (button == SDL_BUTTON_RIGHT) { 63 } else {
46 if (state == SDL_PRESSED) { 64 if (state == SDL_PRESSED) {
47 input_subsystem->GetMouse()->PressButton(x, y, button); 65 input_subsystem->GetMouse()->PressButton(x, y, mouse_button);
48 } else { 66 } else {
49 input_subsystem->GetMouse()->ReleaseButton(button); 67 input_subsystem->GetMouse()->ReleaseButton(mouse_button);
50 } 68 }
51 } 69 }
52} 70}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 51a12a6a9..0e17bbca7 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -18,6 +18,10 @@ namespace InputCommon {
18class InputSubsystem; 18class InputSubsystem;
19} 19}
20 20
21namespace MouseInput {
22enum class MouseButton;
23}
24
21class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { 25class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
22public: 26public:
23 explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); 27 explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem);
@@ -42,6 +46,9 @@ protected:
42 /// Called by WaitEvent when the mouse moves. 46 /// Called by WaitEvent when the mouse moves.
43 void OnMouseMotion(s32 x, s32 y); 47 void OnMouseMotion(s32 x, s32 y);
44 48
49 /// Converts a SDL mouse button into MouseInput mouse button
50 MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const;
51
45 /// Called by WaitEvent when a mouse button is pressed or released 52 /// Called by WaitEvent when a mouse button is pressed or released
46 void OnMouseButton(u32 button, u8 state, s32 x, s32 y); 53 void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
47 54