{"id":51500030,"url":"https://github.com/devslab-kr/kokey","last_synced_at":"2026-07-07T17:01:47.896Z","repository":{"id":369472859,"uuid":"1289973603","full_name":"devslab-kr/kokey","owner":"devslab-kr","description":"Korean ↔ English keyboard layout converter (두벌식 ↔ QWERTY) — TypeScript, zero-dep, ESM/CJS","archived":false,"fork":false,"pushed_at":"2026-07-05T13:54:43.000Z","size":83,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-05T15:07:03.798Z","etag":null,"topics":["converter","dubeolsik","hangul","hangul-converter","ime","keyboard-layout","korean","qwerty","typescript"],"latest_commit_sha":null,"homepage":"https://devslab-kr.github.io/kokey/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devslab-kr.png","metadata":{"files":{"readme":"README.ko.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://devslab.kr"]}},"created_at":"2026-07-05T12:37:53.000Z","updated_at":"2026-07-05T13:50:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/devslab-kr/kokey","commit_stats":null,"previous_names":["devslab-kr/kokey"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/devslab-kr/kokey","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devslab-kr%2Fkokey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devslab-kr%2Fkokey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devslab-kr%2Fkokey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devslab-kr%2Fkokey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devslab-kr","download_url":"https://codeload.github.com/devslab-kr/kokey/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devslab-kr%2Fkokey/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35235818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["converter","dubeolsik","hangul","hangul-converter","ime","keyboard-layout","korean","qwerty","typescript"],"created_at":"2026-07-07T17:01:47.043Z","updated_at":"2026-07-07T17:01:47.889Z","avatar_url":"https://github.com/devslab-kr.png","language":"TypeScript","funding_links":["https://devslab.kr"],"categories":[],"sub_categories":[],"readme":"# kokey\n\n[![npm](https://img.shields.io/npm/v/%40devslab%2Fkokey)](https://www.npmjs.com/package/@devslab/kokey)\n[![CI](https://github.com/devslab-kr/kokey/actions/workflows/ci.yml/badge.svg)](https://github.com/devslab-kr/kokey/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/%40devslab%2Fkokey)](./LICENSE)\n\n자판 오입력 복원 라이브러리 — 잘못된 자판으로 친 텍스트를 되돌립니다.\n한국어(두벌식 ↔ QWERTY) 기본 내장, 러시아어·우크라이나어·히브리어·그리스어·\n태국어·아랍어·조지아어는 서브패스 import (tree-shaking 지원).\nTypeScript-first, **zero-dependency**, ESM/CJS 듀얼 패키지.\n\n[English](./README.md) · **한국어** · [Русский](./README.ru.md) · [Українська](./README.uk.md) · [עברית](./README.he.md) · [Ελληνικά](./README.el.md) · [ไทย](./README.th.md) · [العربية](./README.ar.md) · [ქართული](./README.ka.md) · [라이브 데모](https://devslab-kr.github.io/kokey/)\n\n`안녕`을 치려다 `dkssud`를 쳐본 적, 한글 IME가 켜진 채 바코드를 스캔해서\n`DSATY2068601` 대신 `ㅇㄴㅁ쇼2068601`이 들어온 적 있다면 — `kokey`가\n\"입력된 것\"과 \"의도한 것\" 사이를 양방향으로 변환합니다. 실제 두벌식 IME의\n조합 규칙 그대로.\n\n같은 실수는 비라틴 자판을 QWERTY와 토글하는 모든 언어권에 존재합니다.\n러시아 사람은 `привет` 대신 `ghbdtn`을, 이스라엘 사람은 `שלום` 대신\n`akuo`를 칩니다. `kokey`는 그 자판들도 지원합니다 —\n[한국어 너머](#한국어-너머--등록된-모든-자판) 참고.\n\n## 설치\n\n```sh\nnpm install @devslab/kokey\n```\n\nCDN으로 빌드 없이 바로 — 전부 `kokey` 전역 아래에 노출됩니다:\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@devslab/kokey/dist/kokey.global.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  kokey.enToKo('dkssud')   // '안녕'\n  kokey.toEn('привет안녕')  // 'ghbdtndkssud' — CDN 빌드에는 전 자판 내장\n  kokey.observe()          // \u003cinput data-kokey\u003e / \u003cinput data-hangul\u003e 자동 바인딩\n\u003c/script\u003e\n```\n\n## 사용법\n\n```ts\nimport { koToEn, enToKo } from '@devslab/kokey'\n\n// 한글 → 그 한글을 만든 QWERTY 키 시퀀스\nkoToEn('안녕')            // 'dkssud'\nkoToEn('값없는 닭갈비')     // 'rkqtdjqtsms ekfrrkfql'\nkoToEn('ㅇㄴㅁ쇼2068601')  // 'dsaty2068601' (스캐너 웨지 입력 복원)\n\n// QWERTY 키 시퀀스 → 조합된 한글 (IME 오토마타 완전 구현)\nenToKo('dkssud')          // '안녕'\nenToKo('gksrmf')          // '한글'\nenToKo('ekfrl')           // '달기' (겹받침 분해 — 실제 IME와 동일)\n```\n\n### 디테일\n\n- **Shift 구분**: `R` → ㄲ, `r` → ㄱ, `koToEn('뛰다') === 'Enlek'`\n- **겹모음/겹받침**: ㅘ ↔ `hk`, ㄵ ↔ `sw`, …\n- **받침 넘김**: `enToKo('dkswk') === '안자'`\n- **통과 처리**: 숫자·문장부호·미매핑 문자는 그대로 유지\n- 한글 텍스트 왕복 보장: `enToKo(koToEn(s)) === s`\n\n### 한국어 너머 — 등록된 모든 자판\n\n자판별 모듈은 서브패스 import라 안 쓰는 자판은 번들에 들어가지 않고,\n전부 같은 엔진에 연결됩니다:\n\n```ts\nimport { register, toEn, fromEn } from '@devslab/kokey'\nimport { ru, ruToEn, enToRu } from '@devslab/kokey/ru'\nimport { he } from '@devslab/kokey/he'\n\n// 자판별 직접 변환\nruToEn('привет')   // 'ghbdtn'  — Punto Switcher의 그 사례\nenToRu('ghbdtn')   // 'привет'\n\n// register 후 스크립트 자동 감지 — 혼합 문자열도 OK\nregister(ru, he)\ntoEn('안녕 привет שלום')  // 'dkssud ghbdtn akuo'\nfromEn('ghbdtn', 'ru')    // 'привет'\n```\n\n| 자판 | import | 비고 |\n| --- | --- | --- |\n| 한국어 두벌식 | 기본 내장 (`ko`) | IME 조합 오토마타 완전 구현 |\n| 러시아어 ЙЦУКЕН | `@devslab/kokey/ru` | 이동된 문장부호(백틱의 ё, №, `/`의 `.`)까지 충실 매핑 |\n| 우크라이나어 Enhanced | `@devslab/kokey/uk` | і/є/ї, AltGr 전용 ґ는 역방향 복원, ru/uk 자동 판별 |\n| 히브리어 | `@devslab/kokey/he` | 어말형 문자, 괄호 스왑, Caps Lock 안전 |\n| 그리스어 | `@devslab/kokey/el` | tonos/dialytika dead key (`;a` → ά), 어말 시그마 |\n| 태국어 Kedmanee | `@devslab/kokey/th` | 숫자행까지 전면 재배치 — 태국어 바코드 복원 가능 |\n| 아랍어 (101) | `@devslab/kokey/ar` | `b` 키의 lam-alef لا, hamza 형태, tashkeel |\n| 조지아어 QWERTY | `@devslab/kokey/ka` | 거의 음성적 배열 (`gamarjoba` ↔ გამარჯობა) |\n\nIME에 후보 선택 단계가 있는 언어(중국어 병음, 일본어 한자)는 키 입력 ↔\n텍스트 관계가 결정적이지 않아 원리적으로 지원 대상이 아닙니다. 다른\n결정적 자판이 필요하다면 `defineLayout({ id, script, fromKey })` 테이블\n하나면 됩니다 — [PR 환영](https://github.com/devslab-kr/kokey/pulls).\n\n### DOM 레이어 — 입력 모드 강제\n\n사용자 IME 상태와 무관하게 `\u003cinput\u003e`/`\u003ctextarea\u003e`를 특정 모드로 고정합니다 —\n타이핑하는 대로 변환되고, IME 조합 중엔 건드리지 않으며, 커서가 보존됩니다:\n\n```html\n\u003cinput data-kokey=\"ko\"\u003e   \u003c!-- 영타가 한글로 조합됨 --\u003e\n\u003cinput data-kokey=\"ru\"\u003e   \u003c!-- 영타가 러시아어로 (register(ru) 필요) --\u003e\n\u003cinput data-kokey=\"en\"\u003e   \u003c!-- 등록된 어떤 스크립트든 QWERTY로 복원 --\u003e\n\u003cinput data-hangul=\"ko\"\u003e  \u003c!-- 기존 속성도 계속 동작 --\u003e\n```\n\n```ts\nimport { bind, observe } from '@devslab/kokey'\n\nobserve()                     // [data-kokey]/[data-hangul] 전부 바인딩 + 감시\nconst unbind = bind(el, 'en') // 개별 엘리먼트 명시 바인딩\n```\n\n`data-kokey=\"en\"`은 송장번호/이메일/아이디 필드에 특히 유용합니다 —\n사용자가 한국어든 러시아어든 태국어든 어떤 자판을 켜두고 쳐도 필드가\n알아서 라틴으로 복원되므로 언어별 분기가 필요 없습니다.\n\n### Vue / React\n\n일반(비제어) 인풋에는 디렉티브/훅을:\n\n```vue\n\u003cscript setup\u003e\nimport { vKokey } from '@devslab/kokey/vue'\n\u003c/script\u003e\n\u003ctemplate\u003e\n  \u003cinput v-kokey=\"'ko'\"\u003e\n  \u003cinput v-kokey=\"'ru'\"\u003e\n\u003c/template\u003e\n```\n\n```tsx\nimport { useKokey } from '@devslab/kokey/react'\n\nfunction Field() {\n  return \u003cinput ref={useKokey('en')} /\u003e\n}\n```\n\n`v-model` / controlled 인풋에는 `KokeyInput` 컴포넌트를 쓰세요 — 변환이\n**프레임워크 데이터 플로우 안에서** 일어나므로 바인딩된 상태가 항상 변환된\n값을 갖습니다 (ref 방식은 프레임워크가 값을 읽은 뒤 DOM을 바꾸는 구조라\n`v-model`/`value=`와 충돌할 수 있음):\n\n```vue\n\u003cscript setup\u003e\nimport { KokeyInput } from '@devslab/kokey/vue'\nconst name = ref('')\n\u003c/script\u003e\n\u003ctemplate\u003e\n  \u003cKokeyInput v-model=\"name\" mode=\"ko\" /\u003e\n  \u003cKokeyInput v-model=\"memo\" mode=\"en\" as=\"textarea\" /\u003e\n\u003c/template\u003e\n```\n\n```tsx\nimport { KokeyInput } from '@devslab/kokey/react'\n\nfunction Form() {\n  const [v, setV] = useState('')\n  return \u003cKokeyInput mode=\"en\" value={v} onChange={(e) =\u003e setV(e.target.value)} /\u003e\n}\n```\n\n전부 DOM 레이어의 얇은 래퍼입니다 — `vue`/`react`는 optional peer dependency라\n코어는 여전히 zero-dependency. 기존 `vHangul` / `useHangul` 이름도 유지됩니다.\n\n## API\n\n| 함수 | 시그니처 | 설명 |\n| --- | --- | --- |\n| `koToEn` | `(text: string) =\u003e string` | 한글 음절/자모를 두벌식 QWERTY 키 시퀀스로 분해 |\n| `enToKo` | `(text: string) =\u003e string` | QWERTY 키 시퀀스를 표준 IME 오토마타로 한글 조합 |\n| `toEn` | `(text: string) =\u003e string` | 등록된 모든 스크립트를 자동 감지해 QWERTY로 복원 |\n| `fromEn` | `(text, layoutId) =\u003e string` | QWERTY 키 시퀀스를 지정 자판의 텍스트로 조합 |\n| `register` | `(...layouts) =\u003e void` | `toEn`·DOM `data-kokey` 모드에 자판 등록 |\n| `defineLayout` | `(def) =\u003e Layout` | 테이블 기반 자판 정의 (`{ id, script, fromKey }`) |\n| `bind` | `(el, mode?) =\u003e unbind` | 인풋 하나에 모드 강제 (mode 생략 시 `data-kokey`/`data-hangul` 속성값) |\n| `observe` | `(root?) =\u003e stop` | `root` 아래 `[data-kokey]`/`[data-hangul]` 전부 바인딩 + MutationObserver로 감시 |\n| `createRefBinder` | `(mode?) =\u003e (el \\| null) =\u003e void` | 프레임워크 무관 ref 콜백 팩토리 (`useKokey`의 코어) |\n| `vKokey` | `@devslab/kokey/vue` | Vue 3 디렉티브: `v-kokey=\"'ko'\"` (기존 `vHangul` 유지) |\n| `KokeyInput` | `@devslab/kokey/vue` · `/react` | `v-model` / controlled 인풋용 컴포넌트 (`mode`, `as=\"input\\|textarea\"`) |\n| `useKokey` | `@devslab/kokey/react` | ref 콜백을 반환하는 React 훅 (기존 `useHangul` 유지) |\n| `convert` | `(text, mode) =\u003e string` | 모드 단발 변환 (`'en'` 또는 자판 id) |\n| `applyToInput` | `(el, mode) =\u003e boolean` | 인풋 값을 커서 보존하며 제자리 변환 |\n\n자판별 모듈은 직접 변환 함수도 export 합니다: `ruToEn`/`enToRu`,\n`heToEn`/`enToHe`, `thToEn`/`enToTh`, … 저수준 한국어 테이블(`CHOSUNG`,\n`JUNGSUNG`, `JONGSUNG`, `JAMO_TO_KEY`, `KEY_TO_JAMO`)도 export 됩니다.\n\n## 로드맵\n\n- ~~`v0.2` — DOM 레이어~~ ✅ 출시됨\n- ~~`v0.3` — Vue 디렉티브 / React 훅~~ ✅ 출시됨\n- ~~`v0.4` — 다국어 자판: ru/uk/he/el/th/ar/ka + `toEn` 자동 감지~~ ✅ 출시됨\n\n## inko가 아닌 이유\n\n[inko](https://github.com/738/inko)가 이 영역을 개척했지만 2019년 이후\n유지보수가 멈췄고 현대 TypeScript/ESM 패키징 이전 세대입니다. `kokey`는\n처음부터 다시 구현했습니다: 타입 지원, tree-shaking, ESM/CJS 듀얼,\n실제 IME 동작(겹받침, 받침 넘김, Shift 처리) 기준 테스트.\n\n## 라이선스\n\n[MIT](./LICENSE) © devslab\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevslab-kr%2Fkokey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevslab-kr%2Fkokey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevslab-kr%2Fkokey/lists"}