JavaScript

[javascript]keypress, keydown, keyup 이벤트 차이

  • -
반응형

javascript에서 key 이벤트를 처리하다보면 비슷한 상황에서 3가지 이벤트가 존재한다. 알듯 말듯 미묘한 차이를 보이는 이녀석들에 대해서 살펴보자.

 

이벤트 비교

아래와 같이 간단한 화면을 만들고 동작을 테스트 해보자.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <input type="text" id="msg" placeholder="문자입력" />
  </body>
  <script>
    let target = document.querySelector("#msg");
    target.addEventListener("keypress", (e) => handleEvent("P", e));
    target.addEventListener("keydown", (e) => handleEvent("D", e));
    target.addEventListener("keyup", (e) => handleEvent("U", e));

    function handleEvent(type, e) {
      console.log(
        `type: ${type}: shift: ${e.shiftKey}, ctrl: ${e.ctrlKey}, 
                keycode: ${e.keyCode} , key: ${e.key}, 
                length: ${e.target.value.length}, isComposing: ${e.isComposing}`
      );
    }
  </script>
</html>

 

이벤트들의 관심사항

이름 대로 keyup은 키가 올라갔을 때 keydown은 키가 내려갔을 때,  keypress는 키가 눌렸을 때 발생한다. 그럼 keydown과 keypress는 같지 않을까? 

같아 보이지만 이 둘은 관심 사항이 다르다. keydown(keyup 포함)물리적으로 어떤 키가 눌렸는지에 관심이 있다. 하지만 keypress 실제로 어떤 값이 입력되는지에 대해 관심이 있다. 

그래서 shift 키만 눌렀을 때 실제로 입력되는 내용이 없기 때문에 keypress는 동작하지 않는다.

e.shiftKey나 e.ctrlKey는 KeyboardEvent가 발생했을 때 해당 키가 눌려있는지를 알려준다.  따라서 shift키가 up 된 상태에서 shiftKey 값은 false이다. ctrl과 shift를 동시에 누른 후 ctrl만 떼면 shift는 true이다.

 

위와 같은 특성에 따라  keydown/keyup은 'A'가 입력되는 상황과 'a' 가 입력되는 상황에 대해 동일한 keyCode를 반환한다. 키는 그냥 하나이기 때문이다. 하지만 keypress는  'a'가 입력될 때와 'A'가 입력될 때 keyCode가 다르다.

다음은 'a'를 입력했을 때 콘솔 출력 결과이다. a의 ascii code가 97임에도 불구하고 keydown과 keyup은 keycode가 65로 출력된다.

'A'를 입력했을 때는 다음과 같이 출력된다.

shift 키에 대한 감지는 keydown과 keyup에서만 발생했고 실제 데이터를 판단하는 keycode는 모두 65인 것을 확인할 수 있다.

 

keyCode는 deprecated

위와 같은 이유로 keyup과 keydown의 keyCode을 활용해서 판단하는 프로그램을 작성했다면 상당한 낭패를 볼수 있을 것이다. 그래서인지 keyCode는 이제 deprecated 되었다. 대신 key 속성을 사용하자.

KeyboardEvent의 key 속성은 언제나 방금 입력된 키에 대한 정보를 문자열 형태로 반환해주어 프로그래밍을 훨씬 쉽게 해준다. 예를 들어 기존에는 엔터키가 입력된 상황을 파악하기 위해 keyCode==13과 같은 형태로 작성했는데 이제 key=Enter 형태로 작성하면 된다. 

https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values

 

Key values for keyboard events - Web APIs | MDN

The tables below list the standard values for the KeyboardEvent.key property, with an explanation of what the key is typically used for. Corresponding virtual keycodes for common platforms are included where available.

developer.mozilla.org

 

keypress는 한글 처리 불가

keypress의 또다른 단점은 한글 처리가 불가하다는 점이다.

다음은 '마'가 입력되었을 때 이벤트 결과이다. keydown과 keyup은 동작하지만 keypress는 동작하지 않음을 알 수 있다. 입력 값은 자모단위로 처리된다.

따라서 입력 과정에서 특정 한글이 입력되었을 때 어떤 작업을 처리하고 싶다면 keypress는 안된다. 하지만 대부분 Enter 상황에서 무언가를 처리하는 경우가 많기 때문에 큰 상관은 없을것 같다.

 

데이터가 입력되는 시점 주의

위 이벤트들은 데이터가 input에 입력되는 시점도 다르다.

입력에 '1'을 입력해보자. 로그를 살펴보면 e.target.value.length를 통해서 input이 가지고 있는 데이터의 length를 출력해보았는데 keydown과 keypress는 아직 0이다. 즉 입력되지 않은 것이다. keyup에 가서야 비로서 1이 되었다.

따라서 입력된 글자의 수에 따라서 어떤 작업을 처리하기 위해서는 keyup이나 input 같은 이벤트를 활용해야 한다.

 

한글+enter 입력 시 중복 이벤트 발생 문제

값을 입력하고 엔터키를 입력했을때 어떤 동작을 처리하는 경우가 많은데 한글인 경우 문제가 발생할 수 있다.

일단 다음과 같이 '1'+엔터키를 입력해보자.

정상적으로 1에 대한 이벤트,  엔터에 대한 이벤트가 동작했다. 엔터키에 대한 이벤트는 down -> press -> up의 순으로 동작한것을 볼 수 있다.

다음은 'ㅁ'+엔터키를 입력해보자.

먼저 'ㅁ'에 대해서는 한글이므로 keypress는 동작하지 않았다. 하지만 엔터의 경우에는 down -> up -> down -> press -> up처럼 매우 복잡하게 처리되었다.

이로인해 keydown에서 엔터키를 처리하다보면 이벤트가 중복해서 발생하게 된다. 왜 이런 일이 발생했을까?

자세히 보면 중간에 isComposing 속성이 true인 경우(keycode = 229)가 있는데 이는 한글이 조합되는 과정에서 발생하는 키이다. 한글을 입력하다 보면 글자 아래 '_' 가 표시되는 경우가 있는데 이 과정이 바로 compose 과정이다.

한글 입력 처리 중 한글 입력 처리 완료 영문

 

정리하면 enter 키 처리keypress 이벤트를 사용한다면 중복없이 처리가 가능하다. 하지만 여러가지 이유로 keydown을 써야하는 경우는 isComposing속성이 false 인 상태에서만 처리하도록 하면 중복 없이 처리가 가능하다.

arget.addEventListener("keydown", (e) => {
  if (!e.isComposing) {
    handleEvent("D", e);
  }
});

 

반응형

'JavaScript' 카테고리의 다른 글

[새로운 기능] Optional Chaining  (0) 2023.05.02
[javascript] this - 2  (0) 2023.03.09
[새로운 기능] comma operator(쉼표연산자)  (0) 2022.11.14
[js] dispatchEvent  (0) 2022.09.29
[새로운 기능] fetch API  (0) 2022.07.01
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.