À 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
• lire la position, le bouton et les touches de modification ;
• gérer le clavier avec
• 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.
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
- Un clic produit
mousedown,mouseup, puisclick; un double-clic produit deuxclickpuis undblclick. - Dans les compteurs,
mouseentern'a été déclenché qu'une fois, alors quemouseoverl'a été trois fois : il se redéclenche en passant sur l'enfant. Pour un effet de survol, préférezmouseenter/mouseleave. ev.button: 0 = gauche, 1 = milieu, 2 = droit.contextmenupermet de remplacer le menu du clic droit.- Position :
offsetX/Ydans l'élément,clientX/Ydans la fenêtre,pageX/Ydans 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
ev.keydonne le caractère ou le nom de la touche ("a","A","Enter","ArrowLeft","Escape") : c'est presque toujours ce qu'il faut tester.ev.codedonne 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
É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 :
• Survol :
• Clavier :
• Raccourcis : touches de modification +
• 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) :
- 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 ?
- Associez les touches A Z E R T Y U I du clavier aux notes. Testez avec
ev.keypuisev.code. Un camarade avec un clavier QWERTY obtient-il le même résultat ? Lequel choisir pour un piano ? - 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 ?
- Ajoutez un effet de survol qui affiche le nom de la note. Comparez
mouseoveretmouseentersi la touche contient un<span>avec le nom. - 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.
- 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 →