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

Introduce FingerId #3783

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

daxpedda
Copy link
Member

@daxpedda daxpedda commented Jul 10, 2024

This replaces Touch::id with Touch::finger_id and introduces a new type FingerId instead.

Additionally on Web it exposes PointerEvent.isPrimary which tells the user if the finger is the primary/first one in a multi-touch interaction.
I also went ahead and implemented this for Windows.

@MarijnS95 pointed out how this could be implemented for Android in #3783 (comment).
But other OSs would have to be polyfilled.

We could potentially expose this directly to the user without a platform specific extension trait if we implement enough platforms.

Followup
Entry in #2875: Firefox emits wrong primary fingers (Bugzilla).

@daxpedda daxpedda added this to the Version 0.30.4 milestone Jul 10, 2024
@daxpedda daxpedda changed the title Web: implement DeviceIdExtWebSys::is_primary() Web: implement DeviceIdExtWeb::is_primary() Jul 10, 2024
@kchibisov
Copy link
Member

What's the end goal/motivation with it if you mind sharing? Like it's really not clear how you'd use that aside from touch related stuff?

@daxpedda
Copy link
Member Author

What's the end goal/motivation with it if you mind sharing? Like it's really not clear how you'd use that aside from touch related stuff?

Its only used for touch and multi pointer situations.

I'm considering implementing this cross-platform for touch only and close this.

@daxpedda
Copy link
Member Author

daxpedda commented Jul 14, 2024

So after looking into how exactly browsers implement isPrimary I discovered that its basically a polyfill where they figure out what the first touch was by tracking finger IDs between touch start and end.

Windows is the only OS that supports detecting it via the TOUCHEVENTF_PRIMARY and POINTER_FLAG_PRIMARY flag.

So I see the following options:

  1. Change Touch::id to FingerId and implement platforms traits on it.
  2. Add Touch::primary and polyfill it for all platforms except Web and Windows.
  3. Add extension traits on Touch, which will require us to implement Default or Touch::new() if we want to keep it user constructible.

Personally I'm preferring to go with solution 1.
WDYT?
Cc @kchibisov, @madsmtm, @MarijnS95, @notgull.

@kchibisov
Copy link
Member

But if the primary is the first click couldn't it be entirely user detectable? I also don't really understand how one would use it?

Its only used for touch and multi pointer situations.

But how it's supposed to be utilized by the user and what they'll do with it? Is it some web limitation preventing it detecting multitouch correctly? because you should generally understand the order of touch events, etc?

Like in JS world I'd assume that users can just track amount of fingers pressed at the given time or something.

@daxpedda
Copy link
Member Author

daxpedda commented Jul 14, 2024

But if the primary is the first click couldn't it be entirely user detectable?

Yes and no, its not easy to reliably detect on Web, e.g. starting touch point could be outside the canvas etc.

But how it's supposed to be utilized by the user and what they'll do with it? Is it some web limitation preventing it detecting multitouch correctly? because you should generally understand the order of touch events, etc?

Like in JS world I'd assume that users can just track amount of fingers pressed at the given time or something.

Its only relevant in scenarios where you want to track the primary finger in a multi-touch interaction. This can be common in games, where the primary finger has a certain function that all other fingers don't have, e.g. movement vs shooting.

@kchibisov
Copy link
Member

Its only relevant in scenarios where you want to track the primary finger in a multi-touch interaction. This can be common in games, where the primary finger has a certain function that all other fingers don't have, e.g. movement vs shooting.

@madsmtm @MarijnS95 do you happen to know if something like that exists on ios/android? I'd assume users detect all of that themselves?

In general, I don't really mind having solution 1.

@MarijnS95
Copy link
Member

MarijnS95 commented Jul 14, 2024

I don't exactly understand what this "primary" pointer is in Web; is it just the first pointer/touch that started?

In that case, on Android, you could keep track of the first pointer_id() that went down.

There's also the mention for AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP that a non-primary pointer has gone down/up. Probably the fist finger triggers AMOTION_EVENT_ACTION_DOWN/AMOTION_EVENT_ACTION_UP instead?


Its only relevant in scenarios where you want to track the primary finger in a multi-touch interaction. This can be common in games, where the primary finger has a certain function that all other fingers don't have, e.g. movement vs shooting.

On an unrelated note that sounds very confusing: the first touch controls movement, the second controls aim? I always thought that it was position-based: left half of the screen is moving, right half is panning the camera?

In any case it's fully trackable by the user at least.

@daxpedda
Copy link
Member Author

I don't exactly understand what this "primary" pointer is in Web; is it just the first pointer/touch that started?

Yes.

On an unrelated note that sounds very confusing: the first touch controls movement, the second controls aim? I always thought that it was position-based: left half of the screen is moving, right half is panning the camera?

I have very little experience with games like that, so I can't say much to that.
For our own use-case, where its not position-based, we tracked it ourselves at start, but because we had some controls outside the canvas (for various reasons not in our control), it interfered sometimes.
So we needed to use isPrimary.

@MarijnS95
Copy link
Member

On Android an app is usually fullscreen but it doesn't need to be - we should test what happens when a motion gesture enters and exit the app similar to your canvas example!

@daxpedda daxpedda changed the title Web: implement DeviceIdExtWeb::is_primary() Introduce FingerId Jul 14, 2024
@daxpedda daxpedda requested a review from madsmtm July 14, 2024 20:19
@daxpedda daxpedda removed this from the Version 0.30.4 milestone Jul 14, 2024
@daxpedda
Copy link
Member Author

I went ahead and implemented FingerId, ergo solution 1.

@daxpedda daxpedda force-pushed the web-is-primary branch 3 times, most recently from e663e35 to 2890616 Compare July 18, 2024 20:29
@MarijnS95
Copy link
Member

MarijnS95 commented Jul 23, 2024

In that case, on Android, you could keep track of the first pointer_id() that went down.

There's also the mention for AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP that a non-primary pointer has gone down/up. Probably the fist finger triggers AMOTION_EVENT_ACTION_DOWN/AMOTION_EVENT_ACTION_UP instead?

After testing this in winit, the results are somewhat surprising regarding this action() enum discrepancy:

  • On first finger down, a Down event is emitted with pointer_id() set to 0;
  • On second finger down, a PointerDown event is emitted, as expected for a non-primary. The ID is set to 1;
  • When the first finger is removed, which used to be the primary finger, a PointerUp is emitted, surprisingly not primary. This event carries pointer_id() = 0;
  • Subsequent moves for the "second finger" keep being emitted with pointer_id() = 1 as expected;
  • Finally, removing the second finger emits an Up event.

Note that if, instead of removing the second finger, another finger is added, non-primary PointerUp/PointerDown events are still emitted, but pointer_id() = 0 is reused.


I don't know exactly what kind of API winit wants here, but if we want to track the first finger in a series of touches, you'll do something like this:

EDIT: Since this is a platform extension, there's nothing to winit to "want" if the current platform doesn't support it. No need to polyfill, we're better off providing users the actual info that Android provides which is pointer_id() (already in there). Discrepancies between PointerUp vs Up may be interesting to know if this is the first touch to start or the last touch to finish though.

  • On Down (primary), store its pointer_id();
  • On (Pointer)Up, reset this value if it is equal to pointer_id();
  • is_primary() returns self.primary_pointer == Some(pointer_id()).

Meaning that no motion is primary anymore, if the primary finger was removed after some point in time (while a touch is still ongoing).

@daxpedda
Copy link
Member Author

EDIT: Since this is a platform extension, there's nothing to winit to "want" if the current platform doesn't support it. No need to polyfill, we're better off providing users the actual info that Android provides which is pointer_id() (already in there).

I agree!

Copy link
Member

@MarijnS95 MarijnS95 left a comment

Choose a reason for hiding this comment

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

Looks good on the Android side (very minimal)!

If anyone needs it we could expose whether this is the first ("primary") finger going down or the last (""primary""?) finger to go up.This is also easy for the user to track by keeping a rolling count of how many up and down events they have seen though.

(Which could be a little cheaper if we create a separate extension keyed off the difference between Down and PointerDown, and (Pointer)Up respectively, but would have to store a bool for it anyways)

@daxpedda daxpedda added S - enhancement Wouldn't this be the coolest? S - api Design and usability labels Jul 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DS - web DS - windows S - api Design and usability S - enhancement Wouldn't this be the coolest?
Development

Successfully merging this pull request may close these issues.

None yet

4 participants