diff options
Diffstat (limited to 'www/firefox-esr/files/patch-bug1680982')
-rw-r--r-- | www/firefox-esr/files/patch-bug1680982 | 388 |
1 files changed, 0 insertions, 388 deletions
diff --git a/www/firefox-esr/files/patch-bug1680982 b/www/firefox-esr/files/patch-bug1680982 deleted file mode 100644 index c9fc2344bb44..000000000000 --- a/www/firefox-esr/files/patch-bug1680982 +++ /dev/null @@ -1,388 +0,0 @@ -commit 3204512f58a1 -Author: Greg V <greg@unrelenting.technology> -Date: Sun Dec 6 22:07:00 2020 +0000 - - Bug 1680982 - Use evdev instead of the Linux legacy joystick API for gamepads - - Using evdev is a prerequisite for adding rumble (haptic feedback) and LED support. - - - BTN_GAMEPAD semantic buttons are interpreted directly, - since all kernel drivers are supposed to use them correctly: - https://www.kernel.org/doc/html/latest/input/gamepad.html - - BTN_JOYSTICK legacy style numbered buttons use the model specific remappers - - we support even strange devices that combine both styles in one device - - the Linux gamepad module is enabled on FreeBSD and DragonFly, because - these kernels provide evdev, and libudev-devd provides enough of libudev - (evdev headers are provided by the devel/evdev-proto package) - - Differential Revision: https://phabricator.services.mozilla.com/D98868 ---- - dom/gamepad/linux/LinuxGamepad.cpp | 262 ++++++++++++++++++++++++++++++++----- - dom/gamepad/moz.build | 2 +- - 2 files changed, 229 insertions(+), 35 deletions(-) - -diff --git dom/gamepad/linux/LinuxGamepad.cpp dom/gamepad/linux/LinuxGamepad.cpp -index deee47b9d267..31f0aad7ae4a 100644 ---- dom/gamepad/linux/LinuxGamepad.cpp -+++ dom/gamepad/linux/LinuxGamepad.cpp -@@ -5,15 +5,16 @@ - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - /* -- * LinuxGamepadService: A Linux backend for the GamepadService. -- * Derived from the kernel documentation at -- * http://www.kernel.org/doc/Documentation/input/joystick-api.txt -+ * LinuxGamepadService: An evdev backend for the GamepadService. -+ * -+ * Ref: https://www.kernel.org/doc/html/latest/input/gamepad.html - */ - #include <algorithm> -+#include <unordered_map> - #include <cstddef> - - #include <glib.h> --#include <linux/joystick.h> -+#include <linux/input.h> - #include <stdio.h> - #include <stdint.h> - #include <sys/ioctl.h> -@@ -21,10 +22,14 @@ - #include "nscore.h" - #include "mozilla/dom/GamepadHandle.h" - #include "mozilla/dom/GamepadPlatformService.h" -+#include "mozilla/dom/GamepadRemapping.h" - #include "mozilla/Tainting.h" - #include "mozilla/UniquePtr.h" - #include "udev.h" - -+#define LONG_BITS (sizeof(long) * 8) -+#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) -+ - namespace { - - using namespace mozilla::dom; -@@ -36,19 +41,29 @@ using mozilla::udev_list_entry; - using mozilla::udev_monitor; - using mozilla::UniquePtr; - --static const float kMaxAxisValue = 32767.0; --static const char kJoystickPath[] = "/dev/input/js"; -+static const char kEvdevPath[] = "/dev/input/event"; -+ -+static inline bool TestBit(const unsigned long* arr, int bit) { -+ return !!(arr[bit / LONG_BITS] & (1LL << (bit % LONG_BITS))); -+} -+ -+static inline double ScaleAxis(const input_absinfo& info, int value) { -+ return 2.0 * (value - info.minimum) / (double)(info.maximum - info.minimum) - -+ 1.0; -+} - - // TODO: should find a USB identifier for each device so we can - // provide something that persists across connect/disconnect cycles. --typedef struct { -+struct Gamepad { - GamepadHandle handle; -- guint source_id; -- int numAxes; -- int numButtons; -- char idstring[256]; -- char devpath[PATH_MAX]; --} Gamepad; -+ RefPtr<GamepadRemapper> remapper = nullptr; -+ guint source_id = UINT_MAX; -+ char idstring[256] = {0}; -+ char devpath[PATH_MAX] = {0}; -+ uint8_t key_map[KEY_MAX] = {0}; -+ uint8_t abs_map[ABS_MAX] = {0}; -+ std::unordered_map<uint16_t, input_absinfo> abs_info; -+}; - - class LinuxGamepadService { - public: -@@ -66,7 +81,7 @@ class LinuxGamepadService { - bool is_gamepad(struct udev_device* dev); - void ReadUdevChange(); - -- // handler for data from /dev/input/jsN -+ // handler for data from /dev/input/eventN - static gboolean OnGamepadData(GIOChannel* source, GIOCondition condition, - gpointer data); - -@@ -114,8 +129,14 @@ void LinuxGamepadService::AddDevice(struct udev_device* dev) { - g_io_channel_set_encoding(channel, nullptr, nullptr); - g_io_channel_set_buffered(channel, FALSE); - int fd = g_io_channel_unix_get_fd(channel); -+ -+ struct input_id id {}; -+ if (ioctl(fd, EVIOCGID, &id) == -1) { -+ return; -+ } -+ - char name[128]; -- if (ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1) { -+ if (ioctl(fd, EVIOCGNAME(sizeof(name)), &name) == -1) { - strcpy(name, "unknown"); - } - const char* vendor_id = -@@ -131,20 +152,86 @@ void LinuxGamepadService::AddDevice(struct udev_device* dev) { - model_id = mUdev.udev_device_get_sysattr_value(parent, "id/product"); - } - } -+ if (!vendor_id && id.vendor != 0) { -+ vendor_id = (const char*)alloca(5); -+ snprintf((char*)vendor_id, 5, "%04x", id.vendor); -+ } -+ if (!model_id && id.product != 0) { -+ model_id = (const char*)alloca(5); -+ snprintf((char*)model_id, 5, "%04x", id.product); -+ } - snprintf(gamepad->idstring, sizeof(gamepad->idstring), "%s-%s-%s", - vendor_id ? vendor_id : "unknown", model_id ? model_id : "unknown", - name); - - char numAxes = 0, numButtons = 0; -- ioctl(fd, JSIOCGAXES, &numAxes); -- gamepad->numAxes = numAxes; -- ioctl(fd, JSIOCGBUTTONS, &numButtons); -- gamepad->numButtons = numButtons; -+ unsigned long key_bits[NLONGS(KEY_CNT)] = {0}; -+ unsigned long abs_bits[NLONGS(ABS_CNT)] = {0}; -+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits); -+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits); -+ -+ /* Here, we try to support even strange cases where proper semantic -+ * BTN_GAMEPAD button are combined with arbitrary extra buttons. */ -+ for (uint16_t i = BTN_JOYSTICK; i < KEY_MAX; i++) { -+ /* Do not map semantic buttons, they are handled directly */ -+ if (i == BTN_GAMEPAD) { -+ i = BTN_THUMBR + 1; -+ continue; -+ } -+ if (i == BTN_DPAD_UP) { -+ i = BTN_DPAD_RIGHT + 1; -+ continue; -+ } -+ if (TestBit(key_bits, i)) { -+ gamepad->key_map[i] = numButtons++; -+ } -+ } -+ for (uint16_t i = 0; i < BTN_JOYSTICK; i++) { -+ if (TestBit(key_bits, i)) { -+ gamepad->key_map[i] = numButtons++; -+ } -+ } -+ for (uint16_t i = BTN_GAMEPAD; i <= BTN_THUMBR; i++) { -+ /* But if any semantic event exists, count them all */ -+ if (TestBit(key_bits, i)) { -+ numButtons += BUTTON_INDEX_COUNT; -+ break; -+ } -+ } -+ for (uint16_t i = 0; i < ABS_MAX; ++i) { -+ if (TestBit(abs_bits, i)) { -+ gamepad->abs_info.emplace(i, input_absinfo{}); -+ if (ioctl(fd, EVIOCGABS(i), &gamepad->abs_info[i]) < 0) { -+ continue; -+ } -+ if (gamepad->abs_info[i].minimum == gamepad->abs_info[i].maximum) { -+ gamepad->abs_info.erase(i); -+ continue; -+ } -+ gamepad->abs_map[i] = numAxes++; -+ } -+ } -+ -+ if (numAxes == 0) { -+ NS_WARNING("Gamepad with zero axes detected?"); -+ } -+ if (numButtons == 0) { -+ NS_WARNING("Gamepad with zero buttons detected?"); -+ } -+ -+ bool defaultRemapper = false; -+ RefPtr<GamepadRemapper> remapper = -+ GetGamepadRemapper(id.vendor, id.product, defaultRemapper); -+ MOZ_ASSERT(remapper); -+ remapper->SetAxisCount(numAxes); -+ remapper->SetButtonCount(numButtons); - - gamepad->handle = service->AddGamepad( -- gamepad->idstring, mozilla::dom::GamepadMappingType::_empty, -- mozilla::dom::GamepadHand::_empty, gamepad->numButtons, gamepad->numAxes, -- 0, 0, 0); // TODO: Bug 680289, implement gamepad haptics for Linux. -+ gamepad->idstring, remapper->GetMappingType(), GamepadHand::_empty, -+ remapper->GetButtonCount(), remapper->GetAxisCount(), 0, -+ remapper->GetLightIndicatorCount(), remapper->GetTouchEventCount()); -+ gamepad->remapper = remapper.forget(); -+ // TODO: Bug 680289, implement gamepad haptics for Linux. - // TODO: Bug 1523355, implement gamepad lighindicator and touch for Linux. - - gamepad->source_id = -@@ -257,7 +344,7 @@ bool LinuxGamepadService::is_gamepad(struct udev_device* dev) { - if (!devpath) { - return false; - } -- if (strncmp(kJoystickPath, devpath, sizeof(kJoystickPath) - 1) != 0) { -+ if (strncmp(kEvdevPath, devpath, sizeof(kEvdevPath) - 1) != 0) { - return false; - } - -@@ -292,7 +379,7 @@ gboolean LinuxGamepadService::OnGamepadData(GIOChannel* source, - if (condition & G_IO_ERR || condition & G_IO_HUP) return FALSE; - - while (true) { -- struct js_event event; -+ struct input_event event {}; - gsize count; - GError* err = nullptr; - if (g_io_channel_read_chars(source, (gchar*)&event, sizeof(event), &count, -@@ -301,18 +388,125 @@ gboolean LinuxGamepadService::OnGamepadData(GIOChannel* source, - break; - } - -- // TODO: store device state? -- if (event.type & JS_EVENT_INIT) { -- continue; -- } -- - switch (event.type) { -- case JS_EVENT_BUTTON: -- service->NewButtonEvent(gamepad->handle, event.number, !!event.value); -+ case EV_KEY: -+ switch (event.code) { -+ /* The gamepad events are meaningful, and according to -+ * https://www.kernel.org/doc/html/latest/input/gamepad.html -+ * "No other devices, that do not look/feel like a gamepad, shall -+ * report these events" */ -+ case BTN_SOUTH: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_PRIMARY, -+ !!event.value); -+ break; -+ case BTN_EAST: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_SECONDARY, -+ !!event.value); -+ break; -+ case BTN_NORTH: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_QUATERNARY, -+ !!event.value); -+ break; -+ case BTN_WEST: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_TERTIARY, -+ !!event.value); -+ break; -+ case BTN_TL: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_LEFT_SHOULDER, -+ !!event.value); -+ break; -+ case BTN_TR: -+ service->NewButtonEvent(gamepad->handle, -+ BUTTON_INDEX_RIGHT_SHOULDER, !!event.value); -+ break; -+ case BTN_TL2: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_LEFT_TRIGGER, -+ !!event.value); -+ break; -+ case BTN_TR2: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_RIGHT_TRIGGER, -+ !!event.value); -+ break; -+ case BTN_SELECT: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_BACK_SELECT, -+ !!event.value); -+ break; -+ case BTN_START: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_START, -+ !!event.value); -+ break; -+ case BTN_MODE: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_META, -+ !!event.value); -+ break; -+ case BTN_THUMBL: -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_LEFT_THUMBSTICK, !!event.value); -+ break; -+ case BTN_THUMBR: -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_RIGHT_THUMBSTICK, !!event.value); -+ break; -+ case BTN_DPAD_UP: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_DPAD_UP, -+ !!event.value); -+ break; -+ case BTN_DPAD_DOWN: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_DPAD_DOWN, -+ !!event.value); -+ break; -+ case BTN_DPAD_LEFT: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_DPAD_LEFT, -+ !!event.value); -+ break; -+ case BTN_DPAD_RIGHT: -+ service->NewButtonEvent(gamepad->handle, BUTTON_INDEX_DPAD_RIGHT, -+ !!event.value); -+ break; -+ default: -+ /* For non-gamepad events, this is the "anything goes" numbered -+ * handling that should be handled with remappers. */ -+ gamepad->remapper->RemapButtonEvent( -+ gamepad->handle, gamepad->key_map[event.code], !!event.value); -+ break; -+ } - break; -- case JS_EVENT_AXIS: -- service->NewAxisMoveEvent(gamepad->handle, event.number, -- ((float)event.value) / kMaxAxisValue); -+ case EV_ABS: -+ if (!gamepad->abs_info.count(event.code)) continue; -+ switch (event.code) { -+ case ABS_HAT0X: -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_DPAD_LEFT, -+ AxisNegativeAsButton( -+ ScaleAxis(gamepad->abs_info[event.code], event.value))); -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_DPAD_RIGHT, -+ AxisPositiveAsButton( -+ ScaleAxis(gamepad->abs_info[event.code], event.value))); -+ break; -+ case ABS_HAT0Y: -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_DPAD_UP, -+ AxisNegativeAsButton( -+ ScaleAxis(gamepad->abs_info[event.code], event.value))); -+ service->NewButtonEvent( -+ gamepad->handle, BUTTON_INDEX_DPAD_DOWN, -+ AxisPositiveAsButton( -+ ScaleAxis(gamepad->abs_info[event.code], event.value))); -+ break; -+ case ABS_HAT1X: -+ case ABS_HAT1Y: -+ case ABS_HAT2X: -+ case ABS_HAT2Y: -+ case ABS_HAT3X: -+ case ABS_HAT3Y: -+ break; -+ default: -+ gamepad->remapper->RemapAxisMoveEvent( -+ gamepad->handle, gamepad->abs_map[event.code], -+ ScaleAxis(gamepad->abs_info[event.code], event.value)); -+ break; -+ } - break; - } - } -diff --git dom/gamepad/moz.build dom/gamepad/moz.build -index 5f55d5a95e96..544b7f927736 100644 ---- dom/gamepad/moz.build -+++ dom/gamepad/moz.build -@@ -59,7 +59,7 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": - UNIFIED_SOURCES += ["windows/WindowsGamepad.cpp"] - elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android": - UNIFIED_SOURCES += ["android/AndroidGamepad.cpp"] --elif CONFIG["OS_ARCH"] == "Linux": -+elif CONFIG["OS_ARCH"] in ("Linux", "FreeBSD", "DragonFly"): - UNIFIED_SOURCES += ["linux/LinuxGamepad.cpp"] - else: - UNIFIED_SOURCES += ["fallback/FallbackGamepad.cpp"] |