JavaScript: vérifier si le bouton de la souris est enfoncé?

136

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. Quelques 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?

TM.
la source
14
Pourquoi vous acceptez une réponse qui ne répond pas à votre question. L'enregistrement de mousedown et mouseup est incorrect (car vous pouvez passer la souris en dehors du navigateur et laisser penser que vous faites toujours glisser). Venir après votre problème et atteindre cette page est complètement inutile
Jack
@Jack ça répond à ma question. Veuillez lire ma question, puis lire la réponse. Apparemment, plus de 100 autres personnes conviennent que c'était une bonne réponse.
TM.
4
oui .. mais moi, Alfred et les 8 autres vous disons que le suivi de la souris et de la descente de la souris n'est pas la bonne manière. La réponse correcte doit impliquer l'analyse de l'objet événement dans le gestionnaire de votre choix, ou l'analyse de tous les événements liés à la souris (comme l'entrée / la sortie) si vous avez besoin d'une vérification basée sur le temps au lieu d'une vérification basée sur l'événement.
Jack
Cette question a été posée et répondue il y a plus de 7 ans. Je ne reçois pas de notification lorsqu'il y a de nouvelles réponses (mais je le fais pour les commentaires). Écrivez une meilleure réponse et la communauté la votera en haut :) Beaucoup d'informations deviennent obsolètes et les choses changent.
TM.
2
@TM. Désolé pour nécro, mais ... Non, cette information ne sera jamais au sommet. Une non-réponse, une fois acceptée, reste au sommet pour toujours. De plus, "oh tant de gens ont voté pour celui-ci" ne signifie pas que la réponse est bonne; cela signifie simplement que beaucoup de gens l'ont vu, ont pensé que ça allait bien et ont obtenu le vote positif parce que cela semblait fonctionner pour eux.
Fonder le procès de Monica le

Réponses:

147

En ce qui concerne la solution de Pax: cela ne fonctionne pas si l'utilisateur clique sur plus d'un bouton intentionnellement ou accidentellement. 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 celui-ci:

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

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

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

Vous pouvez maintenant 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 fonctionnera que pour les navigateurs conformes à la norme qui vous transmettent un numéro de bouton à partir de 0. IE utilise un masque de bits des boutons actuellement enfoncés:

  • 0 pour "rien n'est pressé"
  • 1 pour gauche
  • 2 pour la droite
  • 4 pour le milieu
  • et toute combinaison de ci-dessus, par exemple 5 pour gauche + milieu

Alors ajustez votre code en conséquence! Je laisse ça 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 un "bouton" 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 avez besoin de connaître l'état du bouton et vérifier evt.button dès que vous l'avez - vous savez maintenant sur 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 la morte et ne bouge pas.

Liens pertinents:

Mise à jour n ° 1 : Je ne sais pas pourquoi j'ai repris le code de style document.body. Il sera préférable d'attacher des gestionnaires d'événements directement au document.

Eugène Lazutkin
la source
1
Après les tests, il semble que evt.button n'existe en fait pas surmousemove avec IE7 ...
TM.
5
Je pense que cela ne fonctionnera pas dans Chrome, car Chrome ne génère pas d'événements de souris si la souris d'origine s'est produite sur une barre de défilement. Un exemple , tiré de ce problème Chrome / Chromium . Donc, votre bouton gauche de la souris serait enfoncé pour toujours, s'il y a une barre de défilement que quelqu'un utilise! (Dans Chrome)
KajMagnus
1
J'adore votre solution, mais que se passe-t-il si la souris provient d'une autre application, dites ms word et glisse du texte. Comment allez-vous détecter que la souris est en panne?
Shadrack B.Orina
6
Je ne comprends pas pourquoi vous incrémentez les éléments du tableau mousedown dans le deuxième exemple. Pourquoi un compteur pour chaque bouton plutôt qu'un booléen pour chaque bouton?
amwinter
2
C'est une question (et une réponse) très populaire. Je suis surpris que cela ne se soit pas encore produit, mais vous n'avez pas du tout besoin de stocker les données de la souris. Vous pouvez simplement vous connecter event.buttonsà n'importe quel déclencheur d'événement que vous utilisez, sans variables enregistrées externes. J'ai posé une toute nouvelle question (parce que mon événement mouseup ne se déclenche pas toujours, donc cette solution ne fonctionne pas pour moi) et j'ai obtenu cette réponse dans peut-être 5 minutes.
RoboticRenaissance
32

C'est une vieille question, et les réponses ici semblent principalement préconiser l'utilisation mousedownet le mouseupsuivi de la pression sur un bouton. Mais comme d'autres l'ont souligné, mouseupne se déclenche que lorsqu'il est exécuté dans le navigateur, ce qui peut entraîner la perte de trace de l'état du bouton.

Cependant, MouseEvent (maintenant) indique quels boutons sont actuellement enfoncés:

  • Pour tous les navigateurs modernes (sauf Safari), utilisez MouseEvent.buttons
  • Pour Safari, utilisez MouseEvent.which( buttonsne sera pas défini pour Safari) Remarque: whichutilise des nombres différents de ceux buttonsdes clics droit et central.

Lorsqu'il est enregistré sur document, mousemovese déclenche immédiatement dès que le curseur rentre dans le navigateur, donc si l'utilisateur libère à l'extérieur, l'état sera mis à jour dès qu'il reviendra à l'intérieur de 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 compliqués 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.

Jono Job
la source
6
Ce code vérifie si SEUL le bouton principal est enfoncé et nécessite que tous les autres boutons ne soient pas enfoncés. (par exemple, si vous appuyez à la fois sur primaire et secondaire, ce e.buttonssera le cas 1+2=3, ce e.buttons === 1sera faux). Si vous voulez vérifier si le bouton principal est en panne, mais que vous ne vous souciez pas des autres états de bouton, procédez comme suit:(e.buttons & 1) === 1
AJ Richardson
Je me trouve dans une situation où je m'attends à ce que lors d'un déplacement de la souris, le code des boutons soit «1» mais il produit «7», - tout le travail est sur Chrome. Quelqu'un a une idée?
Vasily Hall
@VasilyHall En regardant la documentation MDN pour MouseEvent.buttons, il semblerait que cela 7signifie qu'il pense que les boutons primaire, secondaire et auxiliaire sont tous pressés ensemble. Je ne sais pas pourquoi cela serait le cas - utilisez-vous une souris avancée? Si tel est le cas, cela vaut peut-être la peine d'essayer avec un modèle basique. Si vous avez juste besoin de le faire démarrer, vous pouvez utiliser une vérification au niveau du bit pour vous assurer que le bouton gauche est enfoncé et ignorer les autres. par exemple. MouseEvent.buttons & 1 === 1.
Jono Job
Merci, j'utilisais mon JavaScript dans un navigateur spécial: le Chrome intégré (ium?) Dans l'application Adobe Illustrator - je parie que la combinaison de toutes les différentes choses conduit en quelque sorte à un 7, bien qu'un seul bouton soit enfoncé . Voyant que cela est cohérent dans mon application, je fais simplement une vérification pour 1 ou 7 pour faciliter mon interactivité. J'ajouterai, bien que j'utilise la souris trackball Logitech M570 (ou autre), elle enregistre correctement le 1 dans le navigateur normal mais le 7 à l'intérieur d'Illustrator.
Vasily Hall
16

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

puis, plus loin dans votre code:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}
paxdiablo
la source
+1, et merci. Je pensais que je devrais peut-être recourir à cela, mais j'espérais qu'il y avait une fonctionnalité qui vous permettrait simplement de vérifier l'état directement.
TM.
12
Y a-t-il une raison pour ne pas utiliser de booléen?
moala
1
@moala Je pense que Int semble moins taper, et finalement des performances légèrement meilleures: jsperf.com/bool-vs-int
Johnathan Elmore
12

la solution n'est pas bonne. on pourrait "mousedown" sur le document, puis "mouseup" en dehors du navigateur, et dans ce cas le navigateur penserait toujours que la souris est en bas.

la seule bonne solution consiste à utiliser l'objet IE.event.

Alfred
la source
11
Je vois d'où vous venez, mais avoir une solution qui ne fonctionne que pour IE n'est pas non plus une bonne solution.
TM.
@alfred Dans certains cas, il peut être utile de savoir si mousemove est hors de la fenêtre. Si (event.target.nodeName.toLowerCase === 'html') down = 0;
BF
6

Je sais que c'est un ancien article, mais je pensais que le suivi du bouton de la souris à l'aide de la souris haut / bas me semblait un peu maladroit, alors j'ai 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 bien mieux le clic de la souris que la souris haut / bas, vous avez juste besoin d'un moyen de lire cet état dans l'événement onmousemove. Pour cela, j'avais besoin de tricher et je me suis appuyé sur le fait que le curseur par défaut est "auto" et je l'ai juste changé en "default", qui est ce que sélectionne automatiquement par défaut.

Vous pouvez utiliser n'importe quoi dans l'objet renvoyé par getComputedStyle que vous pouvez utiliser comme indicateur sans perturber l'apparence de votre page, par exemple la couleur de la bordure.

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

Martin
la source
Merci d'avoir partagé ça. J'utilisais cette idée pour une logique de style glisser-déposer, mais j'ai rencontré un problème sur IE et j'ai dû inclure une logique supplémentaire
Eyup Yusein
4

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

Je vous conseillerais d'utiliser une méthode pour l'attachement d'événements entre navigateurs - la définition explicite des propriétés mousedown et mouseup a été effectuée 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);
}

la source
Merci, mais ce n'est pas tout à fait le comportement que je recherchais (même si je peux voir comment ma question indique que c'est ce que j'essaie de faire).
TM.
3

Court et doux

Je ne sais pas pourquoi aucune des réponses précédentes n'a fonctionné pour moi, mais j'ai trouvé cette solution pendant un moment eureka. Cela fonctionne non seulement, mais c'est aussi le plus élégant:

Ajouter à la balise body:

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

Ensuite, testez et exécutez myfunction()si downégal 1:

onmousemove="if (down==1) myfunction();"
Stanley
la source
4
vous êtes nouveau, alors je vais vous aider un peu, ici. Tout d'abord, faites attention à votre grammaire dans vos messages - j'ai probablement passé plus de temps à le réparer que vous n'en avez mis. Deuxièmement, votre solution n'est qu'une autre version des autres énumérées ci-dessus - ce n'est pas nouveau. Troisièmement, votre solution utilise une technique appelée «utilisation d'indicateurs», suggérée ci-dessus par Thomas Hansen. Veuillez prendre soin de vérifier votre grammaire et de ne pas répéter les solutions lorsque vous publiez des messages plus anciens sans fournir d'explications sur les raisons pour lesquelles les autres solutions n'ont pas fonctionné pour vous.
Zachary Kniebel
5
J'ai cependant voté votre solution, car elle est valide et vous êtes nouveau dans SO
Zachary Kniebel
2

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

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
}

la source
Ce n'est pas une mauvaise idée, Jake. Avez-vous besoin de clearInterval () dans onmouseup () avant de définir mousedown sur 0? Je me méfie du déclenchement de la fonction de minuterie entre le réglage sur 0 et l'arrêt de la minuterie, laissant le délai à 200? De même dans onmousedown.
paxdiablo
L'ordre des clearIntervals ne fera aucune différence car le thread d'exécution actuel se terminera avant que les événements (y compris les minuteries) ne se déclenchent.
Nathaniel Reinhart
2

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

Thomas Hansen
la source
2

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 lors de la capture (au lieu de la bulle). Pour ce faire, réglez simplement le 3ème paramètre addEventListenersur true.

De plus, vous voudrez peut-être vérifier pour event.whichvous assurer que vous gérez l'interaction réelle de l'utilisateur 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 de souris en dehors de la fenêtre sont toujours enregistrés.

Micah Miller-Eshleman
la source
1

À l'aide de l' API MouseEvent , 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)
NVRM
la source
0

En utilisant jQuery, la solution suivante gère même le «glisser hors de la page puis relâcher le cas».

$(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 souris. S'il y avait un moyen de démarrer le clic en dehors de la fenêtre, puis d'amener la souris dans la fenêtre, cela ne fonctionnerait probablement pas correctement non plus.

David
la source
0

Ci-dessous l'exemple jQuery, lorsque la souris est sur $ ('. Element'), la couleur change en fonction du bouton de la souris enfoncé.

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
la source
0

Comme dit @Jack, lorsque mouseupcela 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' mouseupévénement 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 de la souris puis l'autre, tous deux en dehors de la fenêtre du navigateur.
dreadcast
la source
-1

Eh bien, vous ne pouvez pas vérifier s'il est en panne après l'événement, mais vous pouvez vérifier s'il est en hausse ... S'il est en hausse ... cela signifie qu'il n'est plus en panne: P lol

Ainsi, l'utilisateur appuie sur le bouton vers le bas (événement onMouseDown) ... et après cela, vous vérifiez s'il est activé (onMouseUp). Même si ce n'est pas le cas, vous pouvez faire ce dont vous avez besoin.

rogeriopvl
la source
2
OnMouseUp n'est-il pas aussi un événement? Comment allez-vous vérifier la "propriété" surMouseup? Ou plutôt la propriété de qui?
Rohit
@Rohit: vous ne vérifiez pas la propriété, vous gérez un drapeau indiquant que l'événement s'est produit ... Le bouton de la souris est soit haut soit bas.
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;
        }

cette version multi-navigateurs fonctionne très bien pour moi.

user2550945
la source