ToolPal
Gros plan sur un clavier d'ordinateur

Événements clavier JavaScript : key, code, keyCode et comment les déboguer

📷 Life Of Pix / Pexels

Événements clavier JavaScript : key, code, keyCode et comment les déboguer

Un guide pratique sur les événements clavier JavaScript — pourquoi keyCode est obsolète, comment key et code diffèrent, et comment créer des raccourcis fiables qui fonctionnent sur tous les navigateurs et dispositions de clavier.

9 avril 202610 min de lecture

Ce bug, je l'ai rencontré plus d'une fois : j'écris un gestionnaire de raccourci clavier dans Chrome, tout fonctionne parfaitement, je déploie, et puis je reçois un rapport de bug de quelqu'un sur Firefox. Même code, comportement différent. Après une heure de fouille, je trouve le coupable — j'utilisais e.keyCode pour détecter la touche, et il retournait des valeurs différentes selon le navigateur et la disposition du clavier.

Ce bug est entièrement évitable. C'est pourquoi il vaut la peine de comprendre correctement les événements clavier JavaScript. Cet article parcourt le modèle complet des événements clavier — quels événements se déclenchent, quelles propriétés utiliser, lesquelles éviter, et comment créer des raccourcis qui fonctionnent vraiment partout.

Les trois événements : keydown, keypress, keyup

Quand un utilisateur appuie sur une touche, le navigateur déclenche jusqu'à trois événements dans l'ordre suivant :

  1. keydown — se déclenche immédiatement à l'appui de la touche, avant l'insertion de caractère
  2. keypress — se déclenche après keydown, mais uniquement pour les touches produisant une valeur de caractère
  3. keyup — se déclenche au relâchement de la touche

En bref : utilisez keydown pour la plupart des cas. Voici pourquoi :

keypress est obsolète. Il ne se déclenchait jamais pour les touches non imprimables comme Escape, Delete, F1-F12 ou les touches fléchées. Si votre gestionnaire de raccourci ne fonctionnait que pour les touches alphabétiques, keypress en était probablement la cause. Ne l'utilisez pas dans du nouveau code.

keyup est utile quand vous voulez réagir spécifiquement après le relâchement d'une touche — comme mettre à jour un aperçu après la saisie d'un caractère. Mais pour les raccourcis et les contrôles de jeu, keydown offre un comportement plus rapide et prévisible.

keydown a aussi l'avantage de se déclencher à répétition quand une touche est maintenue (à la vitesse de répétition du clavier OS), ce qui est exactement ce que vous voulez pour le défilement ou les déplacements d'un personnage de jeu.

document.addEventListener('keydown', (e) => {
  // C'est ici que vous voulez être
  console.log(e.key, e.code);
});

Les propriétés qui comptent vraiment

Quand un KeyboardEvent se déclenche, l'objet événement contient de nombreuses propriétés. Voici celles que vous devez connaître.

key — Ce que la touche produit

key donne la valeur chaîne de ce que la touche représente dans le contexte actuel. Pour une touche alphabétique ordinaire, c'est le caractère lui-même : "a", "A" (avec Shift), "é" (sur un clavier français). Pour les touches spéciales, c'est un nom descriptif : "Enter", "Escape", "ArrowLeft", "F5", "Backspace".

C'est la propriété à utiliser en premier. Elle tient compte de la disposition et des modificateurs, et vous dit ce que la touche signifie pour l'utilisateur.

document.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    submitForm();
  }
  if (e.key === 'Escape') {
    closeModal();
  }
  if (e.key === 'ArrowLeft') {
    goToPreviousSlide();
  }
});

Un point à noter : key est sensible à la casse et aux modificateurs. Appuyer sur a sans Shift donne "a". Avec Shift, cela donne "A". Si votre raccourci ne doit pas dépendre de la casse, normalisez :

if (e.key.toLowerCase() === 'k') {
  openCommandPalette();
}

code — Quelle touche physique a été pressée

code donne l'identifiant de la position physique de la touche sur le clavier, indépendamment des modificateurs ou de la disposition du clavier. La touche en haut à gauche de la zone alphabétique est toujours "KeyQ" — même si la disposition de l'utilisateur place "A" là (comme sur un clavier AZERTY).

Le format est cohérent : les touches alphabétiques sont "KeyA" à "KeyZ", les touches numériques sont "Digit0" à "Digit9", les touches de fonction sont "F1" à "F12".

Utilisez code quand vous vous souciez de la position physique de la touche plutôt que de ce qu'elle produit. Le cas d'usage classique est les contrôles de jeu :

document.addEventListener('keydown', (e) => {
  switch (e.code) {
    case 'KeyW':
    case 'ArrowUp':
      player.moveUp();
      break;
    case 'KeyS':
    case 'ArrowDown':
      player.moveDown();
      break;
    case 'KeyA':
    case 'ArrowLeft':
      player.moveLeft();
      break;
    case 'KeyD':
    case 'ArrowRight':
      player.moveRight();
      break;
  }
});

Utiliser code signifie que les contrôles WASD fonctionnent de la même façon quelle que soit la disposition du clavier du joueur. Sur un clavier AZERTY, la touche W est à une position différente, donc e.key donnerait "z" — mais e.code retourne toujours "KeyW" car la position physique est la même.

keyCode et which — Héritage, obsolète, à éviter

keyCode et which sont l'ancienne méthode. Ils donnent un code numérique pour la touche — 65 pour A, 13 pour Enter, 27 pour Escape. Le problème est que ces valeurs n'étaient pas cohérentes, surtout pour la ponctuation et les touches spéciales. Différents navigateurs retournaient des nombres différents, basés sur des codes de touches virtuelles Windows qui n'avaient aucune signification intuitive.

La documentation MDN marque keyCode et which comme obsolètes. Ils existent encore pour la compatibilité ascendante, mais ne les utilisez pas dans du nouveau code.

Vieux code que vous pourriez encore voir :

// Ne faites pas ça
if (e.keyCode === 13) { /* Enter */ }
if (e.which === 27) { /* Escape */ }

Équivalent moderne :

// Faites plutôt ça
if (e.key === 'Enter') { /* Enter */ }
if (e.key === 'Escape') { /* Escape */ }

charCode — Seulement dans keypress, aussi obsolète

charCode était le point de code Unicode du caractère, mais il ne fonctionnait que dans les événements keypress, et uniquement pour les caractères imprimables. Puisque keypress lui-même est obsolète, charCode l'est doublement. Utilisez simplement e.key et appelez .codePointAt(0) si vous avez besoin de la valeur Unicode.

location — Pour les touches présentes à plusieurs endroits

location indique quelle instance d'une touche a été pressée, pour les touches présentes à plusieurs endroits du clavier. C'est un nombre : 0 est la position standard, 1 est le modificateur gauche, 2 est le modificateur droit, et 3 est le pavé numérique.

e.location === 1 avec e.key === "Shift" signifie que la touche Shift gauche a été pressée. e.location === 3 avec e.key === "5" signifie que le 5 du pavé numérique a été pressé.

Touches modificatrices : Ctrl, Shift, Alt, Meta

Pour les raccourcis clavier, vous combinez généralement une touche ordinaire avec un ou plusieurs modificateurs. L'objet événement a des propriétés booléennes pour chaque modificateur :

  • e.ctrlKey — Ctrl est maintenu
  • e.shiftKey — Shift est maintenu
  • e.altKey — Alt (ou Option sur Mac) est maintenu
  • e.metaKey — Meta est maintenu (Command sur Mac, touche Windows sur Windows)
document.addEventListener('keydown', (e) => {
  // Ctrl+S (ou Cmd+S sur Mac)
  if ((e.ctrlKey || e.metaKey) && e.key === 's') {
    e.preventDefault(); // Empêche la boîte de dialogue Enregistrer du navigateur
    saveDocument();
  }

  // Ctrl+Shift+P — palette de commandes
  if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'p') {
    e.preventDefault();
    openCommandPalette();
  }

  // Alt+Left — retour
  if (e.altKey && e.key === 'ArrowLeft') {
    goBack();
  }
});

Le modèle e.ctrlKey || e.metaKey est l'approche standard pour les raccourcis multiplateformes. Sur macOS, la plupart des raccourcis utilisent Command (metaKey). Sur Windows/Linux, ils utilisent Ctrl. Ce modèle gère les deux.

Le problème des claviers internationaux

Voici un scénario qui surprend beaucoup de développeurs : votre application a un raccourci clavier, disons Ctrl+/ pour basculer les commentaires. Vous le testez sur votre clavier en-US, ça fonctionne parfaitement. Un utilisateur en France remonte un bug — le raccourci ne fonctionne pas.

Sur un clavier AZERTY, le caractère / est souvent accessible via Shift+: ou une autre combinaison. Donc e.key quand on appuie sur cette position de touche est complètement différent de ce à quoi vous vous attendez.

Deux approches pour gérer cela :

Option 1 : Utiliser e.code pour les raccourcis basés sur la position

// La touche / sur un clavier US est à une position physique spécifique
// code retournera toujours 'Slash' pour cette position
if (e.ctrlKey && e.code === 'Slash') {
  toggleComment();
}

Option 2 : Laisser les utilisateurs configurer leurs propres raccourcis

Des applications comme VS Code font cela bien — elles permettent de rebinder n'importe quel raccourci à la combinaison de touches de votre choix. Plus de travail à implémenter, mais la bonne réponse pour un outil professionnel avec une base d'utilisateurs internationale.

Accessibilité : la navigation clavier est importante

Si vous ajoutez des interactions clavier personnalisées à votre application, n'oubliez pas que la navigation clavier est une exigence d'accessibilité fondamentale. Les utilisateurs qui dépendent des lecteurs d'écran ou qui ne peuvent pas utiliser une souris dépendent de l'accès clavier.

Quelques points à garder à l'esprit :

Gestion du focus. Assurez-vous que les éléments interactifs sont focalisables (avec tabindex="0" si nécessaire) et que le focus se déplace logiquement au fil des changements d'interface. Quand vous ouvrez une modale, déplacez le focus à l'intérieur. Quand vous la fermez, renvoyez le focus à l'élément qui l'a déclenchée.

Ne piégez pas le focus (sauf dans les modales). Les utilisateurs doivent pouvoir naviguer dans l'interface avec Tab sans se bloquer.

Ne vous fiez pas uniquement aux raccourcis clavier. Les utilisateurs pourraient ne pas les découvrir. Fournissez des alternatives UI visibles pour chaque action.

Débogage avec le Keycode Viewer

Quand vous créez des interactions clavier, la partie la plus difficile est souvent de déterminer quelles valeurs le navigateur vous donne pour une frappe de touche spécifique. La documentation est utile, mais parfois vous avez juste besoin d'appuyer sur la touche et de voir la sortie.

C'est exactement ce que fait notre outil Keycode Viewer. Ouvrez-le, appuyez sur n'importe quelle touche, et il affiche immédiatement :

  • key — la valeur logique
  • code — l'identifiant de position physique
  • keyCode — la valeur numérique héritée (pour référence avec du vieux code)
  • which — l'autre propriété héritée
  • charCode — le code de caractère des événements keypress
  • location — standard/gauche/droite/pavé numérique
  • ctrlKey, shiftKey, altKey, metaKey — états des modificateurs

Particulièrement utile pour les claviers internationaux, les caractères spéciaux, ou pour comprendre pourquoi du code existant ne reconnaît pas une touche particulière.

Référence rapide

PropriétéUtilisationObsolète ?
keyNom du caractère ou de l'actionNon
codePosition physique de la toucheNon
keyCodeAucune — héritage uniquementOui
whichAucune — héritage uniquementOui
charCodeAucune — héritage uniquementOui
ctrlKeyVérifier si Ctrl est maintenuNon
shiftKeyVérifier si Shift est maintenuNon
altKeyVérifier si Alt/Option est maintenuNon
metaKeyVérifier si Cmd/Win est maintenuNon

Le modèle mental principal : utilisez e.key en premier. Il vous dit ce que la touche signifie. Utilisez e.code uniquement quand la position physique compte spécifiquement (contrôles de jeu, raccourcis indépendants de la disposition). Ne jamais utiliser keyCode, which ou charCode dans du nouveau code.

Maîtrisez cela et vos interactions clavier seront cohérentes sur tous les navigateurs, dispositions de clavier et systèmes d'exploitation. Et vous cesserez de recevoir ces rapports de bug des utilisateurs Firefox.

Questions Fréquentes

Partager

XLinkedIn

Articles associés