From c53359546de0000905d4ea5a96ceda8cb417d2ba Mon Sep 17 00:00:00 2001 From: Petar Tijanic Date: Tue, 4 Aug 2026 15:35:46 +0000 Subject: [PATCH 1/3] [WPE] Add USE_MANETTE_GAMEPAD_PROVIDER build toggle Add USE_MANETTE_GAMEPAD_PROVIDER cmake option (default OFF) that allows WPE to use ManetteGamepadProvider (direct libmanette) instead of the existing GamepadLibWPE (libwpe gamepad) backend. When enabled (-DUSE_MANETTE_GAMEPAD_PROVIDER=ON): - FindManette.cmake searches for manette-1 first, falls back to manette-0.2 - WebCore builds ManetteGamepad.cpp/ManetteGamepadProvider.cpp - WebKit builds UIGamepadProviderManette.cpp When disabled (default): - WebCore builds GamepadLibWPE.cpp/GamepadProviderLibWPE.cpp - WebKit builds UIGamepadProviderLibWPE.cpp - Original libwpe-based gamepad input routing is preserved This brings the WPE port in line with how the GTK port uses libmanette directly, while keeping GamepadLibWPE as the default. * Source/cmake/FindManette.cmake: * Source/cmake/OptionsWPE.cmake: * Source/WebCore/PlatformWPE.cmake: * Source/WebCore/SourcesWPE.txt: * Source/WebKit/PlatformWPE.cmake: * Source/WebKit/SourcesWPE.txt: * Source/WebKit/UIProcess/API/wpe/WPEWebViewLegacy.cpp: * Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp: --- Source/WebCore/PlatformWPE.cmake | 33 +++++++++++++++---- Source/WebCore/SourcesWPE.txt | 2 -- Source/WebKit/PlatformWPE.cmake | 12 +++++++ Source/WebKit/SourcesWPE.txt | 1 - .../UIProcess/API/wpe/WPEWebViewLegacy.cpp | 9 ++++- .../manette/UIGamepadProviderManette.cpp | 8 +++++ Source/cmake/FindManette.cmake | 10 ++++-- Source/cmake/OptionsWPE.cmake | 13 ++++++++ 8 files changed, 75 insertions(+), 13 deletions(-) diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake index d133eae894734..52d7a70cc30e9 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake @@ -131,13 +131,32 @@ elseif (USE_LIBDRM) endif () if (ENABLE_GAMEPAD) - list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES - "${WEBCORE_DIR}/platform/gamepad/libwpe" - ) - - list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS - platform/gamepad/libwpe/GamepadProviderLibWPE.h - ) + if (USE_MANETTE_GAMEPAD_PROVIDER) + list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES + "${WEBCORE_DIR}/platform/gamepad/manette" + ) + list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS + platform/gamepad/manette/ManetteGamepadProvider.h + ) + list(APPEND WebCore_LIBRARIES + Manette::Manette + ) + list(APPEND WebCore_SOURCES + platform/gamepad/manette/ManetteGamepad.cpp + platform/gamepad/manette/ManetteGamepadProvider.cpp + ) + else () + list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES + "${WEBCORE_DIR}/platform/gamepad/libwpe" + ) + list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS + platform/gamepad/libwpe/GamepadProviderLibWPE.h + ) + list(APPEND WebCore_SOURCES + platform/gamepad/libwpe/GamepadLibWPE.cpp + platform/gamepad/libwpe/GamepadProviderLibWPE.cpp + ) + endif () endif () if (ENABLE_SPEECH_SYNTHESIS) diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt index 891c8ea264628..28a5d1572b84c 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt @@ -49,8 +49,6 @@ loader/soup/ResourceLoaderSoup.cpp page/linux/ResourceUsageOverlayLinux.cpp page/linux/ResourceUsageThreadLinux.cpp -platform/gamepad/libwpe/GamepadLibWPE.cpp -platform/gamepad/libwpe/GamepadProviderLibWPE.cpp platform/generic/ScrollbarsControllerGeneric.cpp diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index 1c067e128f4df..b65a5407dec37 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -468,6 +468,18 @@ if (ENABLE_BUBBLEWRAP_SANDBOX) list(APPEND WebKit_LIBRARIES Libseccomp::Libseccomp) endif () +if (ENABLE_GAMEPAD) + if (USE_MANETTE_GAMEPAD_PROVIDER) + list(APPEND WebKit_SOURCES + UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp + ) + else () + list(APPEND WebKit_SOURCES + UIProcess/Gamepad/libwpe/UIGamepadProviderLibWPE.cpp + ) + endif () +endif () + if (USE_GSTREAMER_FULL) list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GSTREAMER_FULL_INCLUDE_DIRS} diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt index 7f5d22aad87f1..b4298dc6b1cbf 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -220,7 +220,6 @@ UIProcess/Automation/libwpe/WebAutomationSessionWPE.cpp UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp -UIProcess/Gamepad/libwpe/UIGamepadProviderLibWPE.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp diff --git a/Source/WebKit/UIProcess/API/wpe/WPEWebViewLegacy.cpp b/Source/WebKit/UIProcess/API/wpe/WPEWebViewLegacy.cpp index 51f763d4dcae1..4724617ae896b 100644 --- a/Source/WebKit/UIProcess/API/wpe/WPEWebViewLegacy.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WPEWebViewLegacy.cpp @@ -38,7 +38,7 @@ #include #include -#if ENABLE(GAMEPAD) +#if ENABLE(GAMEPAD) && !USE(MANETTE_GAMEPAD_PROVIDER) #include #endif @@ -389,6 +389,12 @@ WebKit::WebPageProxy* ViewLegacy::platformWebPageProxyForGamepadInput() if (views.isEmpty()) return nullptr; +#if USE(MANETTE_GAMEPAD_PROVIDER) + auto index = views.findIf([](ViewLegacy* view) { + return view->viewState().contains(WebCore::ActivityState::IsVisible) + && view->viewState().contains(WebCore::ActivityState::IsFocused); + }); +#else struct wpe_view_backend* viewBackend = WebCore::GamepadProviderLibWPE::singleton().inputView(); size_t index = notFound; @@ -405,6 +411,7 @@ WebKit::WebPageProxy* ViewLegacy::platformWebPageProxyForGamepadInput() && view->viewState().contains(WebCore::ActivityState::IsFocused); }); } +#endif if (index != notFound) return &(views[index]->page()); diff --git a/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp b/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp index a16ea593bbf82..a74245fb1383e 100644 --- a/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp +++ b/Source/WebKit/UIProcess/Gamepad/manette/UIGamepadProviderManette.cpp @@ -32,6 +32,10 @@ #include #include +#if PLATFORM(WPE) +#include "WPEWebViewLegacy.h" +#endif + namespace WebKit { using namespace WebCore; @@ -47,7 +51,11 @@ void UIGamepadProvider::platformSetDefaultGamepadProvider() #if !PLATFORM(GTK) WebPageProxy* UIGamepadProvider::platformWebPageProxyForGamepadInput() { +#if PLATFORM(WPE) && USE(MANETTE_GAMEPAD_PROVIDER) + return WKWPE::ViewLegacy::platformWebPageProxyForGamepadInput(); +#else return nullptr; +#endif } #endif diff --git a/Source/cmake/FindManette.cmake b/Source/cmake/FindManette.cmake index 5c1551c1feb69..b2ffd16641b99 100644 --- a/Source/cmake/FindManette.cmake +++ b/Source/cmake/FindManette.cmake @@ -53,7 +53,13 @@ This will define the following variables in your project: #]=======================================================================] find_package(PkgConfig QUIET) -pkg_check_modules(PC_MANETTE QUIET manette-0.2) + +# Try manette-1 first (libmanette 1.0), fall back to manette-0.2 +pkg_check_modules(PC_MANETTE QUIET manette-1) +if (NOT PC_MANETTE_FOUND) + pkg_check_modules(PC_MANETTE QUIET manette-0.2) +endif () + set(Manette_COMPILE_OPTIONS ${PC_MANETTE_CFLAGS_OTHER}) set(Manette_VERSION ${PC_MANETTE_VERSION}) @@ -64,7 +70,7 @@ find_path(Manette_INCLUDE_DIR ) find_library(Manette_LIBRARY - NAMES ${Manette_NAMES} manette-0.2 + NAMES ${Manette_NAMES} manette-1 manette-0.2 HINTS ${PC_MANETTE_LIBDIR} ${PC_MANETTE_LIBRARY_DIRS} ) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 41fb857ec5aea..7928a5ff8b288 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -236,6 +236,19 @@ if (ENABLE_GAMEPAD AND (NOT (WPE_VERSION VERSION_GREATER_EQUAL 1.16.2))) message(FATAL_ERROR "libwpe>=1.16.2 is required for ENABLE_GAMEPAD") endif () +option(USE_MANETTE_GAMEPAD_PROVIDER "Use ManetteGamepadProvider (direct libmanette) instead of libwpe gamepad" OFF) + +if (ENABLE_GAMEPAD) + if (USE_MANETTE_GAMEPAD_PROVIDER) + find_package(Manette) + if (NOT Manette_FOUND) + message(FATAL_ERROR "libmanette is required for USE_MANETTE_GAMEPAD_PROVIDER") + endif () + SET_AND_EXPOSE_TO_BUILD(USE_MANETTE TRUE) + SET_AND_EXPOSE_TO_BUILD(USE_MANETTE_GAMEPAD_PROVIDER TRUE) + endif () +endif () + if (ENABLE_SPEECH_SYNTHESIS) if (USE_FLITE) if (USE_TTS_CLIENT) From 58f1a2ccb960ab40a2b0d08322c1328d64f0f0ec Mon Sep 17 00:00:00 2001 From: Petar Tijanic Date: Tue, 4 Aug 2026 15:46:29 +0000 Subject: [PATCH 2/3] [WPE] Implement playEffect for ManetteGamepadProvider Port gamepad haptic feedback (dual-rumble) support to the WPE ManetteGamepadProvider, matching the GTK port implementation. Uses MANETTE_CHECK_VERSION(0, 2, 13) to select the correct rumble API: - >= 0.2.13 (and all of 1.0): magnitudes passed as double directly - < 0.2.13: magnitudes scaled by G_MAXUINT16 Includes a fallback #define for MANETTE_CHECK_VERSION for libmanette versions < 0.2.10 that lack the macro. Also enables defaultGamepadVibrationActuatorEnabled when USE(MANETTE). * Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp: (WebCore::ManetteGamepad::ManetteGamepad): (WebCore::ManetteGamepad::playEffect): (WebCore::ManetteGamepad::stopEffects): (WebCore::ManetteGamepad::effectDelayTimerFired): (WebCore::ManetteGamepad::startRumble): (WebCore::ManetteGamepad::effectDurationTimerFired): * Source/WebCore/platform/gamepad/manette/ManetteGamepad.h: * Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp: (WebCore::ManetteGamepadProvider::playEffect): (WebCore::ManetteGamepadProvider::stopEffects): * Source/WebKit/Shared/WebPreferencesDefaultValues.cpp: (WebKit::defaultGamepadVibrationActuatorEnabled): --- .../gamepad/manette/ManetteGamepad.cpp | 64 +++++++++++++++++++ .../platform/gamepad/manette/ManetteGamepad.h | 18 ++++-- .../manette/ManetteGamepadProvider.cpp | 22 +++++-- .../Shared/WebPreferencesDefaultValues.cpp | 2 +- 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp index 58d707a5ef9c4..e6aecbc7aee17 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp @@ -28,6 +28,10 @@ #if ENABLE(GAMEPAD) && OS(LINUX) +#ifndef MANETTE_CHECK_VERSION +#define MANETTE_CHECK_VERSION(major,minor,micro) 0 +#endif + #include "ManetteGamepadProvider.h" #include #include @@ -126,6 +130,8 @@ static void onButtonReleaseEvent(ManetteDevice* device, ManetteEvent* event, Man ManetteGamepad::ManetteGamepad(ManetteDevice* device, unsigned index) : PlatformGamepad(index) , m_device(device) + , m_effectDelayTimer(RunLoop::current(), this, &ManetteGamepad::effectDelayTimerFired) + , m_effectDurationTimer(RunLoop::current(), this, &ManetteGamepad::effectDurationTimerFired) { ASSERT(index < 4); @@ -142,6 +148,9 @@ ManetteGamepad::ManetteGamepad(ManetteDevice* device, unsigned index) for (auto& value : m_buttonValues) value.setValue(0.0); + if (manette_device_has_rumble(m_device.get())) + m_supportedEffectTypes.add(GamepadHapticEffectType::DualRumble); + g_signal_connect(device, "button-press-event", G_CALLBACK(onButtonPressEvent), this); g_signal_connect(device, "button-release-event", G_CALLBACK(onButtonReleaseEvent), this); g_signal_connect(device, "absolute-axis-event", G_CALLBACK(onAbsoluteAxisEvent), this); @@ -174,6 +183,61 @@ void ManetteGamepad::absoluteAxisChanged(ManetteDevice*, StandardGamepadAxis axi ManetteGamepadProvider::singleton().gamepadHadInput(*this, ManetteGamepadProvider::ShouldMakeGamepadsVisible::Yes); } +void ManetteGamepad::playEffect(GamepadHapticEffectType type, const GamepadEffectParameters& parameters, CompletionHandler&& completionHandler) +{ + if (!m_supportedEffectTypes.contains(type)) + return completionHandler(false); + + if (m_effectCompletionHandler) + stopEffects({ }); + + m_effectCompletionHandler = WTFMove(completionHandler); + if (parameters.startDelay) { + m_pendingEffectParameters = parameters; + m_effectDelayTimer.startOneShot(Seconds::fromMilliseconds(parameters.startDelay)); + return; + } + + startRumble(parameters); +} + +void ManetteGamepad::stopEffects(CompletionHandler&& completionHandler) +{ + m_effectDelayTimer.stop(); + m_effectDurationTimer.stop(); + if (m_effectCompletionHandler) + m_effectCompletionHandler(false); + + manette_device_rumble(m_device.get(), 0, 0, 0); + + if (completionHandler) + completionHandler(); +} + +void ManetteGamepad::effectDelayTimerFired() +{ + startRumble(std::exchange(m_pendingEffectParameters, { })); +} + +void ManetteGamepad::startRumble(const GamepadEffectParameters& parameters) +{ +#if MANETTE_CHECK_VERSION(0, 2, 13) + manette_device_rumble(m_device.get(), parameters.strongMagnitude, parameters.weakMagnitude, static_cast(parameters.duration)); +#else + manette_device_rumble(m_device.get(), parameters.strongMagnitude * G_MAXUINT16, parameters.weakMagnitude * G_MAXUINT16, static_cast(parameters.duration)); +#endif + + if (parameters.duration) + m_effectDurationTimer.startOneShot(Seconds::fromMilliseconds(parameters.duration)); + else + m_effectCompletionHandler(true); +} + +void ManetteGamepad::effectDurationTimerFired() +{ + m_effectCompletionHandler(true); +} + } // namespace WebCore #endif // ENABLE(GAMEPAD) && OS(LINUX) diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h index 172b05ae6e397..3588f7712a3f1 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h @@ -27,10 +27,11 @@ #if ENABLE(GAMEPAD) && OS(LINUX) +#include "GamepadEffectParameters.h" #include "PlatformGamepad.h" #include -#include +#include #include namespace WebCore { @@ -71,17 +72,26 @@ class ManetteGamepad final : public PlatformGamepad { ManetteGamepad(ManetteDevice*, unsigned index); virtual ~ManetteGamepad(); - const Vector& axisValues() const final { return m_axisValues; } - const Vector& buttonValues() const final { return m_buttonValues; } - void absoluteAxisChanged(ManetteDevice*, StandardGamepadAxis, double value); void buttonPressedOrReleased(ManetteDevice*, StandardGamepadButton, bool pressed); + void playEffect(GamepadHapticEffectType, const GamepadEffectParameters&, CompletionHandler&&) final; + void stopEffects(CompletionHandler&&) final; private: + const Vector& axisValues() const final { return m_axisValues; } + const Vector& buttonValues() const final { return m_buttonValues; } + void effectDelayTimerFired(); + void effectDurationTimerFired(); + void startRumble(const GamepadEffectParameters&); + GRefPtr m_device; Vector m_buttonValues; Vector m_axisValues; + RunLoop::Timer m_effectDelayTimer; + RunLoop::Timer m_effectDurationTimer; + CompletionHandler m_effectCompletionHandler; + GamepadEffectParameters m_pendingEffectParameters; }; } // namespace WebCore diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp index 1782e8c2f7aa7..b41a983269a4f 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp @@ -196,16 +196,26 @@ std::unique_ptr ManetteGamepadProvider::removeGamepadForDevice(M return result; } -void ManetteGamepadProvider::playEffect(unsigned, const String&, GamepadHapticEffectType, const GamepadEffectParameters&, CompletionHandler&& completionHandler) +void ManetteGamepadProvider::playEffect(unsigned gamepadIndex, const String& gamepadID, GamepadHapticEffectType type, const GamepadEffectParameters& parameters, CompletionHandler&& completionHandler) { - // Not supported by this provider. - completionHandler(false); + if (gamepadIndex >= m_gamepadVector.size()) + return completionHandler(false); + auto gamepad = m_gamepadVector[gamepadIndex]; + if (!gamepad || gamepad->id() != gamepadID) + return completionHandler(false); + + static_cast(gamepad.get())->playEffect(type, parameters, WTFMove(completionHandler)); } -void ManetteGamepadProvider::stopEffects(unsigned, const String&, CompletionHandler&& completionHandler) +void ManetteGamepadProvider::stopEffects(unsigned gamepadIndex, const String& gamepadID, CompletionHandler&& completionHandler) { - // Not supported by this provider. - completionHandler(); + if (gamepadIndex >= m_gamepadVector.size()) + return completionHandler(); + auto gamepad = m_gamepadVector[gamepadIndex]; + if (!gamepad || gamepad->id() != gamepadID) + return completionHandler(); + + static_cast(gamepad.get())->stopEffects(WTFMove(completionHandler)); } } // namespace WebCore diff --git a/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp b/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp index 6b4d3406cc7ba..3c50779e79b5c 100644 --- a/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp +++ b/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp @@ -271,7 +271,7 @@ bool defaultShowModalDialogEnabled() #if ENABLE(GAMEPAD) bool defaultGamepadVibrationActuatorEnabled() { -#if HAVE(WIDE_GAMECONTROLLER_SUPPORT) +#if HAVE(WIDE_GAMECONTROLLER_SUPPORT) || USE(MANETTE) return true; #else return false; From f2128890e11fe296ef2570ce97122408a2412b60 Mon Sep 17 00:00:00 2001 From: Petar Tijanic Date: Tue, 4 Aug 2026 15:48:59 +0000 Subject: [PATCH 3/3] [WPE] Support libmanette 1.0 API with 0.2 fallback Add MANETTE_CHECK_VERSION(1, 0, 0) guards to support libmanette 1.0 while retaining compilation with 0.2: - Signal callbacks: 1.0 uses direct parameter signals (button-pressed, button-released, absolute-axis-changed with ManetteButton/ManetteAxis), 0.2 uses ManetteEvent-based signals (button-press-event, etc.) - Button mapping: 1.0 uses ManetteButton enum (MANETTE_BUTTON_SOUTH, etc.), 0.2 uses linux input-event-codes (BTN_A, etc.) - Axis mapping: 1.0 uses ManetteAxis enum with trigger axes, 0.2 uses ABS_* constants - Device iteration: 1.0 uses manette_monitor_list_devices(), 0.2 uses ManetteMonitorIter - Analog trigger support in 1.0 via analogButtonChanged() for MANETTE_AXIS_LEFT_TRIGGER / MANETTE_AXIS_RIGHT_TRIGGER - GUniquePtrManette.h include guarded (ManetteMonitorIter absent in 1.0) * Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp: * Source/WebCore/platform/gamepad/manette/ManetteGamepad.h: * Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp: --- .../gamepad/manette/ManetteGamepad.cpp | 105 ++++++++++++++++++ .../platform/gamepad/manette/ManetteGamepad.h | 1 + .../manette/ManetteGamepadProvider.cpp | 14 +++ 3 files changed, 120 insertions(+) diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp index e6aecbc7aee17..150772fb3a3e7 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp @@ -39,6 +39,24 @@ namespace WebCore { +#if MANETTE_CHECK_VERSION(1, 0, 0) +static ManetteGamepad::StandardGamepadAxis toStandardGamepadAxis(ManetteAxis axis) +{ + switch (axis) { + case MANETTE_AXIS_LEFT_X: + return ManetteGamepad::StandardGamepadAxis::LeftStickX; + case MANETTE_AXIS_LEFT_Y: + return ManetteGamepad::StandardGamepadAxis::LeftStickY; + case MANETTE_AXIS_RIGHT_X: + return ManetteGamepad::StandardGamepadAxis::RightStickX; + case MANETTE_AXIS_RIGHT_Y: + return ManetteGamepad::StandardGamepadAxis::RightStickY; + default: + break; + } + return ManetteGamepad::StandardGamepadAxis::Unknown; +} +#else static ManetteGamepad::StandardGamepadAxis toStandardGamepadAxis(uint16_t axis) { switch (axis) { @@ -55,7 +73,23 @@ static ManetteGamepad::StandardGamepadAxis toStandardGamepadAxis(uint16_t axis) } return ManetteGamepad::StandardGamepadAxis::Unknown; } +#endif +#if MANETTE_CHECK_VERSION(1, 0, 0) +static void onAbsoluteAxisChanged(ManetteDevice* device, ManetteAxis axis, double value, ManetteGamepad* gamepad) +{ + if (axis == MANETTE_AXIS_LEFT_TRIGGER) { + gamepad->analogButtonChanged(device, ManetteGamepad::StandardGamepadButton::LeftTrigger, value); + return; + } + if (axis == MANETTE_AXIS_RIGHT_TRIGGER) { + gamepad->analogButtonChanged(device, ManetteGamepad::StandardGamepadButton::RightTrigger, value); + return; + } + + gamepad->absoluteAxisChanged(device, toStandardGamepadAxis(axis), value); +} +#else static void onAbsoluteAxisEvent(ManetteDevice* device, ManetteEvent* event, ManetteGamepad* gamepad) { uint16_t axis; @@ -65,7 +99,48 @@ static void onAbsoluteAxisEvent(ManetteDevice* device, ManetteEvent* event, Mane gamepad->absoluteAxisChanged(device, toStandardGamepadAxis(axis), value); } +#endif +#if MANETTE_CHECK_VERSION(1, 0, 0) +static ManetteGamepad::StandardGamepadButton toStandardGamepadButton(ManetteButton button) +{ + switch (button) { + case MANETTE_BUTTON_SOUTH: + return ManetteGamepad::StandardGamepadButton::A; + case MANETTE_BUTTON_EAST: + return ManetteGamepad::StandardGamepadButton::B; + case MANETTE_BUTTON_WEST: + return ManetteGamepad::StandardGamepadButton::X; + case MANETTE_BUTTON_NORTH: + return ManetteGamepad::StandardGamepadButton::Y; + case MANETTE_BUTTON_LEFT_SHOULDER: + return ManetteGamepad::StandardGamepadButton::LeftShoulder; + case MANETTE_BUTTON_RIGHT_SHOULDER: + return ManetteGamepad::StandardGamepadButton::RightShoulder; + case MANETTE_BUTTON_SELECT: + return ManetteGamepad::StandardGamepadButton::Select; + case MANETTE_BUTTON_START: + return ManetteGamepad::StandardGamepadButton::Start; + case MANETTE_BUTTON_LEFT_STICK: + return ManetteGamepad::StandardGamepadButton::LeftStick; + case MANETTE_BUTTON_RIGHT_STICK: + return ManetteGamepad::StandardGamepadButton::RightStick; + case MANETTE_BUTTON_DPAD_UP: + return ManetteGamepad::StandardGamepadButton::DPadUp; + case MANETTE_BUTTON_DPAD_DOWN: + return ManetteGamepad::StandardGamepadButton::DPadDown; + case MANETTE_BUTTON_DPAD_LEFT: + return ManetteGamepad::StandardGamepadButton::DPadLeft; + case MANETTE_BUTTON_DPAD_RIGHT: + return ManetteGamepad::StandardGamepadButton::DPadRight; + case MANETTE_BUTTON_MODE: + return ManetteGamepad::StandardGamepadButton::Mode; + default: + break; + } + return ManetteGamepad::StandardGamepadButton::Unknown; +} +#else static ManetteGamepad::StandardGamepadButton toStandardGamepadButton(uint16_t manetteButton) { switch (manetteButton) { @@ -108,7 +183,19 @@ static ManetteGamepad::StandardGamepadButton toStandardGamepadButton(uint16_t ma } return ManetteGamepad::StandardGamepadButton::Unknown; } +#endif + +#if MANETTE_CHECK_VERSION(1, 0, 0) +static void onButtonPressed(ManetteDevice* device, ManetteButton button, ManetteGamepad* gamepad) +{ + gamepad->buttonPressedOrReleased(device, toStandardGamepadButton(button), true); +} +static void onButtonReleased(ManetteDevice* device, ManetteButton button, ManetteGamepad* gamepad) +{ + gamepad->buttonPressedOrReleased(device, toStandardGamepadButton(button), false); +} +#else static void onButtonPressEvent(ManetteDevice* device, ManetteEvent* event, ManetteGamepad* gamepad) { uint16_t button; @@ -126,6 +213,7 @@ static void onButtonReleaseEvent(ManetteDevice* device, ManetteEvent* event, Man gamepad->buttonPressedOrReleased(device, toStandardGamepadButton(button), false); } +#endif ManetteGamepad::ManetteGamepad(ManetteDevice* device, unsigned index) : PlatformGamepad(index) @@ -151,9 +239,15 @@ ManetteGamepad::ManetteGamepad(ManetteDevice* device, unsigned index) if (manette_device_has_rumble(m_device.get())) m_supportedEffectTypes.add(GamepadHapticEffectType::DualRumble); +#if MANETTE_CHECK_VERSION(1, 0, 0) + g_signal_connect(device, "button-pressed", G_CALLBACK(onButtonPressed), this); + g_signal_connect(device, "button-released", G_CALLBACK(onButtonReleased), this); + g_signal_connect(device, "absolute-axis-changed", G_CALLBACK(onAbsoluteAxisChanged), this); +#else g_signal_connect(device, "button-press-event", G_CALLBACK(onButtonPressEvent), this); g_signal_connect(device, "button-release-event", G_CALLBACK(onButtonReleaseEvent), this); g_signal_connect(device, "absolute-axis-event", G_CALLBACK(onAbsoluteAxisEvent), this); +#endif } ManetteGamepad::~ManetteGamepad() @@ -183,6 +277,17 @@ void ManetteGamepad::absoluteAxisChanged(ManetteDevice*, StandardGamepadAxis axi ManetteGamepadProvider::singleton().gamepadHadInput(*this, ManetteGamepadProvider::ShouldMakeGamepadsVisible::Yes); } +void ManetteGamepad::analogButtonChanged(ManetteDevice*, StandardGamepadButton button, double value) +{ + if (button == StandardGamepadButton::Unknown) + return; + + m_lastUpdateTime = MonotonicTime::now(); + m_buttonValues[static_cast(button)].setValue(clampTo(value, 0.0, 1.0)); + + ManetteGamepadProvider::singleton().gamepadHadInput(*this, ManetteGamepadProvider::ShouldMakeGamepadsVisible::Yes); +} + void ManetteGamepad::playEffect(GamepadHapticEffectType type, const GamepadEffectParameters& parameters, CompletionHandler&& completionHandler) { if (!m_supportedEffectTypes.contains(type)) diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h index 3588f7712a3f1..d917c368f868b 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepad.h @@ -74,6 +74,7 @@ class ManetteGamepad final : public PlatformGamepad { void absoluteAxisChanged(ManetteDevice*, StandardGamepadAxis, double value); void buttonPressedOrReleased(ManetteDevice*, StandardGamepadButton, bool pressed); + void analogButtonChanged(ManetteDevice*, StandardGamepadButton, double value); void playEffect(GamepadHapticEffectType, const GamepadEffectParameters&, CompletionHandler&&) final; void stopEffects(CompletionHandler&&) final; diff --git a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp index b41a983269a4f..7ff01c3d8fa6f 100644 --- a/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp +++ b/Source/WebCore/platform/gamepad/manette/ManetteGamepadProvider.cpp @@ -29,7 +29,13 @@ #if ENABLE(GAMEPAD) && OS(LINUX) +#ifndef MANETTE_CHECK_VERSION +#define MANETTE_CHECK_VERSION(major,minor,micro) 0 +#endif + +#if !MANETTE_CHECK_VERSION(1, 0, 0) #include "GUniquePtrManette.h" +#endif #include "GamepadProviderClient.h" #include "Logging.h" #include "ManetteGamepad.h" @@ -90,10 +96,18 @@ void ManetteGamepadProvider::startMonitoringGamepads(GamepadProviderClient& clie m_initialGamepadsConnectedTimer.startOneShot(connectionDelayInterval); RunLoop::current().dispatch([this] { +#if MANETTE_CHECK_VERSION(1, 0, 0) + gsize numDevices = 0; + ManetteDevice** devices = manette_monitor_list_devices(m_monitor.get(), &numDevices); + for (gsize i = 0; i < numDevices; i++) + deviceConnected(devices[i]); + g_free(devices); +#else ManetteDevice* device; GUniquePtr iter(manette_monitor_iterate(m_monitor.get())); while (manette_monitor_iter_next(iter.get(), &device)) deviceConnected(device); +#endif }); }