Detecting that the browser has no mouse and is touch-only

前端 未结 24 1913
终归单人心
终归单人心 2020-11-27 09:35

I\'m developing a webapp (not a website with pages of interesting text) with a very different interface for touch (your finger hides the screen when you click) and mouse (re

相关标签:
24条回答
  • 2020-11-27 09:55

    The best idea in my opinion is the mousemove listener (currently the top answer). I believe that this method needs to be tweaked a bit. It is true that touch-based browsers emulate even the mousemove event, as you can see in this iOS discussion, so we should be a little careful.

    It makes sense that touch-based browsers will only emulate this event when the user taps the screen (the user's finger is down). This means we should add a test during our mousemove handler to see which mouse button is down (if any) during the event. If no mouse button is down, we can safely assume a real mouse is present. If a mouse button is down, the test remains inconclusive.

    So how would this be implemented? This question shows that the most reliable method to examine which mouse button is down during a mousemove is to actually listen for 3 events in document level: mousemove, mousedown and mouseup. The up and down will only set a global boolean flag. The move will perform the test. If you have a move and the boolean is false, we can assume a mouse is present. See question for exact code examples.

    One final comment.. This test isn't ideal because it can't be performed in load time. Therefore, I would use a progressive enhancement method as previously suggested. By default show a version which does not support the mouse-specific hover interface. If a mouse is discovered, enable this mode in runtime using JS. This should appear as seamless as possible to the user.

    In order to support changes in the user's configuration (ie mouse has been disconnected), you can periodically re-test. Although I believe it will be better in this case to simply notify the user about the 2 modes and let users manually switch between them (much like the mobile/desktop choice which can always be reversed).

    0 讨论(0)
  • 2020-11-27 09:55

    I spent hours figuring out this problem for my Phonegap app and I came up with this hack. It generates a console warning if the event triggered is a "passive" event, meaning it doesn't actuate any change, but it works! I would be interested in any ideas to improve or a better method. But this effectively allows my to use $.touch() universally.

    $(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 讨论(0)
  • 2020-11-27 09:55

    Would like to recommend of a script which helped me:

    I had read and tried everything suggested, without sufficient results.

    Then I investigated some more, and found this code - device.js

    I'm using this in my client's website, to detect mouse existence:
    (<html> should have desktop class) and it seems pretty good, and for touch support, i just do the regular check 'ontouchend' in document and use information from both detections to assume a specific thing I need.

    0 讨论(0)
  • 2020-11-27 09:57

    Tera-WURFL can tell you the capabilities of the device that is visiting your site by comparing the browser signature against its database. Give it a look, its free!

    0 讨论(0)
  • 2020-11-27 09:58

    @SamuelRossille No browsers that I'm aware of expose the existence of (or lack thereof) a mouse, unfortunately.

    So, with that being said, we just have to try and do the best we can with our existing option... events. I know it's not exactly what you're looking for... agreed it is currently far from ideal.

    We can do our best to figure out whether a user is using a mouse or touch at any given moment. Here is a quick and dirty example using 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');
    

    You can now bind/subscribe to usingMouse() & usingTouch() and/or style your interface with the body.mouse class. The interface will switch back and forth as soon as a mouse cursor is detected and on touchstart.

    Hopefully we'll have some better options from the browser vendors soon.

    0 讨论(0)
  • 2020-11-27 10:00

    I don't think it's possible to identify touch-only device (to my knowledge of course). The main issue is all mouse and keyboard events are fired by touch devices too. See the following example, both alerts return true for touch devices.

    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());
    
    0 讨论(0)
提交回复
热议问题