I have the need to have two different interaction models based on if you have a touch device or a mouse.
Our mobile version should behave a little different from our desktop, since touch devices don’t support hover.
Is there a standard way in babylon to detect if the input is a touch device or mouse?
For all pointerevents that get triggered there is a property on the event called pointerType, which I could use.
The problem is that OnPointerOverTrigger / OnPointerOutTrigger don’t contain the underlying pointer event. (as far as I can see in when console logging the event.
As far as I know, there is no way to access the event data for a pointer event that triggers the OnPointerOverTrigger / OnPointerOutTrigger action from the action directly but you should be able to use scene.onPrePointerObservable to check for the pointerType and work from there:
scene.onPrePointerObservable.add((eventData) => {
// Use eventData.event.pointerType to determine if it's a mouse or touch
});
I’m talking more about if there is a general API that the Input apis uses to detect what kind of inputs are available.
There are ways to detect what’s available via the matchMedia API, but I though if there was an api already available which tells me whats supported it would be better to use that.
As a reference, this is how you can do some checks with matchMedia
private hasHoverSupport = matchMedia('(hover: hover)').matches
private hasNoHoverSupport = matchMedia('(hover: none)').matches
// or check for pointer type (since some devices has both touch and mouse, this will return true for such a device)
private hasTouchScreenSupport = matchMedia('(any-pointer:coarse)').matches
From within a pointer observable, the only way to tell if a given input is a mouse or touch input is to check its event’s pointer type. For detecting what inputs are available to receive input, using matchMedia is a good approach (we use if (matchMedia("(pointer:fine)").matches) to check for the mouse in the input system). For touch capabilities, you could also use DomManagement.IsNavigatorAvailable() && navigator.maxTouchPoints for touch (maxTouchPoints points will either be 0 or undefined if it doesn’t support touch on the given device). As far as I can recall, there is no user-facing BJS way to check what pointer devices are available, other than creating an instance of the DeviceSourceManager and using getDeviceSources to get a count.
As usual there is some edge case causing problems, which means you cannot use the easy solution and have to implement some complicated logic to check if there is touch support.
I ended up with this which seems to work on all my devices including the samsung ones
let isTouchDeviceCache = null
export function isTouchDevice() {
if (isTouchDeviceCache !== null) {
return isTouchDeviceCache
}
let result = false
if (window.PointerEvent && 'maxTouchPoints' in navigator) {
// if Pointer Events are supported, just check maxTouchPoints
if (navigator.maxTouchPoints > 0) {
result = true
}
} else {
// no Pointer Events...
if (window.matchMedia && window.matchMedia('(any-pointer:coarse)').matches) {
// check for any-pointer:coarse which mostly means touchscreen
result = true
} else if (window.TouchEvent || 'ontouchstart' in window) {
// last resort - check for exposed touch events API / event handler
result = true
}
}
isTouchDeviceCache = result
return result
}