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에서 키보드 인식 모드가 한글 -> 일반으로 변환이 즉각적으로 안되는 듯 합니다.
댓글