web-dev-qa-db-fra.com

JavaScript: Vérifiez si le bouton de la souris est enfoncé?

Existe-t-il un moyen de détecter si un bouton de la souris est actuellement enfoncé dans JavaScript?

Je connais l'événement «mousedown», mais ce n'est pas ce dont j'ai besoin. Quelque temps après avoir appuyé sur le bouton de la souris, je veux être en mesure de détecter s'il est toujours enfoncé.

Est-ce possible?

115
TM.

En ce qui concerne la solution de Pax: cela ne fonctionne pas si l’utilisateur clique sur plusieurs boutons de manière intentionnelle ou accidentelle. Ne me demandez pas comment je sais :-(.

Le code correct devrait être comme ça:

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

Avec le test comme ça:

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

Si vous voulez savoir quel bouton est enfoncé, préparez-vous à faire de mouseDown un tableau de compteurs et à les compter séparément pour des boutons distincts:

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

Maintenant, vous pouvez vérifier quels boutons ont été appuyés exactement:

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!
    }
  }
}

Sachez maintenant que le code ci-dessus ne fonctionne que pour les navigateurs conformes aux normes qui vous transmettent un numéro de bouton à partir de 0 et plus. IE utilise un masque de bits des boutons actuellement enfoncés:

  • 0 pour "rien n'est pressé"
  • 1 pour la gauche
  • 2 pour droit
  • 4 pour le milieu
  • et toute combinaison de ce qui précède, par exemple 5 pour gauche + milieu

Alors ajustez votre code en conséquence! Je le laisse comme un exercice.

Et rappelez-vous: IE utilise un objet événement global appelé… "événement".

Incidemment, IE a une fonctionnalité utile dans votre cas: lorsque d'autres navigateurs envoient "button" uniquement pour les événements de bouton de la souris (onclick, onmousedown et onmouseup), IE l'envoie également avec onmousemove. Ainsi, vous pouvez commencer à écouter onmousemove lorsque vous devez connaître l'état du bouton et rechercher evt.button dès que vous l'avez obtenu - vous savez maintenant quels boutons de la souris ont été enfoncés:

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

Bien sûr, vous n'obtenez rien si elle joue morte et ne bouge pas.

Liens pertinents:

Update # 1: je ne sais pas pourquoi j'ai transféré le code de type document.body. Il sera préférable d'attacher des gestionnaires d'événements directement au document.

130
Eugene Lazutkin

Je pense que la meilleure approche consiste à conserver votre propre enregistrement de l'état du bouton de la souris, comme suit:

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

et ensuite, plus tard dans votre code:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}
16
paxdiablo

C'est une vieille question, et les réponses ici semblent surtout préconiser d'utiliser mousedown et mouseup pour savoir si un bouton est enfoncé. Mais comme d’autres l’ont déjà fait remarquer, mouseup ne sera déclenché que s’il est exécuté dans le navigateur, ce qui peut entraîner une perte de suivi de l’état du bouton.

Cependant, MouseEvent (maintenant) indique les boutons actuellement utilisés:

  • Pour tous les navigateurs modernes (sauf Safari), utilisez MouseEvent.buttons
  • Pour Safari, utilisez MouseEvent.which (buttons sera indéfini pour Safari). Remarque: which utilise des nombres différents de buttons pour les clics droit et moyen.

Lorsqu'il est enregistré sur document, mousemove est immédiatement déclenché dès que le curseur entre à nouveau dans le navigateur. Ainsi, si l'utilisateur relâche l'utilisateur extérieur, l'état sera mis à jour dès qu'il reviendra à la souris.

Une implémentation simple pourrait ressembler à:

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 des scénarios plus complexes sont nécessaires (différents boutons/plusieurs boutons/touches de contrôle), consultez la documentation MouseEvent. Quand/si Safari élève son jeu, cela devrait devenir plus facile.

15
Jono Job

la solution n'est pas bonne ... On peut "coller la souris" sur le document, puis "mouseup" en dehors du navigateur, et dans ce cas, le navigateur penserait toujours que la souris est enfoncée.

la seule bonne solution est d'utiliser l'objet IE.event.

12
alfred

Je sais que ceci est un ancien post, mais je pensais que le suivi du bouton de la souris à l'aide de la souris haut/bas était un peu maladroit; j'ai donc trouvé une alternative qui pourrait plaire à certains.

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

Le sélecteur: active gère le clic de la souris beaucoup mieux que la souris en haut/en bas, vous avez juste besoin d’un moyen de lire cet état dans l’événement onmousemove. Pour cela, je devais tricher et me basais sur le fait que le curseur par défaut était "auto" et que je le changeais simplement pour "par défaut", qui est ce que l'auto sélectionne par défaut.

Vous pouvez utiliser tout élément de l'objet renvoyé par getComputedStyle que vous pouvez utiliser en tant qu'indicateur sans perturber l'apparence de votre page, par exemple. couleur de la bordure.

J'aurais aimé définir mon propre style défini par l'utilisateur dans la section: active, mais je ne pouvais pas le faire fonctionner. Ce serait mieux si c'est possible.

5
Martin

L'extrait de code suivant tente d'exécuter la fonction "doStuff" 2 secondes après que l'événement mouseDown se soit produit dans document.body. Si l'utilisateur lève le bouton, l'événement mouseUp se produira et annulera l'exécution différée.

Je conseillerais d'utiliser une méthode pour l'attachement d'événements entre navigateurs - le paramétrage explicite des propriétés mousedown et mouseup a été effectué pour simplifier l'exemple. 

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);
}
4
Jake Devine

Court et doux

Je ne suis pas sûr de savoir pourquoi aucune des réponses précédentes n'a fonctionné pour moi, mais j'ai proposé cette solution lors d'un moment Eureka. Non seulement ça marche, mais c'est aussi le plus élégant:

Ajouter à la balise body:

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

Puis testez et exécutez myfunction() si down est égal à 1:

onmousemove="if (down==1) myfunction();"
3
Stanley

Vous pouvez combiner @Pax et mes réponses pour obtenir également la durée pendant laquelle la souris est hors service:

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

Puis plus tard:

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

Vous devez gérer MouseDown et MouseUp et définir un indicateur ou quelque chose pour le suivre "plus tard sur la route" ... :(

2
Thomas Hansen

Dans l'exemple ci-dessous, lorsque la souris est au-dessus de $ ('. Élément'), la couleur change en fonction du bouton de la souris sur lequel vous appuyez.

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();
});
0
Marcin Żurek

Si vous travaillez dans une page complexe avec des gestionnaires d'événements de souris existants, je vous recommande de gérer l'événement sur capture (au lieu de bulle). Pour ce faire, il suffit de définir le 3ème paramètre de addEventListener sur true.

En outre, vous pouvez vérifier la présence de event.which pour vous assurer de gérer les interactions utilisateur réelles et non les événements de souris, par exemple. 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);

Ajoutez le gestionnaire au document (ou à la fenêtre) au lieu de document.body est important car il garantit que les événements mouseup hors de la fenêtre sont toujours enregistrés.

0

En utilisant MouseEvent api, pour vérifier le bouton enfoncé, le cas échéant:

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

Retour :

Un nombre représentant un ou plusieurs boutons. Pour plus d'un bouton enfoncé simultanément, les valeurs sont combinées (par exemple, 3 est primaire + secondaire).

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)
0
NVRM

Comme dit @Jack, lorsque mouseup se produit en dehors de la fenêtre du navigateur, nous n'en sommes pas conscients ...

Ce code a (presque) fonctionné pour moi:

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

Malheureusement, je n'obtiendrai pas l'événement mouseup dans l'un de ces cas:

  • l’utilisateur appuie simultanément sur une touche du clavier et un bouton de la souris, relâche le bouton de la souris en dehors de la fenêtre du navigateur, puis relâche la touche.
  • l'utilisateur appuie simultanément sur deux boutons de la souris, relâche un bouton puis l'autre, tous deux en dehors de la fenêtre du navigateur.
0
dreadcast

Avec jQuery, la solution suivante gère même le "glisser de la page puis relâcher la casse".

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

Je ne sais pas comment il gère plusieurs boutons de la souris . S'il y avait un moyen de démarrer le clic en dehors de la fenêtre, puis amener la souris dans la fenêtre, cela ne fonctionnerait probablement pas correctement là-bas non plus.

0
David