views:

285

answers:

3

Hello,

On mouse-down (and up) I need to check which mouse button has changed its state. This is pretty easy with the W3C model and even the old netscape way (event.which) but IE gives me a headache. I know that event.button in IE is a bitmask but the problem is that I can't find out which button was pressed from this bitmask. If IE gives me event.button == 3 then I can't tell if the user pressed the left button while the right button was already down or if the user pressed the right button while the left button was already down.

To solve this problem once and for all I'm searching for a nice generic solution to convert the broken IE event into a W3C compatible event. Maybe someone already did that and wants to share?

A: 

This article may be of some help:

How to equalize the IE and W3C event models

Todd Moses
Unfortunately not. This article is about the event models itself but not about the different meanings of the "button" attribute in mouse events.
kayahr
+1  A: 

You may find this page useful: http://unixpapa.com/js/mouse.html. It has a section on mouse button detection that I have used before and found useful and accurate, including the following:

While there is no browser-independent way to recognize which mouse button is which for all the browsers surveyed, you can come extremely close. The following test works for all browsers except Opera 7. (It mixes up the right and middle mouse buttons in Opera 7, but Opera 7 is pretty old, there were only a few versions where the right and middle buttons even worked, and then only if the user set an obscure option, so you really don't care.) It also doesn't correctly handle simultaneous clicks of multiple mouse buttons in IE. To do that your application needs to track which buttons were reported to be down in previous mousedown events so it can figure out which one was added.

if (event.which == null)
   /* IE case */
   button= (event.button < 2) ? "LEFT" :
             ((event.button == 4) ? "MIDDLE" : "RIGHT");
else
   /* All others */
   button= (event.which < 2) ? "LEFT" :
             ((event.which == 2) ? "MIDDLE" : "RIGHT");
Tim Down
That's fine for detecting single mouse clicks. But as the text already says it doesn't work with simultaneous clicks. And the tracking of the mouse buttons which is mentioned in text is exactly what I'm searching for.
kayahr
Well, it suggests a workaround for that: "To do that your application needs to track which buttons were reported to be down in previous mousedown events so it can figure out which one was added", which isn't too hard.
Tim Down
I know. I was hoping for some actual code because this isn't as trivial as it sounds. Andy E already has provided some code but as he said himself the code is easily confused when some events are not coming (which happens quite often especially in IE (Just think of a double click which sends one mouse down and two mouse up events...))
kayahr
You're right, it's quite a mess, and as Andy E mentions, there's lots of things that could go wrong. Another I would add is the possibility of the user pressing a mouse button on the document and releasing it again outside the document, thus leaving the variable that tracks which mouse buttons are pressed in the wrong state. I don't think there's an easy solution.
Tim Down
+2  A: 

IMO (and quirksmode's), IE's bitmasking is better than the W3C version because you can detect combo clicks, like left+right or middle+left. It offers a bit more flexibility. Both (total buttons pressed and newest button pressed) would be even better.

I don't know of a library or script that already does what you're trying to do, I think most devs would just ignore combo clicks unless they wanted to apply a specific action to a combo click. Also, it's rather tricky, you'd have to detect both onmousedown and onmouseup for the entire document and record the state of the mouse buttons. Then on the element you want to work your magic on, subtract the previous mouse state from the new one. Something like (tested):

if (document.attachEvent)
{
    (function ()
    {
        var mState = 0;
        document.documentElement.attachEvent("onmousedown", function () 
        {
            mState += event.button;
        });
        document.documentElement.attachEvent("onmouseup", function () 
        {
            mState -= event.button;
        });
        document.getElementById("jim").attachEvent("onmousedown", function ()
        {
            var realButton = event.button - mState;

            alert(realButton); 
            // Your code here
        });
    })();
}

Of course, there are only about a million things that could go wrong with this script. For instance, in my example there I have an alert window that pops up with the real button state. If you release the button whilst that alert dialog is up, the document won't detect the mouseup and it will throw everything out of whack. Likewise, any mouseup or mousedown events on other elements that stop propagation up to the documentElement's event handler would cause it to break.

If you want my advice, display a message on a combo mouse click, guess at the "correct" mouse button or ignore them all together. Any one of those options is better than a hacky approach.

Andy E
The bitmasking is NOT better. There is no need to detect simultaneous mouse events in ONE event because each button already sends its own mousedown event. So in IE you get duplicate events. First it tells you you pressed the LEFT button and then it tells you you pressed the LEFT+RIGHT button but the only thing you did was pressing the RIGHT button without releasing the LEFT one. That makes a huge difference. It works perfectly well with the W3C model or even with the old netscape one. But in IE it's pain-in-the-ass.
kayahr
@kayahr: Unfortunately, I'm working from a laptop and don't have a third mouse button to test with. Pressing one button then the other causes the behavior you're suggesting. Pressing both *at exactly the same time* triggers a middle-click. I always thought the same was true of two other buttons - left+middle at exactly the same time should trigger one event with a button value of 5. I would argue that bitmasking, whilst not helpful for what your trying to do, offers more flexibility on the whole. For instance, it allows for a web app to provide shortcuts on combo button clicks.
Andy E