Avant que nous en arrivions au clavier, veuillez noter que sur des appareils modernes il y a d’autres manières de “récupérer quelque chose". Par exemple, les gens utilisent la reconnaissance vocale (en particulier sur les appareils mobiles) oubien le copier/coller avec la souris.
Donc si nous voulons contrôler une entrée dans un champ <input>
, alors les évènements du clavier ne sont pas assez suffisants. Il y a un autre évènement nommé input
pour gérer les changements d’un champ <input>
, par n’importe quelle moyen. Et il peut être un meilleur choix pour une telle tâche. Nous allons traiter cela plus tard dans le chapitre Les événements: change, input, cut, copy, paste.
Les évènements du clavier doivent être utilisés lorsqu’on veut gérer les actions sur le clavier (Le clavier virtuel compte aussi). Par exemple, pour réagir sur les touches de directions Up et Down oubien les touches de raccourcis (y compris les combinaisons de touches).
Teststand
Pour mieux comprendre les évènements du clavier, vous pouvez utiliser le teststand en bas.
Essayez les différentes combinaisons de touches dans la zone de texte.
kinput.onkeydown = kinput.onkeyup = kinput.onkeypress = handle;
let lastTime = Date.now();
function handle(e) {
if (form.elements[e.type + 'Ignore'].checked) return;
area.scrollTop = 1e6;
let text = e.type +
' key=' + e.key +
' code=' + e.code +
(e.shiftKey ? ' shiftKey' : '') +
(e.ctrlKey ? ' ctrlKey' : '') +
(e.altKey ? ' altKey' : '') +
(e.metaKey ? ' metaKey' : '') +
(e.repeat ? ' (repeat)' : '') +
"\n";
if (area.value && Date.now() - lastTime > 250) {
area.value += new Array(81).join('-') + '\n';
}
lastTime = Date.now();
area.value += text;
if (form.elements[e.type + 'Stop'].checked) {
e.preventDefault();
}
}
#kinput {
font-size: 150%;
box-sizing: border-box;
width: 95%;
}
#area {
width: 95%;
box-sizing: border-box;
height: 250px;
border: 1px solid black;
display: block;
}
form label {
display: inline;
white-space: nowrap;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<form id="form" onsubmit="return false">
Prevent default for:
<label>
<input type="checkbox" name="keydownStop" value="1"> keydown</label>
<label>
<input type="checkbox" name="keyupStop" value="1"> keyup</label>
<p>
Ignore:
<label>
<input type="checkbox" name="keydownIgnore" value="1"> keydown</label>
<label>
<input type="checkbox" name="keyupIgnore" value="1"> keyup</label>
</p>
<p>Mettre le focus sur le champ d'entrée et appuyer une touche.</p>
<input type="text" placeholder="Press keys here" id="kinput">
<textarea id="area" readonly></textarea>
<input type="button" value="Clear" onclick="area.value = ''" />
</form>
<script src="script.js"></script>
</body>
</html>
Keydown et keyup
Les évènements keydown
surviennent lorsqu’une touche est appuyée, et ensuite intervient keyup
– lorsqu’elle est relâchée.
event.code et event.key
La propriété key
de l’objet évènement permet d’obtenir un caractère, tandis que la propriété code
de l’objet évènement objet permet d’obtenir le “code de la touche physique”.
Par exemple, la même touche Z peut être appuyée avec ou sans Shift. Cela nous donne deux caractères différents : minuscule z
et majuscule Z
.
La propriété event.key
est exactement le caractère, et il sera diffèrent. Cependant event.code
est la même:
Touche | event.key |
event.code |
---|---|---|
Z | z (minuscule) |
KeyZ |
Shift+Z | Z (majuscule) |
KeyZ |
Si un utilisateur travaille avec des langues différentes, alors le fait de changer vers une autre langue aura pour effet de créer un caractère totalement diffèrent de "Z"
. Cela va devenir la valeur de event.key
, tandis que event.code
est toujours la même que: "KeyZ"
.
Chaque touche a un code qui dépend de sa position sur le clavier. Les codes des touches sont décrits dans le document Spécification des codes des évènements Interfaces Utilisateurs.
Par exemple:
- Les touches des lettres ont des codes de type:
"Key<letter>"
:"KeyA"
,"KeyB"
etc. - Les touches numériques ont des codes de type:
"Digit<number>"
:"Digit0"
,"Digit1"
etc. - Les touches spéciales sont codées par leurs noms:
"Enter"
,"Backspace"
,"Tab"
etc.
Il existe plusieurs formats de claviers usuels, différents de par la présentation, et la spécification donne des codes pour les touches pour chacun d’entre eux.
voir la section alphanumérique de la specification pour plus de codes, ou essayez juste le teststand au-dessus.
"KeyZ"
, pas "keyZ"
Semble être évident, mais beaucoup de gens font toujours des fautes.
S’il vous plait éviter les fautes de frappes: c’est KeyZ
, pas keyZ
. Le control tel que event.code=="keyZ"
ne vas pas fonctionner: la première lettre de "Key"
doit être une majuscule.
Et si une touche ne donne aucun caractère ? Par exemple, Shift ou F1 ou autres. Pour ces touches, event.key
est approximativement la même chose que event.code
:
Key | event.key |
event.code |
---|---|---|
F1 | F1 |
F1 |
Backspace | Backspace |
Backspace |
Shift | Shift |
ShiftRight or ShiftLeft |
Veuillez noter que event.code
spécifie exactement quelle touche est appuyée. Par exemple, la plupart des claviers ont deux touches de Shift: à gauche et à droite. La propriété event.code
nous dit exactement laquelle fut appuyée, et event.key
est responsable de la " signification " de la touche: comment il s’agit d’un (“Shift”).
Disons, nous voulons gérer un raccourci : Ctrl+Z (ou Cmd+Z pour Mac). La plupart des éditeurs accrochent l’action du “Defaire” sur cette touche. Nous pouvons mettre un écouteur lorsqu’on déclenche l’évènement keydown
et chercher à savoir quelle touche est appuyée.
Il existe un dilemme ici: Dans cet écouteur d’évènement, devons-nous contrôler la valeur de event.key
oubien event.code
?
D’une part, la valeur de event.key
est un caractère, elle change en fonction de la langue. Si le visiteur a plusieurs langues dans le système d’exploitation et bascule entre elles, la même clé donne des caractères différents. Il est donc logique de vérifier event.code
, c’est toujours pareil.
Ainsi:
document.addEventListener('keydown', function(event) {
if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
alert('Undo!')
}
});
D’autre part, il existe un problème avec event.code
. Pour des dispositions de clavier différentes, la même touche peut avoir des caractères différents.
Par exemple, voici la disposition du clavier Américain (“QWERTY”) et Allemand (“QWERTZ”) dessous (de Wikipedia) :
Pour la même touche, le clavier Américain a un “Z”, tandis que celui Allemand a un “Y” (les lettres sont échanges).
Donc, event.code
sera égal à KeyZ
pour les gens utilisant le clavier Allemand lorsqu’ils appuient sur Y.
Si on vérifie event.code == 'KeyZ'
dans notre code, alors pour les personnes avec la disposition allemande ce genre de test passera quand ils appuient sur Y.
Cela semble être bizarre, mais c’est ainsi. La specification mentionne explicitement ce comportement.
Donc, event.code
peut correspondre à un caractère incorrect pour une disposition inattendue. Les mêmes lettres dans différentes disposition peuvent mapper sur différentes clés physiques, conduisant à des codes différents. Heureusement, cela ne se produit qu’avec plusieurs codes, par exemple keyA
, keyQ
, keyZ
(comme nous l’avons vu), et ne se produit pas avec des touches spéciales telles que Shift
. Vous pouvez trouver la liste dans la specification.
Pour suivre de manière fiable les caractères dépendant de la disposition, event.key
peut être un meilleur moyen.
D’un autre côté, event.code
a l’avantage de rester toujours le même, lié à l’emplacement de la clé physique. Ainsi, les raccourcis clavier qui en dépendent fonctionnent bien même en cas de changement de langue.
Voulons-nous gérer des clés dépendantes de la disposition ? Alors event.key
est la voie à suivre.
Ou voulons-nous un raccourci clavier même après un changement de langue ? Alors, event.code
peut être une meilleure option.
Auto-repeat
Si une touche est appuyée assez longtemps, elle commence la répétition avec la propriété “auto-repeat”: l’évènement keydown
se déclenche de manière répétitive, et ensuite lorsqu’elle est relâchée nous obtenons finalement l’évènement keyup
. Donc c’est normal d’avoir plusieurs keydown
et un unique évènement keyup
.
Pour les évènements déclenchés par auto-repeat, l’évènement objet a une propriété event.repeat
dont la valeur est assignée à true
.
Actions par défaut
Les actions par défaut varient, comme il y a beaucoup de possibilités pouvant être initiées par le clavier.
Pa exemple:
- Un caractère apparait sur l’écran (le résultat le plus évident).
- Un caractère est supprimé (Delete key).
- Une page est défilée (PageDown key).
- Le navigateur ouvre la boite de dialogue “Sauvegarder la Page” dialog (Ctrl+S)
- …ainsi de suite.
L’empêchement de l’action par défaut à l’évènement keydown
peut annuler la plupart d’entre elles, à l’exception des touches spéciales spécifiques aux systèmes d’exploitations. Par exemple, sur Windows Alt+F4 ferme la fenêtre en cours du navigateur. Et il n’existe aucun moyen de l’arrêter en empêchant l’action par défaut JavaScript.
Par exemple, la balise <input>
en bas s’attend à recevoir un numéro de téléphone, alors elle n’accepte que les touches numériques, +
, ()
oubien -
:
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') || ['+','(',')','-'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
Le gestionnaire onkeydown
utilise ici checkPhoneKey
pour vérifier la touche enfoncée. S’il est valide (de 0..9
ou l’un des +-()
), alors il renvoie true
, sinon false
.
Comme nous le savons, la valeur false
renvoyée par le gestionnaire d’événements, attribuée à l’aide d’une propriété DOM ou d’un attribut, comme ci-dessus, empêche l’action par défaut, donc rien n’apparaît dans le <input>
pour les clés qui ne passent pas le test. (La valeur ‘true’ renvoyée n’affecte rien, seul le renvoi de ‘false’ compte)
Veuillez noter que les touches spéciales, telles que Backspace, Left, Right, ne fonctionnent pas dans l’input. C’est un effet secondaire du filtre strict checkPhoneKey
. Ces clés lui font retourner false
.
Détendons un peu le filtre en autorisant les touches fléchées Left, Right et Delete, Backspace :
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') ||
['+','(',')','-','ArrowLeft','ArrowRight','Delete','Backspace'].includes(key);
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
maintenant les flèches et la suppression marchent bien.
Même si nous avons le filtre de clavier, on peut toujours entrer n’importe quoi à l’aide d’une souris et faire un clic droit + Coller. Les appareils mobiles offrent d’autres moyens de saisir des valeurs. Le filtre n’est donc pas fiable à 100%.
L’approche alternative serait de suivre l’événement oninput
– il se déclenche après toute modification. Là, nous pouvons vérifier le nouveau input.value
et le modifier/mettre en surbrillance le <input>
lorsqu’il est invalide. Ou nous pouvons utiliser les deux gestionnaires d’événements ensemble.
Héritage
Dans le passé, il y’avait un évènement keypress
, et aussi les propriétés keyCode
, charCode
, which
de l’objet évènement.
Il y avait tellement d’incompatibilités au niveau des navigateurs en travaillant avec eux que les développeurs de la spécification n’avaient autre moyen que de les déprécier tous et d’en créer de nouveaux et plus modernes (tels que ceux décrits en haut dans ce chapitre). L’ancien code marche encore, étant donné que les navigateurs continuent de les supporter, mais nous n’avons nullement besoin de les utiliser maintenant.
Claviers mobiles
Lors de l’utilisation de claviers virtuels / mobiles, officiellement appelés IME (Input-Method Editor), la norme W3C indique qu’un KeyboardEvent e.keyCode
devrait être 229
et e.key
devrait être "Unidentified"
.
Bien que certains de ces claviers puissent toujours utiliser les bonnes valeurs pour e.key
, e.code
, e.keyCode
, … lorsque vous appuyez sur certaines touches telles que les flèches ou le retour arrière, il n’y a aucune garantie, donc la logique de votre clavier peut ne pas toujours fonctionner sur les appareils mobiles.
Résumé
Le fait d’appuyer sur une touche génère toujours un évènement du clavier, que cela soit une touche de symbole ou des touches spéciales telles que Shift oubien Ctrl et ainsi de suite. La seule exception est la touche Fn qui est dès fois présente sur un clavier d’ordinateur portable. Il n’y a pas d’évènement de clavier pour cela, parce que cela est implémenté à un niveau plus bas que celui du system d’exploitation.
Les Evènements du Clavier:
keydown
– en appuyant sur la touche (auto-repeats répète automatiquement si un appui long de la touche est effectué),keyup
– en relâchant la touche.
Les propriétés principales des évènements du clavier:
code
– la propriété “key code” ("KeyA"
,"ArrowLeft"
ainsi de suite), spécifique à la position physique de la touche sur le clavier.key
– le caractère ("A"
,"a"
et ainsi de suite), pour les touches ne prenant pas en charge les caractères, telles que Esc, a souvent la même valeur quecode
.
Dans le passé, les évènements du clavier étaient des fois utilisés pour contrôler les entrées dans les champs de formulaires. Cela n’est pas fiable, parce que les données recueillies peuvent provenir de plusieurs sources. Nous avons les évènements input
et change
pour gérer toute entrée de donnée (traitée plus tard dans le chapitre Les événements: change, input, cut, copy, paste). Elles se déclenchent après toute sorte d’entrée, y compris le copier-coller oubien la reconnaissance vocale.
Nous devons utiliser les évènements du clavier quand nous voulons vraiment utiliser le clavier. Par exemple, pour réagir aux raccourcis ou touches spéciales.
Commentaires
<code>
, pour plusieurs lignes – enveloppez-les avec la balise<pre>
, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen…)