I\'m developing a webapp (not a website with pages of interesting text) with a very different interface for touch (your finger hides the screen when you click) and mouse (re
I'd strongly recommend against this approach. Consider touch-screen, desktop-sized devices, and you have a different set of problems to solve.
Please make your app usable without a mouse (i.e. no hover preview).
Why don't you just detect if it has the ability to sense touches and/or to react to mouse movements?
// This will also return false on
// touch-enabled browsers like Chrome
function has_touch() {
return !!('ontouchstart' in window);
}
function has_mouse() {
return !!('onmousemove' in window);
}
It's only possible to detect if a browser is touch capable. There is no way to know if it actually has a touch screen or a mouse connected.
One can prioritize the use though by listening to touch event instead of mouse event if touch capability is detected.
To detect touch capability cross-browser:
function hasTouch() {
return (('ontouchstart' in window) || // html5 browsers
(navigator.maxTouchPoints > 0) || // future IE
(navigator.msMaxTouchPoints > 0)); // current IE10
}
Then one can use this to check:
if (!hasTouch()) alert('Sorry, need touch!);
or to choose which event to listen to, either:
var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);
or use separate approaches for touch vs. non-touch:
if (hasTouch() === true) {
someElement.addEventListener('touchend' , touchHandler, false);
} else {
someElement.addEventListener('click' , mouseHandler, false);
}
function touchHandler(e) {
/// stop event somehow
e.stopPropagation();
e.preventDefault();
window.event.cancelBubble = true;
// ...
return false; // :-)
}
function mouseHandler(e) {
// sorry, touch only - or - do something useful and non-restrictive for user
}
For mouse one can only detect if the mouse is being used, not if it exists or not. One can setup a global flag to indicate that mouse was detected by usage (similar to an existing answer, but simplified a bit):
var hasMouse = false;
window.onmousemove = function() {
hasMouse = true;
}
(one cannot include mouseup
or mousedown
as these event can also be triggered by touch)
Browsers restricts access to low-level system APIs which is needed to be able to detect features such as hardware capabilities of the system it's being used on.
There is the possibility to perhaps write a plugin/extension to access these but via JavaScript and DOM such detection is limited for this purpose and one would have to write a plugin specific for the various OS platforms.
So in conclusion: such detection can only be estimated by a "good guess".
Ran some tests on various PC's, Linux's, iPhone, Android phones and tabs. Weird that there is no easy bullet-proof solution. Problem arises when some that have Touch and no mouse still present Touch and Mouse events to application. Since do want to support mouse-only and touch-only instances, want to process both, but this causes double occurrences of user interactions. If can know mouse is not present on device, then can know to ignore fake/inserted mouse events. Tried setting flag if MouseMove is encountered, but some browsers throw fake MouseMove as well as MouseUp and MouseDown. Tried examining timestamps but figured this was too risky. Bottom line: I found the browsers that created the fake mouse events always inserted a single MouseMove just prior to the inserted MouseDown. In 99.99% of my cases, when running on a system that has a real mouse, there are multiple consecutive MouseMove events - at least two. So, keep track of whether system encounters two consecutive MouseMove events and declare there is no mouse present if this condition is never met. This is probably too simple, but its working on all my test setups. Think I'll stick with it until I find a better solution. - Jim W
Just found a solution that I think is quite elegant.
// flag as mouse interaction by default
var isMouse = true;
// detect a touch event start and flag it
$(window).on('touchstart', function () {
// if triggers touchstart, toggle flag
// since touch events come before mouse event / click
// callback of mouse event will get in callback
// `isMouse === false`
isMouse = false;
});
// now the code that you want to write
// should also work with `mouse*` events
$('a.someClass').on('click', function () {
if (isMouse) {
// interaction with mouse event
// ...
} else {
// reset for the next event detection
// this is crucial for devices that have both
// touch screen and mouse
isMouse = true;
// interaction with touch event
// ...
}
});
This worked for me in a similar situation. Basically, assume the user doesn't have a mouse until you see a short series of consecutive mousemoves, without intervening mousedowns or mouseups. Not very elegant, but it works.
var mousedown = false;
var mousemovecount = 0;
function onMouseDown(e){
mousemovecount = 0;
mousedown = true;
}
function onMouseUp(e){
mousedown = false;
mousemovecount = 0;
}
function onMouseMove(e) {
if(!mousedown) {
mousemovecount++;
if(mousemovecount > 5){
window.removeEventListener('mousemove', onMouseMove, false);
console.log("mouse moved");
$('body').addClass('has-mouse');
}
} else {
mousemovecount = 0;
}
}
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);