키오스크 프로그램을 개발하면서 한국어 타이핑이 가능한 가상 키보드를 구현해야 했다.
react-simple-keyboard라는 좋은 라이브러리가 있지만, 한글 받침입력이 안된다는 치명적인 오류가 있었다.
누군가가 react-simple-keyboard
라이브러리를 개선해서 한글 키보드 입력이 가능하게끔 수정한 라이브러리를 npm에 올려놨다. 이걸 사용해도 되긴 하겠지만 그래도 기왕 구현하는거 내가 직접 한글 입력이 가능하도록 수정해 보았다.
참고 : react-simple-keyboard의 데모가 전부 class형으로 구현되어 있어서 좀 해맸다. 🫠
npm i react-simple-keyboard
npm install hangul-js
CustomKeyboard.jsx
를 생성해주고, 그 안에서 react-simple-keyboard 라이브러리의 <Keyboard />
컴포넌트를 가져왔다.CustomKeyboard.jsx
import React from "react";
import Keyboard from "react-simple-keyboard";
import styled from "styled-components";
const CustomKeyboard = ({ text, setText }) => {
return (
<KeyboardWrapper>
<Keyboard />
</KeyboardWrapper>
);
};
const KeyboardWrapper = styled.div``;
export default CustomKeyboard;
이렇게 작성해주면...
오.. 이게뭐야~ CSS가 없어서이다. react-simple-keyboard에서는 기본적으로 제공해주는 CSS코드가 있다. import 해보자.import "react-simple-keyboard/build/css/index.css";
CSS가 잘 import 되었다.
이제 영문 자판을 한글 자판으로 바꿔보자.
react-simple-keyboard의 layout을 아래의 배열로 바꿔주면 된다.
koreanLayout.js
export const koreanLayout = {
default: [
"ㅂ ㅈ ㄷ ㄱ ㅅ ㅛ ㅕ ㅑ ㅐ ㅔ",
"ㅁ ㄴ ㅇ ㄹ ㅎ ㅗ ㅓ ㅏ ㅣ",
"{shift} ㅋ ㅌ ㅊ ㅍ ㅠ ㅜ ㅡ {pre}",
"{space} {dot} {enterText}",
],
shift: [
"ㅃ ㅉ ㄸ ㄲ ㅆ ㅛ ㅕ ㅑ ㅒ ㅖ",
"ㅁ ㄴ ㅇ ㄹ ㅎ ㅗ ㅓ ㅏ ㅣ",
"{shift} ㅋ ㅌ ㅊ ㅍ ㅠ ㅜ ㅡ {pre}",
"{space} {dot} {enterText}",
],
};
CustomKeyboard.jsx
import React from "react";
import Keyboard from "react-simple-keyboard";
import styled from "styled-components";
import "react-simple-keyboard/build/css/index.css";
import { koreanLayout } from "./koreanLayout";
const CustomKeyboard = ({ text, setText }) => {
return (
<KeyboardWrapper>
<Keyboard layout={{ ...koreanLayout }} />
</KeyboardWrapper>
);
};
const KeyboardWrapper = styled.div``;
export default CustomKeyboard;
layout 설정해주었더니 한글 자판이 잘 보인다.
이제 input 태그와 키보드를 연결해보자.
<CustomKeyboard />
에 input 태그의 state
, setState
를 인자로 주고,
CustomKeyboard.jsx
에서 <Keyboard />
의 onKeyPress
속성에 함수를 아래와 같이 설정한다.
App.jsx
...
function App() {
const [text, setText] = useState("");
return (
<PageContainer>
<CustomInput value={text} onChange={(e) => setText(e.target.value)} />
<CustomKeyboard text={text} setText={setText} />
</PageContainer>
);
}
CustomKeyboard.jsx
...
const CustomKeyboard = ({ text, setText }) => {
const onKeyPress = (key) => {
setText((prev) => prev + key);
};
return (
<KeyboardWrapper>
<Keyboard
layout={{ ...koreanLayout }}
onKeyPress={onKeyPress} />
</KeyboardWrapper>
);
};
onKeyPress에서 prev+key 만 해줬더니 {shift}, {dot}, {enterText}, {pre} 는 제대로 동작하지 않는다.
한글 외의 키를 눌렀을 때 처리도 해주겠다.
CustomKeyboard.jsx
const CustomKeyboard = ({ text, setText }) => {
const [layoutName, setLayoutName] = useState("default"); // default, shift
const onKeyPress = (key) => {
if (key === "{pre}") {
const res = text.slice(0, -1);
setText(res);
} else if (key === "{shift}") {
setLayoutName((prev) => (prev === "default" ? "shift" : "default"));
} else if (key === "{enterNum}" || key === "{enterText}") {
console.log("enter clicked!");
} else if (key === "{dot}") {
setText((prev) => prev + ".");
} else if (key === "{space}") {
setText((prev) => prev + " ");
} else {
setText((prev) => prev + key);
}
};
return (
<KeyboardWrapper>
<Keyboard
layoutName={layoutName}
layout={{ ...koreanLayout }}
onKeyPress={onKeyPress}
/>
</KeyboardWrapper>
);
};
특수 키를 눌렀을 때의 처리가 잘 되었다.
<Keyboard />
의 layoutName
속성에 'default'를 주면 koreanLayout
의 default
가 출력되고, shift
를 주면 koreanLayout
의 shift
가 출력된다.
자 이제 어떤 문제가 있냐하면
위와 같이 한글 키 조합이 안되는 문제가 생긴다.
이를 해결하기 위해 hangul-js
라이브러리를 사용한다.
CustomKeyboard.jsx
const CustomKeyboard = ({ text, setText }) => {
const [layoutName, setLayoutName] = useState("default"); // default, shift
const onKeyPress = (key) => {
if (key === "{pre}") {
const res = text.slice(0, -1);
setText(res);
} else if (key === "{shift}") {
setLayoutName((prev) => (prev === "default" ? "shift" : "default"));
} else if (key === "{enterNum}" || key === "{enterText}") {
console.log("enter clicked!");
} else if (key === "{dot}") {
setText((prev) => prev + ".");
} else if (key === "{space}") {
setText((prev) => prev + " ");
} else {
setText((prev) => hangul.assemble(hangul.disassemble(prev + key)));
}
};
return (
<KeyboardWrapper>
<Keyboard
layoutName={layoutName}
layout={{ ...koreanLayout }}
onKeyPress={onKeyPress}
/>
</KeyboardWrapper>
);
};
와우~ 한글 입력이 잘된다.
hangul-js의 assemble : ['ㅇ','ㅏ','ㄴ'] 와 같은 배열을 입력받아 '안'으로 바꿔준다.
hangul-js의 disassemble : '안'와 같은 문자열을 입력받아 ['ㅇ','ㅏ','ㄴ'] 와 같은 배열로 바꿔준다.
기존 hangul-js에서는 hangul.assemble()
에 prev + key 를 그대로 전달해줬기 때문에 받침이 입력되지 않았던 것이다.
(근데 window에서 개발할 때는 받침이 안되는 오류를 확인했었는데 mac에서는 disassemble 안써도 또 한글 받침이 잘 먹는다 ㅋㅋ 골때리네.)
이제 고치고 싶은게 또 있다. 바로 {dot}, {shift} ... 이런 디자인을 고치는 것.
CustomKeyboard.jsx
에서 <Keyboard />
컴포넌트에 display
속성을 다음과 같이 추가해준다.
CustomKeyboard.jsx
...
return (
<KeyboardWrapper>
<Keyboard
layoutName={layoutName}
layout={{ ...koreanLayout }}
onKeyPress={onKeyPress}
display={{
"{enterText}": "Enter",
"{shift}": "↑",
"{.}": ".",
"{space}": " ",
"{dot}": ".",
"{pre}": "←",
}}
/>
</KeyboardWrapper>
);
짠. 버튼 글자도 내가 원하는대로 커스텀했다.