Detecting browser capabilities and selective events for mouse and touch - javascript

I started using touch events for a while now, but I just stumbled upon quite a problem. Until now, I checked if touch capabilities are supported, and applied selective events based on that. Like this:
if(document.ontouchmove === undefined){
//apply mouse events
}else{
//apply touch events
}
However, my scripts stopped working in Chrome5 (which is currently beta) on my computer. I researched it a bit, and as I expected, in Chrome5 (as opposed to older Chrome, Firefox, IE, etc.) document.ontouchmove is no longer undefined but null.
At first I wanted to submit a bug report, but then I realized: There are devices that have both mouse and touch capabilities, so that might be natural, maybe Chrome now defines it because my OS might support both types of events.
So the solutions seems easy: Apply BOTH event types. Right?
Well the problem now take place on mobile. In order to be backward compatible and support scripts that only use mouse events, mobile browsers might try to fire them as well (on touch). So then with both mouse and touch events set, a certain handler might be called twice every time.
What is the way to approach this? Is there a better way to check and apply selective events, or must I ignore the problems that might occur if browsers fire both touch and mouse events at times?

Try creating a dummy element and attaching a touch event handler to it, then check if the handler is of type "function". This is not foolproof though as some browsers will allow touch event handlers although they are running on a non-touch device - but it's probably as close as you'll get. So, something like this:
var hasTouch = function() {
var dummy = document.createElement("div");
dummy.setAttribute("ontouchmove", "return;");
return typeof dummy.ontouchmove == "function" ? true : false;
}
Happy coding!

Try disabling the mouse events if the touch events fire?
E.g.:
function touch_events() {
document.onmousemove = null;
...
}
function mouse_events() { ... }
document.ontouchmove = touch_events;
document.onmousemove = mouse_events;

Is this too obvious?
if(document.ontouchmove !== undefined || document.ontouchmove == null){
//apply touch events
}else{
//apply mouse events
}

var support_touch = (typeof Touch == "object");

Similar to Ola's answer, I've found just a simple detect works but I also find that in particular quirky android devices (like the wildfire) don't always have this event defined - this works well for me:
//detect capabilities
this.is_touch_device = ('ontouchstart' in document.documentElement) || (navigator.userAgent.match(/ipad|iphone|android/i) != null);
//if so do somemthing
if (this.is_touch_device) {
//like publishing a custom event
}
(probably a better way of doing this :)

Did I get this wrong, or did every post so far here answer a question that you didn't ask? At least you now have loads of alternative ways to check for supported events :)
Anyway, regarding your question:
I would say it depends on what you are building. I assume when you write "applied selective events based on that" you mean adding event Listeners and -Handlers? Also i assume you're not dealing with multitouch (yet)?
In general, if you want your app to work with both input event types, you're left without a choice but to register listeners for all of those. You might be using the same handler for touchstart and mousedown already, so that's the place i would make sure only one out of subsequent identical events is actually processed (to save cpu cycles and redraws as well as help avoiding possible side effects).
When it comes to touch devices, speaking of single touch, i can see my level 10 (2.3.3) phone generates both event - the mouse events, so "classic" web (all those onmousedown-events, etc...) will work, the touch events... well, because it's a touch device apparently. But only checking if the javascript API supports TouchEvents doesn't tell you anything about the input device, for instance: the rekonq browser on kubuntu desktop returns true for the above examples - but it will never fire them unless used with a touchscreen.
Maybe telling devices apart via window.navigator.userAgent would be a more feasible approach?

Related

How can I prevent a browser from generating ContextMenu event for a long touch

Browsers support touch events and might generate mouse events. Also, for a long touch the browser generates a ContextMenu event. However, in my industrial environment, I want all touch events to be handled like a click event. Is there a global setting to prevent the browser to generate context menu events? Or can I at least set the time when the browser will generate such an event?
My only solution I came up with so far is the subscribe to click and context menu events and call the same handler. However I would rather avoid this for every button in my application...
Any ideas?
There are several answers at Disabling the context menu on long taps on Android
But I think the most voted answer over there is not a good one.
Try and see if this work for you,
window.ontouchstart = function(event) {
event.preventDefault();
event.stopPropagation();
return false;
};

createTouch vs ontouchstart - best way to detect touchscreen devices?

Currently, for detecting touchscreen devices I use this in my javascript:
if ('createTouch' in document) {
// do touchscreen-specific stuff
}
I see that many developers use ontouchstart, like this:
if ('ontouchstart' in document) {
// do touchscreen-specific stuff
}
What is the difference between createTouch and ontouchstart? Which one is the safest to use? Are there some other simple, reliable alternatives to these two?
touchstart event is fired when a touch point is placed on the touch surface([MDN][1])
createTouch method creates and returns a new Touch object.([MDN][2])
The better way from my point of view is detecting existance of event in window than only create it.
Also your statement check only for existing of touch events in window object, not touch screens, like windows phones, so probably you would like to check pointer-events too.
P.S.: Look at Modernizr library which have "touch" detection and much more.
ontouchstart is event based trigger. It will be invoked when user does some action. More info at ontouchstart event. Hence, it is more efficient for performing user based action.
While createtouch will be invoked, not matter if user did some action or not. Somebody please correct me, if I'm wrong. :)

A tag getting click instead of touchstart [duplicate]

I have a bootstrap .btn that I want to toggle with the mouse click. The problem is that the response is way too slow on tablets, since the click arrives 300 ms after the touchstart in mobile browsers.
I tried binding the logic in the touchstart event, effectively breaking the app for desktop browsers where there is no touchstart. I then thought of binding the same logic also to click but then I get a repeated event in mobile browsers. I've juggling around, trying to unbind from click the first time I receive a touchstart, and so on, and managed to come up with a design so complicated that there is always some quirk here or there that I cannot solve.
For instance, I can't get a text input to receive focus in the tablet: if I do focus on touchstart then the click event returns the focus to the button. I tried jQuery Mobile's vmousedown, but I couldn't manage to have multi-touch (tapping more than one button at the same time only changed one of them). I don't want to reinvent a lot of wheels, and I'm sure I must be missing something obvious, either on jQuery Mobile, or plain JavaScript.
In concrete, I want an event like vmousedown that works both on desktops and mobiles, only fires once on each, and allows multi-touch.
Utilize Modernizr for handling actions based on the device, etc. It provides great cross-browser/platform support without the need to sniff User Agents and the like. Instead, it uses feature detection.
You can just use the Modernizr functions with jQuery's $(document).ready(function()});
$(function(){
if (Modernizr.touch){
// bind to touchstart, touchmove, etc and watch `event.streamId`
} else {
// bind to normal click, mousemove, etc
}
});
This code has been taken straight from the Modernizr Documentation
Also, here's another resource for performing touch tests
Late to the party, but note that jQueryMobile also has similar touch detection:
if ( $.mobile.support.touch ) {...
And no, IMHO, you are not missing anything obvious :), cross-platform / cross-device / touch-friendly features are still harder than they should be. For example, today I'm looking at a win8 surface tablet: touch-screen and a mouse. There are cases where i'd like to know which device was used. event.originalEvent.type should differentiate between tap and click, right? wrong :(.

Unified and transparent pointer events in jQuery

I have a bootstrap .btn that I want to toggle with the mouse click. The problem is that the response is way too slow on tablets, since the click arrives 300 ms after the touchstart in mobile browsers.
I tried binding the logic in the touchstart event, effectively breaking the app for desktop browsers where there is no touchstart. I then thought of binding the same logic also to click but then I get a repeated event in mobile browsers. I've juggling around, trying to unbind from click the first time I receive a touchstart, and so on, and managed to come up with a design so complicated that there is always some quirk here or there that I cannot solve.
For instance, I can't get a text input to receive focus in the tablet: if I do focus on touchstart then the click event returns the focus to the button. I tried jQuery Mobile's vmousedown, but I couldn't manage to have multi-touch (tapping more than one button at the same time only changed one of them). I don't want to reinvent a lot of wheels, and I'm sure I must be missing something obvious, either on jQuery Mobile, or plain JavaScript.
In concrete, I want an event like vmousedown that works both on desktops and mobiles, only fires once on each, and allows multi-touch.
Utilize Modernizr for handling actions based on the device, etc. It provides great cross-browser/platform support without the need to sniff User Agents and the like. Instead, it uses feature detection.
You can just use the Modernizr functions with jQuery's $(document).ready(function()});
$(function(){
if (Modernizr.touch){
// bind to touchstart, touchmove, etc and watch `event.streamId`
} else {
// bind to normal click, mousemove, etc
}
});
This code has been taken straight from the Modernizr Documentation
Also, here's another resource for performing touch tests
Late to the party, but note that jQueryMobile also has similar touch detection:
if ( $.mobile.support.touch ) {...
And no, IMHO, you are not missing anything obvious :), cross-platform / cross-device / touch-friendly features are still harder than they should be. For example, today I'm looking at a win8 surface tablet: touch-screen and a mouse. There are cases where i'd like to know which device was used. event.originalEvent.type should differentiate between tap and click, right? wrong :(.

How can I detect if a device has a touch screen in Titanium?

I'm targeting Android with Titanium. How can I tell if a device has a touch screen or not?
The easiest way is to test for touch event support. If they are supported, likely the device has a touch screen. If not, it probably doesn't or you can't use them anyway. One solution is:
var touchSupported = ('ontouchstart' in window);
But be careful as the browser may support touch events but the device might not (e.g. Chrome 20 supports lots of touch events in devices that don't have touch).
You may be able to get users to click a button and see if a touch event is dispatched or just a click.
This is the solution I came up with. It's really stupid, but it works. Wherever you create your application window, add this code:
function touchStart(){
Titanium.App.Properties.setBool("touch", true);
self.removeEventListener("touchstart", touchStart);
}
self.addEventListener("touchstart", touchStart);
Replace self with the name of your window. Now, the first time a touch event is detected, an application property will be set.
Later on, check that touch is present with this:
var touchSupported = Titanium.App.Properties.getBool("touch", false);
If you are testing this on an emulator, the property might persist even when you change "devices". So add this line before anything else:
Titanium.App.Properties.setBool("touch", false);

Categories

Resources