@@ -61,9 +61,19 @@ struct hid_instance
6161
6262 hid_log.notice (" Initializing HIDAPI ..." );
6363
64- if (int errorCode = hid_init (); errorCode != 0 )
64+ #if defined(__APPLE__)
65+ int error_code = 0 ;
66+ Emu.BlockingCallFromMainThread ([&error_code]()
67+ {
68+ error_code = hid_init ();
69+ hid_darwin_set_open_exclusive (0 );
70+ });
71+ #else
72+ const int error_code = hid_init ();
73+ #endif
74+ if (error_code != 0 )
6575 {
66- hid_log.fatal (" hid_init error %d: %s" , errorCode , hid_error (nullptr ));
76+ hid_log.fatal (" hid_init error %d: %s" , error_code , hid_error (nullptr ));
6777 return false ;
6878 }
6979
@@ -92,6 +102,11 @@ void HidDevice::close()
92102#endif
93103}
94104
105+ #if defined(__APPLE__)
106+ template <class Device >
107+ std::mutex hid_pad_handler<Device>::s_hid_mutex;
108+ #endif
109+
95110template <class Device >
96111hid_pad_handler<Device>::hid_pad_handler(pad_handler type, std::vector<id_pair> ids)
97112 : PadHandlerBase(type), m_ids(std::move(ids))
@@ -104,6 +119,10 @@ hid_pad_handler<Device>::~hid_pad_handler()
104119 // Join thread
105120 m_enumeration_thread.reset ();
106121
122+ #if defined(__APPLE__)
123+ std::lock_guard static_lock (s_hid_mutex);
124+ #endif
125+
107126 for (auto & controller : m_controllers)
108127 {
109128 if (controller.second )
@@ -122,10 +141,6 @@ bool hid_pad_handler<Device>::Init()
122141 if (!hid_instance::get_instance ().initialize ())
123142 return false ;
124143
125- #if defined(__APPLE__)
126- hid_darwin_set_open_exclusive (0 );
127- #endif
128-
129144 for (usz i = 1 ; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI
130145 {
131146 m_controllers.emplace (m_name_string + std::to_string (i), std::make_shared<Device>());
@@ -186,9 +201,9 @@ void hid_pad_handler<Device>::enumerate_devices()
186201#ifdef ANDROID
187202 {
188203 std::lock_guard lock (g_android_usb_devices_mutex);
189- for (auto device : g_android_usb_devices)
204+ for (const android_usb_device& device : g_android_usb_devices)
190205 {
191- auto filter = [&](id_pair id)
206+ const auto filter = [&](id_pair id)
192207 {
193208 return id.m_vid == device.vendorId && id.m_pid == device.productId ;
194209 };
@@ -202,38 +217,40 @@ void hid_pad_handler<Device>::enumerate_devices()
202217#else
203218 for (const auto & [vid, pid] : m_ids)
204219 {
205- hid_device_info* dev_info = hid_enumerate (vid, pid);
206- hid_device_info* head = dev_info;
207- while (dev_info)
220+ #if defined(__APPLE__)
221+ // Let's make sure hid_enumerate is only done one thread at a time
222+ std::lock_guard static_lock (s_hid_mutex);
223+ Emu.BlockingCallFromMainThread ([&]()
224+ {
225+ #endif
226+ hid_device_info* head = hid_enumerate (vid, pid);
227+ for (hid_device_info* dev_info = head; dev_info != nullptr ; dev_info = dev_info->next )
208228 {
209229 if (!dev_info->path )
210230 {
211231 hid_log.error (" Skipping enumeration of device with empty path." );
212232 continue ;
213233 }
214234
215- const std::string path = dev_info->path ;
235+ std::string path = dev_info->path ;
216236 device_paths.insert (path);
217237
218238#ifdef _WIN32
219239 // Only add serials for col01 ps move device
220240 if (m_type == pad_handler::move && path.find (" &Col01#" ) != umax)
221241#endif
222242 {
223- serials[path] = dev_info->serial_number ? std::wstring (dev_info->serial_number ) : std::wstring ();
243+ serials[std::move ( path) ] = dev_info->serial_number ? std::wstring (dev_info->serial_number ) : std::wstring ();
224244 }
225-
226- dev_info = dev_info->next ;
227245 }
228246 hid_free_enumeration (head);
247+ #if defined(__APPLE__)
248+ });
249+ #endif
229250 }
230251#endif
231252 hid_log.notice (" %s enumeration found %d devices (%f ms)" , m_type, device_paths.size (), timer.GetElapsedTimeInMilliSec ());
232253
233- std::lock_guard lock (m_enumeration_mutex);
234- m_new_enumerated_devices = device_paths;
235- m_enumerated_serials = std::move (serials);
236-
237254#ifdef _WIN32
238255 if (m_type == pad_handler::move)
239256 {
@@ -243,7 +260,7 @@ void hid_pad_handler<Device>::enumerate_devices()
243260 // Filter paths. We only want the Col01 paths.
244261 std::set<std::string> col01_paths;
245262
246- for (const std::string& path : m_new_enumerated_devices )
263+ for (const std::string& path : device_paths )
247264 {
248265 hid_log.trace (" Found ps move device: %s" , path);
249266
@@ -253,27 +270,38 @@ void hid_pad_handler<Device>::enumerate_devices()
253270 }
254271 }
255272
256- m_new_enumerated_devices = std::move (col01_paths);
273+ device_paths = std::move (col01_paths);
257274 }
258275#endif
276+
277+ std::lock_guard lock (m_enumeration_mutex);
278+ m_new_enumerated_devices = std::move (device_paths);
279+ m_new_enumerated_serials = std::move (serials);
259280}
260281
261282template <class Device >
262283void hid_pad_handler<Device>::update_devices ()
263284{
264- std::lock_guard lock (m_enumeration_mutex);
265-
266- if (m_last_enumerated_devices == m_new_enumerated_devices)
267285 {
268- return ;
286+ std::lock_guard lock (m_enumeration_mutex);
287+
288+ if (m_enumerated_devices == m_new_enumerated_devices)
289+ {
290+ return ;
291+ }
292+
293+ m_enumerated_devices = std::move (m_new_enumerated_devices);
294+ m_enumerated_serials = std::move (m_new_enumerated_serials);
269295 }
270296
271- m_last_enumerated_devices = m_new_enumerated_devices;
297+ #if defined(__APPLE__)
298+ std::lock_guard static_lock (s_hid_mutex);
299+ #endif
272300
273301 // Scrap devices that are not in the new list
274302 for (auto & controller : m_controllers)
275303 {
276- if (controller.second && controller.second ->path != hid_enumerated_device_default && !m_new_enumerated_devices .contains (controller.second ->path ))
304+ if (controller.second && controller.second ->path != hid_enumerated_device_default && !m_enumerated_devices .contains (controller.second ->path ))
277305 {
278306 controller.second ->close ();
279307 cfg_pad* config = controller.second ->config ;
@@ -285,7 +313,7 @@ void hid_pad_handler<Device>::update_devices()
285313 bool warn_about_drivers = false ;
286314
287315 // Find and add new devices
288- for (const auto & path : m_new_enumerated_devices )
316+ for (const auto & path : m_enumerated_devices )
289317 {
290318 // Check if we have at least one virtual controller left
291319 if (std::none_of (m_controllers.cbegin (), m_controllers.cend (), [](const auto & c) { return !c.second || !c.second ->hidDevice ; }))
0 commit comments