키보드 이벤트에서 한글 입력 버그가 발생하는 이유

정하승정하승
2 min read

그로윗 프로젝트에서 해시태그를 넣는 기능을 구현하면서 keydown 이벤트 핸들러를 통해 처리하도록 했는데, 이상한 버그를 겪게 됐다. 그래서 이번 글에서는 이 같은 버그가 왜 일어났고 어떻게 해결하면 되는지 적어보고자 한다.

버그 현상

위 이미지처럼 ‘하나둘셋’ 을 입력하면 ‘하나둘셋’과 마지막 글자인 셋이 같이 입력되고 있었고, 마지막 글자에 밑줄이 나타나고 있었다. 그러나 영어에서는 밑줄 현상이 나타나지 않고 있어서 한글만의 문제일거라 생각했다.

원인 분석

const handleHashtagSubmit = (e: KeyboardEvent<HTMLInputElement>) => {
        if (e.key === 'Enter') {}
};

키보드의 keydown 이벤트가 발생했을 때, 이벤트 객체가 어떤 값으로 나오는지 확인해보면 다음과 같이 두번이 나온다.

이 현상은 IME(Input Method Editor) 때문에 발생하는 문제였다. 영어를 제외한 한국어, 중국어, 일본어 등의 입력에서만 발생하는 이슈라고 한다.

그래서 왜 두 번이 나올까?

한글 입력 시 이벤트가 두 번 발생하는 원인은 한글의 조합 방식과 브라우저 이벤트 처리 순서 때문이다.

Keyboard events cannot be used to determine the current state of the input method editor.

Keyboard events correspond to the events generated by the input device after the keyboard layout mapping but before the processing of the input method editor.

즉 키보드 이벤트만으로는 IME의 현재 상태를 알 수 없다는 뜻이다.

IME에서는 compositionstart, compositionupdate, compositionend 같은 이벤트를 통해서만 파악할 수 있다.

https://developer.mozilla.org/en-US/play?id=6Q8ZjOb4BTzBv7BGabN7RGpeS1YZqjeIMMa5GoecZBUcv36bcLZscSENwYe%2FgCJLFpnUG%2FqQ1LtUd7N3

한글 ‘가’를 입력한다고 할 때, 발생하는 흐름 대략 다음과 같다.

compositionstart
compositionupdate
keydown (한글 조합 중)
compositionupdate
keydown (조합 완료)
compositionend

이처럼 한글 입력에 대해서는 조합 중에도 keydown 이벤트가 계속해서 발생하고 조합이 다 끝나고 엔터키 입력 후에도 추가적으로 발생한다.

즉, keydown 이벤트만으로는 현재 입력 상태(조합 중/완료)를 확실히 알 수 없기 때문에 버그가 발생한 것이다.

해결 방법 1 : keypress 이벤트 활용

keydown 이벤트 대신 keypress를 활용하면 해결이 되긴 하지만 공식 문서에서도 deprecated된 상태라 권장하지 않는 방법이었고, 다른 방법을 생각해야 했다.

해결 방법 2 : isComposing 활용

const handleHashtagSubmit = (e: KeyboardEvent<HTMLInputElement>) => {
        if (e.key === 'Enter') {
            // 해시태그 처리        
        }    
};

KeyboardEvent 안에 있는 isComposing을 활용하면 된다. 이 속성은 compositionstart, compositionend 등의 이벤트에 따라 조합 중일 때는 true, 조합이 끝나면 false로 바뀐다.

React에서의 KeyboardEvent는 nativeEvent를 래핑한 SyntheticEvent(합성 이벤트)이기 때문에 event.nativeEvent.isComposing 으로 접근해야 한다.

이제 엔터키 입력이 된 상태 && isComposing이 false일때만 처리하면, 한글 입력 중에는 이벤트가 무시되어 엔터 키 입력 후에도 정상적으로 동작한다.

const handleHashtagSubmit = (e: KeyboardEvent<HTMLInputElement>) => {
        if (e.key === 'Enter' && !e.nativeEvent.isComposing) {
            // 해시태그 처리
        }
};

한글 등 IME 입력이 필요한 환경에서는 항상 isComposing 속성을 체크해서 처리해야, 예상치 못한 버그를 해결할 수 있다.

Reference

https://developer.mozilla.org/ko/docs/Web/API/KeyboardEvent/isComposing

https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/keyset.html

https://velog.io/@gustjq4146/keyDown-keyUp-%EC%9D%B4%EB%B2%A4%ED%8A%B8-2%EB%B2%88-%EC%8B%A4%ED%96%89

0
Subscribe to my newsletter

Read articles from 정하승 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

정하승
정하승