Браузер Android искажает события для двух касаний подряд

Я пытаюсь использовать JavaScript и jQuery для захвата событий касания. Но я наблюдаю очень странное поведение веб-браузера на Android 2.3.2: всякий раз, когда я касаюсь экрана, а затем быстро касаюсь другого места на экране, браузер:

  • мгновенно показывает оранжевую рамку и выделение на всем экране, и
  • посылает мне неправильные события.

Оранжевая рамка, похоже, является лишь сопутствующим симптомом одной и той же основной проблемы, поэтому я не слишком беспокоюсь о ней - она действительно удобна для того, чтобы иметь возможность определить, когда браузер что-то портит. Что я действительно хочу знать, так это как я могу последовательно получить правильные события касания для двух быстрых касаний? Я полагаю, что когда эта проблема будет решена, оранжевая рамка также исчезнет.

Далее следуют все болезненные детали, над которыми я работал до сих пор.

Вот страница, которая показывает проблему и отображает множество диагностической информации о деталях и времени каждого полученного события. Вы обязательно получите оранжевую вспышку / плохие события, если коснетесь внутри синего прямоугольника, а затем быстро коснетесь внутри черного прямоугольника.

Мой код jQuery довольно стандартен. Реализация функции log не важна; проблема в том, что браузер не вызывает ее, когда должен.

el = $('#battle');
el.on('touchstart', function(event) {
  log(event);
  return event.preventDefault();
});
el.on('touchend', function(event) {
  return log(event);
});
el.on('touchcancel', function(event) {
  return log(event);
});
el.mousedown(function(event) {
  log(event);
  return event.preventDefault();
});
return el.mouseup(function(event) {
  return log(event);
});

Более подробно о явлениях, которые я описал вначале:

Оранжевая граница и выделение: Это та же оранжевая граница и выделение, которые браузер рисует вокруг гиперссылки, когда вы нажимаете на нее. Но на странице нет гиперссылок, и браузер рисует эту оранжевую рамку вокруг всего экрана - или, точнее, вокруг внешнего

, к которому я подключаю события через jQuery.

Неправильные события: В обработчике события touchstart я вызываю event.preventDefault(), чтобы сказать браузеру не прокручивать, не синтезировать события мыши и т.д. Поэтому я ожидаю получить только события touchstart и touchend. И я получаю, для первого касания. Но вместо touchstart/touchend для второго касания я получаю все комбинации событий касания, синтезированных событий мыши и случайные touchcancel для второго касания, или даже повторяющиеся события для первого касания. Подробности ниже.

Такое поведение также возникает только в очень специфических обстоятельствах:

  • Первое касание должно быть коротким (менее ~200 мс).
  • Второе касание должно произойти быстро (менее чем через ~450 мс после touchstart первого касания).
  • Второй тап должен находиться на расстоянии не менее 150 пикселей от первого тапа (измеряется по диагонали от координат touchstart первого тапа).
  • Если я удалю свой код, который цепляет mousedown и mouseup, оранжевые прямоугольники больше не появляются. Однако события прикосновения иногда все еще искажаются.

Что касается того, что я имею в виду под искажением событий, вот что я вижу. Когда я пишу "1:", это означает, что события происходят для координат первого касания; "2:" означает координаты второго касания. Я увидел следующие модели событий (в процентах указано, сколько раз каждое из них появлялось после 100 попыток):

  • (50%) 1:touchstart 1:touchend 1:mousedown 1:mouseup (короткая задержка) 2:mousedown 2:mouseup
  • (35%) 1:touchstart 1:touchend 2:touchstart 1:mousedown 1:mouseup 2: touchend
  • (10%) 1:touchstart 1:touchend 2:touchstart 1:mousedown 1:mouseup 2:touchcancel (короткая задержка) 2:mousedown 2:mouseup
  • (3%) 1:touchstart 1:touchend 2:touchstart 2:touchend (короткая задержка) 1:mousedown 1:mouseup
  • (2%) 1:touchstart 1:touchend 1:mousedown 1:mouseup (и вообще ничего при втором нажатии)

Некоторые комбинации событий, похоже, возникают чаще в зависимости от того, как быстро я нажимаю, но я еще не определил закономерность. (Два быстрых, четких касания, похоже, чаще попадают во второй пункт, тогда как более быстрый подход с меньшим акцентом на четкость кажется более вероятным для первого пункта. Но я не определил конкретные цифры времени, которые приводят к каждому из них). Аналогично, "короткие задержки", указанные выше, могут быть в диапазоне от ~150 мс до ~400 мс; я также не проанализировал всю схему.

Если я не подключаю mousedown и mouseup, распределение будет примерно таким:

  • (40%) 1:touchstart 1:touchend 2:touchstart 2:touchcancel
  • (35%) 1:touchstart 1:touchend 2:touchstart 2:touchend (фактически желаемое поведение)
  • (25%) 1: touchstart 1:touchend (и вообще ничего для второго касания)

Таким образом, если я не подключаю события мыши, это работает в трети случаев; и если я готов сделать вид, что touchcancel означает то же самое, что и touchend, я могу добиться этого в 75% случаев. Но это все равно довольно хреново.

Альтернативы, которые я уже пробовал:

  • Я пробовал использовать jQuery Mobile события vmousedown и vmouseup, но они не всегда срабатывают для второго касания, я подозреваю, что из-за этой же основной странности событий.
  • Я мог бы полностью забыть о сенсорных событиях и использовать только синтезированные события мыши, но между физическим касанием и доставкой синтезированного события мыши обычно проходит около полусекунды, в то время как сенсорные события срабатывают немедленно, поэтому я могу быть более отзывчивым. Я также хочу предотвратить прокрутку - это игра для полного экрана, и я бы не хотел, чтобы пользователь случайно прокрутил адресную строку обратно в поле зрения и заблокировал часть игры - и выполнение preventDefault на touchstart обычно достигает этого (хотя иногда второе касание действительно способно прокрутить экран, несмотря на мое preventDefault... еще одна причина, по которой я хочу решить всю эту неразбериху с событиями).
  • Я попробовал сторонний веб-браузер (Dolphin), но у него те же проблемы с событиями. Поэтому я предполагаю, что это, вероятно, проблема с тем, как базовый WebView доставляет события скриптам.

Может ли кто-нибудь предложить способ изменить мой HTML, мои обработчики событий или что-нибудь еще, чтобы надежно получать события касания для двух быстрых касаний подряд?

9
задан Joe White 22 December 2011 в 02:38
поделиться