Opened 6 years ago

Closed 5 years ago

Last modified 3 years ago

#13048 closed defect (fixed)

dojo.touch doesn't handle devices w/touch and mouse

Reported by: bill Owned by: bill
Priority: high Milestone: 1.7.7
Component: Events Version: 1.6.1
Keywords: Cc: kgf
Blocked by: Blocking: #15107

Description

If a device (like blackberry phones or some high end desktop computers) has both mouse and touch, dojo.touch will only monitor touch events.

It should be monitoring both, especially since code converted from "onmousedown"/"onmouseup" to dojo.touch.press/dojo.touch.release technically has regressed for those platforms. (Not too many platforms support both touch and mouse but we are expecting more in the future.)

Change History (36)

comment:1 Changed 6 years ago by Evan

  • Owner changed from evan to Evan

comment:2 Changed 6 years ago by kgf

  • Cc kgf added
  • Status changed from new to open

IMO this is a rather important thing to support, and if I'm not mistaken, it should also be pretty trivial. I'll try to take a look at this and submit a patch for starters.

comment:3 Changed 6 years ago by bill

I agree. I thought it was just a case of connecting to both events (perhaps as trivial as a single on() call: on("mousedown, touchpress", func) ) rather than either/or.

Since this ticket hasn't been touched in 7 months I thinks it's fair game for you to check in something. Can't wait forever.

comment:4 follow-up: Changed 6 years ago by kgf

  • Owner changed from Evan to kgf
  • Status changed from open to assigned

If anyone wants to look at the changes I've made for this, https://github.com/kfranqueiro/dojo/compare/master...touch-mouse

Seems to be working; moveable still works on mobile w/touch and desktop w/mouse. Although test_touch.html only tests mouse events, they pass even on mobile browsers (so far tried Android 2.3.7 default browser + Firefox, and Safari on iOS5). Unfortunately it seems on.emit doesn't suffice for triggering touch events appropriately to pass these tests; from what I've seen in the past, firing touch events can be a bit more involved of a process.

comment:5 Changed 6 years ago by bill

The patch looks good to me.

comment:6 Changed 6 years ago by kgf

  • Resolution set to fixed
  • Status changed from assigned to closed

In [28178]:

Allow dojo/touch to support both touch and mouse on touch-enabled devices, and clean up tests a bit; fixes #13048

comment:7 Changed 6 years ago by bill

  • Milestone changed from tbd to 1.8

comment:8 in reply to: ↑ 4 Changed 6 years ago by Evan

Replying to kgf:

If anyone wants to look at the changes I've made for this, https://github.com/kfranqueiro/dojo/compare/master...touch-mouse

Seems to be working; moveable still works on mobile w/touch and desktop w/mouse. Although test_touch.html only tests mouse events, they pass even on mobile browsers (so far tried Android 2.3.7 default browser + Firefox, and Safari on iOS5). Unfortunately it seems on.emit doesn't suffice for triggering touch events appropriately to pass these tests; from what I've seen in the past, firing touch events can be a bit more involved of a process.

Hi Ken,

Thanks for looking at this, my fault not getting back in time. I had a quick test today seems there is a side effect, following callback will each be invoked twice on mobile(only tested on iOS4+ and Andriod 2.2) - 1 for touchxxx and 1 for mousexxx

on(node, touch.move, callback);
on(node, touch.release, callback);

The tricky thing is once I added following line, it's working well

on(node, touch.press, callback);

I think on most common mobile devices, once 'touchstart' is being listened, 'mousexxx' events won't be fired and that's the reason why it's working well after touch.press is listened.

So [28178] should be safe for most in dijit, dnd and dojox.gesture, the only possibly affected components are:

  1. dijit.layout.BorderContainer
  2. dojo.dnd.Mover

As both of them are only listening to touch.move/release

Ideally 'mousexxx' and 'touchxxx' should be listened simultaneously only on devices that support both touch screen and mouse input, but apparently we don't have an ideal has() condition for that yet.

Last edited 6 years ago by Evan (previous) (diff)

comment:9 follow-up: Changed 6 years ago by bill

Oof, I had forgotten that mobile devices fire mousexxx events in addition to touchxxx events, and I'm certainly surprised that they sometimes do and sometimes don't. Perhaps dojo/touch should always listen to touch.press as a workaround to this bizarre behavior?

comment:10 in reply to: ↑ 9 Changed 6 years ago by Evan

Replying to bill:

Oof, I had forgotten that mobile devices fire mousexxx events in addition to touchxxx events, and I'm certainly surprised that they sometimes do and sometimes don't. Perhaps dojo/touch should always listen to touch.press as a workaround to this bizarre behavior?

Seems that won't work as I got a bit more findings, purely adding

on(node, touch.press, function(e){});

is not enough to avoid the issue, 'e' must be stopped which means only following way can avoid duplicate callbacks:

on(node, touch.press, function(e){event.stop(e)});
on(node, touch.move, callback);
on(node, touch.release, callback);

so it doesn't make sense to let dojo.touch by default always

on(node, touch.press, function(e){event.stop(e)});
Last edited 6 years ago by Evan (previous) (diff)

comment:11 Changed 6 years ago by kgf

  • Resolution fixed deleted
  • Status changed from closed to reopened

I was wondering if there would be issues like this; the call to event.stop in the existing test page had blinded me to it. Certainly might explain why we hadn't gone down this path to begin with.

It seems like the behavior of also firing mouse events in this case is exclusive to iOS, or at least it doesn't seem to happen to me on Android; not sure about other platforms. Unfortunately I'm not sure yet if there's any decent way around this. I wouldn't want to have to preventDefault on touchstart events just to make this work; that seems destructive. I'd rather not have to stoop to some kind of arbitrary timeout though, either. (A 0-ms timeout isn't sufficient to defer past the triggered mouse events; I already checked.)

comment:12 follow-up: Changed 6 years ago by neonstalwart

we need to coordinate efforts with #15107. i believe that r28281 should be reverted to use dojo/touch and we should fix dojo/touch to work so that it allows code to be properly unaware of whether or not a device is using mouse or touch. if everybody is going to need to end up with code like this.connect(this.domNode, has('touch') ? "ontouchstart" : "onmousedown", "onTouchStart") then dojo/touch has failed.

should we revert r28178 and r28281 until we have a complete solution? i think that's better than what we have now.

comment:13 Changed 6 years ago by neonstalwart

marking as blocker since i don't think we should have a release without this being resolved.

comment:14 Changed 6 years ago by neonstalwart

  • Priority changed from high to blocker

comment:15 Changed 6 years ago by neonstalwart

  • Blocking 15107 added

(In #15107) i'm thinking that r28178 should be reverted/fixed and mobile should go back to using dojo/touch - see my comments at #13048. i'm going to reopen this ticket until the discussion at #13048 is resolved.

comment:16 in reply to: ↑ 12 ; follow-up: Changed 6 years ago by kgf

Replying to neonstalwart:

we need to coordinate efforts with #15107. i believe that r28281 should be reverted to use dojo/touch and we should fix dojo/touch to work so that it allows code to be properly unaware of whether or not a device is using mouse or touch. if everybody is going to need to end up with code like this.connect(this.domNode, has('touch') ? "ontouchstart" : "onmousedown", "onTouchStart") then dojo/touch has failed.

should we revert r28178 and r28281 until we have a complete solution? i think that's better than what we have now.

I'm ok with reverting r28178 for now; was hoping to have time over the last couple of days to take another look at this but any notion of free time pretty much completely disappeared for me especially over Tuesday and Wednesday.

Either way, yes, dojo/touch can't stay as it is now; the question is, can we arrive at a decent solution that mitigates this iOS nonsense?

Last edited 6 years ago by kgf (previous) (diff)

comment:17 in reply to: ↑ 16 ; follow-up: Changed 6 years ago by Evan

Replying to kgf:

Replying to neonstalwart:

we need to coordinate efforts with #15107. i believe that r28281 should be reverted to use dojo/touch and we should fix dojo/touch to work so that it allows code to be properly unaware of whether or not a device is using mouse or touch. if everybody is going to need to end up with code like this.connect(this.domNode, has('touch') ? "ontouchstart" : "onmousedown", "onTouchStart") then dojo/touch has failed.

should we revert r28178 and r28281 until we have a complete solution? i think that's better than what we have now.

I'm ok with reverting r28178 for now; was hoping to have time over the last couple of days to take another look at this but any notion of free time pretty much completely disappeared for me especially over Tuesday and Wednesday.

Either way, yes, dojo/touch can't stay as it is now; the question is, can we arrive at a decent solution that mitigates this iOS nonsense?

Besides reverting r28178, we need to figure out/verify what's the expected behavior on those platforms(like blackberry phones or some high end desktop computers supporting both mouse and touch events, though I don't have one for try yet):

  1. Will 'touchxxx' and 'mousexxx' events be fired separately? (Unlike on iOS or Android, they are fired simultaneously which means we only care about 'touchxxx' and that's the reason why the existing logic works well before r28178)
  • If the answer is Yes, I think we can revert r28178 and listen to both 'mousexxx' and 'touchxxx' with has() check for those special platforms.
  • If the answer is No, we can just keep the version with r28178 reverted


  1. On those special platforms, will there be any cases when users want to bind different handles to 'mousexxx' and 'touchxxx'?

comment:18 Changed 6 years ago by kgf

In [28291]:

Reverting r28178 due to problems WRT iOS firing both touch and mouse events; refs #13048

comment:19 in reply to: ↑ 17 Changed 6 years ago by kgf

Replying to Evan:

Besides reverting r28178, we need to figure out/verify what's the expected behavior on those platforms(like blackberry phones or some high end desktop computers supporting both mouse and touch events, though I don't have one for try yet):

  1. Will 'touchxxx' and 'mousexxx' events be fired separately? (Unlike on iOS or Android, they are fired simultaneously which means we only care about 'touchxxx' and that's the reason why the existing logic works well before r28178)
  • If the answer is Yes, I think we can revert r28178 and listen to both 'mousexxx' and 'touchxxx' with has() check for those special platforms.
  • If the answer is No, we can just keep the version with r28178 reverted


  1. On those special platforms, will there be any cases when users want to bind different handles to 'mousexxx' and 'touchxxx'?

Well, I don't think we would have bothered considering this ticket if there weren't devices which distinctly support both touch and mouse input separately (in which case the current behavior, and choice number 2 above, would be fine as you said). The thing is, such devices do exist, and the idea behind dojo/touch as I interpreted it is to normalize the two rather than simply alias to one or the other. (Or at least, that would seem to be a lot more useful, if it's possible.)

At any rate, I've reverted r28178 for now. I'd like to give this some more thought, but I also don't necessarily want to rush into a crappy workaround to deal with what iOS is doing...

comment:20 follow-up: Changed 6 years ago by bill

Two possible solutions:

  1. Call evt.preventDefault() on touchend, to (hopefully) prevent the mousedown/mouseup events from firing. But that might also prevent a click event from firing, thus preventing things like form submission, in which case probably we don't want to do it.
  2. In the dojo/touch code, ignore mousedown/mouseup events if they occur immediately following a touchend event. (This would involve a setTimeout() on the touchend event.)

PS: Why is this ticket a blocker? I thought dojox/mobile and dijit were working in general, right?

Last edited 6 years ago by bill (previous) (diff)

comment:21 in reply to: ↑ 20 Changed 5 years ago by Evan

Replying to bill:

Two possible solutions:

  1. Call evt.preventDefault() on touchend, to (hopefully) prevent the mousedown/mouseup events from firing. But that might also prevent a click event from firing, thus preventing things like form submission, in which case probably we don't want to do it.
  2. In the dojo/touch code, ignore mousedown/mouseup events if they occur immediately following a touchend event. (This would involve a setTimeout() on the touchend event.)

PS: Why is this ticket a blocker? I thought dojox/mobile and dijit were working in general, right?

Don't think this will be a blocker for 1.8 since dojox/mobile and dijit are working well. It's more like an enhancement for those specific devices.

comment:22 Changed 5 years ago by bill

  • Milestone changed from 1.8 to 2.0
  • Priority changed from blocker to high

comment:23 Changed 5 years ago by bill

  • Milestone changed from 2.0 to 1.9
  • Owner changed from kgf to bill
  • Status changed from reopened to assigned

I'll fix for 1.9. Maybe will backport too.

comment:24 Changed 5 years ago by bill

  • Resolution set to fixed
  • Status changed from assigned to closed

In [30397]:

Support machines w/both touch and mouse, fixes #13048 !strict.

comment:25 Changed 5 years ago by bill

In [30398]:

fix typo, refs #13048 !strict.

comment:26 Changed 5 years ago by bill

In [30412]:

Increase delay for ignoring mouse events after touch events, because there's a ~450ms delay between when the touch finishes and when the browser generates the shadow mousedown, mouseup, and click events. Refs #13048 !strict.

comment:27 Changed 5 years ago by bill

In [30449]:

backport [30397] and [30398] to 1.8 branch, to support machines with both touch and mouse, fixes #13048 on 1.8 branch !strict

comment:28 Changed 5 years ago by bill

  • Milestone changed from 1.9 to 1.8.4

I'm not planning to backport this to 1.7 because the changes to touch.js (for this ticket) are tangled with the changes in #15185, which was a bit of an API change.

comment:29 Changed 5 years ago by bill

#16765 is a duplicate of this ticket.

comment:30 Changed 5 years ago by bill

In [30816]:

Update _HasDropDown to leverage dojo/touch::press and dojo/touch::release rather than listening for mousedown/mouseup events that may or may not occur. Refs #13048 !strict.

comment:31 Changed 5 years ago by bill

In [31101]:

Avoid hiding the popup when it has focus. Fixes regression on IE10 starting in [30816] where clicking the icon to close the DateTextBox dropdown closes the containing TooltipDialog. Refs #13048 tangentially !strict.

comment:32 Changed 4 years ago by Bill Keese <bill@…>

In 76216d6d829f011a87ccd11ee12d3a862d6e2e88/dijit:

Fix regression on IE10 clicking blank screen to close drop down.

An e.preventDefault() call on MSPointerDown prevents the button from getting focus,
so I stopped doing it for that case. This is a minimal fix. Other approaches include:

  1. remove the e.preventDefault() call for all cases
  2. make focus manager listen for touch/mouse events in the capture phase rather than the

bubbling phase, to avoid missing the event due to a stopPropagation() call; it used
to do this except for IE6-8, but I normalized the behavior in 9965406.

Fixes #17262. Refs #13048, #13341.

comment:33 Changed 4 years ago by Bill Keese <bill@…>

In d5eef52f83e77b9d501ce0309b4f4d69b64c6a04/dijit:

Fix regression on IE10 clicking blank screen to close drop down.

An e.preventDefault() call on MSPointerDown prevents the button from getting focus,
so I stopped doing it for that case. This is a minimal fix. Other approaches include:

  1. remove the e.preventDefault() call for all cases
  2. make focus manager listen for touch/mouse events in the capture phase rather than the

bubbling phase, to avoid missing the event due to a stopPropagation() call; it used
to do this except for IE6-8, but I normalized the behavior in 9965406.

Fixes #17262. Refs #13048, #13341.
(cherry picked from commit 76216d6d829f011a87ccd11ee12d3a862d6e2e88)

comment:34 Changed 3 years ago by Bill Keese <bill@…>

In 809130120f849c06f71ceadc8edeb3e2edd9db1b/dijit:

Fix regression on IE10 clicking blank screen to close drop down.

Squash of two commits:

---
Fix regression on IE10 clicking blank screen to close drop down.

An e.preventDefault() call on MSPointerDown prevents the button from getting focus,
so I stopped doing it for that case. This is a minimal fix. Other approaches include:

  1. remove the e.preventDefault() call for all cases
  2. make focus manager listen for touch/mouse events in the capture phase rather than the

bubbling phase, to avoid missing the event due to a stopPropagation() call; it used
to do this except for IE6-8, but I normalized the behavior in 9965406.

Fixes #17262. Refs #13048, #13341.
(cherry picked from commit 76216d6d829f011a87ccd11ee12d3a862d6e2e88)

(cherry picked from commit d5eef52f83e77b9d501ce0309b4f4d69b64c6a04)

--
Support unprefixed pointer events
(change applies to _HasDropDown only)

Refs #17600

(cherry picked from commit 275211f84351d18b000b35cb495e8efc6fde7937)

Conflicts:

form/TextBox.js

(cherry picked from commit b9dd78e03fa2d3542350f767e46d2771654b6517)

Conflicts:

_CssStateMixin.js
form/TextBox.js
tests/_HasDropDown.html
tests/_Widget-on.html
tests/tree/Tree_ObjectStoreModel.html

comment:35 Changed 3 years ago by Bill Keese <bill@…>

In b705fc4a494f78f9519a4df8979b94ac1cbb7fb5/dijit:

Fix regression on IE10+ clicking blank screen to close drop down.

Squash of two commits:

---
Fix regression on IE10 clicking blank screen to close drop down.

An e.preventDefault() call on MSPointerDown prevents the button from getting focus,
so I stopped doing it for that case. This is a minimal fix. Other approaches include:

  1. remove the e.preventDefault() call for all cases
  2. make focus manager listen for touch/mouse events in the capture phase rather than the

bubbling phase, to avoid missing the event due to a stopPropagation() call; it used
to do this except for IE6-8, but I normalized the behavior in 9965406.

Fixes #17262. Refs #13048, #13341.
(cherry picked from commit 76216d6d829f011a87ccd11ee12d3a862d6e2e88)

(cherry picked from commit d5eef52f83e77b9d501ce0309b4f4d69b64c6a04)

--
Support unprefixed pointer events
(change applies to _HasDropDown only)

Refs #17600

(cherry picked from commit 275211f84351d18b000b35cb495e8efc6fde7937)

Conflicts:

form/TextBox.js

(cherry picked from commit b9dd78e03fa2d3542350f767e46d2771654b6517)

Conflicts:

_CssStateMixin.js
form/TextBox.js
tests/_HasDropDown.html
tests/_Widget-on.html
tests/tree/Tree_ObjectStoreModel.html

(cherry picked from commit 809130120f849c06f71ceadc8edeb3e2edd9db1b)

Conflicts:

_HasDropDown.js

comment:36 Changed 3 years ago by bill

  • Milestone changed from 1.8.4 to 1.7.7
Note: See TracTickets for help on using tickets.