키보드 이벤트: keydown과 keyup의 활용

keydown과 keyup의 작동 방식

keydown

키를 누르는 순간 발생하며, 누르고 있는 동안에는 자동 반복(auto-repeat) 현상이 발생할 수 있습니다.

keyup

키에서 손을 뗄 때 발생합니다. 반복없이 단일 이벤트로 처리됩니다.

input 필드 내용 변경 추적

키보드 이벤트보다 input 이벤트로 추적해야 합니다. keydown/keyup은 물리적 키 동작만 감지하기 때문에 input 이벤트는 사용자가 마우스나 음성 인식, 붙여넣기 등으로 값을 변경할 경우도 모두 감지할 수 있기 때문입니다.

event.key와 event.code의 차이

event.key

실제 입력된 문자를 나타냅니다. 예를 들어, Shift를 누른 상태에서 "z"를 입력하면 event.key는 "Z"로 나타납니다. 사용자 언어 설정이나 현재 활성화된 키보드 레이아웃에 따라 값이 달라집니다.

event.code

물리적 키 위치에 대응하는 코드를 나타냅니다. 예를 들어, "KeyZ"는 항상 동일한 위치의 키를 의미하며, Shift 키 여부나 언어 설정에 상관없이 일정합니다.

자동 반복과 기본 동작 관리

자동 반복 감지

키를 길게 누르고 있으면 keydown 이벤트는 자동 반복되어 여러 번 발생합니다. 이를 구분하려면 이벤트 객체의 event.repeat 속성을 확인할 수 있습니다. event.repeat가 true면 키가 눌린 상태로 반복 중임을 의미합니다.

기본 동작 제어

event.preventDefault()로 브라우저의 기본 동작(스크롤, 페이지 차단, 입력, 단축키 실행 등)을 차단하지만 OS 단축키는 제어 불가합니다.

자동 반복 감지 후 속도 제어 예제

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>키보드 이벤트: 방향키 이동</title>
  <style>
    #box {
      width: 50px; height: 50px; background: #ffca28;
      position: absolute; top: 100px; left: 0; transition: left 0.1s;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <p>방향키(←, →)로 이동</p>
  <script>
    const box = document.getElementById('box');
    let position = 0;

    document.addEventListener('keydown', (e) => {
      const step = e.repeat ? 5 : 10; // 반복 시 속도 감소
      switch (e.code) {
        case 'ArrowLeft':
          position = Math.max(position - step, 0);
          box.style.left = `${position}px`;
          break;
        case 'ArrowRight':
          position = Math.min(position + step, window.innerWidth - box.offsetWidth);
          box.style.left = `${position}px`;
          break;
      }
    });
  </script>
</body>
</html>
  • e.code: 방향키 위치 판별
  • e.repeat: 방향키 길게 눌렀을 경우 이동 속도 조절

단축키로 모달 토글

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>키보드 이벤트: 단축키 모달</title>
  <style>
    #modal {
      display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
      width: 200px; padding: 20px; background: #fff; border: 1px solid #ccc; box-shadow: 0 2px 5px rgba(0,0,0,0.3);
    }
    #modal.active { display: block; }
  </style>
</head>
<body>
  <div id="modal">모달 창</div>
  <p>alt + M으로 모달 토글</p>
  <script>
    const modal = document.getElementById('modal');

    document.addEventListener('keydown', (e) => {
      if (e.altKey && e.code === 'KeyM' && !e.repeat) {
        e.preventDefault();
        modal.classList.toggle('active');
        console.log(`모달 상태: ${modal.classList.contains('active') ? '열림' : '닫힘'}`);
      }
    });
  </script>
</body>
</html>
  • keydown: alt + M 조합으로 모달 토글, e.repeat로 중복 방지