2015-02-18 7 views
1

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

var isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints; 

if(isTouchDevice) 
{ 
    $('body').addClass('yes-touch'); 
} 
else 
{ 
    $('body').addClass('no-touch'); 
} 

Я использую это, чтобы показывать только :hover состояния, когда он НЕ является сенсорным устройством (как большинство сенсорных устройств интерпретируют краны как зависание).

.no-touch .element:hover { 
    color: red; 
} 

Проблема заключается в том, один из наших компьютеров в офисе является экран ПК все-в-один сенсорным, что означает, что при использовании мыши парения состояние не происходит.

Есть ли способ определить, используется ли мышь на устройстве с сенсорным экраном? Другими словами, он должен иметь класс no-touch, применяемый при использовании мыши, и класс yes-touch, применяемый при использовании сенсорного экрана.

ответ

4

На сегодняшний день нет надежного и надежного способа сделать это. В Modernizr люди, в значительной степени эксперты в обнаружении признака, недавно сказал об этом:

https://github.com/Modernizr/Modernizr/issues/869#issuecomment-57891034

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

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

  1. Не делайте этого. Шутки в сторону. Просто потому, что пользователь имеет «мышь», это не означает, что у них нет нескольких других форм ввода. Вы должны попробовать действительно , чтобы избежать принятия какого-либо решения UI/UX, которое основывается на , по идее, что пользователь мыши был диаметрально противоположным пользователю сенсорного экрана (или любому другому виду, если на то пошло). Сделать вещи универсальный.
  2. Если вам нужно и заботиться только об IE 10 и 11, то IE PointerEvent стоит проверить. Поддержка ужасающая, вне этих двух (и предположительно будущих версий IE).
  3. Вы можете подключить прослушиватель к событию 'hover' на корпусе, и если это правда, то у пользователя , вероятно, есть мышь. Недостатком такого подхода является то, что события касания коротко срабатывают при наведении курсора на касание/касание, поэтому вы можете получить ложные срабатывания.
  4. sniff для мобильных агентов пользователя. Это плохая идея, и идет против самого ядра Modernizr. Пожалуйста, не делай этого.

Так что мне # 1 в значительной степени суммирует его. Однако это отвечает на ваш вопрос, но не дает вам решения. Вы упомянули «один из наших ПК в офисе ...« Это случайно одно внутреннее приложение? Я иногда сталкиваюсь с ситуациями, когда внутреннее специальное использование или одна страница может потребовать какого-либо индивидуального лечения по любой причине (например, у одного из наших сотрудников есть сенсорный AIO с прикрепленной мышью).Тогда я добавлю ?hasmouse в конец URL-адреса и предоставим пользователю ссылку на закладку. Затем внутри JavaScript после вар isTouchDevice, но прежде, чем ваш, если вставить этот код, чтобы отменить его:

if (location.search == '?hasmouse') { 
    isTouchDevice = false; 
} 

Опять же, тот вид так, без излишеств для всего внутреннего использования.

+0

Хотя это может быть позиция реформатором (по уважительной причине я должен сказать), это не означает, что никогда не бывает случая, когда это необходимо. Оп спросил, есть ли способ ... – arctelix

+1

@arctelix Рекомендация не делать этого не была декларативной из-за того, что нет возможного варианта использования. Это связано с тем, что нет надежного способа сделать это так, чтобы он работал эффективно и во всех основных браузерах на данный момент (возможно, когда-нибудь). Код, который вы опубликовали, является хорошим (и умным), но вы полагаетесь на событие <500 мс, и его подводные камни рассматриваются в связи с обсуждением Modernizr. – jwhazel

+0

Я полностью понимаю, почему модернизатор решил не делать этого и полностью согласен с тем, что они не должны этого делать, но опубликованное решение действительно работает для тех, кто хочет жить на грани. Я понимаю все теоретические проблемы с надежностью. Тем не менее, это отлично работает для меня, во всех браузерах, поддерживающих touch & mouse. Теоретически, может быть неправильный результат, но следующий прикосновение или движение мыши исправит его. Я разрабатываю на окнах с сенсорным экраном, чтобы он постоянно тестировался. Моя единственная забота - погода, в которой участвуют два дополнительных слушателя событий. – arctelix

0

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

Идея здесь состоит в том, чтобы захватить реальные события приземления, чтобы вызвать сенсорный режим и использовать mousemove для запуска режима мыши. Проблема в том, что IE не вызывает события касания, а события указателя. Самое замечательное в событиях указателей - вы можете проверить, есть ли это мышь или прикосновение!

Проблема заключается в том, что все другие браузеры запускают поддельную mousemove сразу после события касания. Это действительно безумие!

Вы можете видеть, что работать над этим codepen

// Первая проверка, если это устройство сенсорного:

this.isTouch = 'ontouchstart' in window || (navigator.msMaxTouchPoints > 0); 

// Некоторые вары нам понадобятся позже

var lastTouch = 0 
var lastCheck = 0 

// Затем настройте наших слушателей событий:

function initEvents() { 

    //handle touch/mouse devices detect mouse so that touch is toggled off 
    if (this.isTouch) { 

    $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) { 
     e = e.originalEvent 
     //browser has pointer events 
     var pe = window.PointerEvent || window.MSPointerEvent 

     // handle ie pointer events (polyfill functions are at bottom of answer) 

     if (e.type == msPointerEvent('move')) { 
     var touchEvent = msPointerType(e) == 'touch' 
     if (touchEvent) 
      lastTouch = e.timeStamp; 
     if (!this.isTouch && touchEvent) 
      return setupTouch.call(this, true) 
     else if (this.isTouch && !touchEvent) 
      return setupTouch.call(this, false) 
     } 

     // Handle all other browser touch events 
     if (e.type == "touchstart") { 
     console.log('touchstart fired') 
     lastTouch = e.timeStamp; 
     if (!this.isTouch) 
      setupTouch.call(this, true); 
     } 

     // test mouse move and set up mouse mode if real 
     else if (!pe && e.type == "mousemove" && this.isTouch) { 
     if (realMouseDown.call(this, e)) { 
      setupTouch.call(this, false) 
     } 
     } 
    }.bind(this)); 
    } 
} 
initEvents() 

// Здесь мы умны. Оказывается, поддельный мусмове будет стрелять менее чем за 500 м от касания, поэтому мы используем его для обнаружения подделок. Тогда, конечно, сделать что-то особенное для IE:

function realMouseDown(e) { 

    var touchDif = e.timeStamp - lastTouch 
    var mouseDif = e.timeStamp - lastCheck 

    // false mouse event will get fired within 500ms of a touch (touchDif > 500) 
    // (required for all browsers false mouse after touch event) 
    var real = touchDif > 500 

    lastCheck = e.timeStamp; 
    console.log('real=', real, ' mDif ='+mouseDif, ' tDif ='+touchDif) 

    return real 
} 

// Теперь некоторые IE polyfill, потому что они не могут, кажется, делают свой ум, что делать.

// IE pointer event polyfill 
function msPointerEvent(type) { 

    var n = "" 

    if (window.PointerEvent) // IE 11 
    n = 'pointer' + type 
    else if (window.MSPointerEvent) // IE 10 
    n = 'MSPointer' + type[0].toUpperCase() + type.substr(1); 
    return n 
} 

// IE pointer type polyfill 
function msPointerType(e) { 

    var pt = ['zero', 'one', 'touch', 'pen', 'mouse'] 

    return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType] 
} 

// И, наконец, делать то, что вам нужно ...

// make required changes for touch/mouse 
var $output = $('#output') 
function setupTouch(state) { 
    console.log('TouchMode=', state) 
    if (state) 
    this.isTouch = true 
    else 
    this.isTouch = false 
    $output.html('Touch mode changed to = '+state) 

} 

//First check if this is a touch device: 
 

 
this.isTouch = 'ontouchstart' in window || (navigator.msMaxTouchPoints > 0); 
 

 
// Some vars we'll need later 
 
var lastTouch = 0 
 
var lastCheck = 0 
 

 
//Then set up our event listeners: 
 

 
function initEvents() { 
 

 
    //handle touch/mouse devices detect mouse so that touch is toggled off 
 
    if (this.isTouch) { 
 

 
    $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) { 
 
     e = e.originalEvent 
 
     //browser has pointer events 
 
     var pe = window.PointerEvent || window.MSPointerEvent 
 

 
     // handle ie pointer events (polyfill functions are at bottom of answer) 
 

 
     if (e.type == msPointerEvent('move')) { 
 
     var touchEvent = msPointerType(e) == 'touch' 
 
     if (touchEvent) 
 
      lastTouch = e.timeStamp; 
 
     if (!this.isTouch && touchEvent) 
 
      return setupTouch.call(this, true) 
 
     else if (this.isTouch && !touchEvent) 
 
      return setupTouch.call(this, false) 
 
     } 
 

 
     // Handle all other browser touch events 
 
     else if (e.type == "touchstart") { 
 
     console.log('touchstart fired') 
 
     lastTouch = e.timeStamp; 
 
     if (!this.isTouch) 
 
      setupTouch.call(this, true); 
 
     } 
 

 
     // test mouse move and set up mouse mode if real 
 
     else if (!pe && e.type == "mousemove" && this.isTouch) { 
 
     if (realMouseDown.call(this, e)) { 
 
      setupTouch.call(this, false) 
 
     } 
 
     } 
 
    }.bind(this)); 
 
    } 
 
} 
 
initEvents() 
 
    // Here is where we get clever. It turns out that the fake mousemove will fire in less than 500ms of the touch so we use that to detect fakes: 
 

 
function realMouseDown(e) { 
 

 
    var touchDif = e.timeStamp - lastTouch 
 
    var mouseDif = e.timeStamp - lastCheck 
 

 
    // false mouse event will get fired within 500ms of a touch (touchDif > 500) 
 
    // (required for all browsers false mouse after touch event) 
 
    var real = touchDif > 500 
 

 
    lastCheck = e.timeStamp; 
 
    console.log('real=', real, ' mDif =' + mouseDif, ' tDif =' + touchDif) 
 

 
    return real 
 
} 
 

 
// IE pointer event polyfill 
 
function msPointerEvent(type) { 
 

 
    var n = "" 
 

 
    if (window.PointerEvent) // IE 11 
 
    n = 'pointer' + type 
 
    else if (window.MSPointerEvent) // IE 10 
 
    n = 'MSPointer' + type[0].toUpperCase() + type.substr(1); 
 
    return n 
 
} 
 

 
// IE pointer type polyfill 
 
function msPointerType(e) { 
 

 
    var pt = ['zero', 'one', 'touch', 'pen', 'mouse'] 
 

 
    return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType] 
 
} 
 

 
// make required changes for touch/mouse 
 
var $output = $('#output') 
 

 

 
function setupTouch(state) { 
 
    console.log('TouchMode=', state) 
 
    if (state) { 
 
    this.isTouch = true 
 
    $output.addClass('is-touch') 
 
    } else { 
 
    this.isTouch = false 
 
    $output.removeClass('is-touch') 
 
    } 
 
    $output.html('Touch mode changed to = ' + state) 
 

 
}
body { 
 
    pointer-evetns: none; 
 
} 
 
#output.is-touch { 
 
    background-color: blue; 
 
    color: white; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="output"> 
 
    Touch or movethe mose on the result window to change the TouchMode state. 
 
</div>

Смежные вопросы