본문 바로가기
Flutter/Flutter FAQ

Flutter Web TextField 한글 입력 오류, 띄어쓰기, 숫자, 특수문자 오류

by 베타코드 2021. 12. 20.
반응형

flutter web에서 textfield를 이용하다 보면 한글 입력 중에 띄어쓰기, 숫자, 특수문자를 입력할 때 정상적으로 입력이 안 되는 경우를 볼 수 있다. 특히 한글 입력 중에 빠르게 숫자, 띄어쓰기, 특수문자를 입력할 때 발생한다.

 

한국인이 우리에겐 굉장히 심각한 버그이지만 flutter 측에서는 아직 업데이트 계획이 없다고 합니다. 아래의 코드는 완벽한 해결책은 아니지만 우회하는 방식으로 어떻게든 작동하는 방법입니다.

 

SPEC
Flutter 2.5.3
Dart 2.14.4

 

final textController = TextEditingController();
List undetected_list = [" ", "`", "~", "!", "@", "#", "\$", "%", "^", "&", "*", 
	"(", ")", "-", "_", "=", "+", "[", "]", "{", "}", "'", '"', ";", ":", "/", "?", 
    ",", ".", "<", ">", "\\", "|", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
List numberPad_list = ["Numpad Decimal", "Numpad Divide", "Numpad Multiply", 
	"Numpad Subtract", "Numpad Add", "Numpad 0", "Numpad 1", "Numpad 2", "Numpad 3", 
    "Numpad 4", "Numpad 5", "Numpad 6", "Numpad 7", "Numpad 8", "Numpad 9"];
List numerPad_convert = [".", "/", "*", "-", "+", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];

일단 위와 같은 설정이 필수적으로 필요하다.

 

RawKeyboardListener(
        focusNode: FocusNode(),
        onKey: (RawKeyEvent event) async {  
          if (event.runtimeType == RawKeyDownEvent) {
            String keydownText = event.data.logicalKey.keyLabel; 
            int cursorPosition = textController.selection.baseOffset; 
            if (numberPad_list.contains(keydownText)) { 
              keydownText = numerPad_convert[numberPad_list.indexOf(keydownText)]; 
            }
            if (undetected_list.contains(keydownText)) {               
              await Future.delayed(Duration(milliseconds: 10));
              List text_list = textController.text.split(""); 
              try { 
                if (text_list[cursorPosition] != keydownText) { 
                  text_list.insert(cursorPosition, keydownText); 
                  textController.text = text_list.join(); 
                  textController.selection = TextSelection.fromPosition(TextPosition(offset: cursorPosition+1)); 
                }
              } catch (e) {
                if (text_list[textController.text.length-1] != keydownText) { 
                  textController.text = textController.text + keydownText; 
                  textController.selection = TextSelection.fromPosition(TextPosition(offset: textController.text.length)); 
                }
              }
            }
          }
        },
        child: TextField(
          controller: textController,
        ),
      )

 

 

하나하나 설명해드리자면

if (event.runtimeType == RawKeyDownEvent) {

event 자체가 키보드 다운과 업 2개가 있으니깐 하나만 처리하기 위해서.

String keydownText = event.data.logicalKey.keyLabel; //키보드 인풋 캐치

입력된 키보드를 명명합니다.

 

int cursorPosition = textController.selection.baseOffset; // 인풋 커서 위치 캐치

커서 위치는 한글 중간에 띄어쓰기, 숫자, 특수문자를 입력할 때를 위해 필요합니다.

 

if (numberPad_list.contains(keydownText)) { // 넘버패드 인풋인지 확인
  keydownText = numerPad_convert[numberPad_list.indexOf(keydownText)]; // 넘버패드 인풋 라벨을 보통 키보드 인풋 라벨로 변경
}

넘버 패드들은 일반 키보드와 keyLabel이 달라서 따로 처리했습니다.

 

if (undetected_list.contains(keydownText)) { // 인풋이 인식 안되는 숫자 및 특수문자 인지 확인

입력된 키보드가 인식이 안되는 문자 중에 하나인지 확인합니다.

 

await Future.delayed(Duration(milliseconds: 10));

위에서 잠시 대기하는 이유는 코드 진행 중 List text_list = textController.text.split(""); 로 textController.text를 받아오는데 정상적인 띄어쓰기, 숫자, 특수문자 입력은 정상적으로 추가되었을 것이기 때문에 정상적으로 추가 안된 경우를 판단하기 위해서 잠시 대기 하는 겁니다.

 

List text_list = textController.text.split(""); // 전체 텍스트를 리스트로

띄어쓰기, 숫자, 특수문자가 정상적으로 입력되었는지 확인하고 위해서 텍스트 전체를 리스트로 바꿉니다. 

 

try {

try는 글 끝에 띄어쓰기, 숫자, 특수문자를 추가할 때 text_list[cursorPosition]가 index 오류 나서 사용했습니다.

 

if (text_list[cursorPosition] != keydownText) {
  text_list.insert(cursorPosition, keydownText); 
  textController.text = text_list.join();  
  textController.selection = TextSelection.fromPosition(TextPosition(offset: cursorPosition+1)); 
}

if 문 조건은 입력된 문자가 커서 위치의 문자와 동일한지 확인하는 기능입니다. 그 이유는 위에서 대기 했던 이유와 같습니다. 만약 정상적으로 띄어쓰기, 숫자, 특수문자가 입력되었다면 커서의 위치와 입력한 문자가 동일할 것이기 때문입니다. text_list.insert(cursorPosition, keydownText);는 커서 위치에 맞게 리스트에 입려된 문자를 삽입하는 코드 입니다. 

 

textController.selection = TextSelection.fromPosition(TextPosition(offset: cursorPosition+1));

마지막이 중요한데 커서 위치 설정하는 코드 입니다. 안하면 맨 앞으로 커서가 이동해서 이상하게 됩니다.

 

if (text_list[textController.text.length-1] != keydownText) {
  textController.text = textController.text + keydownText; 
  textController.selection = TextSelection.fromPosition(TextPosition(offset: textController.text.length));
}

위 코드는 문장 마지막에 띄어쓰기, 숫자, 키보드를 입력할 때 사용됩니다. 이해하기 어렵지는 않을 것 같습니다.

 

도움이 되셨다면 좋겠습니다. flutter textfield에서 작업 중 위 오류를 발견하고 구글링을 오래 했는데, 공식 답변이 바로 업데이트할 계획이 없다고 나와서 제가 나름대로 우회 방식으로 해결해보았습니다.

 

print(event)를 해보면 인식 안되는 띄어쓰기, 숫자, 특수문자는 "debugName: Key with ID~~" 와 "debugName: Digit 1" 이런 식으로  2번 인식되지만 입력은 안됩니다.

한글 작성 후 조금 쉬고 숫자 및 특수문자 입력하면 debugName: "Digit 2" 이런식으로 1번만 정상 인식 하고 입력 됩니다.

일반 한글은  debugName: "Key with ID~~"로 정상 인식 및 입력 됩니다.

 

즉, 한글 입력 중 숫자 및 특수문자를 입력하면 flutter에서 키보드 인식 모드가 한글 -> 일반으로 변환이 즉각적으로 안되는 듯 합니다.

반응형

댓글