IT 개발자가 되기위한 여정

컴퓨터 공부를 시작함에 앞서 계획 및 개발에 대한 내용을 풀어나갈 생각입니다.

IT 학습/Problem Solving

[React + Native] 한글 입력 및 키보드 (천지인 키보드) 문제

제로시엘 2024. 7. 25. 14:27

문제 발생

Native (웹앱) 환경에서 빌드중인 웹의 입력기에서 일부 조건 혹은 일부 키보드 형태에 따라 몇가지 문제가 발생했다.

가장 처음의 문제는 천지인 키보드에서 발생했다.

 

문제가 되는건 ㆍ을 입력하는 것

 

문제 1. 자수 제한을 단순하게 걸었더니 천지인 키보드 사용시 문제

가장 심플한 예시로 예를 들어 천지인 키보드로 송을 입력하게 된다면

ㆍ =>  소 로 일시적으로 글자수가 한자 더 늘어나게 된다.

 

이 때 예를 들어 8자 (maxLength나 slice를 통한 강제 조작)을 하게 되는 경우 ㅅ에서 소로 넘어가지 않는 문제가 발생했다.

기존 코드는 다음과 같이 입력을 처리하는 방식이였다.

const changeValue = (e) => {
    const sliceValue = e.target.value.slice(0, maxLength);
    setValue(sliceValue);
  };

 

 

다음 문제는 react의 Composition을 조절하는 기능을 통해 수정할 수 있었다.

const handleCompositionStart = (e) => {
    if (e.target.value.length >= maxLength) {
      return;
    }

    setIsComposing(true);
  };

  const handleCompositionEnd = (e) => {
    setIsComposing(false);
    const inputValue = e.target.value;
    setValue(inputValue.slice(0, maxLength));
  };

  const handleChange = (e) => {
    let inputValue = e.target.value;
    if (!isComposing) {
      inputValue = e.target.value.slice(0, maxLength);
    }
    setValue(inputValue);
  };

// input의 경우
	<textarea
          type="text"
          value={value}
          onChange={handleChange}
          onCompositionStart={handleCompositionStart}
          onCompositionEnd={handleCompositionEnd}
	/>

 

글자가 조합되는 composing 시작 시점과 종료 시점을 컨트롤 하여 조합시에 슬라이스를 치는것이 아닌 문자 조합이 끝나는 시점에서 자수를 체크 및 slice를 치는 방식으로 변경하였다.

문제 2. 일부 자동완성 에서 자수제한이 먹지 않고 비정상적으로 보임

원래는 8자 제한이 되어야 한다

 

위의 문제를 해결하고나니 다음과 같이 조합중에는 따로 slice를 치지 않을뿐더러 일부 "삼성 키보드" 등에서 자동완성 기능이 무제한적으로 늘어나거나 2글짜식 입력되는 골때리는 현상이 발생하였다.

 

    // 포커스를 강제로 취소시키고 다시 설정
    if (inputValue.length >= maxLength) {
      textareaRef.current.setSelectionRange(maxLength, maxLength);
    }


<textarea
          ref={textareaRef}
          value={value}
          onInput={changeValue}
          onCompositionStart={handleCompositionStart}
          onCompositionEnd={handleCompositionEnd}
        />

 

위의 코드를 통해 강제적으로 포커스를 취소시키는 동작을 통해 자동완성이 자수제한을 넘기게 된다면 강제로 끊고 기존 로직에서 처리하도록 변경하였다.

 

 

문제 3. 더 골때리는 상황이 발생

강제로 포커스를 조절하다 보니 더 골때리는 상황이 발생했다. 가장 큰 문제는 리액트의 onCompositionEnd의 시점을 강제로 포커스를 끊거나 다시 활성화하면 제대로 가져오지 않는 현상이 발생하였다. 자동적으로 글자 조합이 끝난다면 정상적으로 handleCompositionEnd가 실행되지만 강제로 포커스 혹은 문자열을 조작하다 보면 해당 이벤트가 누락된 것


 

최종 수정 코드

// 글자 조합 완료
  const handleCompositionEnd = (e) => {
    // 조합이 완성되는 것은 일정 시간 후 해제되는 시점을 감지하여 maxLength를 넘는다면 조정
    setValue(e.target.value.slice(0, maxLength));
  };

  const handleChange = (e) => {
    let inputValue = e.target.value;

    // 천지인 포함 maxLength + 1 초과 혹은 천지인 미포함 maxLength가 초과한다면 인풋 및 글자 자동완성을 해제하고 30자로 조정후 리턴
    if (
      (inputValue.length > maxLength + 1 && inputValue.endsWith("ㆍ")) ||
      (inputValue.length > maxLength && !inputValue.endsWith("ㆍ"))
    ) {
      inputValue = inputValue.slice(0, maxLength);
    }

    setValue(inputValue);
  };

<textarea
          value={value}
          onChange={changeValue}
          onCompositionEnd={handleCompositionEnd}
        />

 

 

최종적으로는 onChange 시점에서 maxLength와 maxLength + 1 시점에 유동적으로 슬라이스 하며 (슬라이스 및 input값을 변경하면 컴포넌트가 재로드(setValue) 하면서 강제적으로 자동완성 또한 해제된다) 또한 내가 글자를 쓰다가 넘어갈 떄 이외에 자동완성 등을 통해 늘어나도 한번 더 slice를 통한 문자열을 재배치 함으로써 해결했다.