Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gamepad: Implement GamepadHapticActuator #32046

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

msub2
Copy link
Contributor

@msub2 msub2 commented Apr 11, 2024

This addresses another item on #31362 by implementing GamepadHapticActuator, allow haptic effects to play on connected gamepads. Note that this currently implements the main spec version of GamepadHapticActuator and not what's present in the Gamepad Extensions.


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #___ (GitHub issue number if applicable)
  • There are tests for these changes OR
  • These changes do not require tests because ___

@msub2
Copy link
Contributor Author

msub2 commented Apr 11, 2024

Also wondering if maybe @gterzian or someone has some insight, currently the subtests that test playEffect and reset in idlharness fail, and I'm not sure why. The specific message is:

FAIL GamepadHapticActuator interface: operation reset() - assert_unreached: Throws "TypeError: "this" object does not implement interface GamepadHapticActuator." instead of rejecting promise Reached unreachable code

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the start!

Bunch of small comments, plus a big one for the doing reset. I've also filed w3c/gamepad#200

components/shared/embedder/lib.rs Show resolved Hide resolved
components/shared/embedder/lib.rs Show resolved Hide resolved
ports/servoshell/Cargo.toml Show resolved Hide resolved
@@ -205,16 +210,32 @@ where
}
},
EventType::Connected => {
let len = self.haptic_effects.len();
self.haptic_effects.resize_with(len + 1, Default::default);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was to add a new slot in the haptic effects vec for any effects that will play on that gamepad, not sure why I did it like this instead of just appending None though. Have adjusted this

ports/servoshell/webview.rs Show resolved Hide resolved
self.global().as_window().send_to_embedder(event);
} else {
let message = DOMString::from("complete");
reset_result_promise.resolve_native(&message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step reads like it should be done only after the effect has been stopped. But the spec is unclear, because it resolves the promise directly from the parallel steps without queuing a task for it. See other comment about restructuring this...

self.reset_result_promise.borrow().is_some()
}

pub fn resolve_reset_result_promise(&self) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So to do this as per the spec we will have to restructure this via a listener on the IPC router thread and using trusted refs to the promises and also the actuator:

  • Look at to setup a route over IPC, see for example BroadcastListener, and do this inside Reset.
  • Put the IPC sender in the EmbedderMsg::StopGamepadHapticEffect
  • Put both the playing_effect_promise and the reset_result_promise, and also the actuator itself, as trusted on the "listener" in the route.
  • Add something in the reply about whether the effect was "successfully stopped"
  • From the route, when you receive the reply, queue a task that runs all steps 4.3 and 4.4 of https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-reset (the spec is wrong because it does 4.4. outside of a task).
  • To do 4.3.1, I think you need to add a "playing effect generation counter", so that you can compare the one you stored on the IPC listener with the current one on the actuator by the time the task runs. Note this is necassary because it plays with the step 4 of playEffect.

let _ = self.global().gamepad_task_source().queue(
task!(preempt_promise: move || {
let promise = trusted_promise.root();
let message = DOMString::from("preempted");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only fire if the promise hasn't already been preempted by a playEffect call after the reset call that ended-up queuing this task(see comment above).

return;
};

effect.stop().expect("Failed to stop haptic effect.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we handle this in some way?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for the "was succesffuly stopped" thing the in the reply(see above comment).


/// <https://www.w3.org/TR/gamepad/#handling-visibility-change>
#[allow(dead_code)]
pub fn handle_visibility_change(&self) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this I filed #32062

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants