'How to detect if a device has mouse support?
I currently use the following test (taken out of Modernizr) to detect touch support:
function is_touch_device() {
var bool;
if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
bool = true;
} else {
injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function(node) {
bool = node.offsetTop === 9;
});
}
return bool;
}
But some devices are both touch and mouse driven, so I want a seperate function to detect if a device has mouse support. What's a good way to do this check?
Ultimately my intention is to be able to do these:
if(is_touch_device())
if(has_mouse_support())
if(is_touch_device() && has_mouse_support())
Solution 1:[1]
There's a CSS media just for that!
You can check whether some device has a mouse by getting the value of the pointer CSS media feature:
if (matchMedia('(pointer:fine)').matches) {
// Device has a mouse
}
Because it's CSS you don't even need to use JavaScript:
@media (pointer: fine) {
/* Rules for devices with mouse here */
}
Solution 2:[2]
I am currently using the following (jQuery) and I haven't found any flaws yet on specific devices
$(window).bind('mousemove.hasMouse',function(){
$(window).unbind('.hasMouse');
agent.hasMouse=true;
}).bind('touchstart.hasMouse',function(){
$(window).unbind('.hasMouse');
agent.hasMouse=false;
});
Explanation: Mouse devices (also touch screen laptops) first fire mousemove before they can fire touchstart and hasMouse is set to TRUE. Touch devices (also for instance iOS which fires mousemove) FIRST fire touchstart upon click, and then mousemove. Then is why hasMouse will be set to FALSE.
The only catch is that this depends on user interaction, the value will only be correct after mouse move or touchstart so cannot be trusted to use on page load.
Solution 3:[3]
As mentioned in the question comments, specifically on https://github.com/Modernizr/Modernizr/issues/869, there is no good answer yet.
Solution 4:[4]
Answer by @josemmo is not working for me: on android phone with mouse attached matchMedia('(pointer:fine)').matches does not match.
Fortunately, I've succeeded with another media query: hover.
if (matchMedia('(hover:hover)').matches) {
// Device has a mouse
}
Solution 5:[5]
var clickHandler = (isMouseEventSupported('click') ? 'click' : 'touchstart');
function isMouseEventSupported(eventName) {
var element = document.createElement('div');
eventName = 'on' + eventName;
var isSupported = (eventName in element);
if (!isSupported) {
element.setAttribute(eventName, 'return;');
isSupported = typeof element[eventName] == 'function';
}
element = null;
return isSupported;
}
This is code from a friend/coworker of mine and he based it off of: http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
Solution 6:[6]
There is no immediate way of knowing, you'll have to wait for a touch event or a mouse event.
Presuming you want to detect either mouse or touch you can do the following: listen for touchstart and mousemove (the latter can fire on touch devices without an actual mouse). Whichever one fires first is 99% bound to be what you're looking for.
This does not take in account devices that actually have both.
document.addEventListener('mousemove', onMouseMove, true)
document.addEventListener('touchstart', onTouchStart, true)
function onTouchStart(){
removeListeners()
// touch detected: do stuff
}
function onMouseMove(){
removeListeners()
// mouse detected: do stuff
}
function removeListeners(){
document.removeEventListener('mousemove', onMouseMove, true)
document.removeEventListener('touchstart', onTouchStart, true)
}
Solution 7:[7]
As of 2021 pointerevents is implemented in all major browsers.
It gives you the posibility to dynamically detect pointerdevices mouse, touch and pen.
var is_touch_device=(('ontouchstart' in window)||
(navigator.maxTouchPoints > 0)||
(navigator.msMaxTouchPoints > 0));
var has_mouse_support=false;
document.addEventListener("pointermove", function(evt) {
var pointerType=evt.pointerType;
/*** Safari quirk ***/
if(pointerType==="touch"&&evt.height===117.97119140625
&&evt.height===evt.width)pointerType="mouse";
/*** Safari quirk ***/
has_mouse_support=(pointerType==="mouse");
}
It is of course dependent on the user moving the mousepointer.
Even safari on ipadOS 14.4.2 detects it, if AssistiveTouch is activated! But there seems to be some quirks in pointerType detection there. It detects pointerType as mouse first time the mouse is used and no touch has been performed. But if you later use touch, it will not detect and change to pointerType of mouse, if mouse is used after touch! No surprise!
Edit: After some messing around with ipadOS safari i have discovered that, when mouse is used after touch, the pointerevent width and height are the exact same, which in ipadOS 14.4.2 is 117.97119140625 every time mouse is used. This can be used as a not to reliable workaround. Who knows when they will change the width/height? Another peculiarity with pointermove detection in ipadOS, is that mouse move is only detected on buttom press on mouse.
It is not tested with pen on ipad/iphone. Who knows which quirks this will show?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | josemmo |
| Solution 2 | Hacktisch |
| Solution 3 | drzaus |
| Solution 4 | danronmoon |
| Solution 5 | |
| Solution 6 | Sjeiti |
| Solution 7 |
