基礎

JavaScriptのキーボードイベント入門|keydown・keyup・keyの取得方法

JavaScriptのキーボードイベントは、ユーザーがキーボードのキーを押したり離したりしたときに発火するイベントです。ショートカットキーの実装、リアルタイム検索、ゲームの操作など、キーボード入力に応じた処理を行う際に使用します。

キーボードイベントには keydownkeyup、そして非推奨の keypress があります。この記事では、現在推奨されている keydownkeyup を中心に、イベントオブジェクトのプロパティや実践的な使い方を解説します。

基本的な使い方

keydown はキーを押した瞬間、keyup はキーを離した瞬間に発火します。押し続けると keydown は繰り返し発火しますが、keyup はキーを離したときに1回だけ発火します。

JavaScript
document.addEventListener('keydown', function(e) {
  console.log('キーが押されました:', e.key);
  console.log('キーコード:', e.code);
  console.log('繰り返し:', e.repeat);
});

document.addEventListener('keyup', function(e) {
  console.log('キーが離されました:', e.key);
});
実行結果
// "a" キーを押して離した場合
キーが押されました: a
キーコード: KeyA
繰り返し: false
キーが離されました: a

// Enter キーを押した場合
キーが押されました: Enter
キーコード: Enter
繰り返し: false

イベントオブジェクトの e.key は入力された文字("a", "Enter", "Shift" など)を返し、e.code は物理的なキーの位置("KeyA", "Enter", "ShiftLeft" など)を返します。日本語キーボードと英語キーボードで同じキーを押しても e.code は同じ値になるため、キー配置に依存する処理では e.code を使うのが適切です。

修飾キーの検出

Ctrl、Shift、Alt、Meta(Cmd)キーが同時に押されているかどうかは、イベントオブジェクトのプロパティで判定できます。ショートカットキーの実装に不可欠です。

JavaScript
document.addEventListener('keydown', function(e) {
  // Ctrl + S(保存ショートカット)
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault(); // ブラウザのデフォルト保存を防止
    console.log('保存処理を実行します');
    saveDocument();
  }

  // Ctrl + Shift + F(検索ショートカット)
  if (e.ctrlKey && e.shiftKey && e.key === 'F') {
    e.preventDefault();
    console.log('検索パネルを開きます');
    openSearchPanel();
  }

  // Escキーでモーダルを閉じる
  if (e.key === 'Escape') {
    console.log('モーダルを閉じます');
    closeModal();
  }
});

e.ctrlKeye.shiftKeye.altKeye.metaKey はそれぞれ対応する修飾キーが押されているときに true を返します。macOSでは e.metaKey がCommandキーに対応するため、クロスプラットフォーム対応では e.ctrlKey || e.metaKey のように判定するのが一般的です。

実践例:リアルタイム文字数カウンター

JavaScript
const textarea = document.querySelector('#message');
const counter = document.querySelector('#char-count');
const maxLength = 140;

textarea.addEventListener('keyup', function() {
  const currentLength = this.value.length;
  const remaining = maxLength - currentLength;
  counter.textContent = remaining + '文字残り';

  if (remaining < 0) {
    counter.style.color = 'red';
    counter.textContent = Math.abs(remaining) + '文字オーバー';
  } else if (remaining < 20) {
    counter.style.color = 'orange';
  } else {
    counter.style.color = '#666';
  }
});

// 特定キーの入力を制限する例(数字のみ許可)
const numberInput = document.querySelector('#phone');
numberInput.addEventListener('keydown', function(e) {
  // 数字、Backspace、Tab、矢印キーのみ許可
  const allowed = ['Backspace', 'Tab', 'ArrowLeft', 'ArrowRight', 'Delete'];
  if (!allowed.includes(e.key) && (e.key < '0' || e.key > '9')) {
    e.preventDefault();
  }
});
実行結果
// 5文字入力した場合
135文字残り

// 141文字入力した場合
1文字オーバー

文字数カウンターでは keyup を使うのがポイントです。keydown の時点ではまだ文字が入力されていないため、カウントが1文字分ずれてしまいます。

keypress は非推奨

keypress イベントは現在非推奨(deprecated)です。代わりに keydown を使いましょう。また、e.keyCodee.which も非推奨で、e.keye.code を使うのが現在の標準です。

IME入力(日本語変換)の注意点

日本語などのIME入力中は keydowne.key が "Process" になり、変換確定後にのみ実際の文字が取得できます。IME入力を正しく扱うには、compositionstartcompositionend イベントと組み合わせて、変換中は処理をスキップする仕組みが必要です。

まとめ

  • keydown はキーを押した瞬間に発火し、押し続けると繰り返し発火する
  • keyup はキーを離した瞬間に1回だけ発火する
  • e.key で入力文字、e.code で物理キー位置を取得できる
  • e.ctrlKeye.shiftKey などでショートカットキーを実装できる
  • keypress は非推奨なので keydown を使う
  • 日本語入力には compositionstart / compositionend の併用が必要