pmndrs / use-gesture

👇Bread n butter utility for component-tied mouse/touch gestures in React and Vanilla Javascript.
https://use-gesture.netlify.app
MIT License
9.01k stars 307 forks source link

On Pinch does not work on Windows 10 (Microsoft Surface) #317

Closed Rafael09ED closed 3 years ago

Rafael09ED commented 3 years ago

Describe the bug

Multitouch / onPinch example does not work on Microsoft Surface Win 10. Attempted in Edge and Chrome.

Sandbox or Video

Official use-gesture CodeSandbox

https://user-images.githubusercontent.com/4006263/120945888-b11bff80-c708-11eb-9662-3581629544b7.mp4

Description of Video: Attempt in Chrome, Attempt to use multitouch in touch list demo on Chrome.

Information:

dbismut commented 3 years ago

That's going to be a pain to debug... by default v10 now uses PointerEvents for pinch, can you try the pointer.touch config option see if that changes anything?

https://v10-beta--use-gesture.netlify.app/docs/options/#pointertouch-drag-and-pinch

dbismut commented 3 years ago

@Rafael09ED any news on this?

Rafael09ED commented 3 years ago

Thanks for reminding me. I found this which is what I assume is the value I am trying to overwrite but I am not sure how to set that configuration you linked. I tried adding { pointer: { touch: true } } to api.start, useGesture and createUseGesture objects of the example Codepen. I assume I am not adding it to the right place. Where should I add it?

dbismut commented 3 years ago

@Rafael09ED its used like this:

usePinch(handler, {
  pointer: { touch: true }
})

Or when using useGesture:

useGesture({
  pinch: handler
}, {
  pinch: {
    pointer: { touch: true }
  }
})
Rafael09ED commented 3 years ago

Thank you. I added that parameter but I still get the same behavior and am not able to pinch. Codepen. I tried running the sandbox just as the page and it did not work. It did continue to work on my phone.

dbismut commented 3 years ago

@Rafael09ED hm... Can you try to describe what happens when you run that code and press the two fingers on the screen:

// this first
<div onPointerDown={e => console.log(e)} />
// then this
<div onTouchStart={e => console.log(e)} />

I'd like to understand the sequence of events in both cases, and I'm interested in event.pointerType, event.pointerId for the first example, and event.touches, event.changedTouches, event.targetTouches for the second example.

If you can run that, it would be a good place to start, otherwise I'll set up a remote debugging session with you if you're up for it^^

Rafael09ED commented 3 years ago

Here are the logs of the four events. Followed this to get the logs to something I could copy onPointerDown&onTouchStart-twoFingers.txt Because of our time zone difference a remote session may be difficult to schedule but I am willing.

dbismut commented 3 years ago

Hm that's weird, everything seems to be in order. It's ok I can stay up late, shouldn't last too long to identify the problem. You'll probably have to clone the project repo, install pnpm and run pnpm install. After that, run pnpm demo:dev to spawn the demos. If you can join pmndrs Discord, we can take it from there and arrange a call when it works out for you.

dbismut commented 3 years ago

Fixed in 10.0.0-beta.17. For the record, Surface doesn't support touch events (at least on Chrome), and supporting touch events was how @use-gesture detected the presence of a touch screen. Now touchscreen is detected with either touch event support or navigator.maxTouchPoints > 1. Thanks again for your help on debugging this @Rafael09ED.

lostfictions commented 3 years ago

Unfortunately, I'm still experiencing an issue with this on 10.0.2 in Chrome. It might be a quirk with Flatpak sandboxing somehow, or maybe it's some kind of deliberate anti-fingerprinting measure.

navigator.maxTouchPoints reports 0 (and 'ontouchstart' in window is also false), but touchstart etc listeners that are actually attached work fine (eg. these sites work properly where the use-gesture demo pinch example doesn't). If doesn't seem to make a difference whether i add pointer: { touch: true } to the pinch gesture config.

Some other React gesture libraries that support both mouse and touch don't seem to have this issue (eg. react-zoom-pan-pinch works fine for me).

Is there maybe a way touch events could be forcibly enabled as soon as a touch is detected on the window, even if the browser itself lies about touch support up until that point?

EDIT: Actually I'm not too sure what's going on -- even with pointer.touch set to true it seems to be attaching pointer event handlers instead of touch handlers: image

What's more, this sandbox (using react-use-gesture@9.1.3) works fine for me.

dbismut commented 3 years ago

Hi @lostfictions, thanks for the detailed explanation. Just to clarify 100%, could you please link to the dysfunctional sandbox and provide your hardware / software details?

Also is there anything on the window / document object that I could use to check for touch support? The touch option does force the use of TouchEvents only when they're actually supported. And also, PointerEvents aren't supported on the machine you're using right?

LAST EDIT: can you please check how the following works out in the console?

const touchSupported = 'ontouchstart' in window || (window.DocumentTouch && document instanceof DocumentTouch)
lostfictions commented 3 years ago

Oops, forgot to link the non-working sandbox! It's this one from the official examples.

This is happening in Ubuntu 20.04 x64, with Chrome 94.0.4606.71. The device is a Lenovo laptop with a touchscreen, similar to this model.

Your snippet returns undefined for me (DocumentTouch isn't defined).

I did find a helpful comment here:

onTouchStartInWindow is the old-old-legacy way to determine a touch device and many websites interpreted it to mean that the device is a touch only phone, so today browsers on a desktop/laptop computer with a touch screen (primary input mouse) have onTouchStartInWindow as false (to prevent from being confused with a touchOnly phone) even though they support the TouchEvents API, so need to check both onTouchStartInWindow and touchEventInWindow for TouchEvent support, however, some browsers (chromium) support the TouchEvents API even when running on a mouse only device (touchEventInWindow true, but onTouchStartInWindow false) so the touchEventInWindow check needs to include an coarse pointer media query

'TouchEvent' in window does return true for me in Chrome, though matchMedia('(any-pointer: coarse)')... doesn't match. So I'm really not sure what's going on. Effectively my browser seems to be hiding its touch capabilities right up until it fires a touch event (at which point event.touches happily includes full multitouch info, so it's not like it's just somehow emulating a touch device).

dbismut commented 3 years ago

The problem is that 'TouchEvent' in window does return true on I believe all browsers regardless of the hardware actually supporting touch (it does on my Macbook at least). I'm not sure what to do there... Would you mind moving this conversation on Discord so we can have 1 on 1 chat and run some tests? I'm on pmndrs Discord.