Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
JavaScript

Les événements de la souris et du clavier

Les événements de la souris et du clavier. Dans cette leçon du cours JavaScript, vous apprendrez à : connaître les événements de la souris et leur ordre ; distinguer mouseenter/mouseleave et mouseover...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

Les événements de la souris et du clavier. Dans cette leçon du cours JavaScript, vous apprendrez à : connaître les événements de la souris et leur ordre ; distinguer mouseenter/mouseleave et mouseover/mouseout ; lire la position, le bouton et les touches de modification ; gérer le clavier avec key et code, et créer des raccourcis.

Chapitre 13 — Les événements · 13.3 Les événements de la souris et du clavier

🎯 Objectifs de la leçon
• connaître les événements de la souris et leur ordre ;
• distinguer mouseenter/mouseleave et mouseover/mouseout;
• lire la position, le bouton et les touches de modification ;
• gérer le clavier avec key et code, et créer des raccourcis.

Ordre des événements de la souris et du clavier
Figure 1 — L'ordre des événements.

1. La souris

📄 l3_souris.html

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css">
  <style>
    #cadre { padding: 30px; background: #e3f2fd; border-radius: 10px; }
    #cible { padding: 30px; background: #1565c0; color: #fff; border-radius: 8px; text-align: center; }
    #cible span { display: inline-block; padding: 6px 12px; background: #0d47a1; border-radius: 6px; }
  </style>
</head>
<body>
  <div id="cadre">
    <div id="cible">Zone bleue <span>avec un enfant</span></div>
  </div>
  <pre id="sortie"></pre>

  <script>
    const cible = document.querySelector("#cible");
    const compteurs = {};
    const lignes = [];
    const noter = (ev, detail = "") => {
      compteurs[ev.type] = (compteurs[ev.type] ?? 0) + 1;
      lignes.push(`${ev.type.padEnd(12)} ${detail}`);
      document.querySelector("#sortie").textContent =
        lignes.slice(-8).join("\n") + "\n\nCompteurs : " + JSON.stringify(compteurs);
    };

    // Entrer / sortir : mouseenter ne se répète pas pour les enfants, mouseover si
    cible.addEventListener("mouseenter", (ev) => noter(ev));
    cible.addEventListener("mouseleave", (ev) => noter(ev));
    cible.addEventListener("mouseover", (ev) => noter(ev, `sur <${ev.target.tagName.toLowerCase()}>`));

    // Les clics : mousedown → mouseup → click (→ dblclick au 2e clic rapide)
    cible.addEventListener("mousedown", (ev) => noter(ev, `bouton ${ev.button}`));
    cible.addEventListener("mouseup", (ev) => noter(ev));
    cible.addEventListener("click", (ev) => noter(ev, `detail = ${ev.detail}`));
    cible.addEventListener("dblclick", (ev) => noter(ev));

    // Clic droit : menu contextuel
    cible.addEventListener("contextmenu", (ev) => {
      ev.preventDefault(); // pas de menu du navigateur
      noter(ev, "menu du navigateur bloqué");
    });

    // Position, avec les touches de modification
    cible.addEventListener("mousemove", (ev) => {
      cible.firstChild.textContent = `x = ${ev.offsetX}, y = ${ev.offsetY}${ev.shiftKey ? " (Maj)" : ""} `;
    });
  </script>
</body>
</html>

Après une entrée dans la zone, un passage sur l'enfant, un double-clic puis un clic droit
Après une entrée dans la zone, un passage sur l'enfant, un double-clic puis un clic droit

  • Un clic produit mousedown, mouseup, puis click; un double-clic produit deux click puis un dblclick.
  • Dans les compteurs, mouseenter n'a été déclenché qu'une fois, alors que mouseover l'a été trois fois : il se redéclenche en passant sur l'enfant. Pour un effet de survol, préférez mouseenter/mouseleave.
  • ev.button: 0 = gauche, 1 = milieu, 2 = droit. contextmenu permet de remplacer le menu du clic droit.
  • Position : offsetX/Y dans l'élément, clientX/Y dans la fenêtre, pageX/Y dans la page entière.

2. Le clavier

📄 l3_clavier.html

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css">
  <style>
    #touche { font-size: 42px; font-weight: 700; text-align: center; padding: 16px; background: #263238; color: #fff; border-radius: 10px; }
  </style>
</head>
<body>
  <p>Appuyez sur des touches (essayez Ctrl + S, les flèches, Échap, Maj + A).</p>
  <div id="touche">…</div>
  <pre id="sortie"></pre>

  <script>
    const lignes = [];
    document.addEventListener("keydown", (ev) => {
      // ev.key  : le CARACTÈRE ou le nom de la touche ("a", "A", "Enter", "ArrowLeft", "Escape")
      // ev.code : la POSITION physique sur le clavier ("KeyQ" pour la touche A d'un clavier AZERTY)
      const mods = ["ctrlKey", "shiftKey", "altKey", "metaKey"].filter((m) => ev[m]).map((m) => m.replace("Key", ""));
      document.querySelector("#touche").textContent = ev.key === " " ? "Espace" : ev.key;

      // Raccourci clavier : Ctrl + S (ou Cmd + S sur Mac)
      if ((ev.ctrlKey || ev.metaKey) && ev.key.toLowerCase() === "s") {
        ev.preventDefault(); // empêche « Enregistrer la page sous »
        lignes.push("→ raccourci Ctrl + S intercepté : brouillon enregistré");
      }
      if (ev.key === "Escape") lignes.push("→ Échap : on fermerait une fenêtre modale");

      lignes.push(`key = ${JSON.stringify(ev.key).padEnd(12)} code = ${ev.code.padEnd(12)} ` +
                  `${mods.length ? "+ " + mods.join(" + ") : ""}${ev.repeat ? " (répétée)" : ""}`);
      document.querySelector("#sortie").textContent = lignes.slice(-9).join("\n");
    });
  </script>
</body>
</html>

Après les touches a, Maj + A, ←, Ctrl + S et Échap
Après les touches a, Maj + A, ←, Ctrl + S et Échap

  • ev.key donne le caractère ou le nom de la touche ("a", "A", "Enter", "ArrowLeft", "Escape") : c'est presque toujours ce qu'il faut tester.
  • ev.code donne la position physique : sur un clavier AZERTY, la touche A a pour code "KeyQ". Utile pour les jeux (touches ZQSD/WASD).
  • ctrlKey, shiftKey, altKey, metaKey (touche Cmd sur Mac) indiquent les touches de modification ; repeat, une touche maintenue.
  • Pour un raccourci comme Ctrl + S, preventDefault() empêche l'action du navigateur (« Enregistrer sous »).
⚠️ Attention
Écoutez le clavier sur document pour un raccourci global, ou sur un champ pour une saisie. Un <div> ne reçoit les touches que s'il peut avoir le focus (attribut tabindex="0"). Et n'oubliez pas les utilisateurs sans souris : tout ce qui se fait au clic doit être possible au clavier.
ℹ️ À retenir
• Souris : mousedown → mouseup → click (→ dblclick) ; contextmenu pour le clic droit.
• Survol : mouseenter/mouseleave (sans les enfants) plutôt que mouseover/mouseout.
• Clavier : keydown/keyup; ev.key (caractère), ev.code (position) ; plus de keyCode.
• Raccourcis : touches de modification + preventDefault().

🛠 Activité 3 — Un piano virtuel

Mission : Créez un clavier de piano de 8 touches (do ré mi fa sol la si do) jouable à la souris et au clavier de l'ordinateur.

Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :

  1. Chaque touche s'enfonce visuellement tant que le bouton de la souris est maintenu. Quels événements utilisez-vous ? Que se passe-t-il si l'on relâche la souris en dehors de la touche ? Comment le gérer ?
  2. Associez les touches A Z E R T Y U I du clavier aux notes. Testez avec ev.key puis ev.code. Un camarade avec un clavier QWERTY obtient-il le même résultat ? Lequel choisir pour un piano ?
  3. Si l'on maintient une touche enfoncée, la note se rejoue en boucle. Quelle propriété de l'événement permet de l'éviter ?
  4. Ajoutez un effet de survol qui affiche le nom de la note. Comparez mouseover et mouseenter si la touche contient un <span> avec le nom.
  5. Ajoutez le raccourci Ctrl + R pour « enregistrer » une mélodie (au lieu de recharger la page). Est-ce une bonne idée de détourner un raccourci connu du navigateur ? Proposez-en un autre.
  6. Bonus : jouez un vrai son avec new Audio("do.mp3").play() ou l'API Web Audio.

Je vérifie / je rends :

  • ☐ Le piano jouable à la souris et au clavier.

← 13.2 Les gestionnaires d'événements : addEventListener et l'objet Event13.4 La propagation des événements : bubbling, capture et stopPropagation →