feat: gamepad feature flag (#41451)

Put the Gamepad API and its supporting infrastructure behind a `gamepad`
feature flag. This allows embedders to opt-out of gamepad support at
compile time to save on binary size and reduce dependencies.

Testing:
1. `./mach build -d` (Gamepad enabled by default)
2. `cargo build -p servoshell --no-default-features --features
"libservo/clipboard,js_jit,max_log_level,webgpu"` (Gamepad Disabled)
3. `cargo build -p servoshell --features "gamepad,webxr,..."` (Gamepad &
WebXR Enabled)

Fixes: #40897

Signed-off-by: WaterWhisperer <waterwhisperer24@qq.com>
This commit is contained in:
WaterWhisperer
2025-12-21 21:18:06 +08:00
committed by GitHub
parent 1a6b18937a
commit 6623cc1dbb
28 changed files with 111 additions and 21 deletions

View File

@@ -14,6 +14,7 @@ path = "lib.rs"
[features]
default = []
bluetooth = ["bluetooth_traits"]
gamepad = ["embedder_traits/gamepad"]
tracing = ["dep:tracing", "canvas/tracing"]
vello = ["canvas/vello"]
vello_cpu = ["canvas/vello_cpu"]

View File

@@ -94,6 +94,7 @@ mod from_embedder {
}
match self.event {
InputEvent::EditingAction(..) => target_variant!("EditingAction"),
#[cfg(feature = "gamepad")]
InputEvent::Gamepad(..) => target_variant!("Gamepad"),
InputEvent::Ime(..) => target_variant!("Ime"),
InputEvent::Keyboard(..) => target_variant!("Keyboard"),

View File

@@ -16,6 +16,7 @@ path = "lib.rs"
bluetooth = ['bluetooth_traits', 'script_bindings/bluetooth']
crown = ['js/crown']
debugmozjs = ['js/debugmozjs']
gamepad = ["script_bindings/gamepad", "embedder_traits/gamepad"]
jitspew = ['js/jitspew']
js_backtrace = []
js_jit = ["js/jit"]
@@ -25,7 +26,7 @@ testbinding = ["script_bindings/testbinding"]
tracing = ["dep:tracing", "script_bindings/tracing"]
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
webgpu = ["script_bindings/webgpu", "script_traits/webgpu"]
webxr = ["webxr-api", "script_bindings/webxr"]
webxr = ["gamepad", "webxr-api", "script_bindings/webxr"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(crown)'] }

View File

@@ -83,6 +83,7 @@ use crate::dom::bindings::codegen::Bindings::ElementBinding::ScrollLogicalPositi
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
#[cfg(any(feature = "webxr", feature = "gamepad"))]
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
@@ -4688,6 +4689,7 @@ impl Document {
// state and document. Any other specs' visibility steps will go here.
// <https://www.w3.org/TR/gamepad/#handling-visibility-change>
#[cfg(feature = "gamepad")]
if visibility_state == DocumentVisibilityState::Hidden {
self.window
.Navigator()

View File

@@ -11,12 +11,15 @@ use std::time::{Duration, Instant};
use constellation_traits::{KeyboardScroll, ScriptToConstellationMessage};
use embedder_traits::{
Cursor, EditingActionEvent, EmbedderMsg, GamepadEvent as EmbedderGamepadEvent,
GamepadSupportedHapticEffects, GamepadUpdateType, ImeEvent, InputEvent, InputEventAndId,
Cursor, EditingActionEvent, EmbedderMsg, ImeEvent, InputEvent, InputEventAndId,
InputEventResult, KeyboardEvent as EmbedderKeyboardEvent, MouseButton, MouseButtonAction,
MouseButtonEvent, MouseLeftViewportEvent, ScrollEvent, TouchEvent as EmbedderTouchEvent,
TouchEventType, TouchId, UntrustedNodeAddress, WheelEvent as EmbedderWheelEvent,
};
#[cfg(feature = "gamepad")]
use embedder_traits::{
GamepadEvent as EmbedderGamepadEvent, GamepadSupportedHapticEffects, GamepadUpdateType,
};
use euclid::{Point2D, Vector2D};
use ipc_channel::ipc;
use js::jsapi::JSAutoRealm;
@@ -46,7 +49,9 @@ use crate::dom::bindings::root::MutNullableDom;
use crate::dom::clipboardevent::ClipboardEventType;
use crate::dom::document::{FireMouseEventType, FocusInitiator};
use crate::dom::event::{EventBubbles, EventCancelable, EventComposed, EventFlags};
#[cfg(feature = "gamepad")]
use crate::dom::gamepad::gamepad::{Gamepad, contains_user_gesture};
#[cfg(feature = "gamepad")]
use crate::dom::gamepad::gamepadevent::GamepadEventType;
use crate::dom::inputevent::HitTestResult;
use crate::dom::node::{self, Node, NodeTraits, ShadowIncluding};
@@ -195,6 +200,7 @@ impl DocumentEventHandler {
self.handle_keyboard_event(keyboard_event, can_gc)
},
InputEvent::Ime(ime_event) => self.handle_ime_event(ime_event, can_gc),
#[cfg(feature = "gamepad")]
InputEvent::Gamepad(gamepad_event) => {
self.handle_gamepad_event(gamepad_event);
InputEventResult::default()
@@ -1163,6 +1169,7 @@ impl DocumentEventHandler {
dom_event.flags().into()
}
#[cfg(feature = "gamepad")]
fn handle_gamepad_event(&self, gamepad_event: EmbedderGamepadEvent) {
match gamepad_event {
EmbedderGamepadEvent::Connected(index, name, bounds, supported_haptic_effects) => {
@@ -1184,6 +1191,7 @@ impl DocumentEventHandler {
}
/// <https://www.w3.org/TR/gamepad/#dfn-gamepadconnected>
#[cfg(feature = "gamepad")]
fn handle_gamepad_connect(
&self,
// As the spec actually defines how to set the gamepad index, the GilRs index
@@ -1223,6 +1231,7 @@ impl DocumentEventHandler {
}
/// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected>
#[cfg(feature = "gamepad")]
fn handle_gamepad_disconnect(&self, index: usize) {
let trusted_window = Trusted::new(&*self.window);
self.window
@@ -1242,6 +1251,7 @@ impl DocumentEventHandler {
}
/// <https://www.w3.org/TR/gamepad/#receiving-inputs>
#[cfg(feature = "gamepad")]
fn receive_new_gamepad_button_or_axis(&self, index: usize, update_type: GamepadUpdateType) {
let trusted_window = Trusted::new(&*self.window);

View File

@@ -681,7 +681,9 @@ macro_rules! window_event_handlers(
event_handler!(unhandledrejection, GetOnunhandledrejection,
SetOnunhandledrejection);
event_handler!(unload, GetOnunload, SetOnunload);
#[cfg(feature = "gamepad")]
event_handler!(gamepadconnected, GetOngamepadconnected, SetOngamepadconnected);
#[cfg(feature = "gamepad")]
event_handler!(gamepaddisconnected, GetOngamepaddisconnected, SetOngamepaddisconnected);
);
(ForwardToWindow) => (
@@ -711,7 +713,9 @@ macro_rules! window_event_handlers(
window_owned_event_handler!(unhandledrejection, GetOnunhandledrejection,
SetOnunhandledrejection);
window_owned_event_handler!(unload, GetOnunload, SetOnunload);
#[cfg(feature = "gamepad")]
window_owned_event_handler!(gamepadconnected, GetOngamepadconnected, SetOngamepadconnected);
#[cfg(feature = "gamepad")]
window_owned_event_handler!(gamepaddisconnected, GetOngamepaddisconnected, SetOngamepaddisconnected);
);
);

View File

@@ -307,7 +307,9 @@ pub(crate) mod filereadersync;
pub(crate) mod focusevent;
pub(crate) mod formdata;
pub(crate) mod formdataevent;
#[cfg(feature = "gamepad")]
pub(crate) mod gamepad;
#[cfg(feature = "gamepad")]
pub(crate) use self::gamepad::*;
pub(crate) mod geolocation;
pub(crate) use self::geolocation::*;

View File

@@ -38,7 +38,9 @@ use crate::dom::bluetooth::Bluetooth;
use crate::dom::clipboard::Clipboard;
use crate::dom::credentialmanagement::credentialscontainer::CredentialsContainer;
use crate::dom::csp::{GlobalCspReporting, Violation};
#[cfg(feature = "gamepad")]
use crate::dom::gamepad::Gamepad;
#[cfg(feature = "gamepad")]
use crate::dom::gamepad::gamepadevent::GamepadEventType;
use crate::dom::geolocation::Geolocation;
use crate::dom::globalscope::GlobalScope;
@@ -114,6 +116,7 @@ pub(crate) struct Navigator {
xr: MutNullableDom<XRSystem>,
mediadevices: MutNullableDom<MediaDevices>,
/// <https://www.w3.org/TR/gamepad/#dfn-gamepads>
#[cfg(feature = "gamepad")]
gamepads: DomRefCell<Vec<MutNullableDom<Gamepad>>>,
permissions: MutNullableDom<Permissions>,
mediasession: MutNullableDom<MediaSession>,
@@ -121,6 +124,7 @@ pub(crate) struct Navigator {
#[cfg(feature = "webgpu")]
gpu: MutNullableDom<GPU>,
/// <https://www.w3.org/TR/gamepad/#dfn-hasgamepadgesture>
#[cfg(feature = "gamepad")]
has_gamepad_gesture: Cell<bool>,
servo_internals: MutNullableDom<ServoInternals>,
}
@@ -138,12 +142,14 @@ impl Navigator {
#[cfg(feature = "webxr")]
xr: Default::default(),
mediadevices: Default::default(),
#[cfg(feature = "gamepad")]
gamepads: Default::default(),
permissions: Default::default(),
mediasession: Default::default(),
clipboard: Default::default(),
#[cfg(feature = "webgpu")]
gpu: Default::default(),
#[cfg(feature = "gamepad")]
has_gamepad_gesture: Cell::new(false),
servo_internals: Default::default(),
}
@@ -158,10 +164,12 @@ impl Navigator {
self.xr.get()
}
#[cfg(feature = "gamepad")]
pub(crate) fn get_gamepad(&self, index: usize) -> Option<DomRoot<Gamepad>> {
self.gamepads.borrow().get(index).and_then(|g| g.get())
}
#[cfg(feature = "gamepad")]
pub(crate) fn set_gamepad(&self, index: usize, gamepad: &Gamepad, can_gc: CanGc) {
if let Some(gamepad_to_set) = self.gamepads.borrow().get(index) {
gamepad_to_set.set(Some(gamepad));
@@ -174,6 +182,7 @@ impl Navigator {
}
}
#[cfg(feature = "gamepad")]
pub(crate) fn remove_gamepad(&self, index: usize) {
if let Some(gamepad_to_remove) = self.gamepads.borrow_mut().get(index) {
gamepad_to_remove.set(None);
@@ -182,6 +191,7 @@ impl Navigator {
}
/// <https://www.w3.org/TR/gamepad/#dfn-selecting-an-unused-gamepad-index>
#[cfg(feature = "gamepad")]
pub(crate) fn select_gamepad_index(&self) -> u32 {
let mut gamepad_list = self.gamepads.borrow_mut();
if let Some(index) = gamepad_list.iter().position(|g| g.get().is_none()) {
@@ -193,6 +203,7 @@ impl Navigator {
}
}
#[cfg(feature = "gamepad")]
fn shrink_gamepads_list(&self) {
let mut gamepad_list = self.gamepads.borrow_mut();
for i in (0..gamepad_list.len()).rev() {
@@ -204,10 +215,12 @@ impl Navigator {
}
}
#[cfg(feature = "gamepad")]
pub(crate) fn has_gamepad_gesture(&self) -> bool {
self.has_gamepad_gesture.get()
}
#[cfg(feature = "gamepad")]
pub(crate) fn set_has_gamepad_gesture(&self, has_gamepad_gesture: bool) {
self.has_gamepad_gesture.set(has_gamepad_gesture);
}
@@ -384,6 +397,7 @@ impl NavigatorMethods<crate::DomTypeHolder> for Navigator {
}
/// <https://www.w3.org/TR/gamepad/#dom-navigator-getgamepads>
#[cfg(feature = "gamepad")]
fn GetGamepads(&self) -> Vec<Option<DomRoot<Gamepad>>> {
let global = self.global();
let window = global.as_window();

View File

@@ -53,6 +53,7 @@ serde_json = { workspace = true }
[features]
bluetooth = []
gamepad = []
testbinding = []
tracing = ["dep:tracing"]
webgpu = []

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#gamepad-interface
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface Gamepad {

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#gamepadbutton-interface
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface GamepadButton {

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface GamepadButtonList {

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#gamepadevent-interface
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface GamepadEvent : Event {

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#gamepadhapticactuator-interface
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface GamepadHapticActuator {

View File

@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/extensions.html#gamepadpose-interface
[Exposed=Window, Pref="dom_gamepad_enabled"]
interface GamepadPose {

View File

@@ -67,11 +67,6 @@ partial interface Navigator {
[Pref="dom_permissions_enabled"] readonly attribute Permissions permissions;
};
// https://w3c.github.io/gamepad/#navigator-interface-extension
partial interface Navigator {
[Pref="dom_gamepad_enabled"] sequence<Gamepad?> getGamepads();
};
// https://html.spec.whatwg.org/multipage/#navigatorconcurrenthardware
interface mixin NavigatorConcurrentHardware {
readonly attribute unsigned long long hardwareConcurrency;

View File

@@ -0,0 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// skip-unless CARGO_FEATURE_GAMEPAD
// https://w3c.github.io/gamepad/#navigator-interface-extension
partial interface Navigator {
[Pref="dom_gamepad_enabled"] sequence<Gamepad?> getGamepads();
};

View File

@@ -29,6 +29,11 @@ clipboard = ["dep:arboard"]
crown = ["script/crown"]
debugmozjs = ["script/debugmozjs"]
dynamic_freetype = ["webrender/dynamic_freetype"]
gamepad = [
"script/gamepad",
"constellation/gamepad",
"embedder_traits/gamepad",
]
jitspew = ["script/jitspew"]
js_backtrace = ["script/js_backtrace"]
js_jit = ["script/js_jit"]

View File

@@ -537,6 +537,7 @@ impl ServoInner {
self.servo_errors.sender(),
));
},
#[cfg(feature = "gamepad")]
EmbedderMsg::PlayGamepadHapticEffect(
webview_id,
gamepad_index,
@@ -552,6 +553,7 @@ impl ServoInner {
);
}
},
#[cfg(feature = "gamepad")]
EmbedderMsg::StopGamepadHapticEffect(webview_id, gamepad_index, ipc_sender) => {
if let Some(webview) = self.get_webview_handle(webview_id) {
webview.delegate().stop_gamepad_haptic_effect(

View File

@@ -9,14 +9,15 @@ use base::generic_channel::GenericSender;
use base::id::{PipelineId, WebViewId};
use compositing_traits::rendering_context::RenderingContext;
use constellation_traits::EmbedderToConstellationMessage;
#[cfg(feature = "gamepad")]
use embedder_traits::GamepadHapticEffectType;
use embedder_traits::{
AlertResponse, AllowOrDeny, AuthenticationResponse, ConfirmResponse, ConsoleLogLevel,
ContextMenuAction, ContextMenuElementInformation, ContextMenuItem, Cursor, EmbedderControlId,
EmbedderControlResponse, FilePickerRequest, FilterPattern, GamepadHapticEffectType,
InputEventId, InputEventResult, InputMethodType, LoadStatus, MediaSessionEvent, Notification,
PermissionFeature, PromptResponse, RgbColor, ScreenGeometry, SelectElementOptionOrOptgroup,
SimpleDialogRequest, TraversalId, ViewportDetails, WebResourceRequest, WebResourceResponse,
WebResourceResponseMsg,
EmbedderControlResponse, FilePickerRequest, FilterPattern, InputEventId, InputEventResult,
InputMethodType, LoadStatus, MediaSessionEvent, Notification, PermissionFeature,
PromptResponse, RgbColor, ScreenGeometry, SelectElementOptionOrOptgroup, SimpleDialogRequest,
TraversalId, ViewportDetails, WebResourceRequest, WebResourceResponse, WebResourceResponseMsg,
};
use ipc_channel::ipc::IpcSender;
use url::Url;
@@ -941,6 +942,7 @@ pub trait WebViewDelegate {
fn hide_embedder_control(&self, _webview: WebView, _control_id: EmbedderControlId) {}
/// Request to play a haptic effect on a connected gamepad.
#[cfg(feature = "gamepad")]
fn play_gamepad_haptic_effect(
&self,
_webview: WebView,
@@ -950,6 +952,7 @@ pub trait WebViewDelegate {
) {
}
/// Request to stop a haptic effect on a connected gamepad.
#[cfg(feature = "gamepad")]
fn stop_gamepad_haptic_effect(&self, _webview: WebView, _: usize, _: IpcSender<bool>) {}
/// Triggered when this [`WebView`] will load a web (HTTP/HTTPS) resource. The load may be

View File

@@ -15,6 +15,7 @@ path = "lib.rs"
# bakes default resources into the library.
# This feature is mainly intended for testing purposes.
baked-default-resources = []
gamepad = []
[dependencies]
base = { workspace = true }

View File

@@ -41,6 +41,7 @@ bitflags! {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum InputEvent {
EditingAction(EditingActionEvent),
#[cfg(feature = "gamepad")]
Gamepad(GamepadEvent),
Ime(ImeEvent),
Keyboard(KeyboardEvent),
@@ -79,6 +80,7 @@ impl InputEvent {
pub fn point(&self) -> Option<WebViewPoint> {
match self {
InputEvent::EditingAction(..) => None,
#[cfg(feature = "gamepad")]
InputEvent::Gamepad(..) => None,
InputEvent::Ime(..) => None,
InputEvent::Keyboard(..) => None,
@@ -319,12 +321,14 @@ pub enum ImeEvent {
Dismissed,
}
#[cfg(feature = "gamepad")]
#[derive(
Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
)]
/// Index of gamepad in list of system's connected gamepads
pub struct GamepadIndex(pub usize);
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// The minimum and maximum values that can be reported for axis or button input from this gamepad
pub struct GamepadInputBounds {
@@ -334,6 +338,7 @@ pub struct GamepadInputBounds {
pub button_bounds: (f64, f64),
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// The haptic effects supported by this gamepad
pub struct GamepadSupportedHapticEffects {
@@ -343,6 +348,7 @@ pub struct GamepadSupportedHapticEffects {
pub supports_trigger_rumble: bool,
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// The type of Gamepad event
pub enum GamepadEvent {
@@ -362,6 +368,7 @@ pub enum GamepadEvent {
Updated(GamepadIndex, GamepadUpdateType),
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// The type of Gamepad input being updated
pub enum GamepadUpdateType {

View File

@@ -503,8 +503,10 @@ pub enum EmbedderMsg {
/// Ask the user to allow a devtools client to connect.
RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
/// Request to play a haptic effect on a connected gamepad.
#[cfg(feature = "gamepad")]
PlayGamepadHapticEffect(WebViewId, usize, GamepadHapticEffectType, IpcSender<bool>),
/// Request to stop a haptic effect on a connected gamepad.
#[cfg(feature = "gamepad")]
StopGamepadHapticEffect(WebViewId, usize, IpcSender<bool>),
/// Informs the embedder that the constellation has completed shutdown.
/// Required because the constellation can have pending calls to make
@@ -635,6 +637,7 @@ pub enum InputMethodType {
Week,
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype-dual-rumble>
pub struct DualRumbleEffectParams {
@@ -644,6 +647,7 @@ pub struct DualRumbleEffectParams {
pub weak_magnitude: f64,
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype>
pub enum GamepadHapticEffectType {

View File

@@ -35,9 +35,10 @@ OriginalFilename = "servo.exe"
ProductName = "Servo"
[features]
default = ["libservo/clipboard", "js_jit", "max_log_level", "webgpu", "webxr"]
default = ["gamepad", "libservo/clipboard", "js_jit", "max_log_level", "webgpu", "webxr"]
crown = ["libservo/crown"]
debugmozjs = ["libservo/debugmozjs"]
gamepad = ["libservo/gamepad"]
jitspew = ["libservo/jitspew"]
js_backtrace = ["libservo/js_backtrace"]
js_jit = ["libservo/js_jit"]

View File

@@ -9,6 +9,7 @@ pub(crate) mod app;
pub(crate) mod cli;
pub(crate) mod dialog;
pub(crate) mod event_loop;
#[cfg(feature = "gamepad")]
pub(crate) mod gamepad;
pub mod geometry;
mod gui;

View File

@@ -5,6 +5,7 @@
#[cfg(target_os = "android")]
mod android;
mod app;
#[cfg(feature = "gamepad")]
pub(crate) mod gamepad;
mod host_trait;
mod log;

View File

@@ -25,9 +25,12 @@ mod running_app_state;
mod webdriver;
mod window;
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
#[cfg(all(
feature = "gamepad",
not(any(target_os = "android", target_env = "ohos"))
))]
pub(crate) use crate::desktop::gamepad::GamepadSupport;
#[cfg(any(target_os = "android", target_env = "ohos"))]
#[cfg(all(feature = "gamepad", any(target_os = "android", target_env = "ohos")))]
pub(crate) use crate::egl::gamepad::GamepadSupport;
pub mod platform {

View File

@@ -13,17 +13,19 @@ use crossbeam_channel::{Receiver, Sender, unbounded};
use euclid::Rect;
use image::{DynamicImage, ImageFormat, RgbaImage};
use log::{error, info, warn};
#[cfg(feature = "gamepad")]
use servo::GamepadHapticEffectType;
use servo::{
AllowOrDenyRequest, AuthenticationRequest, CSSPixel, ConsoleLogLevel, CreateNewWebViewRequest,
DeviceIntPoint, DeviceIntSize, EmbedderControl, EmbedderControlId, EventLoopWaker,
GamepadHapticEffectType, GenericSender, InputEvent, InputEventId, InputEventResult, IpcSender,
JSValue, LoadStatus, MediaSessionEvent, PermissionRequest, PrefValue, ScreenshotCaptureError,
Servo, ServoDelegate, ServoError, TraversalId, WebDriverCommandMsg, WebDriverJSResult,
WebDriverLoadStatus, WebDriverScriptCommand, WebDriverSenders, WebView, WebViewDelegate,
WebViewId, pref,
GenericSender, InputEvent, InputEventId, InputEventResult, IpcSender, JSValue, LoadStatus,
MediaSessionEvent, PermissionRequest, PrefValue, ScreenshotCaptureError, Servo, ServoDelegate,
ServoError, TraversalId, WebDriverCommandMsg, WebDriverJSResult, WebDriverLoadStatus,
WebDriverScriptCommand, WebDriverSenders, WebView, WebViewDelegate, WebViewId, pref,
};
use url::Url;
#[cfg(feature = "gamepad")]
use crate::GamepadSupport;
use crate::prefs::{EXPERIMENTAL_PREFS, ServoShellPreferences};
use crate::webdriver::WebDriverEmbedderControls;
@@ -146,6 +148,7 @@ pub(crate) enum UserInterfaceCommand {
pub(crate) struct RunningAppState {
/// Gamepad support, which may be `None` if it failed to initialize.
#[cfg(feature = "gamepad")]
gamepad_support: RefCell<Option<GamepadSupport>>,
/// The [`WebDriverSenders`] used to reply to pending WebDriver requests.
@@ -200,6 +203,7 @@ impl RunningAppState {
) -> Self {
servo.set_delegate(Rc::new(ServoShellServoDelegate));
#[cfg(feature = "gamepad")]
let gamepad_support = if pref!(dom_gamepad_enabled) {
GamepadSupport::maybe_new()
} else {
@@ -218,6 +222,7 @@ impl RunningAppState {
Self {
windows: Default::default(),
focused_window: Default::default(),
#[cfg(feature = "gamepad")]
gamepad_support: RefCell::new(gamepad_support),
webdriver_senders: RefCell::default(),
webdriver_embedder_controls: Default::default(),
@@ -345,6 +350,7 @@ impl RunningAppState {
self.handle_webdriver_messages(create_platform_window);
#[cfg(feature = "gamepad")]
if pref!(dom_gamepad_enabled) {
self.handle_gamepad_events();
}
@@ -549,6 +555,7 @@ impl RunningAppState {
webview.load(url);
}
#[cfg(feature = "gamepad")]
pub(crate) fn handle_gamepad_events(&self) {
let Some(active_webview) = self
.focused_window()
@@ -721,6 +728,7 @@ impl WebViewDelegate for RunningAppState {
self.window_for_webview_id(webview.id()).set_needs_repaint();
}
#[cfg(feature = "gamepad")]
fn play_gamepad_haptic_effect(
&self,
_webview: WebView,
@@ -738,6 +746,7 @@ impl WebViewDelegate for RunningAppState {
}
}
#[cfg(feature = "gamepad")]
fn stop_gamepad_haptic_effect(
&self,
_webview: WebView,