- From: Alex Kempton <notifications@github.com>
- Date: Fri, 16 Dec 2022 01:04:13 -0800
- To: w3c/uievents <uievents@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3c/uievents/issues/337/1354417620@github.com>
Here ya go! Please note that it's not 100% reliable and for Windows users we just completely disable the check and always assume a scrollwheel (so no two-finger panning for Windows users on trackpads).
I hope this:
- Helps you in your case
- Illustrated to the W3C why we desperately need a native solution to this problem
```ts
/*
For Mac, we want to tell the difference between a touchpad two-finger scroll and a mousewheel.
Unfortunately there is no simple way to do this, because both devices trigger a 'wheel' event
We can have a good guess with the following assumptions (in priority order):
- Mac touchpads never produce deltas with a fractional part
- Wheel deltas never happen on the X axis
- Wheels often produce the same deltas twice in a row, or some multiple of a delta (e.g. 150, 300, 450)
For windows users the above rules do not apply, we treat the wheel event the same, touchpad or mouse.
Here's a sandbox for testing this function. Update the function and fork it, share it for user testing:
https://codesandbox.io/s/inspiring-hill-b7evw
*/
import round from "lodash/round"
import { isMac } from "./detectPlatform"
type ScrollType = "wheel" | "touchPad" | "pinchZoom" | "undetermined"
const allowedDivisors = [0.25, 0.5, 0.333, 0.667, 1.5, 2, 3, 4]
const trackPadSlowMax = 20
const timeoutMs = 500
let timer: NodeJS.Timeout | undefined
// Checks sample of delta values
export const checkDeltasAreFromWheel = (arr: number[]) => {
let prevVal: number | undefined
let isWheel = false
let wasOverMax = false
let sameCount = 0
let divisorCount = 0
for (let i = 0; i < arr.length; i++) {
const v = Math.abs(arr[i])
if (v % 1 !== 0) {
// Has irregular fractional part
return true
}
if (prevVal && prevVal !== v) {
// Values are different
isWheel = false
if (v > trackPadSlowMax && prevVal > trackPadSlowMax) {
const test = round(v / prevVal, 3)
if (allowedDivisors.includes(test)) {
// Values are different but neatly divisible
divisorCount++
}
}
} else if (v > trackPadSlowMax) {
// Values are same (and not low)
sameCount++
}
if (v > trackPadSlowMax) {
wasOverMax = true
}
prevVal = v
}
if (!wasOverMax) {
// If the entire sample was under max, we can assume trackpad
return false
}
if (divisorCount > arr.length / 2) {
// If more than 50% of consecutive vals had neat divisors, we can assume wheel
return true
}
if (sameCount > arr.length / 2) {
// If more than 50% of consecutive vals were the same, we can assume wheel
return true
}
return isWheel
}
let deltas: number[] = []
export const determineScrollType = (e: WheelEvent): ScrollType => {
if (e.ctrlKey) {
// ctrlKey is set to true when use pinchzoom on touchpad
return "pinchZoom"
} else if (!isMac()) {
// Non-Mac users always get wheel type
return "wheel"
} else if (Math.abs(e.deltaX) > 0) {
// If the delta is on the X axis, it must be a touchpad
return "touchPad"
}
deltas.unshift(e.deltaY)
if (deltas.length > 10) {
deltas.pop()
}
// Clear deltas after some short period in case user has switched between mouse/touchpad
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
deltas = []
}, timeoutMs)
if (deltas.length > 2) {
return checkDeltasAreFromWheel(deltas) ? "wheel" : "touchPad"
}
return "undetermined"
}
```
--
Reply to this email directly or view it on GitHub:
https://github.com/w3c/uievents/issues/337#issuecomment-1354417620
You are receiving this because you are subscribed to this thread.
Message ID: <w3c/uievents/issues/337/1354417620@github.com>
Received on Friday, 16 December 2022 09:04:25 UTC