| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  joypad_linux.cpp                                                      */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the        */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including    */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
					
						
							|  |  |  | /* the following conditions:                                              */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be         */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.        */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-21 22:39:03 +01:00
										 |  |  | #ifdef JOYDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 21:29:57 +01:00
										 |  |  | #include "joypad_linux.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 15:06:19 +02:00
										 |  |  | #include <dirent.h>
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | #include <linux/input.h>
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-15 15:09:48 +01:00
										 |  |  | #ifdef UDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #ifdef SOWRAP_ENABLED
 | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | #include "libudev-so_wrap.h"
 | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #include <libudev.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-02-15 15:09:48 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #define LONG_BITS (sizeof(long) * 8)
 | 
					
						
							|  |  |  | #define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0)
 | 
					
						
							|  |  |  | #define NBITS(x) ((((x)-1) / LONG_BITS) + 1)
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-03 23:19:22 +02:00
										 |  |  | #ifdef UDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | static const char *ignore_str = "/dev/input/js"; | 
					
						
							| 
									
										
										
										
											2016-07-03 23:19:22 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | JoypadLinux::Joypad::~Joypad() { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 	for (int i = 0; i < MAX_ABS; i++) { | 
					
						
							|  |  |  | 		if (abs_info[i]) { | 
					
						
							|  |  |  | 			memdelete(abs_info[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | void JoypadLinux::Joypad::reset() { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 	dpad = 0; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	fd = -1; | 
					
						
							|  |  |  | 	for (int i = 0; i < MAX_ABS; i++) { | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		abs_map[i] = -1; | 
					
						
							| 
									
										
										
										
											2021-12-25 09:29:08 +00:00
										 |  |  | 		curr_axis[i] = 0; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	events.clear(); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 15:19:37 +02:00
										 |  |  | JoypadLinux::JoypadLinux(Input *in) { | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | #ifdef UDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #ifdef SOWRAP_ENABLED
 | 
					
						
							| 
									
										
										
										
											2021-02-20 00:13:33 +01:00
										 |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							|  |  |  | 	int dylibloader_verbose = 1; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	int dylibloader_verbose = 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	use_udev = initialize_libudev(dylibloader_verbose) == 0; | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | 	if (use_udev) { | 
					
						
							| 
									
										
										
										
											2023-03-16 10:44:47 +02:00
										 |  |  | 		if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) { | 
					
						
							|  |  |  | 			// There's no API to check version, check if functions are available instead.
 | 
					
						
							|  |  |  | 			use_udev = false; | 
					
						
							|  |  |  | 			print_verbose("JoypadLinux: Unsupported udev library version!"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			print_verbose("JoypadLinux: udev enabled and loaded successfully."); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads."); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	input = in; | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	monitor_joypads_thread.start(monitor_joypads_thread_func, this); | 
					
						
							|  |  |  | 	joypad_events_thread.start(joypad_events_thread_func, this); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | JoypadLinux::~JoypadLinux() { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	monitor_joypads_exit.set(); | 
					
						
							|  |  |  | 	joypad_events_exit.set(); | 
					
						
							|  |  |  | 	monitor_joypads_thread.wait_to_finish(); | 
					
						
							|  |  |  | 	joypad_events_thread.wait_to_finish(); | 
					
						
							|  |  |  | 	close_joypads(); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::monitor_joypads_thread_func(void *p_user) { | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	if (p_user) { | 
					
						
							| 
									
										
										
										
											2022-04-05 13:40:26 +03:00
										 |  |  | 		JoypadLinux *joy = static_cast<JoypadLinux *>(p_user); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		joy->monitor_joypads_thread_run(); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::monitor_joypads_thread_run() { | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | #ifdef UDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | 	if (use_udev) { | 
					
						
							|  |  |  | 		udev *_udev = udev_new(); | 
					
						
							|  |  |  | 		if (!_udev) { | 
					
						
							|  |  |  | 			use_udev = false; | 
					
						
							| 
									
										
										
										
											2021-02-18 10:28:37 +01:00
										 |  |  | 			ERR_PRINT("Failed getting an udev context, falling back to parsing /dev/input."); | 
					
						
							|  |  |  | 			monitor_joypads(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			enumerate_joypads(_udev); | 
					
						
							|  |  |  | 			monitor_joypads(_udev); | 
					
						
							|  |  |  | 			udev_unref(_udev); | 
					
						
							| 
									
										
										
										
											2021-02-17 11:28:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		monitor_joypads(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2017-01-08 17:05:51 -03:00
										 |  |  | 	monitor_joypads(); | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | #ifdef UDEV_ENABLED
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | void JoypadLinux::enumerate_joypads(udev *p_udev) { | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	udev_enumerate *enumerate; | 
					
						
							|  |  |  | 	udev_list_entry *devices, *dev_list_entry; | 
					
						
							|  |  |  | 	udev_device *dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	enumerate = udev_enumerate_new(p_udev); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	udev_enumerate_add_match_subsystem(enumerate, "input"); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	udev_enumerate_scan_devices(enumerate); | 
					
						
							|  |  |  | 	devices = udev_enumerate_get_list_entry(enumerate); | 
					
						
							|  |  |  | 	udev_list_entry_foreach(dev_list_entry, devices) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		const char *path = udev_list_entry_get_name(dev_list_entry); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		dev = udev_device_new_from_syspath(p_udev, path); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		const char *devnode = udev_device_get_devnode(dev); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (devnode) { | 
					
						
							|  |  |  | 			String devnode_str = devnode; | 
					
						
							|  |  |  | 			if (devnode_str.find(ignore_str) == -1) { | 
					
						
							| 
									
										
										
										
											2017-01-08 17:05:51 -03:00
										 |  |  | 				open_joypad(devnode); | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		udev_device_unref(dev); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	udev_enumerate_unref(enumerate); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | void JoypadLinux::monitor_joypads(udev *p_udev) { | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	udev_device *dev = nullptr; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev"); | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	udev_monitor_filter_add_match_subsystem_devtype(mon, "input", nullptr); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	udev_monitor_enable_receiving(mon); | 
					
						
							|  |  |  | 	int fd = udev_monitor_get_fd(mon); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	while (!monitor_joypads_exit.is_set()) { | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		fd_set fds; | 
					
						
							|  |  |  | 		struct timeval tv; | 
					
						
							|  |  |  | 		int ret; | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		FD_ZERO(&fds); | 
					
						
							|  |  |  | 		FD_SET(fd, &fds); | 
					
						
							|  |  |  | 		tv.tv_sec = 0; | 
					
						
							|  |  |  | 		tv.tv_usec = 0; | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 		ret = select(fd + 1, &fds, nullptr, nullptr, &tv); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		/* Check if our file descriptor has received data. */ | 
					
						
							|  |  |  | 		if (ret > 0 && FD_ISSET(fd, &fds)) { | 
					
						
							|  |  |  | 			/* Make the call to receive the device.
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			   select() ensured that this will not block. */ | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 			dev = udev_monitor_receive_device(mon); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 14:02:50 +02:00
										 |  |  | 			if (dev && udev_device_get_devnode(dev) != nullptr) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 				String action = udev_device_get_action(dev); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				const char *devnode = udev_device_get_devnode(dev); | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 				if (devnode) { | 
					
						
							|  |  |  | 					String devnode_str = devnode; | 
					
						
							|  |  |  | 					if (devnode_str.find(ignore_str) == -1) { | 
					
						
							| 
									
										
										
										
											2021-04-05 14:09:59 +02:00
										 |  |  | 						if (action == "add") { | 
					
						
							| 
									
										
										
										
											2017-01-08 17:05:51 -03:00
										 |  |  | 							open_joypad(devnode); | 
					
						
							| 
									
										
										
										
											2021-04-05 14:09:59 +02:00
										 |  |  | 						} else if (String(action) == "remove") { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							close_joypad(devnode); | 
					
						
							| 
									
										
										
										
											2021-04-05 14:09:59 +02:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				udev_device_unref(dev); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		usleep(50000); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	udev_monitor_unref(mon); | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | void JoypadLinux::monitor_joypads() { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	while (!monitor_joypads_exit.is_set()) { | 
					
						
							|  |  |  | 		DIR *input_directory; | 
					
						
							|  |  |  | 		input_directory = opendir("/dev/input"); | 
					
						
							|  |  |  | 		if (input_directory) { | 
					
						
							|  |  |  | 			struct dirent *current; | 
					
						
							|  |  |  | 			char fname[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			while ((current = readdir(input_directory)) != nullptr) { | 
					
						
							|  |  |  | 				if (strncmp(current->d_name, "event", 5) != 0) { | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				sprintf(fname, "/dev/input/%.*s", 16, current->d_name); | 
					
						
							|  |  |  | 				if (attached_devices.find(fname) == -1) { | 
					
						
							|  |  |  | 					open_joypad(fname); | 
					
						
							| 
									
										
										
										
											2020-02-26 11:28:13 +01:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		closedir(input_directory); | 
					
						
							| 
									
										
										
										
											2022-12-03 20:10:48 -08:00
										 |  |  | 		usleep(1000000); // 1s
 | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::close_joypads() { | 
					
						
							| 
									
										
										
										
											2017-01-08 17:05:51 -03:00
										 |  |  | 	for (int i = 0; i < JOYPADS_MAX; i++) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		MutexLock lock(joypads_mutex[i]); | 
					
						
							|  |  |  | 		Joypad &joypad = joypads[i]; | 
					
						
							|  |  |  | 		close_joypad(joypad, i); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::close_joypad(const char *p_devpath) { | 
					
						
							|  |  |  | 	for (int i = 0; i < JOYPADS_MAX; i++) { | 
					
						
							|  |  |  | 		MutexLock lock(joypads_mutex[i]); | 
					
						
							|  |  |  | 		Joypad &joypad = joypads[i]; | 
					
						
							|  |  |  | 		if (joypads[i].devpath == p_devpath) { | 
					
						
							|  |  |  | 			close_joypad(joypad, i); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::close_joypad(Joypad &p_joypad, int p_id) { | 
					
						
							|  |  |  | 	if (p_joypad.fd != -1) { | 
					
						
							|  |  |  | 		close(p_joypad.fd); | 
					
						
							|  |  |  | 		p_joypad.fd = -1; | 
					
						
							|  |  |  | 		attached_devices.erase(p_joypad.devpath); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		input->joy_connection_changed(p_id, false, ""); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	p_joypad.events.clear(); | 
					
						
							| 
									
										
										
										
											2016-07-21 21:11:34 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static String _hex_str(uint8_t p_byte) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	static const char *dict = "0123456789abcdef"; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	char ret[3]; | 
					
						
							|  |  |  | 	ret[2] = 0; | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ret[0] = dict[p_byte >> 4]; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	ret[1] = dict[p_byte & 0xF]; | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2016-07-21 21:11:34 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::setup_joypad_properties(Joypad &p_joypad) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 	unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; | 
					
						
							|  |  |  | 	unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; | 
					
						
							| 
									
										
										
										
											2016-01-02 03:52:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int num_buttons = 0; | 
					
						
							|  |  |  | 	int num_axes = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if ((ioctl(p_joypad.fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || | 
					
						
							|  |  |  | 			(ioctl(p_joypad.fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (test_bit(i, keybit)) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			p_joypad.key_map[i] = num_buttons++; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (test_bit(i, keybit)) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			p_joypad.key_map[i] = num_buttons++; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (int i = 0; i < ABS_MISC; ++i) { | 
					
						
							|  |  |  | 		/* Skip hats */ | 
					
						
							|  |  |  | 		if (i == ABS_HAT0X) { | 
					
						
							|  |  |  | 			i = ABS_HAT3Y; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (test_bit(i, absbit)) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			p_joypad.abs_map[i] = num_axes++; | 
					
						
							|  |  |  | 			p_joypad.abs_info[i] = memnew(input_absinfo); | 
					
						
							|  |  |  | 			if (ioctl(p_joypad.fd, EVIOCGABS(i), p_joypad.abs_info[i]) < 0) { | 
					
						
							|  |  |  | 				memdelete(p_joypad.abs_info[i]); | 
					
						
							|  |  |  | 				p_joypad.abs_info[i] = nullptr; | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	p_joypad.force_feedback = false; | 
					
						
							|  |  |  | 	p_joypad.ff_effect_timestamp = 0; | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 	unsigned long ffbit[NBITS(FF_CNT)]; | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if (ioctl(p_joypad.fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 		if (test_bit(FF_RUMBLE, ffbit)) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			p_joypad.force_feedback = true; | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-08 22:22:00 +01:00
										 |  |  | void JoypadLinux::open_joypad(const char *p_path) { | 
					
						
							| 
									
										
										
										
											2017-02-21 17:02:49 +01:00
										 |  |  | 	int joy_num = input->get_unused_joy_id(); | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 	int fd = open(p_path, O_RDWR | O_NONBLOCK); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	if (fd != -1 && joy_num != -1) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		unsigned long evbit[NBITS(EV_MAX)] = { 0 }; | 
					
						
							|  |  |  | 		unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; | 
					
						
							|  |  |  | 		unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-14 15:13:11 +01:00
										 |  |  | 		// add to attached devices so we don't try to open it again
 | 
					
						
							|  |  |  | 		attached_devices.push_back(String(p_path)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || | 
					
						
							|  |  |  | 				(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { | 
					
						
							| 
									
										
										
										
											2016-02-01 13:39:50 +01:00
										 |  |  | 			close(fd); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 10:16:35 +01:00
										 |  |  | 		// Check if the device supports basic gamepad events
 | 
					
						
							| 
									
										
										
										
											2022-02-03 22:56:43 -05:00
										 |  |  | 		bool has_abs_left = (test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit)); | 
					
						
							|  |  |  | 		bool has_abs_right = (test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit)); | 
					
						
							|  |  |  | 		if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && (has_abs_left || has_abs_right))) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			close(fd); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		char uid[128]; | 
					
						
							|  |  |  | 		char namebuf[128]; | 
					
						
							|  |  |  | 		String name = ""; | 
					
						
							|  |  |  | 		input_id inpid; | 
					
						
							|  |  |  | 		if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) { | 
					
						
							|  |  |  | 			name = namebuf; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (ioctl(fd, EVIOCGID, &inpid) < 0) { | 
					
						
							|  |  |  | 			close(fd); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		MutexLock lock(joypads_mutex[joy_num]); | 
					
						
							|  |  |  | 		Joypad &joypad = joypads[joy_num]; | 
					
						
							|  |  |  | 		joypad.reset(); | 
					
						
							|  |  |  | 		joypad.fd = fd; | 
					
						
							|  |  |  | 		joypad.devpath = String(p_path); | 
					
						
							|  |  |  | 		setup_joypad_properties(joypad); | 
					
						
							| 
									
										
										
										
											2019-03-05 22:17:20 +01:00
										 |  |  | 		sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0); | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 		if (inpid.vendor && inpid.product && inpid.version) { | 
					
						
							| 
									
										
										
										
											2019-03-05 22:17:20 +01:00
										 |  |  | 			uint16_t vendor = BSWAP16(inpid.vendor); | 
					
						
							|  |  |  | 			uint16_t product = BSWAP16(inpid.product); | 
					
						
							|  |  |  | 			uint16_t version = BSWAP16(inpid.version); | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0); | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			input->joy_connection_changed(joy_num, true, name, uid); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 			String uidname = uid; | 
					
						
							|  |  |  | 			int uidlen = MIN(name.length(), 11); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			for (int i = 0; i < uidlen; i++) { | 
					
						
							| 
									
										
										
										
											2016-01-26 23:04:57 +01:00
										 |  |  | 				uidname = uidname + _hex_str(name[i]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			uidname += "00"; | 
					
						
							|  |  |  | 			input->joy_connection_changed(joy_num, true, name, uidname); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::joypad_vibration_start(Joypad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { | 
					
						
							|  |  |  | 	if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if (p_joypad.ff_effect_id != -1) { | 
					
						
							|  |  |  | 		joypad_vibration_stop(p_joypad, p_timestamp); | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct ff_effect effect; | 
					
						
							|  |  |  | 	effect.type = FF_RUMBLE; | 
					
						
							|  |  |  | 	effect.id = -1; | 
					
						
							|  |  |  | 	effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff); | 
					
						
							|  |  |  | 	effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff); | 
					
						
							|  |  |  | 	effect.replay.length = floor(p_duration * 1000); | 
					
						
							|  |  |  | 	effect.replay.delay = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if (ioctl(p_joypad.fd, EVIOCSFF, &effect) < 0) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct input_event play; | 
					
						
							|  |  |  | 	play.type = EV_FF; | 
					
						
							|  |  |  | 	play.code = effect.id; | 
					
						
							|  |  |  | 	play.value = 1; | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if (write(p_joypad.fd, (const void *)&play, sizeof(play)) == -1) { | 
					
						
							| 
									
										
										
										
											2019-06-19 10:41:07 +02:00
										 |  |  | 		print_verbose("Couldn't write to Joypad device."); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	p_joypad.ff_effect_id = effect.id; | 
					
						
							|  |  |  | 	p_joypad.ff_effect_timestamp = p_timestamp; | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::joypad_vibration_stop(Joypad &p_joypad, uint64_t p_timestamp) { | 
					
						
							|  |  |  | 	if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_joypad.ff_effect_id == -1) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	if (ioctl(p_joypad.fd, EVIOCRMFF, p_joypad.ff_effect_id) < 0) { | 
					
						
							| 
									
										
										
										
											2016-06-20 11:01:07 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 	p_joypad.ff_effect_id = -1; | 
					
						
							|  |  |  | 	p_joypad.ff_effect_timestamp = p_timestamp; | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 09:29:08 +00:00
										 |  |  | float JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	int min = p_abs->minimum; | 
					
						
							|  |  |  | 	int max = p_abs->maximum; | 
					
						
							| 
									
										
										
										
											2021-12-25 09:29:08 +00:00
										 |  |  | 	// Convert to a value between -1.0f and 1.0f.
 | 
					
						
							|  |  |  | 	return 2.0f * (p_value - min) / (max - min) - 1.0f; | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | void JoypadLinux::joypad_events_thread_func(void *p_user) { | 
					
						
							|  |  |  | 	if (p_user) { | 
					
						
							|  |  |  | 		JoypadLinux *joy = (JoypadLinux *)p_user; | 
					
						
							|  |  |  | 		joy->joypad_events_thread_run(); | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void JoypadLinux::joypad_events_thread_run() { | 
					
						
							|  |  |  | 	while (!joypad_events_exit.is_set()) { | 
					
						
							|  |  |  | 		bool no_events = true; | 
					
						
							|  |  |  | 		for (int i = 0; i < JOYPADS_MAX; i++) { | 
					
						
							|  |  |  | 			MutexLock lock(joypads_mutex[i]); | 
					
						
							|  |  |  | 			Joypad &joypad = joypads[i]; | 
					
						
							|  |  |  | 			if (joypad.fd == -1) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			input_event event; | 
					
						
							|  |  |  | 			while (read(joypad.fd, &event, sizeof(event)) > 0) { | 
					
						
							|  |  |  | 				no_events = false; | 
					
						
							|  |  |  | 				JoypadEvent joypad_event; | 
					
						
							|  |  |  | 				joypad_event.type = event.type; | 
					
						
							|  |  |  | 				joypad_event.code = event.code; | 
					
						
							|  |  |  | 				joypad_event.value = event.value; | 
					
						
							|  |  |  | 				joypad.events.push_back(joypad_event); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (errno != EAGAIN) { | 
					
						
							|  |  |  | 				close_joypad(joypad, i); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (no_events) { | 
					
						
							|  |  |  | 			usleep(10000); // 10ms
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void JoypadLinux::process_joypads() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (int i = 0; i < JOYPADS_MAX; i++) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		MutexLock lock(joypads_mutex[i]); | 
					
						
							|  |  |  | 		Joypad &joypad = joypads[i]; | 
					
						
							|  |  |  | 		if (joypad.fd == -1) { | 
					
						
							| 
									
										
										
										
											2020-05-10 12:56:01 +02:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		for (uint32_t j = 0; j < joypad.events.size(); j++) { | 
					
						
							|  |  |  | 			const JoypadEvent &joypad_event = joypad.events[j]; | 
					
						
							|  |  |  | 			// joypad_event may be tainted and out of MAX_KEY range, which will cause
 | 
					
						
							|  |  |  | 			// joypad.key_map[joypad_event.code] to crash
 | 
					
						
							|  |  |  | 			if (joypad_event.code >= MAX_KEY) { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			switch (joypad_event.type) { | 
					
						
							|  |  |  | 				case EV_KEY: | 
					
						
							|  |  |  | 					input->joy_button(i, (JoyButton)joypad.key_map[joypad_event.code], joypad_event.value); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				case EV_ABS: | 
					
						
							|  |  |  | 					switch (joypad_event.code) { | 
					
						
							|  |  |  | 						case ABS_HAT0X: | 
					
						
							|  |  |  | 							if (joypad_event.value != 0) { | 
					
						
							|  |  |  | 								if (joypad_event.value < 0) { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 									joypad.dpad.set_flag(HatMask::LEFT); | 
					
						
							|  |  |  | 									joypad.dpad.clear_flag(HatMask::RIGHT); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 								} else { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 									joypad.dpad.set_flag(HatMask::RIGHT); | 
					
						
							|  |  |  | 									joypad.dpad.clear_flag(HatMask::LEFT); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 								joypad.dpad.clear_flag(HatMask::LEFT); | 
					
						
							|  |  |  | 								joypad.dpad.clear_flag(HatMask::RIGHT); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 							input->joy_hat(i, joypad.dpad); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						case ABS_HAT0Y: | 
					
						
							|  |  |  | 							if (joypad_event.value != 0) { | 
					
						
							|  |  |  | 								if (joypad_event.value < 0) { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 									joypad.dpad.set_flag(HatMask::UP); | 
					
						
							|  |  |  | 									joypad.dpad.clear_flag(HatMask::DOWN); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 								} else { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 									joypad.dpad.set_flag(HatMask::DOWN); | 
					
						
							|  |  |  | 									joypad.dpad.clear_flag(HatMask::UP); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 								joypad.dpad.clear_flag(HatMask::UP); | 
					
						
							|  |  |  | 								joypad.dpad.clear_flag(HatMask::DOWN); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2023-01-08 00:55:54 +01:00
										 |  |  | 							input->joy_hat(i, joypad.dpad); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 							break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						default: | 
					
						
							|  |  |  | 							if (joypad_event.code >= MAX_ABS) { | 
					
						
							|  |  |  | 								return; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (joypad.abs_map[joypad_event.code] != -1 && joypad.abs_info[joypad_event.code]) { | 
					
						
							|  |  |  | 								float value = axis_correct(joypad.abs_info[joypad_event.code], joypad_event.value); | 
					
						
							|  |  |  | 								joypad.curr_axis[joypad.abs_map[joypad_event.code]] = value; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		joypad.events.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-03 02:24:43 +01:00
										 |  |  | 		for (int j = 0; j < MAX_ABS; j++) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			int index = joypad.abs_map[j]; | 
					
						
							| 
									
										
										
										
											2016-01-03 02:24:43 +01:00
										 |  |  | 			if (index != -1) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 				input->joy_axis(i, (JoyAxis)index, joypad.curr_axis[index]); | 
					
						
							| 
									
										
										
										
											2016-01-03 02:24:43 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 		if (joypad.force_feedback) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 			uint64_t timestamp = input->get_joy_vibration_timestamp(i); | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 			if (timestamp > joypad.ff_effect_timestamp) { | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 				Vector2 strength = input->get_joy_vibration_strength(i); | 
					
						
							|  |  |  | 				float duration = input->get_joy_vibration_duration(i); | 
					
						
							|  |  |  | 				if (strength.x == 0 && strength.y == 0) { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 					joypad_vibration_stop(joypad, timestamp); | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 					joypad_vibration_start(joypad, strength.x, strength.y, duration, timestamp); | 
					
						
							| 
									
										
										
										
											2016-06-15 07:25:35 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-18 19:15:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-18 06:12:53 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-12-18 20:00:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif // JOYDEV_ENABLED
 |