JavaScript: Comprobar si el botón del mouse está presionado

136

¿Hay alguna manera de detectar si un botón del mouse está actualmente desactivado en JavaScript?

Sé sobre el evento "mousedown", pero eso no es lo que necesito. Algún tiempo DESPUÉS de presionar el botón del mouse, quiero poder detectar si todavía está presionado.

es posible?

TM.
fuente
14
Por qué acepta una respuesta que no responde a su pregunta. Registrar el mousedown y el mouseup es incorrecto (ya que puede mover el mouse fuera del navegador y dejar que piense que todavía está arrastrando). Llegar después de su problema y llegar a esta página es completamente inútil
Jack
@ Jack responde mi pregunta. Por favor lea mi pregunta y luego lea la respuesta. Aparentemente, más de 100 personas están de acuerdo en que fue una buena respuesta.
TM.
44
sí ... pero yo, alfred y otros 8 te estamos diciendo que rastrear mouseup y mousedown no es la forma correcta. La respuesta correcta debe incluir el análisis del objeto de evento en el controlador que elija, o el análisis de todos los eventos relacionados con el mouse (como ingresar / salir) si necesita una verificación controlada por tiempo en lugar de una verificación controlada por evento.
Jack
Esta pregunta fue formulada y respondida hace más de 7 años. No recibo una notificación cuando hay nuevas respuestas (pero sí para comentarios). Escriba una mejor respuesta y la comunidad la votará a la cabeza :) Mucha información se pone obsoleta y las cosas cambian.
TM.
2
@TM. Perdón por necro, pero ... No, esa información nunca llegará a la cima. Una persona que no responde a sí mismo, una vez aceptado, se queda en la cima para siempre. Además, "oh, muchas personas votaron por este" no significa que la respuesta sea buena; solo significa que muchas personas lo vieron, pensaron que se veía bien y dieron el voto positivo porque parecía funcionar para ellos.
Financia la demanda de Mónica el

Respuestas:

147

Con respecto a la solución de Pax: no funciona si el usuario hace clic en más de un botón de manera intencional o accidental. No me preguntes cómo sé :-(.

El código correcto debería ser así:

var mouseDown = 0;
document.body.onmousedown = function() { 
  ++mouseDown;
}
document.body.onmouseup = function() {
  --mouseDown;
}

Con la prueba como esta:

if(mouseDown){
  // crikey! isn't she a beauty?
}

Si desea saber qué botón se presiona, prepárese para hacer que mouseDown sea una matriz de contadores y contarlos por separado para botones separados:

// let's pretend that a mouse doesn't have more than 9 buttons
var mouseDown = [0, 0, 0, 0, 0, 0, 0, 0, 0],
    mouseDownCount = 0;
document.body.onmousedown = function(evt) { 
  ++mouseDown[evt.button];
  ++mouseDownCount;
}
document.body.onmouseup = function(evt) {
  --mouseDown[evt.button];
  --mouseDownCount;
}

Ahora puede verificar qué botones se presionaron exactamente:

if(mouseDownCount){
  // alright, let's lift the little bugger up!
  for(var i = 0; i < mouseDown.length; ++i){
    if(mouseDown[i]){
      // we found it right there!
    }
  }
}

Ahora tenga en cuenta que el código anterior funcionaría solo para navegadores compatibles con el estándar que le pasen un número de botón a partir de 0. IE usa una máscara de bits de los botones presionados actualmente:

  • 0 para "nada se presiona"
  • 1 para la izquierda
  • 2 por derecho
  • 4 para el medio
  • y cualquier combinación de arriba, por ejemplo, 5 para izquierda + medio

¡Ajuste su código en consecuencia! Lo dejo como ejercicio.

Y recuerde: IE usa un objeto de evento global llamado ... "evento".

Por cierto, IE tiene una función útil en su caso: cuando otros navegadores envían "botón" solo para eventos de botón del mouse (onclick, onmousedown y onmouseup), IE también lo envía con onmousemove. Entonces puede comenzar a escuchar onmousemove cuando necesite conocer el estado del botón y verificar el botón evt. Tan pronto como lo tenga, ahora ya sabe qué botones del mouse se presionaron:

// for IE only!
document.body.onmousemove = function(){
  if(event.button){
    // aha! we caught a feisty little sheila!
  }
};

Por supuesto, no obtienes nada si se hace la muerta y no se mueve.

Enlaces relevantes:

Actualización n. ° 1 : No sé por qué transfirí el documento. Será mejor adjuntar controladores de eventos directamente al documento.

Eugene Lazutkin
fuente
1
Después de la prueba, parece que evt.button de hecho no existe onmousemove con IE7 ...
TM.
55
Creo que esto no funcionará en Chrome, porque Chrome no genera eventos de mouseup si el mousedown original ocurrió en una barra de desplazamiento. Un ejemplo de este problema de Chrome / Chromium . Entonces, el botón izquierdo del mouse estaría presionado para siempre, si hay una barra de desplazamiento que alguien usa (En Chrome)
KajMagnus
1
Me encanta su solución, pero ¿qué pasa si el mouse viene de una aplicación diferente? Diga ms word y arrastre algo de texto. ¿Cómo detectará que el mouse está abajo?
Shadrack B. Orina
66
No entiendo por qué estás incrementando la matriz de mousedown en el segundo ejemplo. ¿Por qué un contador para cada botón en lugar de un bool para cada botón?
amwinter
2
Esta es una pregunta (y respuesta) realmente popular. Me sorprende que aún no haya surgido, pero no es necesario que almacene los datos del mouse. Simplemente puede conectarse event.buttonsal desencadenador de eventos que esté utilizando, sin variables externas guardadas. Hice una nueva pregunta (porque mi evento de mouseup no siempre se dispara, por lo que esta solución no funciona para mí) y obtuve esa respuesta en unos 5 minutos como máximo.
RoboticRenaissance
32

Esta es una vieja pregunta, y las respuestas aquí parecen recomendar principalmente el uso mousedowny mouseuprealizar un seguimiento de si se presiona un botón. Pero como otros han señalado, mouseupsolo se disparará cuando se realice dentro del navegador, lo que puede conducir a perder la noción del estado del botón.

Sin embargo, MouseEvent (ahora) indica qué botones se presionan actualmente:

  • Para todos los navegadores modernos (excepto Safari) use MouseEvent.buttons
  • Para Safari, use MouseEvent.which( buttonsno estará definido para Safari) Nota: whichusa números diferentes buttonspara los clics derecho y medio.

Cuando se registre document, mousemovese disparará inmediatamente tan pronto como el cursor vuelva a ingresar al navegador, por lo que si el usuario libera afuera, el estado se actualizará tan pronto como vuelva a colocar el mouse dentro.

Una implementación simple podría verse así:

var leftMouseButtonOnlyDown = false;

function setLeftButtonState(e) {
  leftMouseButtonOnlyDown = e.buttons === undefined 
    ? e.which === 1 
    : e.buttons === 1;
}

document.body.onmousedown = setLeftButtonState;
document.body.onmousemove = setLeftButtonState;
document.body.onmouseup = setLeftButtonState;

Si se requieren escenarios más complicados (botones diferentes / botones múltiples / teclas de control), consulte los documentos de MouseEvent. Cuando / si Safari levanta su juego, esto debería ser más fácil.

Jono Job
fuente
66
Este código verifica si SOLO se presiona el botón primario y requiere que todos los demás botones no estén presionados. (p. ej., si se presionan tanto primario como secundario, e.buttonsserá 1+2=3, entonces e.buttons === 1será falso). Si desea verificar si el botón primario está presionado, pero no le importa ningún otro estado de botón, haga esto:(e.buttons & 1) === 1
AJ Richardson
Tengo una situación en la que espero que durante un movimiento del mouse debería obtener el código de los botones para que sea '1' pero produce '7', todo el trabajo está en Chrome. Alguien tiene alguna idea?
Vasily Hall
@VasilyHall Al mirar los documentos de MDN MouseEvent.buttons, parece que eso 7significa que piensa que los botones Primario, Secundario y Auxiliar se están presionando juntos. No estoy seguro de por qué este sería el caso: ¿está utilizando un mouse avanzado? Si es así, quizás valga la pena intentarlo con uno básico. Si solo necesita ponerlo en marcha, puede usar una comprobación bit a bit para asegurarse de que se presiona el botón izquierdo e ignorar cualquier otro. p.ej. MouseEvent.buttons & 1 === 1.
Jono Job
Gracias, estaba usando mi JavaScript dentro de un navegador especial: el Chrome incrustado (ium?) Dentro de la aplicación Adobe Illustrator: apuesto a que la combinación de todas las diversas cosas de alguna manera conduce a un 7, aunque solo se presiona un botón . Al ver cómo esto es consistente dentro de mi aplicación, simplemente estoy haciendo una comprobación de 1 o 7 para facilitar mi interactividad. Agregaré, aunque uso el mouse de bola de seguimiento Logitech M570 (o lo que sea), registra correctamente el 1 en el navegador normal pero el 7 dentro de Illustrator.
Vasily Hall
16

Creo que el mejor enfoque para esto es mantener su propio registro del estado del botón del mouse, de la siguiente manera:

var mouseDown = 0;
document.body.onmousedown = function() { 
    mouseDown = 1;
}
document.body.onmouseup = function() {
    mouseDown = 0;
}

y luego, más adelante en tu código:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}
paxdiablo
fuente
+1, y gracias. Pensé que podría tener que recurrir a esto, pero esperaba que hubiera alguna característica que le permitiera simplemente verificar el estado directamente.
TM.
12
¿Hay alguna razón para no usar un booleano?
moala
1
@moala Creo que Int parece tener menos tipeo y, en última instancia, un rendimiento ligeramente mejor: jsperf.com/bool-vs-int
Johnathan Elmore
12

La solución no es buena. uno podría "pasar el mouse" sobre el documento, luego "pasar el mouse" fuera del navegador, y en este caso el navegador aún estaría pensando que el mouse está abajo.

La única buena solución es usar el objeto IE.event.

Alfredo
fuente
11
Veo de dónde vienes, pero tener una solución que solo funcione para IE tampoco es una buena solución.
TM.
@alfred En algunos casos, podría ser útil saber si mousemove está fuera de la ventana. If (event.target.nodeName.toLowerCase === 'html') abajo = 0;
BF
6

Sé que esta es una publicación antigua, pero pensé que el seguimiento del botón del mouse usando el mouse arriba / abajo se sentía un poco torpe, así que encontré una alternativa que puede ser atractiva para algunos.

<style>
    div.myDiv:active {
        cursor: default;
    }
</style>

<script>
    function handleMove( div ) {
        var style = getComputedStyle( div );
        if (style.getPropertyValue('cursor') == 'default')
        {
            // You're down and moving here!
        }
    }
</script>

<div class='myDiv' onmousemove='handleMove(this);'>Click and drag me!</div>

El selector activo maneja el clic del mouse mucho mejor que el mouse arriba / abajo, solo necesita una forma de leer ese estado en el evento onmousemove. Para eso necesitaba hacer trampa y confiar en el hecho de que el cursor predeterminado es "automático" y simplemente lo cambio a "predeterminado", que es lo que selecciona automáticamente por defecto.

Puede usar cualquier cosa en el objeto que devuelve getComputedStyle que puede usar como bandera sin alterar el aspecto de su página, por ejemplo, el color del borde.

Me hubiera gustado establecer mi propio estilo definido por el usuario en la sección: active, pero no pude lograr que funcione. Sería mejor si es posible.

Martín
fuente
Gracias por compartir esto. Estaba usando esta idea para una lógica de estilo de arrastrar y soltar, pero enfrenté un problema en IE y tuve que incluir una lógica adicional
Eyup Yusein
4

El siguiente fragmento intentará ejecutar la función "doStuff" 2 segundos después de que ocurra el evento mouseDown en document.body. Si el usuario levanta el botón, se producirá el evento mouseUp y cancelará la ejecución retrasada.

Aconsejaría usar algún método para la conexión de eventos entre navegadores: se configuró explícitamente las propiedades de mousedown y mouseup para simplificar el ejemplo.

function doStuff() {
  // does something when mouse is down in body for longer than 2 seconds
}

var mousedownTimeout;

document.body.onmousedown = function() { 
  mousedownTimeout = window.setTimeout(doStuff, 2000);
}

document.body.onmouseup = function() {
  window.clearTimeout(mousedownTimeout);
}

fuente
Gracias, pero este no es el comportamiento que estaba buscando (aunque puedo ver cómo mi pregunta indica que esto es lo que estoy tratando de hacer).
TM.
3

Corto y dulce

No estoy seguro de por qué ninguna de las respuestas anteriores funcionó para mí, pero se me ocurrió esta solución durante un momento eureka. No solo funciona, sino que también es muy elegante:

Añadir a la etiqueta del cuerpo:

onmouseup="down=0;" onmousedown="down=1;"

Luego pruebe y ejecute myfunction()si downes igual a 1:

onmousemove="if (down==1) myfunction();"
Stanley
fuente
44
eres nuevo, así que te ayudaré un poco, aquí. En primer lugar, tenga en cuenta su gramática en sus publicaciones: probablemente pasé más tiempo reparándola de lo que usted puso. En segundo lugar, su solución es solo otra versión de las otras enumeradas anteriormente: no es nada nuevo. En tercer lugar, su solución utiliza una técnica denominada "uso de banderas", que Thomas Hansen sugirió anteriormente. Asegúrese de revisar su gramática y de no repetir soluciones cuando publique en publicaciones anteriores sin proporcionar alguna explicación sobre por qué las otras soluciones no funcionaron para usted.
Zachary Kniebel
55
Lo hice, sin embargo, voté su solución, ya que ES válida y usted es nuevo en SO
Zachary Kniebel
2

Puede combinar @Pax y mis respuestas para obtener también la duración de la inactividad del mouse:

var mousedownTimeout,
    mousedown = 0;

document.body.onmousedown = function() {
  mousedown = 0; 
  window.clearInterval(mousedownTimeout);
  mousedownTimeout = window.setInterval(function() { mousedown += 200 }, 200);
}

document.body.onmouseup = function() {
  mousedown = 0;
  window.clearInterval(mousedownTimeout);
}

Entonces despúes:

if (mousedown >= 2000) {
  // do something if the mousebutton has been down for at least 2 seconds
}

fuente
Esa no es una mala idea, Jake. ¿Necesita borrar Intervalo () en onmouseup () antes de establecer el mousedown en 0? Tengo cuidado con el disparo de la función del temporizador entre configurarlo en 0 y detener el temporizador, dejando el tiempo de espera en 200? Del mismo modo en onmousedown.
paxdiablo
El orden de clearIntervals no va a hacer una diferencia, ya que el hilo de ejecución actual finalizará antes de que se activen los eventos (incluidos los temporizadores).
Nathaniel Reinhart
2

Debe manejar MouseDown y MouseUp y establecer alguna bandera o algo para rastrearlo "más adelante" ... :(

Thomas Hansen
fuente
2

Si está trabajando dentro de una página compleja con controladores de eventos de mouse existentes, le recomiendo manejar el evento en la captura (en lugar de la burbuja). Para hacer esto, simplemente configure el tercer parámetro de addEventListenerto true.

Además, es posible que desee verificar para event.whichasegurarse de que maneja la interacción real del usuario y no los eventos del mouse, por ejemplo elem.dispatchEvent(new Event('mousedown')).

var isMouseDown = false;

document.addEventListener('mousedown', function(event) { 
    if ( event.which ) isMouseDown = true;
}, true);

document.addEventListener('mouseup', function(event) { 
    if ( event.which ) isMouseDown = false;
}, true);

Agregue el controlador al documento (o ventana) en lugar de document.body es importante porque garantiza que los eventos de mouse fuera de la ventana aún se graben .

Micah Miller-Eshleman
fuente
1

Usando la API MouseEvent , para verificar el botón presionado, si lo hay:

document.addEventListener('mousedown', (e) => console.log(e.buttons))

Vuelta :

Un número que representa uno o más botones. Para más de un botón presionado simultáneamente, los valores se combinan (por ejemplo, 3 es primario + secundario).

0 : No button or un-initialized
1 : Primary button (usually the left button)
2 : Secondary button (usually the right button)
4 : Auxilary button (usually the mouse wheel button or middle button)
8 : 4th button (typically the "Browser Back" button)
16 : 5th button (typically the "Browser Forward" button)
NVRM
fuente
0

Usando jQuery, la siguiente solución maneja incluso el "arrastre de la página y luego suelte el caso".

$(document).mousedown(function(e) {
    mouseDown = true;
}).mouseup(function(e) {
    mouseDown = false;
}).mouseleave(function(e) {
    mouseDown = false;
});

No sé cómo maneja múltiples botones del mouse. Si hubiera una manera de iniciar el clic fuera de la ventana, luego acerque el mouse a la ventana, entonces esto probablemente tampoco funcionaría correctamente allí.

David
fuente
0

Debajo del ejemplo de jQuery, cuando el mouse está sobre $ ('elemento'), el color cambia dependiendo del botón del mouse que se presione.

var clicableArea = {
    init: function () {
        var self = this;
        ('.element').mouseover(function (e) {
            self.handlemouseClick(e, $(this));
        }).mousedown(function (e) {
            self.handlemouseClick(e, $(this));
        });
    },
    handlemouseClick: function (e, element) {
        if (e.buttons === 1) {//left button
            element.css('background', '#f00');
        }
        if (e.buttons === 2) { //right buttom
            element.css('background', 'none');
        }
    }
};
$(document).ready(function () {
    clicableArea.init();
});
Marcin Żurek
fuente
0

Como dijo @Jack, cuando mouseupsucede fuera de la ventana del navegador, no nos damos cuenta ...

Este código (casi) funcionó para mí:

window.addEventListener('mouseup', mouseUpHandler, false);
window.addEventListener('mousedown', mouseDownHandler, false);

Desafortunadamente, no obtendré el mouseupevento en uno de esos casos:

  • el usuario presiona simultáneamente una tecla del teclado y un botón del mouse, suelta el botón del mouse fuera de la ventana del navegador y luego suelta la tecla.
  • el usuario presiona dos botones del mouse simultáneamente, suelta un botón del mouse y luego el otro, ambos fuera de la ventana del navegador.
temible
fuente
-1

Bueno, no puedes comprobar si está inactivo después del evento, pero puedes comprobar si está activo ... Si está activo ... significa que ya no está inactivo: jajaja

Entonces, el usuario presiona el botón hacia abajo (evento onMouseDown) ... y después de eso, verifica si está activo (onMouseUp). Si bien no está activo, puedes hacer lo que necesites.

rogeriopvl
fuente
2
¿No es onMouseUp un evento también? ¿Cómo comprobará la "propiedad" en Mouseup? ¿O de quién es la propiedad?
Rohit
@Rohit: no verifica la propiedad, administra una bandera que indica que el evento ha sucedido ... El botón del mouse está arriba o abajo.
PhiLho
-1
        var mousedown = 0;
        $(function(){
            document.onmousedown = function(e){
                mousedown = mousedown | getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.onmouseup = function(e){
                mousedown = mousedown ^ getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.oncontextmenu = function(e){
                // to suppress oncontextmenu because it blocks
                // a mouseup when two buttons are pressed and 
                // the right-mouse button is released before
                // the other button.
                return false;
            }
        });

        function getWindowStyleButton(e){
            var button = 0;
                if (e) {
                    if (e.button === 0) button = 1;
                    else if (e.button === 1) button = 4;
                    else if (e.button === 2) button = 2;  
                }else if (window.event){
                    button = window.event.button;
                }
            return button;
        }

Esta versión de navegador cruzado funciona bien para mí.

usuario2550945
fuente