ブラウザにマウスがなく、タッチのみであることを検出する


149

タッチ(クリックすると画面が非表示になります)とマウス(ホバープレビューに大きく依存)のインターフェイスが非常に異なるWebアプリケーション(興味深いテキストのページがあるWebサイトではありません)を開発しています。ユーザーにマウスがなく、適切なインターフェースを提示できないことをどのように検出できますか?マウスとタッチの両方(一部のノートブックのように)を使用する人のためにスイッチを残すつもりです。

ブラウザーのタッチイベント機能は、実際にはユーザーがタッチデバイスを使用していることを意味しません(たとえば、Modernizrはそれを切り取りません)。質問に正しく答えるコードは、デバイスにマウスがある場合はfalseを返し、そうでない場合はtrueを返します。マウスとタッチを備えたデバイスの場合、falseを返します(タッチのみではありません)。

余談ですが、私のタッチインターフェイスはキーボードのみのデバイスにも適している可能性があります。そのため、検出したいマウスが不足していることになります。

必要性をより明確にするために、私が実装しようとしているAPIは次のとおりです。

// Level 1


// The current answers provide a way to do that.
hasTouch();

// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();

// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)

// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);

// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);


1つのアプリをデスクトップとモバイル/タッチの両方に適用したいが、それぞれに異なる動作が必要な場合は、デザインを再考する必要があると思います。Googleで「javascript検出マウス」をすばやく検索すると、マウスのさまざまな状態(クリック、位置、など)、ただし、マウスが実際に存在するかどうかの結果はZEROです。
davethegr8

24
多分それは私がここでそれを尋ねたことをグーグルが助けなかったからです。
nraynaud

2
jqueryからmouseenterのドキュメントを試しましたか?$(document).mouseenter(function(e){alert( "mouse");});
Parag Gajjar

4
ほんの数十通りの有望な手段を数分以内にそれぞれ拒否することを検討した後、この質問は私を非常に素晴らしく悩ませています。
ジョーダングレイ

回答:


65

主な問題は、次の異なるクラスのデバイス/ユースケースがあることです。

  1. マウスとキーボード(デスクトップ)
  2. タッチのみ(電話/タブレット)
  3. マウス、キーボード、タッチ(タッチラップトップ)
  4. タッチとキーボード(タブレットのBluetoothキーボード)
  5. マウスのみ(無効なユーザー/閲覧設定)
  6. キーボードのみ(無効なユーザー/閲覧設定)
  7. タッチとマウス(Galaxy Note 2ペンからのホバーイベント)

さらに悪いことに、これらのクラスの一部から別のクラスに移行したり(マウスを接続したり、キーボードに接続したり)、ユーザーが手を伸ばして画面に触れるまで、通常のラップトップにいるように見えることがあります。

ブラウザーにイベントコンストラクターが存在することは、前進するのに適した方法ではない(そして多少矛盾している)と想定するのは正しいことです。さらに、非常に具体的なイベントを追跡する場合や、上記のいくつかのクラスのみを除外する場合を除いて、イベント自体を使用することは完全な証拠ではありません。

たとえば、ユーザーが実際のマウスムーブを発したことを発見したとします(タッチイベントからの誤動作ではありません。http: //www.html5rocks.com/en/mobile/touchandmouse/を参照してください)。

じゃあ何?

ホバースタイルを有効にしますか?ボタンを追加しますか?

どちらの方法でも、イベントが発生するのを待たなければならないので、グラスに入れる時間を増やしています。

しかし、高貴なユーザーがマウスを取り外してフルタッチしたい場合はどうなりますか?詰め込まれているインターフェイスに触れるまで待ってから、混雑しているUIを特定しようとした直後に変更しますか?

箇条書きの形式で、https: //github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101でstucoxを引用

  • マウスの存在を検出したい
  • イベントが発生する前に、AEはおそらく検出できません
  • そのため、このセッションでマウスが使用されているかどうかが検出されます。ページのロードからすぐに実行されるわけではありません
  • おそらく、マウスがないことも検出できません— trueになるまで未定義になるでしょう(証明されるまでfalseに設定するよりも、これは理にかなっていると思います)
  • また、セッションの途中でマウスが切断されているかどうかを検出することはおそらくできません。これは、マウスを放棄しただけのユーザーと見分けがつかないでしょう。

余談ですが、ブラウザは、ユーザーがマウスを接続したりキーボードに接続したりしたときにそれを認識しますが、JavaScriptには公開しません。

これにより、次のようになります。

特定のユーザーの現在の機能の追跡は複雑で信頼性が低く、疑わしいメリットがあります

ただし、プログレッシブエンハンスメントの考え方は、ここでもかなり当てはまります。ユーザーのコンテキストに関係なくスムーズに機能するエクスペリエンスを構築します。次に、ブラウザーの機能/メディアクエリに基づいて想定を行い、想定されるコンテキストで相対的になる機能を追加します。マウスの存在は、さまざまなデバイスのさまざまなユーザーがあなたのWebサイトを体験する多くの方法の1つにすぎません。カーネルでメリットのあるものを作成し、人々がボタンをクリックする方法についてあまり心配しないでください。


3
素晴らしい答え。うまくいけば、ユーザーは常に画面を持っています!ユーザーの現在の対話モードにぴったり合うインターフェースを構築することは理にかなっていると思います。タッチラップトップでは、:hoverユーザーがマウスからタッチに切り替えたときにアプリ(つまり、要素など)を調整することは理にかなっています。ユーザーが現在マウスとタッチを同時に使用している可能性は低いようです(つまり、2台のマウスを同じコンピューターに接続しているようなものです)
Sebastien Lorber

@SebastienLorber-あなたにそれを壊すのは嫌いですが、ユーザー必ずしも画面を持っているとは限りません。(スクリーンリーダーがユーザーのマシンで実行されているかどうかを検出するためにJavaScriptを使用することは可能ですか?
ashleedawg

57

ドキュメントでのmousemoveイベントをリッスンしてみませんか。次に、そのイベントが聞こえるまで、デバイスがタッチまたはキーボードのみであると想定します。

var mouseDetected = false;
function onMouseMove(e) {
  unlisten('mousemove', onMouseMove, false);
  mouseDetected = true;
  // initializeMouseBehavior();
}
listen('mousemove', onMouseMove, false);

(ここで、listen及びunlisten委任するaddEventListenerか、attachEvent必要に応じて)。

うまくいけば、これが過度のビジュアルジャンクにつながることはなく、モードに基づいた大規模な再レイアウトが必要な場合はうまくいきません...


2
それは良い考えですが、残念ながら、アプリケーションのUIがマウスが利用可能かどうかに依存している場合、応答の遅延により使用できなくなります。これは、アプリケーションがiframedである可能性がある場合に特に当てはまるため、マウスイベントがヒットするのは、インラインフレーム自体の上にマウスを移動..
ジョンGjengset

7
これは、アプリケーションがスプラッシュ画面と「続行」ボタンで始まる場合に機能します。マウスが最初のmousedownイベントの前に移動する場合は、マウスがあります。ボタンがマウスの真下にロードされ、ユーザーが非常に安定した手である場合にのみ失敗します(1ピクセル移動してもピックアップされます)。
SpliFF 2012

49
素晴らしいアイデアですが、テストでは機能しないようです。iPadがこのイベントをトリガーします。
Jeff Atwood、

3
@JeffAtwoodあなたはあなたのケースで何をしてしまったのですか?
マイケルハーレン2013

2
iPadは確実にmousedownイベントの直前にmousemoveイベントをトリガーします。mousedown count> 0およびmousedown count == mousemove countは、マウスがないことを検出する良い方法であることがわかりました。これを実際のマウスで複製することはできません。
Peter Wooster

36

2018年現在、ブラウザーにマウス(または同様の入力デバイス)が搭載されているかどうかを検出するための優れた信頼できる方法があります。CSS4メディアインタラクション機能は、ほとんどすべての最新ブラウザー(IE 11と特別なモバイルブラウザーを除く)でサポートされています。

W3C:

ポインターメディア機能は、マウスなどのポインティングデバイスの存在と精度を照会するために使用されます。

次のオプションを参照してください。

    /* The primary input mechanism of the device includes a 
pointing device of limited accuracy. */
    @media (pointer: coarse) { ... }

    /* The primary input mechanism of the device 
includes an accurate pointing device. */
    @media (pointer: fine) { ... }

    /* The primary input mechanism of the 
device does not include a pointing device. */
    @media (pointer: none) { ... }

    /* Primary input mechanism system can 
       hover over elements with ease */
    @media (hover: hover) { ... }

    /* Primary input mechanism cannot hover 
       at all or cannot conveniently hover 
       (e.g., many mobile devices emulate hovering
       when the user performs an inconvenient long tap), 
       or there is no primary pointing input mechanism */
    @media (hover: none) { ... }

    /* One or more available input mechanism(s) 
       can hover over elements with ease */
    @media (any-hover: hover) { ... }


    /* One or more available input mechanism(s) cannot 
       hover (or there are no pointing input mechanisms) */
    @media (any-hover: none) { ... }

メディアクエリはJSでも使用できます。

if(window.matchMedia("(any-hover: none)").matches) {
    // do sth
}

関連:

W3ドキュメント: https //www.w3.org/TR/mediaqueries-4/#mf-interaction

ブラウザのサポート: https //caniuse.com/#search=media%20features

同様の問題:クライアントデバイスが:hoverおよび:focus状態をサポートしているかどうかを検出する


私は個人的にこの答えが好きですが、現時点(10/19)で、@ mediaホバーとポインターのCSSクエリは、caniuse.comによると世界中のデバイスの〜85%でのみ利用できます。確かに悪くない、95%以上が好ましい。うまくいけば、これはすぐにデバイスの標準になるでしょう。
MQuiggGeorgia

1
@MQuiggGeorgia基本的に私はあなたの批判に基本的に同意します、それはまだどこでもサポートされていません。それでもcaniuse.comは91.2%をサポートしていると言っています(caniuse.com/#feat=css-media-interaction)。よく見ると、IE 11とモバイル上の特別にフラット化されたブラウザーを除くすべての場所でサポートされています。Microsoftがずっと前にIE機能の実装を停止したため、公平を期すために、これはすべての最新機能に当てはまります。IE 11の場合、ここで他の回答からのフォールバックを使用できます。
Blackbam

23

@ワイアットの答えは素晴らしく、考えることをたくさん与えてくれます。

私の場合、最初のインタラクションをリッスンすることを選択しました。そのため、ユーザーがマウスを使用している場合でも、最初の操作がタッチであった場合は、タッチデバイスとして扱います。

イベントが処理される特定の順序を検討します

  1. タッチスタート
  2. タッチムーブ
  3. タッチエンド
  4. マウスオーバー
  5. マウスムーブ
  6. マウスダウン
  7. マウスアップ
  8. クリック

タッチの前にマウスイベントがトリガーされた場合、それは実際のマウスイベントであり、エミュレートされたイベントではないと想定できます。例(jQueryを使用):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

それは私のために働いた


Ipad Safari(IOS8.3)もこのスニペットでマウスを検出します
netzaffin

3
@netzaffin。フィードバックのおかげで、マウスオーバーではなくマウスダウンを使用した方が一貫性があることがわかりました。IOSからこのフィドルを見て、結果を教えていただけませんか?乾杯jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva

1
マウス付きのタッチスクリーンを使用している場合は、最初に使用された入力方法のみが検出されます。
0xcaff

11

ブラウザがタッチ対応かどうかを検出することのみが可能ですです。実際にタッチスクリーンまたはマウスが接続されているかどうかを確認する方法はありません。

ただし、タッチ機能が検出された場合は、マウスイベントではなくタッチイベントをリッスンすることにより、使用を優先できます。

タッチ機能のクロスブラウザを検出するには:

function hasTouch() {
    return (('ontouchstart' in window) ||       // html5 browsers
            (navigator.maxTouchPoints > 0) ||   // future IE
            (navigator.msMaxTouchPoints > 0));  // current IE10
}

次に、これを使用して確認できます。

if (!hasTouch()) alert('Sorry, need touch!);

または、次のいずれかをリッスンするイベントを選択します。

var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);

または、タッチと非タッチで別々のアプローチを使用します。

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
}

マウスの場合、マウスが使用されているかどうかだけを検出できます。存在しているかどうかは検出できません。使用法によってマウスが検出されたことを示すグローバルフラグを設定できます(既存の回答と同様ですが、少し簡略化されています)。

var hasMouse = false;

window.onmousemove = function() {
    hasMouse = true;
}

(これらのイベントを含めることはできません、mouseupまたはmousedownこれらのイベントはタッチによってトリガーすることもできます)

ブラウザは、使用されているシステムのハードウェア機能などの機能を検出できるようにするために必要な低レベルシステムAPIへのアクセスを制限します。

これらにアクセスするためのプラグイン/拡張機能を作成する可能性がありますが、JavaScriptとDOMを介してこのような検出は制限されており、さまざまなOSプラットフォームに固有のプラグインを作成する必要があります。

結論として、そのような検出は「良い推測」でしか推定できません。


8

ときにメディアクエリレベル4ブラウザで利用可能で、我々は、マウスを使ってデバイスを検出するために、「ポインタ」と「ホバー」クエリを使用することができるようになります。

その情報をJavaScriptに伝達したい場合は、CSSクエリを使用して、デバイスタイプに応じて特定のスタイルを設定し、次に getComputedStyle、Javascriptでしてそのスタイルを読み取り、そこから元のデバイスタイプを派生させることができます。

ただし、マウスはいつでも接続または取り外し可能で、ユーザーはタッチとマウスを切り替えたい場合があります。したがって、この変更を検出し、インターフェースを変更するか、自動的に変更する必要があるかもしれません。


1
具体的に、any-pointerそしてany-hoverあなたは、該当するすべてのデバイスの能力を調査できるようになります。将来この問題をどのように解決できるかを覗いてみてください。:)
ジョーダン・グレイ、

2
window.matchMedia( "(任意のポインタ:粗い)")。matches === true?
4esn0k

7

とにかくインターフェースを切り替える方法を提供することを計画しているので、アプリケーションの正しいバージョンを「入力」するためにリンクまたはボタンをクリックするようにユーザーに要求するだけで実現可能でしょうか?そうすれば、将来の訪問に対する彼らの好みを思い出すことができます。ハイテクではありませんが、100%信頼できます:-)


2
これは実際にはかなり良い提案ですが、ユーザーが実際のインターフェースに到達するまでの時間を遅らせます。また、最初の選択後に切り替え方法を提供する必要があります。それは簡単に検出することができれば、より多くの作業されて終わる...
ジョンGjengset

1
ユーザーに質問することは明らかに最善の方法です-常に簡単であるとは限りませんが-アップグレード通知とそうでないものを置くのに便利な場所を提供します。私は..あなたが「問題」を考える上だと思う
T4NK3R

4

@SamuelRossille残念ながら、私が認識しているブラウザーでマウスの存在(またはその欠如)を公開しているブラウザーはありません。

ですから、それが言われても、私たちは既存のオプションでできる限りのことをやってみなければなりません...イベント。それがあなたが探しているものとは正確に違うことは知っています...現在、理想からかけ離れていることに同意しました。

ユーザーがマウスを使用しているか、任意の瞬間にタッチしているかを把握するために最善を尽くすことができます。以下は、jQueryとKnockoutを使用した簡単で汚い例です。

//namespace
window.ns = {};

// for starters, we'll briefly assume if touch exists, they are using it - default behavior
ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity.  Substitute any touch detection method you desire

// now, let's sort out the mouse
ns.usingMouse = ko.computed(function () {
    //touch
    if (ns.usingTouch()) {
        //first, kill the base mousemove event
        //I really wish browsers would stop trying to handle this within touch events in the first place
        window.document.body.addEventListener('mousemove', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }, true);

        //remove mouse class from body
        $('body').removeClass("mouse");

        //switch off touch listener
        $(document).off(".ns-touch");

        // switch on a mouse listener
        $(document).on('mousemove.ns-mouse', function (e) {
            if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) {
                ns.usingTouch(false);  //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true
            }
        });

        return false;
    }
    //mouse
    else {
        //add mouse class to body for styling
        $('body').addClass("mouse");

        //switch off mouse listener
        $(document).off(".ns-mouse");

        //switch on a touch listener
        $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) });

        return true;
    }
});

//tests:
//ns.usingMouse()
//$('body').hasClass('mouse');

これで、usingMouse()およびusingTouch()にバインド/サブスクライブしたり、body.mouseクラスを使用してインターフェースのスタイルを設定したりできます。マウスカーソルが検出され、タッチスタートすると、インターフェイスは前後に切り替わります。

うまくいけば、ブラウザーベンダーからすぐにいくつかのより良いオプションがあるでしょう。


2

Tera-WURFL、ブラウザーの署名をデータベースと比較することにより、サイトにアクセスしているデバイスの機能を通知します。無料で見てみましょう!


1
これは、タッチスクリーンとマウスを備えている場合と備えていない場合があるデバイスでは機能しません。たとえば、デスクトップWindowsコンピューターはタッチスクリーンに接続されている場合がありますが、通常はマウスも備えていますが、タブレットはWindowsを実行している場合でも、マウスが接続されていない場合があります。
ジョンGjengset

@Jonhooデスクトップオペレーティングシステムにマウスが接続されていると仮定します。結局のところ、彼らはタッチスクリーンを念頭に置いて開発されなかった幅広いソフトウェアをサポートしなければなりません。
ジジ

1
プレーンWindows 8を実行しているタブレットはどうですか?またはLinux?またはAndroidを実行しているラップトップ?
Jon Gjengset

2
@Jonhoo明らかにこのアプローチは最適ではありませんが、それを(まだ)知るポータブルな方法はありません。Android搭載のラップトップを実行している場合は、タッチ対応であると想定してください。Windows8タブレットを実行している場合は、マウス対応であると想定します(OSは非タッチプログラム用にマウスをエミュレートする必要があります)。
ジジ

これは非常に古くなっているので、もう関係ありません。
エンジニア

2

タッチを感知する機能やマウスの動きに反応する機能があるかどうかを検出しませんか?

// 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);
}

4
一部のブラウザー(IE9など)は、トリガーされない場合でも関数が存在すると報告するためです。これは「正しい」動作でもあると思います。
Jon Gjengset 2012

なぜ関数を使うのですか?だけでhas_touch = 'ontouchstart' in window十分です。
vsync

まあ、少なくともOS XのChrome 47で動作します。ontouchstartを報告しません。
phreakhead 2016年

2

これは同じような状況で私のために働いた。基本的に、ユーザーがマウスを離したり、離したりせずに、一連の連続したマウスの動きが表示されるまで、ユーザーがマウスを持っていないと想定します。エレガントではありませんが、機能します。

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);

0

modenizrの機能の1つはタッチです

http://modernizr.com/docs/#features-misc

私は完全にはテストしていませんが、非常にうまく機能しているようです

また、これはmodernizrのページhttp://www.html5rocks.com/en/mobile/touchandmouse/からリンクされてい ます


これは、タッチのみでマウス機能がないかどうかではなく、タッチ機能を検出しようとします。この質問はタッチ検出とは根本的に異なります。
Jimbo Jonny

0

他の人が指摘したように、マウスを持っているかどうかを確実に検出することは信頼できません。これは、デバイスによっては簡単に変更できます。これは、少なくともドキュメントスケールでは、ブール値のtrueまたはfalseでは確実に実行できないものです。

タッチイベントとマウスイベントは排他的です。したがって、これはさまざまなアクションを実行する際にいくらか役立ちます。問題は、タッチイベントがマウスのアップ/ダウン/移動イベントに近く、クリックイベントをトリガーすることです。

あなたの質問から、プレビューするホバーを持ちたいと言います。それを超えて、私はあなたのインターフェースについて他の詳細を知りません。私はだと仮定すると、クリックが原因ホバープレビューの異なるアクションをしながら、マウスの欠如とプレビューにタップをしたいということ。

その場合は、検出に遅延アプローチをいくらか取ることができます。

onclickイベントの前には常にマウスのonmouseoverイベントがあります。マウスがクリックされた要素の上にあることに注意してください。

これは、ドキュメント全体のonmousemoveイベントで実行できます。を使用event.targetして、マウスが存在する要素を記録できます。次に、onclickイベント内で、クリックされている要素(または要素の子)の上に実際にマウスがあるかどうかを確認できます。

そこから、両方のクリックイベントに依存するか、結果に応じてAまたはBアクションを実行するかを選択できます。一部のタッチデバイスがクリックイベントを発行しない場合、Bアクションは何もできません(代わりに、ontouch *イベントに依存する必要があります)。


0

タッチ専用デバイスを特定することはできないと思います(もちろん、私の知る限り)。主な問題は、すべてのマウスイベントとキーボードイベントがタッチデバイスによっても発生することです。次の例を参照してください。両方のアラートがタッチデバイスに対してtrueを返します。

function is_touch_present() {
  return ('ontouchstart' in window) || ('onmsgesturechange' in window);
}

function is_mouse_present() {
  return (('onmousedown' in window) && ('onmouseup' in window) && ('onmousemove' in window) && ('onclick' in window) && ('ondblclick' in window) && ('onmousemove' in window) && ('onmouseover' in window) && ('onmouseout' in window) && ('oncontextmenu' in window));
}

alert("Touch Present: " + is_touch_present());
alert("Mouse Present: " + is_mouse_present());

2
Safari ipadが返さtrueれる'onmousedown' in window
vsync

0

私の意見では、最良のアイデアはmousemoveリスナーです(現在、一番上の答え)。この方法は少し調整する必要があると思います。このiOSのディスカッションでわかるように、タッチベースのブラウザーはmousemoveイベントでさえエミュレートすることは事実ですでので、少し注意する必要があります。

タッチベースのブラウザは、ユーザーが画面をタップしたとき(ユーザーの指が下がっているとき)だけこのイベントをエミュレートするのは当然です。つまり、イベント中にどのマウスボタンが押されているか(存在する場合)を確認するために、mousemoveハンドラーの間にテストを追加する必要があります。マウスボタンが1つも押されていない場合は、実際のマウスが存在すると想定できます。マウスボタンが押されている場合、テストは決定的ではありません。

では、これはどのように実装されますか?この質問は、マウスムーブ中にどのマウスボタンが押されているを確認する最も信頼できる方法は、ドキュメントレベルで3つのイベント(mousemove、mousedown、mouseup)を実際にリッスンすることであることを示しています。アップとダウンはグローバルブールフラグのみを設定します。移動はテストを実行します。動きがあり、ブール値がfalseの場合、マウスが存在すると想定できます。正確なコード例については、質問を参照してください。

最後のコメント..このテストはロード時に実行できないため、理想的ではありません。したがって、以前に提案したように、プログレッシブエンハンスメント方法を使用します。デフォルトでは、マウス固有のホバーインターフェイスをサポートしないバージョンを表示します。マウスが検出された場合は、JSを使用してランタイムでこのモードを有効にします。これは、ユーザーにとって可能な限りシームレスに見える必要があります。

ユーザーの構成の変更(つまり、マウスが切断されている)をサポートするために、定期的に再テストできます。この場合は、2つのモードについてユーザーに通知し、ユーザーが手動でモードを切り替えられるようにするほうがよいと思います(常に逆にできるモバイル/デスクトップの選択のように)。


良い回避策の提案をありがとう...解決されていない主な問題は、私はこれらの1つに頼らなければならないでしょう
Samuel Rossille

残念ながら、iPadでクリックするとマウスムーブがトリガーされます。シミュレータでのみテストされています。hasMouse()の場合、私はif(!( 'ontouchstart' in window))を使用してtrueを返しました。タッチ対応のラップトップでは機能しません。
Chris Gunawardena 14年

@Chris G-iPad地獄...(壁に頭をぶつけた)
vsync

0

さまざまなPC、Linux、iPhone、Androidスマートフォン、タブでいくつかのテストを実行しました。簡単な防弾ソリューションがないことは奇妙です。タッチがあり、マウスがないアプリケーションでも、タッチイベントとマウスイベントが存在する場合に問題が発生します。マウスのみのインスタンスとタッチのみのインスタンスをサポートしたいので、両方を処理したいのですが、これによりユーザーインタラクションが2回発生します。マウスがデバイス上にないことを知ることができる場合、偽の/挿入されたマウスイベントを無視することを知ることができます。MouseMoveが検出された場合にフラグの設定を試みましたが、一部のブラウザーは、MouseUpとMouseDownだけでなく、偽のMouseMoveもスローします。タイムスタンプを調べてみましたが、これは危険すぎると考えました。結論:偽のマウスイベントを作成したブラウザーでは、MouseDownを挿入する直前に常に1つのMouseMoveが挿入されていました。私のケースの99.99%で、実際のマウスがあるシステムで実行している場合、複数の連続したMouseMoveイベントがあります-少なくとも2つ。したがって、システムで2つのMouseMoveイベントが連続して発生するかどうかを追跡し、この条件が満たされない場合はマウスが存在しないことを宣言します。これは単純すぎると思いますが、私のすべてのテスト設定で機能します。より良い解決策が見つかるまで、これに固執すると思います。-ジムW


0

マウスの使用を検出するjQueryのシンプルなソリューション。モバイルデバイスも「mousemove」イベントをトリガーする問題を解決します。タッチスタートリスナーを追加してマウスムーブリスナーを削除するだけで、タッチ時にトリガーされなくなります。

$('body').one('touchstart.test', function(e) {
  // Remove the mousemove listener for touch devices
  $('body').off('mousemove.test');
}).one('mousemove.test', function(e) {
  // MOUSE!
});

もちろん、デバイスはまだタッチANDマウスである可能性がありますが、上記は実際のマウスが使用されたことを保証します。


0

とてもエレガントな解決策を見つけました。

// 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
    // ...
  }
});

0

同じ問題が発生しました。シングルタッチもクリックとして登録されました。上位投票の回答のコメントを読んだ後、私は自分の解決策を思いつきました:

var body = document.getElementsByTagName('body')[0];
var mouseCount = 0;

// start in an undefined state 
// (i use this to blend in elements once we decide what input is used)
var interactionMode = 'undefined';


var registerMouse = function() {
  // count up mouseCount every time, the mousemove event is triggered
  mouseCount++;

  // but dont set it instantly. 
  // instead wait 20 miliseconds (seems to be a good value for multiple move actions), 
  // if another mousemove event accoures switch to mouse as interaction 
  setTimeout(function() {
    // a touch event triggers also exactly 1 mouse move event.
    // So only if mouseCount is higher than 1 we are really moving the cursor by mouse.
    if (mouseCount > 1) {
      body.removeEventListener('mousemove', registerMouse);
      body.removeEventListener('touchend', registerTouch);

      interactionMode = 'mouse';
      console.log('now mousing');
      listenTouch();
    }

    // set the counter to zero again
    mouseCount = 0;
  }, 20);
};

var registerTouch = function() {
  body.removeEventListener('mousemove', registerMouse);
  body.removeEventListener('touchend', registerTouch);

  interactionMode = 'touch';
  console.log('now touching');
  mouseCount = 0;

  listenMouse();
};

var listenMouse = function() {
  body.addEventListener("mousemove", registerMouse);
};
var listenTouch = function() {
  body.addEventListener("touchend", registerTouch);
};

listenMouse();
listenTouch();

// after one second without input, assume, that we are touching
// could be adjusted to several seconds or deleted
// without this, the interactionMode would stay 'undefined' until first mouse or touch event
setTimeout(function() {
  if (!body.classList.contains('mousing') || body.classList.contains('touching')) {
    registerTouch();
  }
}, 1000);
/* fix, so that scrolling is possible */

html,
body {
  height: 110%;
}
Mouse or touch me

私が見つけた唯一の問題は、タッチイベントを適切に検出するために、スクロールできる必要があることです。1つのタブ(タッチ)で問題が発生する可能性があります。


0

私はPhonegapアプリでこの問題を解決するために何時間も費やし、このハックを思いつきました。トリガーされたイベントが「パッシブ」イベントである場合、コンソール警告が生成されます。つまり、変更は行われませんが、機能します。私は改善するためのアイデアや、より良い方法に興味があります。しかし、これにより$ .touch()を普遍的に使用できるようになります。

$(document).ready(function(){
  $("#aButton").touch(function(origElement, origEvent){
    console.log('Original target ID: ' + $(origEvent.target).attr('id'));
  });
});

$.fn.touch = function (callback) {
    var touch = false;
    $(this).on("click", function(e){
        if (!touch)
        {
            console.log("I click!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }else{
            touch = true;
        }
        touch = false;
    });
    $(this).on("touchstart", function(e){
        if (typeof e.touches != typeof undefined)
        {
            e.preventDefault();
            touch = true;
            console.log("I touch!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="aButton">A Button</button>


0

ここで私が目にする主な問題は、ほとんどのタッチデバイスが対応するタッチ1と一緒にマウスイベントを発生させることです(touchstart-> mousedown、touchmove-> mousemoveなど)。キーボードのみのものについては、ついに最近のものについては、それらに汎用ブラウザーがあり、MouseEventクラスの存在を検出することさえできません。

私の意見では、ここでの痛みの少ない解決策は、起動時にメニューを表示し(キーボードのみのユーザーに対して「alt」管理を使用)、おそらくlocalStorage / cookies / serversideを使用して選択肢を保存するか、次の同じ選択肢を維持することです訪問者が来る時間。


-4

このアプローチはお勧めしません。タッチスクリーンのデスクトップサイズのデバイスを検討してください。解決する必要のあるさまざまな問題があります。

マウスなしでアプリを使用できるようにしてください(ホバープレビューなし)


1
それがまさに私がやろうとしていることです。私は、タブレット(マウスなし)とマウスの両方で可能な限り最良の方法で機能するインターフェイスを作成しようとしていますが、これらのインターフェイスは必然的に大きく異なります。
Jon Gjengset

概して同意します。デバイス検出(DeviceAtlasなど)を使用し、ロード時に提供されたインターフェイスを選択することをお勧めします。
Teemu Ikonen

-4

私を助けてくれたスクリプトをお勧めしたいと思います:

私は提案されたすべてを読んで試しましたが、十分な結果はありませんでした。

その後、私はさらに調査し、このコードを見つけました-device.js

:私は、マウスの存在を検出するために、私のクライアントのウェブサイトでこれを使用しています
<html>持っていなければならないdesktopクラス)、それはかなり良いようだ、とのためのtouchサポート、私はちょうど定期点検を行う'ontouchend' in document特定の事Iの必要性を前提とするために、両方の検出から、使用する情報を。


これは、すでにこのトピックで何度も取り上げられているUAスニッフィングに相当します。Windows 8のように、マウスとタッチを備えたデバイスの場合は解決されません。また、将来の保証はありません。
Hugo Silva

私はそれを使用して、クライアントのアプリケーションであなたが言及したこの正確なケースを解決し、それはうまく機能します。それはその開発者によって維持されているので、それは将来の証拠です。
vsync 2014年

2
私が言及したケース(タッチ対応のラップトップ)は、マウスを使用できなくても、スクリプトによって「デスクトップ」として識別されます。「開発者が管理しているため、将来の証拠です」-「将来の証拠」のポイントを完全に逃したと思います。そして、もしあなたが述べたようにすべてを読んで試したなら、Gigiの答えがすでにUAスニッフィングを示唆していることに気付くでしょう。
Hugo Silva

-7

一般に、OS /ブラウザーのタイプを検出するよりも、マウスオーバー機能がサポートされているかどうかを検出する方が適切です。次の方法で簡単に実行できます。

if (element.mouseover) {
    //Supports the mouseover event
}

次のことは行わないでください。

if (element.mouseover()) {
    // Supports the mouseover event
}

後者は、その存在をチェックするのではなく、実際にメソッドを呼び出します。

詳しくは、http//www.quirksmode.org/js/support.htmlをご覧ください。


2
私はあなたの投稿から何を得るのか本当にわかりませんが、もし(( 'onmouseover' in $( 'body')[0])alert( 'onmouseover'); iPhoneにもメッセージを表示します
nraynaud '20年

1
これは、マウスオーバー機能が定義されているかどうかのみをチェックします。これは、ほとんどすべてのブラウザーで定義されています。マウスが実際に存在するかどうかは検出されません。
Jon Gjengset、2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.