이름 대로 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 형태로 작성하면 된다.
다음은 '마'가 입력되었을 때 이벤트 결과이다. 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 인 상태에서만 처리하도록 하면 중복 없이 처리가 가능하다.